Merge branch 'master' into upstream-master

Conflicts:
	mediagoblin/templates/mediagoblin/base.html
	mediagoblin/templates/mediagoblin/user_pages/user.html
This commit is contained in:
Sebastian Spaeth
2013-12-12 16:24:34 +01:00
118 changed files with 4314 additions and 5 deletions

View File

@@ -0,0 +1,121 @@
#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 os
import logging
_log = logging.getLogger(__name__)
from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.blog.models import Blog, BlogPostData
from mediagoblin.tools import pluginapi
PLUGIN_DIR = os.path.dirname(__file__)
MEDIA_TYPE = 'mediagoblin.media_types.blogpost'
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
_log.info("setting up blog media type plugin.")
routes = [
#blog_create
('mediagoblin.media_types.blog.create',
'/u/<string:user>/b/create/',
'mediagoblin.media_types.blog.views:blog_edit'
),
#blog_edit
('mediagoblin.media_types.blog.edit',
'/u/<string:user>/b/<string:blog_slug>/edit/',
'mediagoblin.media_types.blog.views:blog_edit'
),
#blog post create
('mediagoblin.media_types.blog.blogpost.create',
'/u/<string:user>/b/<string:blog_slug>/p/create/',
'mediagoblin.media_types.blog.views:blogpost_create'
),
#blog post edit
('mediagoblin.media_types.blog.blogpost.edit',
'/u/<string:user>/b/<string:blog_slug>/p/<string:blog_post_slug>/edit/',
'mediagoblin.media_types.blog.views:blogpost_edit'
),
#blog collection dashboard in case of multiple blogs
('mediagoblin.media_types.blog.blog_admin_dashboard',
'/u/<string:user>/b/dashboard/',
'mediagoblin.media_types.blog.views:blog_dashboard'
),
#blog dashboard
('mediagoblin.media_types.blog.blog-dashboard',
'/u/<string:user>/b/<string:blog_slug>/dashboard/',
'mediagoblin.media_types.blog.views:blog_dashboard'
),
#blog post listing view
('mediagoblin.media_types.blog.blog_post_listing',
'/u/<string:user>/b/<string:blog_slug>/',
'mediagoblin.media_types.blog.views:blog_post_listing'
),
#blog post draft view
('mediagoblin.media_types.blog.blogpost_draft_view',
'/u/<string:user>/b/<string:blog_slug>/p/<string:blog_post_slug>/draft/',
'mediagoblin.media_types.blog.views:draft_view'
),
#blog delete view
('mediagoblin.media_types.blog.blog_delete',
'/u/<string:user>/b/<string:blog_slug>/delete/',
'mediagoblin.media_types.blog.views:blog_delete'
),
# blog about view
('mediagoblin.media_types.blog.blog_about',
'/u/<string:user>/b/<string:blog_slug>/about/',
'mediagoblin.media_types.blog.views:blog_about_view'
)]
pluginapi.register_routes(routes)
pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates'))
pluginapi.register_template_hooks({"user_profile": "mediagoblin/blog/url_to_blogs_dashboard.html",
"blog_dashboard_home": "mediagoblin/blog/url_to_blogging.html",
"create_blog_home": "mediagoblin/blog/url_to_create_blog.html",
})
class BlogPostMediaManager(MediaManagerBase):
human_readable = "Blog Post"
display_template = "mediagoblin/media_displays/blogpost.html"
default_thumb = "images/media_thumbs/blogpost.jpg"
def get_blog_by_blogpost(self):
blog_post_data = BlogPostData.query.filter_by(media_entry=self.entry.id).first()
blog = Blog.query.filter_by(id=blog_post_data.blog).first()
return blog
def add_to_user_home_context(context):
blogs = context['request'].db.Blog.query.filter_by(author=context['user'].id)
if blogs:
context['blogs'] = blogs
else:
context['blogs'] = None
return context
hooks = {
'setup': setup_plugin,
('media_manager', MEDIA_TYPE): lambda: BlogPostMediaManager,
# Inject blog context on user profile page
("mediagoblin.user_pages.user_home",
"mediagoblin/user_pages/user.html"): add_to_user_home_context
}

View File

@@ -0,0 +1,2 @@
[plugin_spec]
max_blog_count = integer(default=4)

View File

@@ -0,0 +1,46 @@
# 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 wtforms
from mediagoblin.tools.text import tag_length_validator, TOO_LONG_TAG_WARNING
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from mediagoblin.tools.licenses import licenses_as_choices
class BlogPostEditForm(wtforms.Form):
title = wtforms.TextField(_('Title'),
[wtforms.validators.Length(min=0, max=500)])
description = wtforms.TextAreaField(_('Description'))
tags = wtforms.TextField(_('Tags'), [tag_length_validator],
description="Seperate tags by commas.")
license = wtforms.SelectField(_('License'),
[wtforms.validators.Optional(),], choices=licenses_as_choices())
class BlogEditForm(wtforms.Form):
title = wtforms.TextField(_('Title'),
[wtforms.validators.Length(min=0, max=500)])
description = wtforms.TextAreaField(_('Description'))
class ConfirmDeleteForm(wtforms.Form):
confirm = wtforms.BooleanField(
_('I am sure I want to delete this'))

View File

@@ -0,0 +1,49 @@
# 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/>.
def check_blog_slug_used(author_id, slug, ignore_b_id=None):
from mediagoblin.media_types.blog.models import Blog
query = Blog.query.filter_by(author=author_id, slug=slug)
if ignore_b_id:
query = query.filter(Blog.id != ignore_b_id)
does_exist = query.first() is not None
return does_exist
def may_edit_blogpost(request, blog):
if request.user.is_admin or request.user.id == blog.author:
return True
return False
def set_blogpost_state(request, blogpost):
if request.form['status'] == 'Publish':
blogpost.state = u'processed'
else:
blogpost.state = u'failed'
def get_all_blogposts_of_blog(request, blog, state=None):
blog_posts_list = []
blog_post_data = request.db.BlogPostData.query.filter_by(blog=blog.id).all()
for each_blog_post_data in blog_post_data:
blog_post = each_blog_post_data.get_media_entry
if state == None:
blog_posts_list.append(blog_post)
if blog_post.state == state:
blog_posts_list.append(blog_post)
blog_posts_list.reverse()
return blog_posts_list

View File

@@ -0,0 +1,79 @@
# 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 datetime
from mediagoblin.db.base import Base
from mediagoblin.db.base import Session
from mediagoblin.db.models import Collection, User, MediaEntry
from mediagoblin.db.mixin import GenerateSlugMixin
from mediagoblin.media_types.blog.lib import check_blog_slug_used
from mediagoblin.tools.text import cleaned_markdown_conversion
from sqlalchemy import (
Column, Integer, ForeignKey, Unicode, UnicodeText, DateTime)
from sqlalchemy.orm import relationship, backref
class BlogMixin(GenerateSlugMixin):
def check_slug_used(self, slug):
return check_blog_slug_used(self.author, slug, self.id)
class Blog(Base, BlogMixin):
__tablename__ = "mediatype__blogs"
id = Column(Integer, primary_key=True)
title = Column(Unicode)
description = Column(UnicodeText)
author = Column(Integer, ForeignKey(User.id), nullable=False, index=True) #similar to uploader
created = Column(DateTime, nullable=False, default=datetime.datetime.now, index=True)
slug = Column(Unicode)
def get_all_blog_posts(self, state=None):
blog_posts = Session.query(MediaEntry).join(BlogPostData)\
.filter(BlogPostData.blog == self.id)
if state is not None:
blog_posts = blog_posts.filter(MediaEntry.state==state)
return blog_posts
def delete(self, **kwargs):
all_posts = self.get_all_blog_posts()
for post in all_posts:
post.delete(del_orphan_tags=False, commit=False)
from mediagoblin.db.util import clean_orphan_tags
clean_orphan_tags(commit=False)
super(Blog, self).delete(**kwargs)
BACKREF_NAME = "blogpost__media_data"
class BlogPostData(Base):
__tablename__ = "blogpost__mediadata"
# The primary key *and* reference to the main media_entry
media_entry = Column(Integer, ForeignKey('core__media_entries.id'), primary_key=True)
blog = Column(Integer, ForeignKey('mediatype__blogs.id'), nullable=False)
get_media_entry = relationship("MediaEntry",
backref=backref(BACKREF_NAME, uselist=False,
cascade="all, delete-orphan"))
DATA_MODEL = BlogPostData
MODELS = [BlogPostData, Blog]

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/>.
#}
{% extends "mediagoblin/base.html" %}
{% block mediagoblin_head%}
<style type = "text/css">
h2 { font-weight: bold; text-transform:capitalize; }
#blogs_list {border-collapse:separate; border-spacing: 40px 0px ;}
</style>
{% endblock %}
{% block mediagoblin_content %}
<h2> {{ blog.title }}</h2>
<br/>
<p> {{ blog.description|safe }}</p>
<br/>
<em>{{ blog.created.strftime("%d %b, %Y") }}</em>
&nbsp;
<em>posts({{ blogpost_count }})</em>
{% endblock mediagoblin_content %}

View File

@@ -0,0 +1,110 @@
{#
# 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/>.
#}
{% extends "mediagoblin/base.html" %}
{% from "mediagoblin/utils/pagination.html" import render_pagination %}
{% block title -%}
{{blog.title}} Dashboard &mdash; {{ super() }}
{%- endblock title %}
{% block mediagoblin_head%}
<style type = "text/css">
td > a { text-decoration:none; font-weight: bold; }
</style>
{% endblock %}
{% block mediagoblin_content %}
<h1 style="text-transform:capitalize"> {{blog.title}}</h1>
<p>
{{blog.description|safe}}
</p>
<p>
{% set blogpost_create_url = request.urlgen('mediagoblin.media_types.blog.blogpost.create',
blog_slug=blog.slug,
user=request.user.username) %}
<a class="button_action" href="{{ blogpost_create_url }}">
{%- trans %}Add Blog Post{% endtrans -%}
</a>
&middot;
{% set blog_edit_url = request.urlgen('mediagoblin.media_types.blog.edit',
blog_slug=blog.slug,
user=request.user.username) %}
<a class="button_action" href="{{ blog_edit_url }}">
{%- trans %}Edit Blog{% endtrans -%}
</a>
&middot;
{% set blog_delete_url = request.urlgen('mediagoblin.media_types.blog.blog_delete',
blog_slug=blog.slug,
user=request.user.username) %}
<a class="button_action" href="{{ blog_delete_url }}">
{%- trans %}Delete Blog{% endtrans -%}
</a>
</p>
<h2> Blog Post Entries </h2>
{% if blog_posts_list.count() %}
<table class="media_panel processing">
<tr>
<th>Title</th>
<th>submitted</th>
<th></th>
</tr>
{% for blog_post in blog_posts_list %}
<tr>
{% if blog_post.state == 'processed' %}
<td><a href="{{ blog_post.url_for_self(request.urlgen) }}">{{ blog_post.title }}</a></td>
{% else %}
{% set draft_url = request.urlgen('mediagoblin.media_types.blog.blogpost_draft_view',
blog_slug=blog.slug, user=request.user.username,
blog_post_slug=blog_post.slug) %}
<td><a href="{{ draft_url }}">{{ blog_post.title }}</a></td>
{% endif %}
<td>{{ blog_post.created.strftime("%F %R") }}</td>
{% if blog_post.state == 'processed' %}
<td><h6><em>Published</em></h6></td>
{% else %}
<td><h6><em>Draft</em></h6></td>
{% endif %}
{% set blogpost_edit_url = request.urlgen('mediagoblin.media_types.blog.blogpost.edit',
blog_slug=blog.slug, user=request.user.username,
blog_post_slug=blog_post.slug) %}
{% set blogpost_delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete',
user= blog_post.get_uploader.username,
media_id=blog_post.id) %}
<td>
<a class="button_action" href="{{ blogpost_edit_url }}">{% trans %}Edit{% endtrans %}</a>
<a class="button_action" href="{{ blogpost_delete_url }}">{% trans %}Delete{% endtrans %}</a>
</td>
</tr>
{% endfor %}
</table>
{% set blogpost_listing_url = request.urlgen('mediagoblin.media_types.blog.blog_post_listing',
blog_slug=blog_slug, user=user.username) %}
<br/>
<br/>
<a href="{{ blogpost_listing_url}}">{% trans %}<em> Go to list view </em>{% endtrans %}</a>
{% else %}
{% trans %} No blog post yet. {% endtrans %}
{% endif %}
{{ render_pagination(request, pagination) }}
{% endblock %}

View File

@@ -0,0 +1,53 @@
{#
# 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/>.
#}
{% extends "mediagoblin/base.html" %}
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% block mediagoblin_content %}
<form action="{{ request.urlgen('mediagoblin.media_types.blog.blog_delete',
user=request.user.username,
blog_slug=blog.slug) }}"
method="POST" enctype="multipart/form-data">
<div class="form_box">
<h1>
{%- trans title=blog.title -%}
Really delete {{ title }}?
{%- endtrans %}
</h1>
<br/>
<p class="delete_checkbox_box">
{{ form.confirm }}
{{ wtforms_util.render_label(form.confirm) }}
</p>
<div class="form_submit_buttons">
{# TODO: This isn't a button really... might do unexpected things :) #}
{% set blog_dashboard_url = request.urlgen('mediagoblin.media_types.blog.blog-dashboard',
blog_slug=blog.slug, user=request.user.username) %}
<a class="button_action" href="{{ blog_dashboard_url }}">{% trans %}Cancel{% endtrans %}</a>
<input type="submit" value="{% trans %}Delete permanently{% endtrans %}" class="button_form" />
{{ csrf_token }}
</div>
</div>
</form>
{% endblock %}

View File

@@ -0,0 +1,41 @@
{#
# 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/>.
#}
{% extends "mediagoblin/base.html" %}
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% block mediagoblin_content %}
<form action=""
method="POST" enctype="multipart/form-data">
<div class="blog_form_box_xl">
<h1>{% trans %}Create/Edit a Blog{% endtrans %}</h1>
<b>Title</b>
<div class="blog_form_field_input input">
<h3>{{ form.title}}</h3>
</div>
<b>Description</b>
<div class="blog_form_field_input textarea">
<h3>{{form.description|safe}}</h3>
</div>
<div class="form_submit_buttons">
{{ csrf_token }}
<input type="submit" value="{% trans %}Add{% endtrans %}" class="button_form" />
</div>
</div>
</form>
{% endblock %}

View File

@@ -0,0 +1,53 @@
{#
# 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/>.
#}
{% extends "mediagoblin/base.html" %}
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% block title -%}
{% trans %}Create/Edit a blog post.{% endtrans %} &mdash; {{ super() }}
{%- endblock %}
{% block mediagoblin_content %}
<form action="" method="POST">
<div class="blog_form_box_xl">
<h1>{% trans %}Create/Edit a Blog Post.{% endtrans %}</h1>
<b>Title</b>
<div class="blog_form_field_input input">
<h3>{{ form.title}}</h3>
</div>
<b>Description</b>
<div class="blog_form_field_input textarea">
<h3>{{form.description|safe}}</h3>
</div>
<b>Tags</b>
<div class="blog_form_field_input input">
<h3>{{form.tags}}</h3>
</div>
<b>License</b>
<div class="blog_form_field_input input">
<h3>{{form.license}}</h3>
</div>
<div class="form_submit_buttons">
{{ csrf_token }}
<input type="submit" name="status" value="Publish" class="button_form">
<input type="submit" name="status" value="Save as Draft" class="button_form">
</div>
</div>
</form>
{% endblock %}

View File

@@ -0,0 +1,66 @@
{#
# 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/>.
#}
{% extends "mediagoblin/base.html" %}
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% from "mediagoblin/utils/pagination.html" import render_pagination %}
{% block title -%}
{% trans %}{{ blog_owner }} 's Blog{% endtrans %} &mdash; {{ super() }}
{%- endblock %}
{% block mediagoblin_head -%}
<style type="text/css">
h4 {margin:0; padding : 0;
font-size:.7 em;}
a{text-decoration:none;
text-transform:capitalize
}
</style>
{%- endblock %}
{% block mediagoblin_content %}
<div class="b_list_owner"> <h1><font color="black"> {{ blog.title }} <font size="2">by {{ blog_owner }}</font> </font></h1></div>
<div>
{% for post in blog_posts %}
<div class="b_listing_title"><a href="{{ post.url_for_self(request.urlgen) }}">
<h2><font color="black">{{ post.title }}</font></h2></a>
</div>
<h4 align="right">{{ post.created.strftime("%d %b, %Y") }}</h4>
{% if post.tags %}
{% for tag in post.tags %}
<a href="{{ request.urlgen(
'mediagoblin.user_pages.user_tag_gallery',
tag=tag['slug'],
user=post.get_uploader.username) }}">{{ tag['name'] }} |</a>
{% endfor %}
{% endif %}
<div class="b_list_des"> <p>{{ post.description|safe }} </p></div>
</br>
</br>
{% endfor %}
</div>
<br/>
<br/>
{% set blog_about_url = request.urlgen('mediagoblin.media_types.blog.blog_about',
blog_slug=blog.slug, user=blog_owner) %}
<a style="text-decoration:underline" href="{{ blog_about_url}}">About Blog</a>
<br/>
{{ render_pagination(request, pagination) }}
{% endblock %}

View File

@@ -0,0 +1,42 @@
{#
# 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/>.
#}
{% extends 'mediagoblin/base.html' %}
{% block mediagoblin_head %}
{{ super() }}
{% endblock %}
{% block mediagoblin_content %}
<h1> {{ blogpost.title}}</h1>
<p>{{ blogpost.description|safe}}</p>
{% set blogpost_edit_url = request.urlgen('mediagoblin.media_types.blog.blogpost.edit',
blog_slug=blog.slug, user=request.user.username,
blog_post_slug=blogpost.slug) %}
{% set blogpost_delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete',
user= blogpost.get_uploader.username,
media_id=blogpost.id) %}
<a class="button_action" href="{{ blogpost_edit_url }}">{% trans %}Edit{% endtrans %}</a>
<a class="button_action" href="{{ blogpost_delete_url }}">{% trans %}Delete{% endtrans %}</a>
{% endblock %}

View File

@@ -0,0 +1,69 @@
{#
# 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/>.
#}
{% extends "mediagoblin/base.html" %}
{% block mediagoblin_head%}
<style type = "text/css">
table a { text-decoration:none; font-weight: bold; text-transform:capitalize; }
#blogs_list {border-collapse:separate; border-spacing: 40px 0px ;}
</style>
{% endblock %}
{% block mediagoblin_content %}
{% if blogs %}
<h2>My Blogs</h2>
<table id="blogs_list">
{% for blog in blogs %}
{% set others_blog_url = request.urlgen('mediagoblin.media_types.blog.blog_post_listing',
blog_slug=blog.slug, user=user.username) %}
<tr>
{% if not request.user or request.user.username != user.username%}
<td><a href="{{ others_blog_url }}">{{ blog.title }}</a></td>
{% else %}
{% set my_blog_url = request.urlgen('mediagoblin.media_types.blog.blog-dashboard',
blog_slug=blog.slug, user=request.user.username) %}
<td><a href="{{ my_blog_url }}">{{ blog.title }}</a></td>
{% endif %}
<td>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</td>
<td><a class="button_action" href="{{ others_blog_url }}">{% trans %}View{% endtrans %}</a></td>
</tr>
{% endfor %}
</table>
{% else %}
{% if request.user and request.user.username==user.username %}
<p>You have not created any blog yet.</p>
{% else %}
<p>No blog has been created by <strong>{{ user.username }}</strong>yet.</p>
{% endif %}
{% endif %}
<br/>
<br/>
<br/>
{% if blogs.__len__() <max_blog_count and request.user and request.user.username==user.username %}
{% set blog_create_url = request.urlgen('mediagoblin.media_types.blog.create',
user=request.user.username) %}
<a class="button_action" href="{{ blog_create_url }}">{% trans %}Create a Blog{% endtrans %}</a>
{% endif %}
{% endblock mediagoblin_content %}

View File

@@ -0,0 +1,22 @@
{#
# 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/>.
#}
<a href="{{ request.urlgen('mediagoblin.media_types.blog.blog_admin_dashboard',
user=request.user.username) }}">
{%- trans %} Blog Dashboard {% endtrans -%}
</a>

View File

@@ -0,0 +1,27 @@
{#
# 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 the URL to a user's blog dashboard on her profile.
#}
{%if blogs %}
<h3>Blog</h3>
{% set blogs_url = request.urlgen('mediagoblin.media_types.blog.blog_admin_dashboard',
blogs=blogs, user=user.username) %}
<p><a href="{{ blogs_url }}"><em>Go to blogs</em></a></p>
{%endif%}

View File

@@ -0,0 +1,22 @@
{#
# 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/>.
#}
<a class="button_action" href="{{ request.urlgen('mediagoblin.media_types.blog.create',
user=request.user.username) }}">
{%- trans %} Create Blog {% endtrans -%}
</a>

View File

@@ -0,0 +1,382 @@
# 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
_log = logging.getLogger(__name__)
from datetime import datetime
from werkzeug.exceptions import Forbidden
from mediagoblin.tools import pluginapi
from mediagoblin import mg_globals
from mediagoblin.media_types.blog import forms as blog_forms
from mediagoblin.media_types.blog.models import Blog, BlogPostData
from mediagoblin.media_types.blog.lib import may_edit_blogpost, set_blogpost_state, get_all_blogposts_of_blog
from mediagoblin.messages import add_message, SUCCESS, ERROR
from mediagoblin.decorators import (require_active_login, active_user_from_url,
get_media_entry_by_id, user_may_alter_collection,
get_user_collection, uses_pagination)
from mediagoblin.tools.pagination import Pagination
from mediagoblin.tools.response import (render_to_response,
redirect, render_404)
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.template import render_template
from mediagoblin.tools.text import (
convert_to_tag_list_of_dicts, media_tags_as_string, clean_html,
cleaned_markdown_conversion)
from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
from mediagoblin.db.models import User, Collection, MediaEntry
from mediagoblin.notifications import add_comment_subscription
@require_active_login
def blog_edit(request):
"""
View for editing an existing blog or creating a new blog
if user have not exceeded maximum allowed acount of blogs.
"""
url_user = request.matchdict.get('user', None)
blog_slug = request.matchdict.get('blog_slug', None)
config = pluginapi.get_config('mediagoblin.media_types.blog')
max_blog_count = config['max_blog_count']
form = blog_forms.BlogEditForm(request.form)
# creating a blog
if not blog_slug:
if Blog.query.filter_by(author=request.user.id).count()<max_blog_count:
if request.method=='GET':
return render_to_response(
request,
'mediagoblin/blog/blog_edit_create.html',
{'form': form,
'user' : request.user,
'app_config': mg_globals.app_config})
if request.method=='POST' and form.validate():
_log.info("Here")
blog = request.db.Blog()
blog.title = unicode(form.title.data)
blog.description = unicode(cleaned_markdown_conversion((form.description.data)))
blog.author = request.user.id
blog.generate_slug()
blog.save()
return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
user=request.user.username
)
else:
add_message(request, ERROR, "Welcome! You already have created \
maximum number of blogs.")
return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
user=request.user.username)
#Blog already exists.
else:
blog = request.db.Blog.query.filter_by(slug=blog_slug).first()
if not blog:
return render_404(request)
if request.method == 'GET':
defaults = dict(
title = blog.title,
description = cleaned_markdown_conversion(blog.description),
author = request.user.id)
form = blog_forms.BlogEditForm(**defaults)
return render_to_response(
request,
'mediagoblin/blog/blog_edit_create.html',
{'form': form,
'user': request.user,
'app_config': mg_globals.app_config})
else:
if request.method == 'POST' and form.validate():
blog.title = unicode(form.title.data)
blog.description = unicode(cleaned_markdown_conversion((form.description.data)))
blog.author = request.user.id
blog.generate_slug()
blog.save()
add_message(request, SUCCESS, "Your blog is updated.")
return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
user=request.user.username,
blog_slug=blog.slug)
@require_active_login
def blogpost_create(request):
form = blog_forms.BlogPostEditForm(request.form, license=request.user.license_preference)
if request.method == 'POST' and form.validate():
blog_slug = request.matchdict.get('blog_slug')
blog = request.db.Blog.query.filter_by(slug=blog_slug,
author=request.user.id).first()
if not blog:
return render_404(request)
blogpost = request.db.MediaEntry()
blogpost.media_type = 'mediagoblin.media_types.blogpost'
blogpost.title = unicode(form.title.data)
blogpost.description = unicode(cleaned_markdown_conversion((form.description.data)))
blogpost.tags = convert_to_tag_list_of_dicts(form.tags.data)
blogpost.license = unicode(form.license.data) or None
blogpost.uploader = request.user.id
blogpost.generate_slug()
set_blogpost_state(request, blogpost)
blogpost.save()
# connect this blogpost to its blog
blog_post_data = request.db.BlogPostData()
blog_post_data.blog = blog.id
blog_post_data.media_entry = blogpost.id
blog_post_data.save()
add_message(request, SUCCESS, _('Woohoo! Submitted!'))
add_comment_subscription(request.user, blogpost)
return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
user=request.user.username,
blog_slug=blog.slug)
return render_to_response(
request,
'mediagoblin/blog/blog_post_edit_create.html',
{'form': form,
'app_config': mg_globals.app_config,
'user': request.user.username})
@require_active_login
def blogpost_edit(request):
blog_slug = request.matchdict.get('blog_slug', None)
blog_post_slug = request.matchdict.get('blog_post_slug', None)
blogpost = request.db.MediaEntry.query.filter_by(slug=blog_post_slug, uploader=request.user.id).first()
blog = request.db.Blog.query.filter_by(slug=blog_slug, author=request.user.id).first()
if not blogpost or not blog:
return render_404(request)
defaults = dict(
title = blogpost.title,
description = cleaned_markdown_conversion(blogpost.description),
tags=media_tags_as_string(blogpost.tags),
license=blogpost.license)
form = blog_forms.BlogPostEditForm(request.form, **defaults)
if request.method == 'POST' and form.validate():
blogpost.title = unicode(form.title.data)
blogpost.description = unicode(cleaned_markdown_conversion((form.description.data)))
blogpost.tags = convert_to_tag_list_of_dicts(form.tags.data)
blogpost.license = unicode(form.license.data)
set_blogpost_state(request, blogpost)
blogpost.generate_slug()
blogpost.save()
add_message(request, SUCCESS, _('Woohoo! edited blogpost is submitted'))
return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
user=request.user.username,
blog_slug=blog.slug)
return render_to_response(
request,
'mediagoblin/blog/blog_post_edit_create.html',
{'form': form,
'app_config': mg_globals.app_config,
'user': request.user.username,
'blog_post_slug': blog_post_slug
})
@uses_pagination
def blog_dashboard(request, page):
"""
Dashboard for a blog, only accessible to
the owner of the blog.
"""
url_user = request.matchdict.get('user')
user = request.db.User.query.filter_by(username=url_user).one()
blog_slug = request.matchdict.get('blog_slug', None)
blogs = request.db.Blog.query.filter_by(author=user.id)
config = pluginapi.get_config('mediagoblin.media_types.blog')
max_blog_count = config['max_blog_count']
if (request.user and request.user.id == user.id) or (request.user and request.user.is_admin):
if blog_slug:
blog = blogs.filter(Blog.slug==blog_slug).first()
if not blog:
return render_404(request)
else:
blog_posts_list = blog.get_all_blog_posts().order_by(MediaEntry.created.desc())
pagination = Pagination(page, blog_posts_list)
pagination.per_page = 15
blog_posts_on_a_page = pagination()
if may_edit_blogpost(request, blog):
return render_to_response(
request,
'mediagoblin/blog/blog_admin_dashboard.html',
{'blog_posts_list': blog_posts_on_a_page,
'blog_slug':blog_slug,
'blog':blog,
'user':user,
'pagination':pagination
})
if not request.user or request.user.id != user.id or not blog_slug:
blogs = blogs.all()
return render_to_response(
request,
'mediagoblin/blog/list_of_blogs.html',
{
'blogs':blogs,
'user':user,
'max_blog_count':max_blog_count
})
@uses_pagination
def blog_post_listing(request, page):
"""
Page, listing all the blog posts of a particular blog.
"""
blog_owner = request.matchdict.get('user')
blog_slug = request.matchdict.get('blog_slug', None)
owner_user = User.query.filter_by(username=blog_owner).one()
blog = request.db.Blog.query.filter_by(slug=blog_slug).first()
if not owner_user or not blog:
return render_404(request)
all_blog_posts = blog.get_all_blog_posts(u'processed').order_by(MediaEntry.created.desc())
pagination = Pagination(page, all_blog_posts)
pagination.per_page = 8
blog_posts_on_a_page = pagination()
return render_to_response(
request,
'mediagoblin/blog/blog_post_listing.html',
{'blog_posts': blog_posts_on_a_page,
'pagination': pagination,
'blog_owner': blog_owner,
'blog':blog
})
@require_active_login
def draft_view(request):
blog_slug = request.matchdict.get('blog_slug', None)
blog_post_slug = request.matchdict.get('blog_post_slug', None)
user = request.matchdict.get('user')
blog = request.db.Blog.query.filter_by(author=request.user.id, slug=blog_slug).first()
blogpost = request.db.MediaEntry.query.filter_by(state = u'failed', uploader=request.user.id, slug=blog_post_slug).first()
if not blog or not blogpost:
return render_404(request)
return render_to_response(
request,
'mediagoblin/blog/blogpost_draft_view.html',
{'blogpost':blogpost,
'blog': blog
})
@require_active_login
def blog_delete(request, **kwargs):
"""
Deletes a blog and media entries, tags associated with it.
"""
url_user = request.matchdict.get('user')
owner_user = request.db.User.query.filter_by(username=url_user).first()
blog_slug = request.matchdict.get('blog_slug', None)
blog = request.db.Blog.query.filter_by(slug=blog_slug, author=owner_user.id).first()
if not blog:
return render_404(reequest)
form = blog_forms.ConfirmDeleteForm(request.form)
if request.user.id == blog.author or request.user.is_admin:
if request.method == 'POST' and form.validate():
if form.confirm.data is True:
blog.delete()
add_message(
request, SUCCESS, _('You deleted the Blog.'))
return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
user=request.user.username)
else:
add_message(
request, ERROR,
_("The media was not deleted because you didn't check that you were sure."))
return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
user=request.user.username)
else:
if request.user.is_admin:
add_message(
request, WARNING,
_("You are about to delete another user's Blog. "
"Proceed with caution."))
return render_to_response(
request,
'mediagoblin/blog/blog_confirm_delete.html',
{'blog':blog,
'form':form
})
else:
add_message(
request, ERROR,
_("The blog was not deleted because you have no rights."))
return redirect(request, "mediagoblin.media_types.blog.blog_admin_dashboard",
user=request.user.username)
def blog_about_view(request):
"""
Page containing blog description and statistics
"""
blog_slug = request.matchdict.get('blog_slug', None)
url_user = request.matchdict.get('user', None)
user = request.db.User.query.filter_by(username=url_user).first()
blog = request.db.Blog.query.filter_by(author=user.id, slug=blog_slug).first()
if not user or not blog:
return render_404(request)
else:
blog_posts_processed = blog.get_all_blog_posts(u'processed').count()
return render_to_response(
request,
'mediagoblin/blog/blog_about.html',
{'user': user,
'blog': blog,
'blogpost_count': blog_posts_processed
})

View File

@@ -27,6 +27,8 @@ _log = logging.getLogger(__name__)
ACCEPTED_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "tiff"]
MEDIA_TYPE = 'mediagoblin.media_types.image'
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
class ImageMediaManager(MediaManagerBase):
human_readable = "Image"

View File

@@ -399,7 +399,7 @@ class BaseProcessingFail(Exception):
subclass from.
You shouldn't call this itself; instead you should subclass it
and provid the exception_path and general_message applicable to
and provide the exception_path and general_message applicable to
this error.
"""
general_message = u''

View File

@@ -39,6 +39,7 @@ def get_url_map():
import mediagoblin.listings.routing
import mediagoblin.notifications.routing
import mediagoblin.oauth.routing
for route in PluginManager().get_routes():
add_route(*route)

View File

@@ -293,6 +293,48 @@ text-align: center;
max-width: 460px;
}
.blog_form_box_xl {
background-color: #222;
border-top: 6px solid #D49086;
padding: 3% 5%;
display: block;
float: none;
width: 90%;
max-width: 800px;
min-height: 500px;
margin-left: auto;
margin-right: auto;
}
.b_listing_title {
height: 30px;
width: 100%;
padding: 0px;
background-color: #86D4B1;
text-transform:capitalize;
text-decoration: none;
#border-radius: 4px;
}
.b_listing_title > a {
text-decoration: none;
}
.b_list_owner {
height: 100px;
width: 100%;
padding: 0em;
margin-right: auto;
background-color: #DDA0DD;
#border-radius: 4px;
text-transform: capitalize;
}
.b_list_des {
text-align:justify;
}
.edit_box {
border-top: 6px dashed #D49086
}
@@ -301,6 +343,10 @@ text-align: center;
width: 100%;
}
.blog_form_field_input input, .blog_form_field_input textarea {
width: 100%;
}
.form_field_input {
margin-bottom: 10px;
}

View File

@@ -0,0 +1 @@
../../../extlib/tinymce

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -126,6 +126,8 @@
{%- trans %}Media processing panel{% endtrans -%}
</a>
&middot;
{% template_hook("blog_dashboard_home") %}
&middot;
<a id="logout" href=
{% if persona is not defined %}
"{{ request.urlgen('mediagoblin.auth.logout') }}"
@@ -140,6 +142,7 @@
<a class="button_action" href="{{ request.urlgen('mediagoblin.submit.collection') }}">
{%- trans %}Create new collection{% endtrans -%}
</a>
{% template_hook("create_blog_home") %}
{% if request.user.has_privilege('admin','moderator') %}
<p>
<span class="dropdown_title">Moderation powers:</span>

View File

@@ -17,3 +17,19 @@
-#}
{# Add extra head declarations here for your theme, if appropriate #}
<script type="text/javascript"
src="{{request.staticdirect('extlib/tinymce/js/tinymce/tinymce.min.js')}}"></script>
<script type="text/javascript">
tinyMCE.init({
selector: "div.blog_form_field_input textarea",
height: 300,
width: 800,
plugins: [
"advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker",
"searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking",
"save table contextmenu directionality emoticons template paste textcolor"
]
})
</script>

View File

@@ -0,0 +1,33 @@
{#
# 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/>.
#}
{% extends 'mediagoblin/user_pages/blog_media.html' %}
{% block mediagoblin_head %}
{{ super() }}
{% endblock %}
{% block mediagoblin_media %}
<h1> {{media.title}}</h1>
<p>{{media.description|safe}}</p>
{% endblock %}

View File

@@ -0,0 +1,176 @@
{#
# 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/>.
#}
{%- extends "mediagoblin/base.html" %}
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% from "mediagoblin/utils/pagination.html" import render_pagination %}
{% block title %}{{ media.title }} &mdash; {{ super() }}{% endblock %}
{% block mediagoblin_head %}
<!--[if lte IE 8]><link rel="stylesheet"
href="{{ request.staticdirect('/extlib/leaflet/leaflet.ie.css') }}" /><![endif]-->
<script type="text/javascript"
src="{{ request.staticdirect('/js/comment_show.js') }}"></script>
<script type="text/javascript"
src="{{ request.staticdirect('/js/keyboard_navigation.js') }}"></script>
{% template_hook("media_head") %}
{% endblock mediagoblin_head %}
{% block mediagoblin_content %}
<p class="context">
{%- trans user_url=request.urlgen(
'mediagoblin.user_pages.user_home',
user=media.get_uploader.username),
username=media.get_uploader.username -%}
❖ Blog post by <a href="{{user_url}}">{{username}}</a>
{%- endtrans -%}
</p>
{% include "mediagoblin/utils/prev_next.html" %}
<div class="media_pane">
<div class="media_image_container">
{% block mediagoblin_media %}
{% set display_media = request.app.public_store.file_url(
media.get_display_media()[1]) %}
{# if there's a medium file size, that means the medium size
# isn't the original... so link to the original!
#}
{% if media.media_files.has_key('medium') %}
<a href="{{ request.app.public_store.file_url(
media.media_files['original']) }}">
<img class="media_image"
src="{{ display_media }}"
alt="{% trans media_title=media.title -%}
Image for {{ media_title }}{% endtrans %}" />
</a>
{% else %}
<img class="media_image"
src="{{ display_media }}"
alt="{% trans media_title=media.title -%}
Image for {{ media_title }}{% endtrans %}" />
{% endif %}
{% endblock %}
</div>
{% if request.user and
(media.uploader == request.user.id or
request.user.is_admin) %}
{% set edit_url = request.urlgen('mediagoblin.media_types.blog.blogpost.edit',
blog_slug=media.media_manager.get_blog_by_blogpost().slug,
user=request.user.username, blog_post_slug=media.slug) %}
<a class="button_action" href="{{ edit_url }}">{% trans %}Edit{% endtrans %}</a>
{% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete',
user= media.get_uploader.username,
media_id=media.id) %}
<a class="button_action" href="{{ delete_url }}">{% trans %}Delete{% endtrans %}</a>
{% endif %}
</br>
</br>
{% if comments %}
{% if app_config['allow_comments'] %}
<a
{% if not request.user %}
href="{{ request.urlgen('mediagoblin.auth.login') }}"
{% endif %}
class="button_action" id="button_addcomment" title="Add a comment">
{% trans %}Add a comment{% endtrans %}
</a>
{% include "mediagoblin/utils/comment-subscription.html" %}
{% endif %}
{% if request.user %}
<form action="{{ request.urlgen('mediagoblin.user_pages.media_post_comment',
user= media.get_uploader.username,
media_id=media.id) }}" method="POST" id="form_comment">
{{ wtforms_util.render_divs(comment_form) }}
<div class="form_submit_buttons">
<input type="submit" value="{% trans %}Add this comment{% endtrans %}" class="button_action" />
{{ csrf_token }}
</div>
</form>
{% endif %}
<ul style="list-style:none">
{% for comment in comments %}
{% set comment_author = comment.get_author %}
<li id="comment-{{ comment.id }}"
{%- if pagination.active_id == comment.id %}
class="comment_wrapper comment_active">
<a name="comment" id="comment"></a>
{%- else %}
class="comment_wrapper">
{%- endif %}
<div class="comment_author">
<img src="{{ request.staticdirect('/images/icon_comment.png') }}" />
<a href="{{ request.urlgen('mediagoblin.user_pages.user_home',
user=comment_author.username) }}"
class="comment_authorlink">
{{- comment_author.username -}}
</a>
<a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment',
comment=comment.id,
user=media.get_uploader.username,
media=media.slug_or_id) }}#comment"
class="comment_whenlink">
<span title='{{- comment.created.strftime("%I:%M%p %Y-%m-%d") -}}'>
{%- trans formatted_time=timesince(comment.created) -%}
{{ formatted_time }} ago
{%- endtrans -%}
</span></a>:
</div>
<div class="comment_content">
{% autoescape False -%}
{{ comment.content_html }}
{%- endautoescape %}
</div>
</li>
{% endfor %}
</ul>
{{ render_pagination(request, pagination,
media.url_for_self(request.urlgen)) }}
{% endif %}
</div>
<div class="media_sidebar">
<h3>{% trans %}Added{% endtrans %}</h3>
<p><span title="{{ media.created.strftime("%I:%M%p %Y-%m-%d") }}">
{%- trans formatted_time=timesince(media.created) -%}
{{ formatted_time }} ago
{%- endtrans -%}
</span></p>
{% block mediagoblin_after_added_sidebar %}
{% endblock %}
{% if media.tags %}
{% include "mediagoblin/utils/tags.html" %}
{% endif %}
{% include "mediagoblin/utils/collections.html" %}
{% include "mediagoblin/utils/license.html" %}
{% include "mediagoblin/utils/exif.html" %}
{% template_hook("media_sideinfo") %}
{% block mediagoblin_sidebar %}
{% endblock %}
</div>
<div class="clear"></div>
{% endblock %}

View File

@@ -111,6 +111,11 @@
href="{{ request.urlgen('mediagoblin.submit.start') }}">
{%- trans %}Add media{% endtrans -%}
</a>
{% set feed_url = request.urlgen(
'mediagoblin.user_pages.atom_feed',
user=user.username) %}
{% template_hook("user_profile") %}
{% include "mediagoblin/utils/feed_link.html" %}
</div>
{% else %}
<div class="profile_showcase empty_space">

View File

@@ -286,11 +286,29 @@ def media_collect(request, media):
#TODO: Why does @user_may_delete_media not implicate @require_active_login?
@get_media_entry_by_id
@require_active_login
@user_may_delete_media
def media_confirm_delete(request, media):
@require_active_login
def media_confirm_delete(request):
allowed_state = [u'failed', u'processed']
media = None
for media_state in allowed_state:
media = request.db.MediaEntry.query.filter_by(id=request.matchdict['media_id'], state=media_state).first()
if media:
break
if not media:
return render_404(request)
given_username = request.matchdict.get('user')
if given_username and (given_username != media.get_uploader.username):
return render_404(request)
uploader_id = media.uploader
if not (request.user.is_admin or
request.user.id == uploader_id):
raise Forbidden()
form = user_forms.ConfirmDeleteForm(request.form)
if request.method == 'POST' and form.validate():