Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikko Lehtinen committed Sep 25, 2010
0 parents commit 708f748
Show file tree
Hide file tree
Showing 952 changed files with 115,483 additions and 0 deletions.
22 changes: 22 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
About
=====
This is a blogging engine based on [[Bloggart-tipfy|http://github.com/mikkolehtinen/bloggart-tipfy]]

Installation
---------------------------
@git clone git@github.com:mikkolehtinen/mikkolehtinen.com.git@
@git submodule init && git submodule update@

- In your project folder run:
python bootstrap.py --distribute
bin/buildout

- Start the development server calling bin/dev_appserver. It will use the
application from /app by default:

bin/dev_appserver

- Open a browser and test the URLs:

http://localhost:8080/
http://localhost:8080/
27 changes: 27 additions & 0 deletions app/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
application: myappid
version: 1
runtime: python
api_version: 1

derived_file_type:
- python_precompiled

handlers:

- url: /remote_api
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
login: admin

- url: /_ah/queue/deferred
script: main.py
login: admin

- url: /admin/static
static_dir: templates/admin/static/

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

- url: /.*
script: main.py
1 change: 1 addition & 0 deletions app/apps/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Empty file added app/apps/blog/__init__.py
Empty file.
93 changes: 93 additions & 0 deletions app/apps/blog/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import os
DEV_SERVER = os.environ.get('SERVER_SOFTWARE', '').startswith('Development/')
DEBUG = TEMPLATE_DEBUG = DEV_SERVER

# Name of the blog
blog_name = 'mikkolehtinen.com'

# Your name (used for copyright info)
author_name = 'Mikko Lehtinen'

# (Optional) slogan
slogan = 'This is my blog'

# The hostname this site will primarially serve off (used for Atom feeds)
host = 'http://www.mikkolehtinen.com'

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

# 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'

# A nested list of sidebar menus, for convenience. If this isn't versatile
# enough, you can edit themes/default/base.html instead.
sidebars = [
('Menu', [
]),
]

# Number of entries per page in indexes.
posts_per_page = 5

# The mime type to serve HTML files as.
html_mime_type = "text/html; charset=utf-8"

# To use disqus for comments, set this to the 'short name' of the disqus forum
# created for the purpose.
disqus_forum = 'mikkolehtinen'

# Length (in words) of summaries, by default
summary_length = 200

# If you want to use Google Analytics, enter your 'web property id' here
analytics_id = None

# If you want to use PubSubHubbub, supply the hub URL to use here.
hubbub_hub_url = 'http://pubsubhubbub.appspot.com/'

# If you want to ping Google Sitemap when your sitemap is generated change this to True, else False
# see: http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=34609 for more information
google_sitemap_ping = False

# If you want to use Google Site verification, go to
# https://www.google.com/webmasters/tools/ , add your site, choose the 'upload
# an html file' method, then set the NAME of the file below.
# Note that you do not need to download the file provided - just enter its name
# here.
google_site_verification = None

# Default markup language for entry bodies (defaults to html).
default_markup = 'html'

# Syntax highlighting style for RestructuredText and Markdown,
# one of 'manni', 'perldoc', 'borland', 'colorful', 'default', 'murphy',
# 'vs', 'trac', 'tango', 'fruity', 'autumn', 'bw', 'emacs', 'pastie',
# 'friendly', 'native'.
highlighting_style = 'friendly'

# Absolute url of the blog application use '/blog' for host/blog/
# and '' for host/.Also remember to change app.yaml accordingly
url_prefix = ''

# Defines where the user is defined in the rel="me" of your pages.
# This allows you to expand on your social graph.
rel_me = None

# For use a feed proxy like feedburne.google.com
feed_proxy = None

# To use Google Friends Connect.
# If you want use Google Friends Connect, go to http://www.google.com/friendconnect/
# and register your domain for get a Google Friends connect ID.
google_friends_id = None
google_friends_comments = True # For comments.
google_friends_members = True # For a members container.

# To format the date of your post.
date_format = "%A %d. %B %Y"
13 changes: 13 additions & 0 deletions app/apps/blog/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from tipfy.ext.jinja2 import create_jinja2_instance

def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
return value.strftime(format)

def to_int(value):
return int(value)

def create_environment():
env = create_jinja2_instance()
env.filters['datetimeformat'] = datetimeformat
env.filters['to_int'] = to_int
return env
Empty file added app/apps/blog/posts/__init__.py
Empty file.
Empty file.
41 changes: 41 additions & 0 deletions app/apps/blog/posts/admin/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import logging
from tipfy.ext.wtforms import Form, fields
from ..models import BlogPost
from wtforms.ext.appengine.db import ModelConverter, model_form

class SetPropertyField(fields.TextAreaField):
"""
A field for ``db.SetProperty``. The set items are rendered in a
textarea.
"""
def process_data(self, value):
if isinstance(value, set):
value = '\n'.join(value)
self.data = value

def populate_obj(self, obj, name):
if isinstance(self.data, basestring):
value = set(self.data.strip().splitlines())
else:
value = set()
setattr(obj, name, value)


class BlogModelConverter(ModelConverter):
"""
Extends ModelConverter to support aetycoon's SetProperty
"""
def __init__(self, converters=None):
self.extended_converters = self.default_converters
self.extended_converters['SetProperty'] = convert_SetProperty
self.converters = converters or self.extended_converters

def convert_SetProperty(model, prop, kwargs):
return SetPropertyField(**kwargs)

class BasePostForm(Form):
# Add an extra, non-model related field.
draft = fields.BooleanField('Draft?')

PostForm = model_form(BlogPost, base_class=BasePostForm, converter=BlogModelConverter())

136 changes: 136 additions & 0 deletions app/apps/blog/posts/admin/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
"""
Admin handlers
"""

import os, logging, datetime

from google.appengine.ext import db
from google.appengine.ext import deferred

from tipfy import (RequestHandler, RequestRedirect, Response, abort,
cached_property, redirect, url_for, render_json_response)
from tipfy.ext.auth import AppEngineAuthMixin, login_required, user_required, admin_required

from tipfy.ext.jinja2 import Jinja2Mixin, render_response, render_template
from tipfy.ext.session import AllSessionMixins, SessionMiddleware
from tipfy.ext.wtforms import Form, fields, validators

from ... import config
from ..models import BlogPost
from utils import with_post
from forms import PostForm
from .. import markup
from .. import post_deploy

class BaseHandler(RequestHandler, AppEngineAuthMixin, Jinja2Mixin):
def render_to_response(self, template_name, template_vals=None, theme=None):
template = os.path.join("admin", template_name)
context = {
'config': config
}
if template_vals:
context.update(template_vals)

return self.render_response(template, **context)


class HomeHandler(BaseHandler):
"""A handler that outputs the result of a rendered template."""
def get(self, **kwargs):
return render_response('home.html', message='Hello, Jinja!')


class AdminHandler(BaseHandler):
@admin_required
def get(self, **kwargs):
"""
Show a list of posts
"""
offset = int(self.request.args.get('start', 0))
count = int(self.request.args.get('count', 20))

posts = BlogPost.all().order('-published').fetch(count, offset)
template_vals = {
'is_admin': True,
'offset': offset,
'count': count,
'last_post': offset + len(posts) - 1,
'prev_offset': max(0, offset - count),
'next_offset': offset + count,
'posts': posts,
}

return self.render_to_response('index.html', template_vals)



class PostHandler(BaseHandler):
def render_form(self, post=None):
self.form = self.get_form(post)
return self.render_to_response("edit.html", {'form': self.form})

@admin_required
@with_post
def get(self, post):
return self.render_form(post)

@admin_required
@with_post
def post(self, post):
self.form = self.get_form(post)

newpost = False
if not post:
newpost = True
post = BlogPost(title=self.form.title.data, body=self.form.body.data)

if self.form.validate():
self.form.populate_obj(post)
if newpost:
post.published = datetime.datetime.now()
post.updated = datetime.datetime.now()
post.publish()
return self.render_to_response("published.html", {'post': post})

return self.render_form()

def get_form(self, post):
return PostForm(self.request, obj=post)

class DeleteHandler(BaseHandler):
@with_post
def post(self, post):
if post.path:# Published post
post.remove()
else:# Draft
post.delete()
return self.render_to_response("deleted.html", None)

class PreviewHandler(RequestHandler):
def get(self):
logging.info('get called')
return Response('test')

def post(self, **kwargs):
body = self.request.form.get('body')
title = self.request.form.get('title')
body_markup = self.request.form.get('body_markup')

try:
post = BlogPost(title=title, body=body, body_markup=body_markup)
html = markup.render_body(post)
result = {'success': 'True',
'content': html}
except Exception, e:
error = ("Unable to markup data: %s" % e)
result = {'success': 'False',
'content': error}
return render_json_response(result)

class RegenerateHandler(BaseHandler):
def post(self):
regen = post_deploy.PostRegenerator()
deferred.defer(regen.regenerate)
deferred.defer(post_deploy.post_deploy, post_deploy.BLOG_VERSION)
return self.render_to_response("regenerating.html")

13 changes: 13 additions & 0 deletions app/apps/blog/posts/admin/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from ..models import BlogPost

def with_post(fun, *args, **kwargs):
def decorate(self, post_id=None):
post = None
if post_id:
post = BlogPost.get_by_id(int(post_id))
if not post:
self.error(404)
return

return fun(self, post, *args, **kwargs)
return decorate
Loading

0 comments on commit 708f748

Please sign in to comment.