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"