added best practices

This commit is contained in:
sanj 2010-12-06 23:33:00 +01:00
parent df99d01610
commit 0bef11834f
16 changed files with 840 additions and 10 deletions

0
itf/api/__init__.py Normal file
View File

3
itf/api/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

23
itf/api/tests.py Normal file
View File

@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

155
itf/api/views.py Normal file
View File

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os.path
import re
from datetime import datetime
from urllib2 import unquote
import mimetypes
from django import forms
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.db.models import Q, Avg, Count, Sum
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
from django.template import RequestContext
from django.conf import settings
from ox.utils import json
from ox.django.decorators import login_required_json
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
from ox.django.http import HttpFileResponse
import ox
def api(request):
if request.META['REQUEST_METHOD'] == "OPTIONS":
response = HttpResponse('')
response = render_to_json_response({'status': {'code': 200, 'text': 'use POST'}})
response['Access-Control-Allow-Origin'] = '*'
return response
if not 'action' in request.POST:
return apidoc(request)
function = request.POST['action']
#FIXME: possible to do this in f
#data = json.loads(request.POST['data'])
f = globals().get('api_'+function, None)
if f:
response = f(request)
else:
response = render_to_json_response(json_response(status=400,
text='Unknown function %s' % function))
response['Access-Control-Allow-Origin'] = '*'
return response
def api_api(request):
'''
returns list of all known api action
return {'status': {'code': int, 'text': string},
'data': {actions: ['api', 'hello', ...]}}
'''
actions = globals().keys()
actions = map(lambda a: a[4:], filter(lambda a: a.startswith('api_'), actions))
actions.sort()
return render_to_json_response(json_response({'actions': actions}))
def api_apidoc(request):
'''
returns array of actions with documentation
'''
actions = globals().keys()
actions = map(lambda a: a[4:], filter(lambda a: a.startswith('api_'), actions))
actions.sort()
docs = {}
for f in actions:
docs[f] = get_api_doc(f)
return render_to_json_response(json_response({'actions': docs}))
def api_hello(request):
'''
return {'status': {'code': int, 'text': string},
'data': {user: object}}
'''
#data = json.loads(request.POST['data'])
response = json_response({})
if request.user.is_authenticated():
response['data']['user'] = get_user_json(request.user)
else:
response['data']['user'] = {'name': 'Guest', 'group': 'guest', 'preferences': {}}
return render_to_json_response(response)
def api_error(request):
'''
trows 503 error
'''
success = error_is_success
return render_to_json_response({})
def get_api_doc(f):
f = 'api_' + f
import sys
def trim(docstring):
if not docstring:
return ''
# Convert tabs to spaces (following the normal Python rules)
# and split into a list of lines:
lines = docstring.expandtabs().splitlines()
# Determine minimum indentation (first line doesn't count):
indent = sys.maxint
for line in lines[1:]:
stripped = line.lstrip()
if stripped:
indent = min(indent, len(line) - len(stripped))
# Remove indentation (first line is special):
trimmed = [lines[0].strip()]
if indent < sys.maxint:
for line in lines[1:]:
trimmed.append(line[indent:].rstrip())
# Strip off trailing and leading blank lines:
while trimmed and not trimmed[-1]:
trimmed.pop()
while trimmed and not trimmed[0]:
trimmed.pop(0)
# Return a single string:
return '\n'.join(trimmed)
return trim(globals()[f].__doc__)
def apidoc(request):
'''
this is used for online documentation at http://127.0.0.1:8000/api/
'''
functions = filter(lambda x: x.startswith('api_'), globals().keys())
api = []
for f in sorted(functions):
api.append({
'name': f[4:],
'doc': get_api_doc(f[4:]).replace('\n', '<br>\n')
})
context = RequestContext(request, {'api': api,
'sitename': settings.SITENAME,})
return render_to_response('api.html', context)
def jsdoc(request):
'''
Used to document OxUI JS Widgets
'''
context = RequestContext(request, {})
return render_to_response("jsdoc.html", context)
'''
ajax html snapshots
http://code.google.com/web/ajaxcrawling/docs/html-snapshot.html
'''
def html_snapshot(request):
fragment = unquote(request.GET['_escaped_fragment_'])
url = request.build_absolute_uri('/ra')
url = 'http://'+settings.URL
response = HttpResponse('sorry, server side rendering for %s!#%s not yet implemented'%(url, fragment))
return response

0
itf/app/__init__.py Normal file
View File

3
itf/app/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

23
itf/app/tests.py Normal file
View File

@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

23
itf/app/views.py Normal file
View File

@ -0,0 +1,23 @@
from django.template import RequestContext
from django.conf import settings
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from ox.django.shortcuts import json_response, render_to_json_response, get_object_or_404_json
from api.views import html_snapshot
def index(request):
context = RequestContext(request, {'settings':settings})
if request.GET.get('_escaped_fragment_', None):
return html_snapshot(request)
return render_to_response('index.html', context)
def site_json(request):
data = {
'site': {
'name': 'India Theatre Forum.'
}
}
return render_to_json_response(data)

View File

@ -0,0 +1,4 @@
from django.contrib import admin
from models import *
admin.site.register(BestPractice)

View File

@ -6,7 +6,7 @@ import urllib2
from django.http import HttpResponse from django.http import HttpResponse
from django.core.mail import send_mail from django.core.mail import send_mail
from django.db.models import Q from django.db.models import Q
from oxdjango.shortcuts import render_to_json_response from ox.django.shortcuts import render_to_json_response
from django.core.paginator import Paginator, InvalidPage, EmptyPage from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.template import RequestContext from django.template import RequestContext

View File

@ -3,6 +3,7 @@
import os import os
from os.path import join from os.path import join
SITENAME = "India Theatre Forum"
DEBUG = True DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
JSON_DEBUG = DEBUG JSON_DEBUG = DEBUG
@ -125,6 +126,7 @@ INSTALLED_APPS = (
'festival', 'festival',
'erang_organised', 'erang_organised',
'scriptbank', 'scriptbank',
'bestpractices',
# 'solango', # 'solango',
'multilingual', 'multilingual',
# 'multilingual.flatpages', # 'multilingual.flatpages',

565
itf/static/js/itf.js Normal file
View File

@ -0,0 +1,565 @@
var app = new Ox.App({
apiURL: '/api/',
init: 'hello',
config: 'site.json' //FIXME: shouldn't need this, get data with 'hello' or 'init'.
});
app.launch(function(data) {
Ox.print(data);
app.$body = $('body');
app.$document = $(document);
app.$window = $(window);
/*
app.user = data.user;
app.config = data.config;
*/
/*
//FIXME: should this be a nested structure as their representation on the page?
app.constructors = ['wrapper', 'headerPanel', 'mainPanel', 'leftPanel', 'cityPicker', 'calendarBox', 'currentEventsList', 'middlePanel', 'middleTopPanel', 'newsfeedBox', 'aboutBox', 'itfBox', 'middleBottomPanel', 'erangBox', 'scriptArchiveBox', 'bestPracticesBox', 'biblioBox', 'offersNeedsBox', 'surveysBox', 'rightPanel', 'searchBox', 'loginBox', 'featureBox', 'footerPanel']
*/
app.$ui = {};
/*
Ox.each(app.constructors, function(i, v) {
app.$ui[v] = app.construct[v]();
});
*/
var wrapper = app.construct.wrapper();
app.$body.css({'opacity': 0});
wrapper.appendTo(app.$body);
app.$body.animate({
'opacity': 1
}, 2000);
/*
//FIXME: make sure to add a loading icon
Ox.Request.requests() && app.$ui.loadingIcon.start();
Ox.Event.bind('', 'requestStart', function() {
Ox.print('requestStart')
app.$ui.loadingIcon.start();
});
Ox.Event.bind('', 'requestStop', function() {
Ox.print('requestStop')
app.$ui.loadingIcon.stop();
});
*/
// $(body).append(app.$ui.wrapper);
});
app.construct = {
/*
Structure:
wrapper
headerPanel
homeBox
searchBox
mainPanel
leftPanel
cityPicker
calendarBox
currentEventsList
middlePanel
middleTopPanel
newsfeedBox
aboutBox
itfBox
middleMiddlePanel
erangBox
scriptArchiveBox
bestPracticesBox
middleBottomPanel
biblioBox
offersNeedsBox
surveysBox
rightPanel
loginBox
featureBox
footerPanel
*/
'wrapper': function() {
var id = 'wrapper';
// Constructs overall wrapper for the page, and should be appended to $(body)
return app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'vertical',
elements: [
{
element: app.construct.headerPanel(),
size: 40
},
{
element: app.construct.mainPanel(),
},
{
element: app.construct.footerPanel(),
size: 40
}
]
});
},
/*
BEGIN headerPanel
*/
'headerPanel': function() {
var id = 'headerPanel';
var p = app.$ui[id] = new Ox.SplitPanel({
orientation: 'horizontal',
id: id,
elements: [
{
element: app.construct.homeBox(),
},
{
element: app.construct.searchBox(),
size: 128
}
]
});
return p;
},
'homeBox': function() {
var id = 'homeBox';
var c = app.$ui.homeBox = new Ox.Container({
id: id
});
c.$content.html("This is the header - maybe load from a template?");
return c;
},
'searchBox': function() {
var id = 'searchBox';
var i = app.$ui.searchBox = new Ox.Input({
'id': id,
'placeholder': 'Search'
});
i.bindEvent("submit", function(val) {
Ox.print("Should be doing a search");
});
return i;
},
/*
END headerPanel
*/
/*
BEGIN mainPanel
*/
'mainPanel': function() {
var id = 'mainPanel';
var p = app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'horizontal',
elements: [
{
element: app.construct.leftPanel(),
size: 256,
resizable: true,
resize: [0, 128, 256, 384]
},
{
element: app.construct.middlePanel(),
resizable: true
},
{
element: app.construct.rightPanel(),
size: 256,
resizable: true,
resize: [0, 128, 256, 384]
}
]
});
return p;
},
/*
BEGIN leftPanel
*/
'leftPanel': function() {
var id = 'leftPanel';
var p = app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'vertical',
elements: [
{
element: app.construct.cityPicker(),
size: 40
},
{
element: app.construct.calendarBox()
},
{
element: app.construct.currentEventsList(),
size: 300
}
]
});
return p;
},
'cityPicker': function() {
var id = 'cityPicker';
var i = app.$ui[id] = new Ox.Input({
id: id,
placeholder: 'Chose Your City'
});
i.submit(function(val) {
Ox.Print("should handle submit of city name");
});
return i;
},
'calendarBox': function() {
var id = 'calendarBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("somehow, the bookmyshow calendar goes here.");
return c;
},
'currentEventsList': function() {
var id = 'currentEventsList';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("List of current events");
return c;
},
/*
END leftPanel
*/
/*
BEGIN middlePanel
*/
'middlePanel': function() {
var id = 'middlePanel';
var p = app.$ui[id] = new Ox.SplitPanel({
orientation: 'vertical',
id: id,
elements: [
{
element: app.construct.middleTopPanel(),
size: 128,
resizable: true,
resize: [0, 64, 128, 196, 256],
collapsible: true
},
{
element: app.construct.middleMiddlePanel(),
collapsible: true
},
{
element: app.construct.middleBottomPanel(),
size: 128,
resizable: true,
resize: [0, 64, 128, 196, 256],
collapsible: true
}
]
});
return p;
},
/*
BEGIN middleTopPanel
*/
'middleTopPanel': function() {
var id = 'middleTopPanel';
var p = app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'horizontal',
elements: [
{
element: app.construct.newsfeedBox(),
size: 256
},
{
element: app.construct.aboutBox()
},
{
element: app.construct.itfBox(),
size: 256
}
]
});
return p;
},
'newsfeedBox': function() {
var id = 'newsfeedBox';
var c = app.$ui[id] = new Ox.ItfBox({
id: id,
title: 'ITF NewsFeed'
});
for (var i=0; i<25; i++) {
var content = new Ox.Element().html('newsfeed content goes here');
c.$content.append(content);
}
return c;
},
'aboutBox': function() {
var id = 'aboutBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("about goes here");
return c;
},
'itfBox': function() {
var id = 'itfBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("about itf goes here");
return c;
},
/*
END middleTopPanel
*/
/*
BEGIN middleMiddlePanel
*/
'middleMiddlePanel': function() {
var id = 'middleMiddlePanel';
var p = app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'horizontal',
elements: [
{
element: app.construct.erangBox(),
size: 256
},
{
element: app.construct.scriptArchiveBox()
},
{
element: app.construct.bestPracticesBox(),
size: 256
}
]
});
return p;
},
'erangBox': function() {
var id = 'erangBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("erang goes here");
return c;
},
'scriptArchiveBox': function() {
var id = 'scriptArchiveBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("script archive goes here");
return c;
},
'bestPracticesBox': function() {
var id = 'bestPracticesBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("best practices goes here");
return c;
},
/*
END middleMiddlePanel
*/
/*
BEGIN middleBottomPanel
*/
'middleBottomPanel': function() {
var id = 'middleBottomPanel';
var p = app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'horizontal',
elements: [
{
element: app.construct.biblioBox(),
size: 256
},
{
element: app.construct.offersNeedsBox()
},
{
element: app.construct.surveysBox(),
size: 256
}
]
});
return p;
},
'biblioBox': function() {
var id = 'biblioBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("biblioBox here");
return c;
},
'offersNeedsBox': function() {
var id = 'offersNeedsBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("offers and needs here");
return c;
},
'surveysBox': function() {
var id = 'surveysBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("surveys go here");
return c;
},
/*
END middleBottomPanel
*/
/*
END middlePanel
*/
/*
BEGIN rightPanel
*/
'rightPanel': function() {
var id = 'rightPanel';
var p = app.$ui[id] = new Ox.SplitPanel({
id: id,
orientation: 'vertical',
elements: [
{
element: app.construct.loginBox(),
size: 256
},
{
element: app.construct.featureBox()
}
]
});
return p;
},
'loginBox': function() {
var id = 'loginBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("login goes here");
return c;
},
'featureBox': function() {
var id = 'featureBox';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("featured profile here");
return c;
},
/*
END rightPanel
*/
/*
END mainPanel
*/
/*
BEGIN footerPanel
*/
'footerPanel': function() {
var id = 'footerPanel';
var c = app.$ui[id] = new Ox.Container({
id: id
});
c.$content.html("footer goes here");
return c;
}
/*
END footerPanel
*/
}
/*
Ox.Box - generic box element, with a bar, some help, possibility for a short menu, and should some-how be able to contain items / elements.
*/
Ox.ItfBox = function(options, self) {
var self = self || {};
var that = new Ox.Container(options, self)
.defaults({
'title': ''
})
.options(options);
var title = self.options.title;
var $titlebar = new Ox.Bar({
orientation: 'horizontal',
size: 16
})
// .dblclick(dblclickTitlebar)
.appendTo(that.$content),
/*
$switch = new Ox.Button({
id: options.id + 'Switch',
style: 'symbol',
title: title,
type: 'image',
})
// .click(toggleCollapsed)
.appendTo($titlebar),
*/
$title = new Ox.Element()
.addClass('OxTitle')
.html(title/*.toUpperCase()*/)
.appendTo($titlebar);
// $buttons = new Ox.
return that;
}

File diff suppressed because one or more lines are too long

View File

@ -1 +1,23 @@
Welcome :-) <!DOCTYPE html>
<html>
<head>
<title>India Theatre Forum</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="shortcut icon" type="image/png" href="/favicon.ico"/>
<link rel="stylesheet" type="text/css" href="/static/oxjs/build/css/ox.ui.css"/>
<script type='text/javascript'>
if(typeof(console)=='undefined') {
console = {};
console.log = function() {};
}
</script>
<script type="text/javascript" src="/static/js/jquery.js"></script>
<script type="text/javascript" src="/static/js/jquery/jquery.tmpl.min.js"></script>
<!-- <script type="text/javascript" src="/static/js/jquery/jquery.videosupport.js"></script> -->
<script type="text/javascript" src="/static/oxjs/build/js/ox.load.js"></script>
<script type="text/javascript" src="/static/oxjs/build/js/ox.js"></script>
<script type="text/javascript" src="/static/oxjs/build/js/ox.ui.js"></script>
<script type="text/javascript" src="/static/js/itf.js"></script>
</head>
<body></body>
</html>

View File

@ -17,6 +17,9 @@ urlpatterns = patterns('',
(r'^ckeditor/', include('ckeditor.urls')), (r'^ckeditor/', include('ckeditor.urls')),
(r'^robots.txt$', direct_to_template, {'template': 'robots.txt', 'mimetype': 'text/plain'}), (r'^robots.txt$', direct_to_template, {'template': 'robots.txt', 'mimetype': 'text/plain'}),
(r'^erang/', include('erang_organised.urls')), (r'^erang/', include('erang_organised.urls')),
(r'api/', 'api.views.api'),
(r'jsdoc/', 'api.views.jsdoc'),
(r'site.json', 'app.views.site_json'),
(r'^itf/$', 'festival.views.home'), (r'^itf/$', 'festival.views.home'),
(r'^itf/wireframe', 'festival.views.wireframe'), (r'^itf/wireframe', 'festival.views.wireframe'),
(r'^itf/projects', 'festival.views.projects'), (r'^itf/projects', 'festival.views.projects'),
@ -39,19 +42,22 @@ urlpatterns = patterns('',
# (r'profile', 'itfcore.views.edit_profile'), # (r'profile', 'itfcore.views.edit_profile'),
(r'i/', include('itfcore.urls')), (r'i/', include('itfcore.urls')),
(r'^admin/doc/', include('django.contrib.admindocs.urls')), (r'^admin/doc/', include('django.contrib.admindocs.urls')),
(r'^mockup/', 'itfcore.views.mockup'),
(r'x0news/', 'itfcore.views.allnews'), # (r'^mockup/', 'itfcore.views.mockup'),
(r'x0disc/', 'itfcore.views.disc'), # (r'x0news/', 'itfcore.views.allnews'),
(r'x0multi/', 'itfcore.views.multi'), # (r'x0disc/', 'itfcore.views.disc'),
(r'x0resources/', 'itfcore.views.resources'), # (r'x0multi/', 'itfcore.views.multi'),
(r'x0erang/', 'itfcore.views.erang'), # (r'x0resources/', 'itfcore.views.resources'),
(r'x0profile/', 'itfcore.views.profile'), # (r'x0erang/', 'itfcore.views.erang'),
# (r'x0profile/', 'itfcore.views.profile'),
(r'googlehostedservice.html', 'itfcore.views.googlehosted'), (r'googlehostedservice.html', 'itfcore.views.googlehosted'),
(r'emailsignuplist', 'festival.views.email_signups'), (r'emailsignuplist', 'festival.views.email_signups'),
(r'^favicon.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}), (r'^favicon.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}),
# (r'^ajax_filtered_fields/', include('ajax_filtered_fields.urls')), # (r'^ajax_filtered_fields/', include('ajax_filtered_fields.urls')),
# Uncomment the next line to enable the admin: # Uncomment the next line to enable the admin:
(r'^test$', 'app.views.index'),
(r'^$', 'festival.views.home') (r'^$', 'festival.views.home')
) )

View File

@ -1,5 +1,5 @@
-e svn+http://code.djangoproject.com/svn/django/branches/releases/1.2.X/#egg=django -e svn+http://code.djangoproject.com/svn/django/branches/releases/1.2.X/#egg=django
-e bzr+http://code.0xdb.org/python-oxdjango/#egg=python-oxdjango -e bzr+http://code.0x2620.org/python-ox/#egg=python-ox
-e svn+http://django-multilingual.googlecode.com/svn/trunk/#egg=multilingual -e svn+http://django-multilingual.googlecode.com/svn/trunk/#egg=multilingual
-e bzr+http://firefogg.org/dev/python-firefogg/#egg=python-firefogg -e bzr+http://firefogg.org/dev/python-firefogg/#egg=python-firefogg
-e bzr+http://firefogg.org/dev/django_firefogg/#egg=django_firefogg -e bzr+http://firefogg.org/dev/django_firefogg/#egg=django_firefogg