Skip to content

Commit

Permalink
Basic admin interface for submitting posts
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicholas Johnson committed Oct 7, 2009
1 parent 7618ea1 commit 4ca97f0
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 0 deletions.
106 changes: 106 additions & 0 deletions admin.py
@@ -0,0 +1,106 @@
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

from django import newforms as forms
from google.appengine.ext.db import djangoforms

import os
import re

import fix_path
import config
import static


def slugify(s):
return re.sub('[^a-zA-Z0-9-]+', '-', s).strip('-')


def format_post_path(post, num):
slug = slugify(post.title)
if num > 0:
slug += "-" + str(num)
return config.post_path_format % {
'slug': slug,
'year': post.published.year,
'month': post.published.month,
'day': post.published.day,
}


def render_template(template_name, template_vals=None, theme=None):
template_path = os.path.join("themes", theme or config.theme, template_name)
return template.render(template_path, template_vals or {})


class BlogPost(db.Model):
# The URL path to the blog post. Posts have a path iff they are published.
path = db.StringProperty()
title = db.StringProperty(required=True, indexed=False)
body = db.TextProperty(required=True)
published = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)

def render(self):
template_vals = {
'config': config,
'post': self,
}
return render_template("post.html", template_vals)

def publish(self):
rendered = self.render()
if not self.path:
num = 0
content = None
while not content:
path = format_post_path(self, num)
content = static.add(path, rendered, "text/html")
num += 1
self.path = path
self.put()
else:
static.set(self.path, rendered, "text/html")


class PostForm(djangoforms.ModelForm):
class Meta:
model = BlogPost
exclude = [ 'path', 'published', 'updated' ]


class PostHandler(webapp.RequestHandler):
def render_to_response(self, template_name, template_vals=None, theme=None):
template_name = os.path.join("admin", template_name)
self.response.out.write(render_template(template_name, template_vals,
theme))

def render_form(self, form):
self.render_to_response("edit.html", {'form': form})

def get(self):
self.render_form(PostForm())

def post(self):
form = PostForm(data=self.request.POST)
if form.is_valid():
post = form.save(commit=False)
post.publish()
self.render_to_response("published.html", {'post': post})
else:
self.render_form(form)


application = webapp.WSGIApplication([
('/admin/newpost', PostHandler),
])


def main():
run_wsgi_app(application)


if __name__ == '__main__':
main()
8 changes: 8 additions & 0 deletions app.yaml
Expand Up @@ -8,5 +8,13 @@ handlers:
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
login: admin

- url: /admin/.*
script: admin.py
login: admin

- url: /static/([^/]+)/(.*)
static_files: themes/\1/static/\2
upload: static/.*

- url: /.*
script: static.py
13 changes: 13 additions & 0 deletions config.py
@@ -0,0 +1,13 @@
# Name of the blog
blog_name = 'My Blog'

# Selects the theme to use. Theme names correspond to directories under
# the 'themes' directory, containing templates and static content.
theme = 'default'

# Defines the URL organization to use for blog postings. Valid substitutions:
# slug - the identifier for the post, derived from the title
# year - the year the post was published in
# month - the month the post was published in
# day - the day the post was published in
post_path_format = '/%(year)d/%(month)02d/%(slug)s'
14 changes: 14 additions & 0 deletions static.py
Expand Up @@ -54,7 +54,21 @@ def set(path, body, content_type, **kwargs):
content.put()
return content

def add(path, body, content_type, **kwargs):
"""Adds a new StaticContent and returns it.
Args:
As per set().
Returns:
A StaticContent object, or None if one already exists at the given path.
"""
def _tx():
if StaticContent.get_by_key_name(path):
return None
return set(path, body, content_type, **kwargs)
return db.run_in_transaction(_tx)


class StaticContentHandler(webapp.RequestHandler):
def output_content(self, content, serve=True):
self.response.headers['Content-Type'] = content.content_type
Expand Down
10 changes: 10 additions & 0 deletions themes/default/admin/edit.html
@@ -0,0 +1,10 @@
{% extends "../base.html" %}
{% block title %}New Post{% endblock %}
{% block body %}
<form method="post" action="">
<table>
{{form}}
</table>
<input type="submit" />
</form>
{% endblock %}
6 changes: 6 additions & 0 deletions themes/default/admin/published.html
@@ -0,0 +1,6 @@
{% extends "../base.html" %}
{% block title %}Post published{% endblock %}
{% block body %}
<p>Your post has been published!</p>
<p><a href="{{post.path}}">View your post</a></p>
{% endblock %}
9 changes: 9 additions & 0 deletions themes/default/base.html
@@ -0,0 +1,9 @@
<html>
<head>
<title>{% block title %}Bloggart{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
5 changes: 5 additions & 0 deletions themes/default/post.html
@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block title %}{{post.title}} - {{config.blog_name}}{% endblock %}
{% block body %}
{{post.body}}
{% endblock %}

0 comments on commit 4ca97f0

Please sign in to comment.