aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--mediagoblin.ini1
-rw-r--r--mediagoblin/media_types/blog/__init__.py44
-rw-r--r--mediagoblin/media_types/blog/config_spec.ini2
-rw-r--r--mediagoblin/media_types/blog/forms.py42
-rw-r--r--mediagoblin/media_types/blog/lib.py30
-rw-r--r--mediagoblin/media_types/blog/models.py60
-rw-r--r--mediagoblin/media_types/blog/routing.py57
-rw-r--r--mediagoblin/media_types/blog/views.py277
-rw-r--r--mediagoblin/media_types/image/__init__.py2
-rw-r--r--mediagoblin/plugins/blog/LICENCE0
-rw-r--r--mediagoblin/plugins/blog/README.srt0
-rw-r--r--mediagoblin/plugins/blog/__init__.py0
-rw-r--r--mediagoblin/plugins/blog/forms.py17
-rw-r--r--mediagoblin/plugins/blog/setup.py10
-rw-r--r--mediagoblin/plugins/blog/templates/blogpost_edit.html19
-rw-r--r--mediagoblin/plugins/blog/views.py16
-rw-r--r--mediagoblin/processing/__init__.py2
-rw-r--r--mediagoblin/routing.py1
-rw-r--r--mediagoblin/static/css/base.css18
-rw-r--r--mediagoblin/templates/mediagoblin/blog/blog_admin_dashboard.html74
-rw-r--r--mediagoblin/templates/mediagoblin/blog/blog_edit_create.html41
-rw-r--r--mediagoblin/templates/mediagoblin/blog/blog_post_edit_create.html53
-rw-r--r--mediagoblin/templates/mediagoblin/extra_head.html11
-rw-r--r--mediagoblin/templates/mediagoblin/media_displays/blogpost.html33
25 files changed, 810 insertions, 2 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..d6b023a9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+mediagoblin_blog
+================
diff --git a/mediagoblin.ini b/mediagoblin.ini
index 30dacadf..cb908dd2 100644
--- a/mediagoblin.ini
+++ b/mediagoblin.ini
@@ -45,3 +45,4 @@ base_url = /mgoblin_media/
[[mediagoblin.plugins.geolocation]]
[[mediagoblin.plugins.basic_auth]]
[[mediagoblin.media_types.image]]
+[[mediagoblin.media_types.blog]]
diff --git a/mediagoblin/media_types/blog/__init__.py b/mediagoblin/media_types/blog/__init__.py
new file mode 100644
index 00000000..a579a179
--- /dev/null
+++ b/mediagoblin/media_types/blog/__init__.py
@@ -0,0 +1,44 @@
+#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/>.
+
+from mediagoblin.media_types import MediaManagerBase
+
+from mediagoblin.tools import pluginapi
+
+MEDIA_TYPE = 'mediagoblin.media_types.blogpost'
+
+def setup_plugin():
+ config = pluginapi.get_config(MEDIA_TYPE)
+
+class BlogPostMediaManager(MediaManagerBase):
+ human_readable = "Blog Post"
+ display_template = "mediagoblin/media_displays/blogpost.html"
+ default_thumb = "images/media_thumbs/blogpost.jpg"
+
+def get_media_type_and_manager(ext):
+ return MEDIA_TYPE, BlogPostMediaManager
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'get_media_type_and_manager': get_media_type_and_manager,
+ ('media_manager', MEDIA_TYPE): lambda: BlogPostMediaManager,
+}
+
+
+
+
+
diff --git a/mediagoblin/media_types/blog/config_spec.ini b/mediagoblin/media_types/blog/config_spec.ini
new file mode 100644
index 00000000..e0a6844e
--- /dev/null
+++ b/mediagoblin/media_types/blog/config_spec.ini
@@ -0,0 +1,2 @@
+[plugin_spec]
+max_blog_count = integer(default=1)
diff --git a/mediagoblin/media_types/blog/forms.py b/mediagoblin/media_types/blog/forms.py
new file mode 100644
index 00000000..9f595fcf
--- /dev/null
+++ b/mediagoblin/media_types/blog/forms.py
@@ -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/>.
+
+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'))
+
+
+
+
+
+
+
diff --git a/mediagoblin/media_types/blog/lib.py b/mediagoblin/media_types/blog/lib.py
new file mode 100644
index 00000000..f95ecca5
--- /dev/null
+++ b/mediagoblin/media_types/blog/lib.py
@@ -0,0 +1,30 @@
+# 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
+
diff --git a/mediagoblin/media_types/blog/models.py b/mediagoblin/media_types/blog/models.py
new file mode 100644
index 00000000..a9288c00
--- /dev/null
+++ b/mediagoblin/media_types/blog/models.py
@@ -0,0 +1,60 @@
+# 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.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)
+
+
+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]
diff --git a/mediagoblin/media_types/blog/routing.py b/mediagoblin/media_types/blog/routing.py
new file mode 100644
index 00000000..b34c8280
--- /dev/null
+++ b/mediagoblin/media_types/blog/routing.py
@@ -0,0 +1,57 @@
+# 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/>.
+
+from mediagoblin.tools.routing import add_route
+
+#URL mapping for blog-admin, where all the blog posts of a particular blog
+#are listed. providing the facility of edit, delete and view a particular blog post."
+add_route('mediagoblin.media_types.blog.blog-dashboard', \
+ '/u/<string:user>/b/<string:blog_slug>/blog_dashboard/', 'mediagoblin.media_types.blog.views:blog_dashboard')
+
+#URL mapping for creating a new blog post. (add blo_slug in the url at "blogpost" place later"
+add_route('mediagoblin.media_types.blog.blogpost.create',
+ '/u/<string:user>/b/<string:blog_slug>/p/create/',
+ 'mediagoblin.media_types.blog.views:blogpost_create')
+
+#URL mapping for editing an existing blog post.
+add_route('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')
+
+#URL mapping for blog-collection-admin, where all the blogs of the user
+#are listed. providing the facility of edit, delete and view a blog.
+#view facility redirects to blog-admin page of that particular blog.
+add_route('mediagoblin.media_types.blog.blog-collection-admin', \
+ '/u/<string:user>/blog-collection-admin/', 'mediagoblin.media_types.blog.views:blog-collection-admin')
+
+#URL mapping for creating a new blog.
+add_route('mediagoblin.media_types.blog.create', '/u/<string:user>/b/create/',
+ 'mediagoblin.media_types.blog.views:blog_edit')
+
+
+#URL mapping for editing an existing blog.
+add_route('mediagoblin.media_types.blog.edit', '/u/<string:user>/b/<string:blog_slug>/edit/',
+ 'mediagoblin.media_types.blog.views:blog_edit')
+
+#URL mapping for blog_post_listing view.
+add_route('mediagoblin.media_types.blog.blog_post_listing', '/u/<string:user>/b/',
+ 'mediagoblin.media_types.blog.views:blog_post_listing')
+
+
+
+
+
+
diff --git a/mediagoblin/media_types/blog/views.py b/mediagoblin/media_types/blog/views.py
new file mode 100644
index 00000000..44f61f0f
--- /dev/null
+++ b/mediagoblin/media_types/blog/views.py
@@ -0,0 +1,277 @@
+# 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 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
+
+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)
+from mediagoblin.tools.response import (render_to_response,
+ redirect, redirect_obj, 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.tools.url import slugify
+
+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 the existing blog or automatically
+ creating a new blog if user does not have any yet.
+ """
+ url_user = request.matchdict.get('user', None)
+ blog_slug = request.matchdict.get('blog_slug', None)
+
+ max_blog_count = 1
+ form = blog_forms.BlogEditForm(request.form)
+ # the blog doesn't exists yet
+ 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 = Blog()
+ blog.title = unicode(form.title.data)
+ blog.description = unicode(form.description.data) #remember clean html data.
+ blog.author = request.user.id
+ blog.generate_slug()
+
+ blog.save()
+ return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
+ user=request.user.username,
+ blog_slug=blog.slug)
+ else:
+ #the case when max blog count is one.
+ blog = request.db.Blog.query.filter_by(author=request.user.id).first()
+ add_message(request, ERROR, "You can not create any more blogs")
+ return redirect(request, "mediagoblin.media_types.blog.blog-dashboard",
+ user=request.user.username,
+ blog_slug=blog.slug)
+
+
+ #Blog already exists.
+ else:
+ blog = Blog.query.filter_by(slug=blog_slug).first()
+ if request.method == 'GET':
+ defaults = dict(
+ title = blog.title,
+ description = 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(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():
+
+ state_value = request.form['status']
+ if state_value == u'Publish':
+ state_value = u'processed'
+
+ blog_slug = request.matchdict.get('blog_slug')
+ blog = request.db.Blog.query.filter_by(slug=blog_slug,
+ author=request.user.id).first()
+
+
+ blogpost = request.db.MediaEntry()
+ blogpost.media_type = 'mediagoblin.media_types.blogpost'
+ blogpost.title = unicode(form.title.data)
+ blogpost.description = unicode(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.state = state_value
+
+ blogpost.generate_slug()
+
+ 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 = 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():
+
+ state_value = request.form['status']
+ if state_value == u'Publish':
+ state_value = u'processed'
+ blogpost.title = unicode(form.title.data)
+ blogpost.description = unicode(form.description.data)
+ blogpost.tags = convert_to_tag_list_of_dicts(form.tags.data)
+ blogpost.license = unicode(form.license.data)
+
+ blogpost.generate_slug()
+ blogpost.state = state_value
+ 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
+ })
+
+@require_active_login
+def blog_dashboard(request):
+
+ url_user = request.matchdict.get('user')
+ blog_posts_list = []
+ blog_slug = request.matchdict.get('blog_slug')
+ _log.info(blog_slug)
+
+ blog = request.db.Blog.query.filter_by(slug=blog_slug).first()
+
+ if not blog:
+ return render_404(request)
+
+ 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 blog_post:
+ blog_posts_list.append(blog_post)
+ blog_posts_list.reverse()
+ blog_post_count = len(blog_posts_list)
+
+ if may_edit_blogpost(request, blog):
+ return render_to_response(
+ request,
+ 'mediagoblin/blog/blog_admin_dashboard.html',
+ {'blog_posts_list': blog_posts_list,
+ 'blog_slug':blog_slug,
+ 'blog':blog,
+ 'blog_post_count':blog_post_count
+ })
+
+#supposed to list all the blog posts not just belonging to a particular post.
+def blog_post_listing(request):
+
+ blog_owner = request.matchdict.get('user')
+ _log.info("Username is %s"%(blog_owner))
+ owner_user = User.query.filter_by(username=blog_owner).one()
+
+ if not owner_user:
+ return render_404(request)
+
+ all_blog_posts = MediaEntry.query.filter_by(
+ uploader=owner_user.id, media_type='mediagoblin.media_types.blogpost',
+ state=u'processed').all()
+ all_blog_posts.reverse()
+ _log.info(len(all_blog_posts))
+
+ return render_to_response(
+ request,
+ 'mediagoblin/blog/blog_post_listing.html',
+ {'blog_posts': all_blog_posts,
+ 'blog_owner': blog_owner
+ })
+
+
+
+
+
diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py
index 1bb9c6f3..bf42e0b3 100644
--- a/mediagoblin/media_types/image/__init__.py
+++ b/mediagoblin/media_types/image/__init__.py
@@ -26,7 +26,7 @@ MEDIA_TYPE = 'mediagoblin.media_types.image'
def setup_plugin():
- config = pluginapi.get_config('mediagoblin.media_types.image')
+ config = pluginapi.get_config(MEDIA_TYPE)
class ImageMediaManager(MediaManagerBase):
diff --git a/mediagoblin/plugins/blog/LICENCE b/mediagoblin/plugins/blog/LICENCE
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/mediagoblin/plugins/blog/LICENCE
diff --git a/mediagoblin/plugins/blog/README.srt b/mediagoblin/plugins/blog/README.srt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/mediagoblin/plugins/blog/README.srt
diff --git a/mediagoblin/plugins/blog/__init__.py b/mediagoblin/plugins/blog/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/mediagoblin/plugins/blog/__init__.py
diff --git a/mediagoblin/plugins/blog/forms.py b/mediagoblin/plugins/blog/forms.py
new file mode 100644
index 00000000..52af1cf1
--- /dev/null
+++ b/mediagoblin/plugins/blog/forms.py
@@ -0,0 +1,17 @@
+# 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
diff --git a/mediagoblin/plugins/blog/setup.py b/mediagoblin/plugins/blog/setup.py
new file mode 100644
index 00000000..c4e0ee97
--- /dev/null
+++ b/mediagoblin/plugins/blog/setup.py
@@ -0,0 +1,10 @@
+from setuptools import setup, find_packages
+
+setup(
+ name = 'blog',
+ version = '1.0',
+ packages = find_packages();
+ include_package_data = True,
+ install_requires = [],
+ license = 'AGPLv3',
+ )
diff --git a/mediagoblin/plugins/blog/templates/blogpost_edit.html b/mediagoblin/plugins/blog/templates/blogpost_edit.html
new file mode 100644
index 00000000..fec7a9c2
--- /dev/null
+++ b/mediagoblin/plugins/blog/templates/blogpost_edit.html
@@ -0,0 +1,19 @@
+{#
+# 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" %}
+
diff --git a/mediagoblin/plugins/blog/views.py b/mediagoblin/plugins/blog/views.py
new file mode 100644
index 00000000..c4e8601d
--- /dev/null
+++ b/mediagoblin/plugins/blog/views.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# 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/>.
diff --git a/mediagoblin/processing/__init__.py b/mediagoblin/processing/__init__.py
index f3a85940..27d89895 100644
--- a/mediagoblin/processing/__init__.py
+++ b/mediagoblin/processing/__init__.py
@@ -171,7 +171,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''
diff --git a/mediagoblin/routing.py b/mediagoblin/routing.py
index 986eb2ed..4228d29b 100644
--- a/mediagoblin/routing.py
+++ b/mediagoblin/routing.py
@@ -36,6 +36,7 @@ def get_url_map():
import mediagoblin.webfinger.routing
import mediagoblin.listings.routing
import mediagoblin.notifications.routing
+ import mediagoblin.media_types.blog.routing
for route in PluginManager().get_routes():
add_route(*route)
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index 84d274d1..85027d77 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -288,6 +288,20 @@ 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: 700px;
+ min-height: 500px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+
.edit_box {
border-top: 6px dashed #D49086
}
@@ -296,6 +310,10 @@ text-align: center;
width: 100%;
}
+.blog_form_field_input input, .blog_form_field_input textarea {
+ width: 100%;
+}
+
.form_field_input {
margin-bottom: 10px;
}
diff --git a/mediagoblin/templates/mediagoblin/blog/blog_admin_dashboard.html b/mediagoblin/templates/mediagoblin/blog/blog_admin_dashboard.html
new file mode 100644
index 00000000..c45f0e30
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/blog/blog_admin_dashboard.html
@@ -0,0 +1,74 @@
+{#
+# 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 title -%}
+{{blog.title}} Dashboard &mdash; {{ super() }}
+{%- endblock title %}
+
+{% block mediagoblin_content %}
+<h1> {{blog.title}}</h1>
+<p>
+ {{blog.description}}
+</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>
+</p>
+<h2> Blog Post Entries </h2>
+ {% if blog_post_count!=0 %}
+ <table class="media_panel processing">
+ <tr>
+ <th>Title</th>
+ <th>submitted</th>
+ <th></th>
+ </tr>
+ {% for blog_post in blog_posts_list %}
+ <tr>
+ <td><a href="{{ blog_post.url_for_self(request.urlgen) }}">{{ blog_post.title }}</a></td>
+ <td>{{ blog_post.created.strftime("%F %R") }}</td>
+ <td><h6><em>{{ blog_post.state }}</em></h6></td>
+ {% 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) %}
+ <td><a class="button_action" href="{{ blogpost_edit_url }}">Edit</a>
+ <a class="button_action" >Delete</a>
+ </td>
+
+ </tr>
+ {% endfor %}
+ </table>
+ {% else %}
+ {% trans %} No blog post yet. {% endtrans %}
+ {% endif %}
+{% endblock %}
+
+
+
diff --git a/mediagoblin/templates/mediagoblin/blog/blog_edit_create.html b/mediagoblin/templates/mediagoblin/blog/blog_edit_create.html
new file mode 100644
index 00000000..fbed93db
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/blog/blog_edit_create.html
@@ -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}}</h3>
+ </div>
+ <div class="form_submit_buttons">
+ {{ csrf_token }}
+ <input type="submit" value="{% trans %}Add{% endtrans %}" class="button_form" />
+ </div>
+ </div>
+ </form>
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/blog/blog_post_edit_create.html b/mediagoblin/templates/mediagoblin/blog/blog_post_edit_create.html
new file mode 100644
index 00000000..b380d44c
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/blog/blog_post_edit_create.html
@@ -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 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="Draft" class="button_form">
+ </div>
+ </div>
+ </form>
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/extra_head.html b/mediagoblin/templates/mediagoblin/extra_head.html
index 973e2b48..176a77da 100644
--- a/mediagoblin/templates/mediagoblin/extra_head.html
+++ b/mediagoblin/templates/mediagoblin/extra_head.html
@@ -17,3 +17,14 @@
-#}
{# Add extra head declarations here for your theme, if appropriate #}
+
+<script type="text/javascript"
+ src="{{request.staticdirect('/tinymce/js/tinymce/tinymce.min.js')}}"></script>
+ <script type="text/javascript">
+ tinyMCE.init({
+ selector: "div.blog_form_field_input textarea",
+ height: "100%",
+ width:"100%"
+
+ })
+</script>
diff --git a/mediagoblin/templates/mediagoblin/media_displays/blogpost.html b/mediagoblin/templates/mediagoblin/media_displays/blogpost.html
new file mode 100644
index 00000000..b96ab34b
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/media_displays/blogpost.html
@@ -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/media.html' %}
+
+{% block mediagoblin_head %}
+ {{ super() }}
+{% endblock %}
+
+{% block mediagoblin_media %}
+<h1> {{media.title}}</h1>
+<p>{{media.description}}</p>
+
+{% endblock %}
+
+
+
+