Add admin interface and views for proceedings. Booklet is also setup to generate paper.
authorMadhusudan.C.S <madhusudancs@gmail.com>
Thu, 01 Apr 2010 11:59:35 +0530
changeset 94 e86755df35da
parent 92 3743275f7291
child 95 34e28994fec5
Add admin interface and views for proceedings. Booklet is also setup to generate paper.
buildout.cfg
development.cfg
project/kiwipycon/proceedings/admin.py
project/kiwipycon/proceedings/booklet/__init__.py
project/kiwipycon/proceedings/booklet/mk_booklet.py
project/kiwipycon/proceedings/booklet/mk_scipy_paper.py
project/kiwipycon/proceedings/forms.py
project/kiwipycon/proceedings/views.py
project/kiwipycon/user/views.py
project/static/css/autosuggest_inquisitor.css
project/static/jquery/jquery.autosuggest.js
project/static/jquery/jquery.watermarkinput.js
project/templates/proceedings/submit.html
project/urls.py
--- a/buildout.cfg	Thu Jan 14 21:07:03 2010 +0530
+++ b/buildout.cfg	Thu Apr 01 11:59:35 2010 +0530
@@ -51,9 +51,8 @@
     ${registration:location}
 
 [basic-apps]
-recipe = infrae.subversion
-urls =
-    http://django-basic-apps.googlecode.com/svn/trunk/ basic
+recipe = zerokspot.recipe.git
+repository = http://github.com/nathanborror/django-basic-apps.git
 
 [tagging]
 recipe = infrae.subversion
--- a/development.cfg	Thu Jan 14 21:07:03 2010 +0530
+++ b/development.cfg	Thu Apr 01 11:59:35 2010 +0530
@@ -2,8 +2,8 @@
 extends =
     buildout.cfg
 
-#eggs +=
-#    pysqlite
+eggs +=
+    pysqlite
 
 [django]
 settings = development
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/kiwipycon/proceedings/admin.py	Thu Apr 01 11:59:35 2010 +0530
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+from django.contrib import admin
+
+from project.kiwipycon.proceedings.models import Paper
+
+
+class PaperAdmin(admin.ModelAdmin):
+    list_display = ('title', 'abstract')
+    list_filter = ('title', 'authors')
+    search_fields = ('title', 'abstract', 'authors')
+    fieldsets = (
+        ('Details', {
+            'fields': ('title', 'abstract', 'body', 'authors')
+        }),
+    )
+
+admin.site.register(Paper, PaperAdmin)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/kiwipycon/proceedings/booklet/mk_booklet.py	Thu Apr 01 11:59:35 2010 +0530
@@ -0,0 +1,94 @@
+# encoding: utf-8
+
+import os
+import sys
+import codecs
+import re
+
+try:
+    from sanum import model
+except:
+    root_dir = os.path.abspath(os.getcwd() + '/../../')
+    os.chdir(root_dir)
+    sys.path.append(root_dir)
+    from sanum import model
+
+import sanum
+
+import turbogears
+turbogears.update_config(configfile="dev.cfg",
+                         modulename="sanum.config")
+
+
+from mk_scipy_paper import tex2pdf, current_dir , copy_files, preamble, \
+        render_abstract, addfile, sourcedir, outdir, outfilename
+
+
+def hack_include_graphics(latex_text, attach_dir):
+    """ Replaces all the \includegraphics call with call that impose the
+        width to be 0.9\linewidth.
+    """
+    latex_text = re.sub(r'\\includegraphics(\[.*\])?\{',
+                        r'\includegraphics\1{' + attach_dir,
+                        latex_text)
+    return latex_text
+
+
+class MyStringIO(object):
+    """ An unicode-friendly stringIO-like object.
+    """
+
+    def __init__(self):
+        self.lines = []
+
+    def write(self, line):
+        self.lines.append(line)
+
+    def getvalue(self):
+        return u''.join(self.lines)
+
+def mk_booklet_tex(outfilename):
+    """ Generate the entire booklet latex file.
+    """
+    outfile = codecs.open(outfilename, 'w', 'utf-8')
+    preamble(outfile)
+    copy_files()
+    #addfile(outfile, sourcedir + os.sep + 'title.tex')
+    addfile(outfile, sourcedir + os.sep + 'introduction.tex')
+
+    #outfile.write(ur'\setcounter{page}{0}' + '\n')
+
+    #from sanum.controllers import Root as Controller
+    abstracts = model.Abstract.select()
+    for abstract in abstracts:
+        if not abstract.approved:
+            continue
+        print abstract.title
+        # Hack: I don't use a stringIO, because it is not unicode-safe.
+        tmpout = MyStringIO()
+        # Hack: I don't wont to be bound to the controller, to be
+        # abstractle to run without cherrypy.
+        #attach_dir = Controller._paper_attach_dir(abstract.id)
+        attach_dir = os.path.abspath(os.sep.join(
+                    (os.path.dirname(sanum.__file__), 'static', 
+                    'papers', '%i' % abstract.id))) + os.sep
+        render_abstract(tmpout, abstract)
+        outstring = hack_include_graphics(tmpout.getvalue(),
+                            attach_dir)
+        outfile.write(outstring)
+        #outfile.write(ur'\fillbreak' + '\n')
+
+    outfile.write(ur'\end{document}' + '\n')
+
+
+
+
+def mk_booklet(outfilename=outfilename):
+    """ Generate the entire booklet pdf file.
+    """
+    name, ext = os.path.splitext(outfilename)
+    mk_booklet_tex(name + '.tex')
+    return tex2pdf(name, remove_tex=False, timeout=60)
+
+if __name__ == '__main__':
+    mk_booklet(outfilename)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/kiwipycon/proceedings/booklet/mk_scipy_paper.py	Thu Apr 01 11:59:35 2010 +0530
@@ -0,0 +1,463 @@
+# encoding: utf-8
+
+import os
+import re
+import sys
+import shutil
+import codecs
+from glob import glob
+
+from docutils import core as docCore
+
+conf_name = 'SciPy2009'
+
+current_dir = '/media/python/workspace/kiwipycon/project/kiwipycon/proceedings/booklet'
+
+outdir = current_dir + os.sep + 'output'
+
+sourcedir = current_dir + os.sep + 'sources'
+try:
+    os.mkdir(outdir)
+except:
+    pass
+
+outfilename = outdir + os.sep + 'booklet.tex'
+
+##############################################################################
+# Routines for supervised execution
+##############################################################################
+
+from threading import Thread
+import os
+import signal
+from subprocess import Popen
+from time import sleep
+
+def delayed_kill(pid, delay=10):
+    sleep(delay)
+    try:
+        os.kill(pid, signal.SIGTERM)
+    except OSError:
+        pass
+
+def supervise_popen(command, timeout=10):
+    process = Popen(command)
+    Thread(target=delayed_kill, args=(process.pid,timeout),).start()
+
+    process.wait()
+
+
+
+##############################################################################
+# LaTeX generation functions.
+##############################################################################
+
+def protect(string):
+    r''' Protects all the "\" in a string by adding a second one before
+
+    >>> protect(r'\foo \*')
+    '\\\\foo \\\\*'
+    '''
+    return re.sub(r"\\", r"\\\\", string)
+
+
+def safe_unlink(filename):
+    """ Remove a file from the disk only if it exists, if not r=fails silently
+    """
+    if os.path.exists(filename):
+        os.unlink(filename)
+
+rxcountpages = re.compile(r"$\s*/Type\s*/Page[/\s]", re.MULTILINE|re.DOTALL)
+
+def count_pages(filename):
+    data = file(filename,"rb").read()
+    return len(rxcountpages.findall(data))
+
+
+def tex2pdf(filename, remove_tex=True, timeout=10, runs=2):
+    """ Compiles a TeX file with pdfLaTeX (or LaTeX, if or dvi ps requested)
+        and cleans up the mess afterwards
+    """
+    current_dir = os.getcwd()
+    os.chdir(os.path.dirname(filename))
+    print >> sys.stderr, "Compiling document to pdf"
+    basename = os.path.splitext(os.path.basename(filename))[0]
+    if os.path.exists(basename + '.pdf'):
+        os.unlink(basename + '.pdf')
+    for _ in range(runs):
+        supervise_popen(("pdflatex",  "--interaction", "scrollmode",
+                        os.path.basename(filename)), timeout=timeout)
+    error_file = None
+    errors =  file(os.path.abspath(basename + '.log')).readlines()[-1]
+    if not os.path.exists(basename + '.pdf') or \
+                                    "Fatal error" in errors:
+        error_file = os.path.abspath(basename + '.log')
+    if remove_tex:
+        safe_unlink(filename+".tex")
+        safe_unlink(filename+".log")
+    safe_unlink(filename+".aux")
+    safe_unlink(filename+".out")
+    os.chdir(current_dir)
+    return error_file
+
+
+def rst2latex(rst_string, no_preamble=True, allow_latex=True):
+    """ Calls docutils' engine to convert a rst string to a LaTeX file.
+    """
+    overrides = {'output_encoding': 'utf-8', 'initial_header_level': 3,
+                 'no_doc_title': True, 'use_latex_citations': True, 
+                 'use_latex_footnotes':True}
+    if allow_latex:
+        rst_string = u'''.. role:: math(raw)
+                    :format: latex
+                    \n\n''' + rst_string
+    tex_string = docCore.publish_string(
+                source=rst_string,
+                writer_name='latex2e', 
+                settings_overrides=overrides)
+    if no_preamble:
+        extract_document = \
+            re.compile(r'.*\\begin\{document\}(.*)\\end\{document\}',
+            re.DOTALL)
+        matches = extract_document.match(tex_string)
+        tex_string = matches.groups()[0]
+    return tex_string
+
+
+def get_latex_preamble():
+    """ Retrieve the required preamble from docutils.
+    """
+    full_document = rst2latex('\n', no_preamble=False)
+    preamble = re.split(r'\\begin\{document\}', full_document)[0]
+    ## Remove the documentclass.
+    preamble = r"""
+                %s
+                \makeatletter
+                \newcommand{\class@name}{gael}
+                \makeatother
+                \usepackage{ltxgrid}
+                %s
+                """ % (
+                    preamble.split('\n')[0],
+                    '\n'.join(preamble.split('\n')[1:]),
+                )
+    return preamble
+
+
+##############################################################################
+# Functions to generate part of the booklet
+##############################################################################
+def addfile(outfile, texfilename):
+    """ Includes the content of a tex file in our outfile.
+    """
+    include = codecs.open(texfilename, 'r')
+    data = include.readlines()
+    outfile.write(ur'\thispagestyle{empty}' + u'\n')
+    outfile.writelines(data)
+
+
+def preamble(outfile):
+    outfile.write(r'''
+    %s
+    \usepackage{abstracts}
+    \usepackage{ltxgrid}
+    \usepackage{amssymb,latexsym,amsmath,amsthm}
+    \usepackage{longtable}
+    \geometry{left=.8cm, textwidth=17cm, bindingoffset=0.6cm,
+                textheight=25.3cm, twoside}
+    \usepackage{hyperref}
+    \hypersetup{pdftitle={Proceedings of the 8th Annual Python in Science Conference}}
+    \begin{document}
+
+    '''.encode('utf-8') % get_latex_preamble())
+
+    # XXX SciPy08 should not be hard coded, but to run out of the webapp
+
+def hack_include_graphics(latex_text):
+    """ Replaces all the \includegraphics call with call that impose the
+        width to be 0.9\linewidth.
+    """
+    latex_text = re.sub(r'\\setlength\{\\rightmargin\}\{\\leftmargin\}',
+                        r'\\setlength{\\leftmargin}{4ex}\\setlength{\\rightmargin}{0ex}',
+                        latex_text)
+    latex_text = re.sub(r'\\begin\{quote\}\n\\begin\{itemize\}',
+                        r'\\begin{itemize}',
+                        latex_text)
+    latex_text = re.sub(r'\\end\{itemize\}\n\\end\{quote\}',
+                        r'\\end{itemize}',
+                        latex_text)
+    latex_text = re.sub(r'\\includegraphics(\[.*\])?\{',
+                        r'\includegraphics[width=\linewidth]{',
+                        latex_text)
+    latex_text = re.sub(r'\\href\{([^}]+)\}\{http://(([^{}]|(\{[^}]*\}))+)\}', 
+                        r'''%
+% Break penalties to have URL break easily:
+\mathchardef\UrlBreakPenalty=0
+\mathchardef\UrlBigBreakPenalty=0
+%\hskip 0pt plus 2em
+\href{\1}{\url{\1}}''',
+                        latex_text)
+    latex_text = re.sub(r'\\href\{([^}]+)\}\{https://(([^{}]|(\{[^}]*\}))+)\}', 
+                        r'''%
+% Break penalties to have URL break easily:
+\mathchardef\UrlBreakPenalty=0
+\mathchardef\UrlBigBreakPenalty=0
+\linebreak
+\href{\1}{\url{\1}}''',
+                        latex_text)
+
+    return latex_text
+
+
+def render_abstract(outfile, abstract, start_page=None):
+    """ Writes the LaTeX string corresponding to one abstract.
+    """
+    if start_page is not None:
+        outfile.write(r"""
+\setcounter{page}{%i}
+""" % start_page)
+    else:
+        if hasattr(abstract, 'start_page'):
+            start_page = abstract.start_page
+        else:
+            start_page = 1
+    if not abstract.authors:
+        author_list = abstract.owners
+    else:
+        author_list = abstract.authors
+    authors = []
+    print dir(author_list[0])
+    for author in author_list:
+        # If the author has no surname, he is not an author 
+        if author.surname:
+            if author.email_address:
+                email = r'(\email{%s})' % author.email_address
+            else:
+                email = ''
+            authors.append(ur'''\otherauthors{
+                            %s %s
+                            %s --
+                            \address{%s, %s}
+                            }''' % (author.first_names, author.surname,
+                                    email,
+                                    author.institution,
+                                    author.city))
+    if authors:
+        authors = u'\n'.join(authors)
+        authors += r'\addauthorstoc{%s}' % ', '.join(
+                '%s. %s' % (author.first_names[0], author.surname)
+                for author in author_list
+                )
+        author_cite_list = ['%s. %s' % (a.first_names[0], a.surname) 
+                                for a in author_list]
+        if len(author_cite_list) > 4:
+            author_cite_list = author_cite_list[:3]
+            author_cite_list.append('et al.')
+        citation = ', '.join(author_cite_list) + \
+        'in Proc. SciPy 2009, G. Varoquaux, S. van der Walt, J. Millman (Eds), '
+        copyright = '\\copyright 2009, %s' % ( ', '.join(author_cite_list))
+    else:
+        authors = ''
+        citation = 'Citation'
+        copyright = 'Copyright'
+    if hasattr(abstract, 'num_pages'):
+        citation += 'pp. %i--%i' % (start_page, start_page +
+                                        abstract.num_pages)
+    else:
+        citation += 'p. %i'% start_page
+    if hasattr(abstract, 'number'):
+        abstract.url = 'http://conference.scipy.org/proceedings/%s/paper_%i' \
+        % (conf_name, abstract.number)
+        url = r'\url{%s}' % abstract.url
+    else:
+        url = ''
+    paper_text = abstract.paper_text
+    if paper_text == '':
+        paper_text = abstract.summary
+    # XXX: It doesn't seem to be right to be doing this, but I get a
+    # nasty UnicodeDecodeError on some rare abstracts, elsewhere.
+    paper_text = codecs.utf_8_decode(hack_include_graphics(
+                                rst2latex(paper_text)))[0]
+    paper_abstract = abstract.paper_abstract
+    if paper_abstract is None:
+        paper_abstract = ''
+    if not paper_abstract=='':
+        paper_abstract = ur'\begin{abstract}%s\end{abstract}' % \
+                    paper_abstract#.encode('utf-8')
+    abstract_dict = {
+            'text': paper_text.encode('utf-8'),
+            'abstract': paper_abstract.encode('utf-8'),
+            'authors': authors.encode('utf-8'),
+            'title': abstract.title.encode('utf-8'),
+            'citation': citation.encode('utf-8'),
+            'copyright': copyright.encode('utf-8'),
+            'url': url.encode('utf-8'),
+        }
+    outfile.write(codecs.utf_8_decode(ur'''
+\phantomsection
+\hypertarget{chapter}{} 
+\vspace*{-2em}
+
+\resetheadings{%(title)s}{%(citation)s}{%(url)s}{%(copyright)s}
+\title{%(title)s}
+
+\begin{minipage}{\linewidth}
+%(authors)s
+\end{minipage}
+
+\noindent\rule{\linewidth}{0.2ex}
+\vspace*{-0.5ex}
+\twocolumngrid
+%(abstract)s
+
+\sloppy
+
+%(text)s
+
+\fussy
+\onecolumngrid
+\smallskip
+\vfill
+\filbreak
+\clearpage
+
+'''.encode('utf-8') % abstract_dict )[0])
+
+def copy_files(dest=outfilename):
+    """ Copy the required file from the source dir to the output dir.
+    """
+    dirname = os.path.dirname(dest)
+    if dirname == '':
+        dirname = '.'
+    for filename in glob(sourcedir+os.sep+'*'):
+        destfile = os.path.abspath(dirname + os.sep +
+                                os.path.basename(filename))
+        shutil.copy2(filename, destfile)
+
+
+def mk_abstract_preview(abstract, outfilename, attach_dir, start_page=None):
+    """ Generate a preview for an given paper.
+    """
+    copy_files()
+    outdir = os.path.dirname(os.path.abspath(outfilename))
+    for f in glob(os.path.join(attach_dir, '*')):
+        if  os.path.isdir(f) and not os.path.exists(f):
+            os.makedirs(f)
+        else:
+            if not outdir == os.path.dirname(os.path.abspath(f)):
+                shutil.copy2(f, outdir)
+    for f in glob(os.path.join(sourcedir, '*')):
+        if  os.path.isdir(f):
+            os.makedirs(f)
+        else:
+            destfile = os.path.abspath(os.path.join(outdir, f))
+            shutil.copy2(f, outdir)
+
+    outbasename = os.path.splitext(outfilename)[0]
+    outfilename = outbasename + '.tex'
+
+    outfile = codecs.open(outfilename, 'w', 'utf-8')
+    preamble(outfile)
+    render_abstract(outfile, abstract, start_page=start_page)
+    outfile.write(ur'\end{document}' + u'\n')
+    outfile.close()
+
+    tex2pdf(outbasename, remove_tex=False)
+    abstract.num_pages = count_pages(outbasename + '.pdf')
+
+    # Generate the tex file again, now that we know the length.
+    outfile = codecs.open(outfilename, 'w', 'utf-8')
+    preamble(outfile)
+    render_abstract(outfile, abstract, start_page=start_page)
+    outfile.write(ur'\end{document}' + u'\n')
+    outfile.close()
+
+    return tex2pdf(os.path.splitext(outfilename)[0], remove_tex=False)
+
+
+##############################################################################
+# Code for using outside of the webapp.
+##############################################################################
+
+def mk_zipfile():
+    """ Generates a zipfile with the required files to build an
+        abstract.
+    """
+    from zipfile import ZipFile
+    zipfilename = os.path.join(os.path.dirname(__file__), 
+                            'mk_scipy_paper.zip')
+    z = ZipFile(zipfilename, 'w')
+    for filename in glob(os.path.join(sourcedir, '*')):
+        if not os.path.isdir(filename):
+            z.write(filename, arcname='source/' + os.path.basename(filename))
+    z.write(__file__, arcname='mk_scipy_paper.py')
+    return zipfilename
+
+class Bunch(dict):
+    def __init__(self, **kwargs):
+        dict.__init__(self, **kwargs)
+        self.__dict__ = self
+
+    def __reprt(self):
+        return repr(self.__dict__)
+
+author_like = Bunch(
+        first_names='XX', 
+        surname='XXX',
+        email_address='xxx@XXX',
+        institution='XXX',
+        address='XXX',
+        country='XXX'
+)
+
+
+abstract_like = Bunch(
+        paper_abstract='An abstract',
+        authors=[author_like, ],
+        title='',
+    )
+
+if __name__ == '__main__':
+    from optparse import OptionParser
+    parser = OptionParser()
+    parser.add_option("-o", "--output", dest="outfilename",
+                    default="./paper.pdf",
+                    help="output to FILE", metavar="FILE")
+    parser.usage = """%prog [options] rst_file [data_file]
+    Compiles a given rest file and information file to pdf for the SciPy
+    proceedings.
+    """
+    
+    (options, args) = parser.parse_args()
+    if not len(args) in (1, 2):
+        print "One or two arguments required: the input rest file and " \
+                "the input data file"
+        print ''
+        parser.print_help()
+        sys.exit(1)
+    infile = args[0]
+    if len(args)==1:
+        data_file = 'data.py'
+        if os.path.exists('data.py'):
+            print "Using data file 'data.py'"
+        else:
+            print "Generating the data file and storing it in data.py"
+            print "You will need to edit this file to add title, author " \
+                "information, and abstract."
+            abstract = abstract_like
+            file('data.py', 'w').write(repr(abstract))
+    elif len(args)==2:
+        data_file = args[1]
+    
+    abstract = Bunch( **eval(file(data_file).read()))
+    abstract.authors = [Bunch(**a) for a in abstract.authors]
+
+    abstract['summary'] = u''
+    abstract['paper_text'] = file(infile).read().decode('utf-8')
+
+    outfilename = options.outfilename
+
+    mk_abstract_preview(abstract, options.outfilename, 
+                        os.path.dirname(options.outfilename))
+    # Ugly, but I don't want to wait on the thread.
+    sys.exit()
--- a/project/kiwipycon/proceedings/forms.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/kiwipycon/proceedings/forms.py	Thu Apr 01 11:59:35 2010 +0530
@@ -26,5 +26,5 @@
         "'Abstract' and other with a heading 'Body'.")
 
     authors = forms.CharField(
-        required=False, label=u'Author',
-        help_text=u'User ID of the author.')
+        required=False, label=u'Author(s)',
+        help_text=u'Comma separated list of User ID of the author(s).')
--- a/project/kiwipycon/proceedings/views.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/kiwipycon/proceedings/views.py	Thu Apr 01 11:59:35 2010 +0530
@@ -1,20 +1,46 @@
-# -*- coding: utf-8 -*-
+  # -*- coding: utf-8 -*-
+
+import os
 
 from django.contrib.auth import login
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.forms import AuthenticationForm
+from django.contrib.auth.models import User
+from django.core.urlresolvers import reverse
 from django.shortcuts import render_to_response
 from django.template import RequestContext
 
+from project.kiwipycon.proceedings.models import Paper
 from project.kiwipycon.user.forms import RegisterForm
 from project.kiwipycon.user.models import UserProfile
+from project.kiwipycon.utils import set_message_cookie
+from project.kiwipycon.proceedings.booklet import mk_scipy_paper
 from project.kiwipycon.proceedings.forms import ProceedingsForm
 
 
+def handleUploadedFile(proceedings_form_data, rst_file):
+    """Handles the uploaded file content and process the form
+    """
+
+    title = proceedings_form_data.get('title')
+    abstract = proceedings_form_data.get('abstract')
+    body = proceedings_form_data.get('body')
+    authors = proceedings_form_data.get('authors')
+
+    if rst_file:
+        destination = open('some/file/name.txt', 'wb+')
+        for chunk in rst_file.chunks():
+            destination.write(chunk)
+        destination.close()
+
+    return title, abstract, body, authors
+
+
 @login_required
-def submit(request, template = 'proceedings/submit.html'):
+def submit(request, id=None, template='proceedings/submit.html'):
     """View to submit the proceedings paper.
     """
+
     user = request.user
     if user.is_authenticated():
         try:
@@ -26,10 +52,7 @@
     message = None
 
     if request.method == 'POST':
-        proceedings_form = ProceedingsForm(data=request.POST)
-
-        register_form = RegisterForm(data=request.POST,
-                                        files=request.FILES)
+        register_form = RegisterForm(data=request.POST)
 
         if request.POST.get('action', None) == 'login':
             login_form = AuthenticationForm(data=request.POST)
@@ -47,28 +70,49 @@
 
                 user = kiwipycon_createuser(request, register_form.data)
 
+        proceedings_form = ProceedingsForm(data=request.POST,
+                                           files=request.FILES)
+  
         if proceedings_form.is_valid():
             if user.is_authenticated():
-                title = proceedings_form.data.get('title')
+                # Data from reSt file is appended to the data in fields
+                title, abstract, body, authors = handleUploadedFile(
+                    proceedings_form.cleaned_data, request.FILES.get('file'))
 
-                # Saved, ... redirect back to account
-                redirect_to = reverse('kiwipycon_account')
-                return set_message_cookie(redirect_to,
-                        msg = u'Thanks, your paper has been submitted.')
+                paper = edit(id, title=title,
+                    abstract=abstract, body=body,
+                    authors=authors) if id else create(title=title,
+                    abstract=abstract, body=body,
+                    authors=authors)
+
+                # Successfully saved. So get back to the edit page.
+                redirect_to = reverse('kiwipycon_submit_proceedings',
+                                  args=[paper.id])
+                return set_message_cookie(
+                redirect_to, msg = u'Thanks, your paper has been submitted.')
             else:
+                # This is impossible. Something was wrong so return back
+                # to submit page
                 redirect_to = reverse('kiwipycon_submit_proceedings')
-                return set_message_cookie(redirect_to,
-                        msg = u'Something is wrong here.')
+                return set_message_cookie(
+                redirect_to, msg = u'Something is wrong here.')          
+    else:
+        if id:
+            # If id exists initialize the form with old values
+            paper = Paper.objects.get(id=id)
+            proceedings_form = ProceedingsForm(
+                initial={'title': paper.title,
+                         'abstract': paper.abstract,
+                         'body': paper.body,
+                         'authors': ', '.join([
+                             author.username for author in paper.authors.all()])
+                })
+        else:
+            # Otherwise create a new form
+            proceedings_form = ProceedingsForm()
 
-    else:
-        proceedings_form = ProceedingsForm()
         register_form = RegisterForm()
-    login_form = AuthenticationForm()
-
-        
-    proceedings_form = ProceedingsForm()
-    register_form = RegisterForm()
-    login_form = AuthenticationForm()
+        login_form = AuthenticationForm()
 
     context = RequestContext(request, {
         'proceedings_form': proceedings_form,
@@ -77,18 +121,83 @@
         'login_form' : login_form
         })
 
+    context['id'] = id if id else None
+
     return render_to_response(template, context)
 
 
-def edit(request, id, template = 'proceedings/edit.html'):
+def create(**kwargs):
+    """View to create a new proceedings.
+    """
+
+    title = kwargs.get('title')
+    abstract = kwargs.get('abstract')
+    body = kwargs.get('body')
+    authors = kwargs.get('authors')
+
+    paper = Paper(title=title, abstract=abstract, body=body)
+    paper.save()
+
+    if authors:
+        authors = authors.split(',')
+        for author in authors:
+            user = User.objects.get(username=author.strip())
+            paper.authors.add(user)
+
+    return paper
+
+
+def edit(id, **kwargs):
     """View to edit the proceedings paper.
     """
 
-    context = RequestContext(request, {
-        'proceedings_form': proceedings_form,
-        'register_form' : register_form,
-        'message' : message,
-        'login_form' : login_form
-        })
+    paper = Paper.objects.get(id=id)
+
+    paper.title = kwargs.get('title')
+    paper.abstract = kwargs.get('abstract')
+    paper.body = kwargs.get('body')
+    authors = kwargs.get('authors')
+
+    if authors:
+        authors = authors.split(',')
+        for author in authors:
+            user = User.objects.get(username=author.strip())
+            paper.authors.add(user)
+
+    paper.save()
+
+    return paper
+
+
+def show_paper(request, id):
+    """Display the thumbnail of the rendered paper for download
+    """
+    
+    paper = Paper.objects.get(id=id)
 
-    return render_to_response(template, context)
+    paper_data = {
+      'paper_abstract': paper.abstract,
+      'authors': [
+          {'first_names': author.first_name,
+            'surname': author.last_name,
+            'address': 'XXX',
+            'country': 'XXX',
+            'email_address': 'XXX@xx.com',
+            'institution': 'XXX'
+           } for author in paper.authors.all()],
+      'title': paper.title
+      }
+    
+    abstract = mk_scipy_paper.Bunch(**paper_data)
+    abstract.authors = [mk_scipy_paper.Bunch(**a) for a in abstract.authors]
+
+    abstract['paper_text'] = paper.body
+
+    outfilename = '/media/python/workspace/kiwipycon/project/kiwipycon/proceedings/booklet/output/paper.pdf'
+    attach_dir = os.path.dirname('/media/python/workspace/kiwipycon/project/kiwipycon/proceedings/booklet/output/')
+    mk_scipy_paper.mk_abstract_preview(abstract, outfilename, attach_dir)
+
+    from django.http import HttpResponse
+    return HttpResponse('Machi')
+
+ 
\ No newline at end of file
--- a/project/kiwipycon/user/views.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/kiwipycon/user/views.py	Thu Apr 01 11:59:35 2010 +0530
@@ -1,12 +1,16 @@
 # -*- coding: utf-8 -*-
 from __future__ import absolute_import
+
 #python
 from urlparse import urlparse
+import json
 import urllib
 import os
 
 #django
 from django.conf import settings
+from django.db.models import Q
+from django.http import HttpResponse
 from django.shortcuts import render_to_response
 from django.template import RequestContext
 from django.core.urlresolvers import reverse
@@ -16,6 +20,7 @@
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.forms import AuthenticationForm
 from django.contrib.auth.forms import PasswordChangeForm
+from django.contrib.auth.models import User
 from django.core.exceptions import ObjectDoesNotExist
 
 #PIL
@@ -236,3 +241,38 @@
         "form": username_form
     }))
 
+
+def get_usernames(request):
+    """Returns in json the list of ten possible usernames
+    starting with the last pattern in the comma separated string
+    """
+
+    get_params = request.GET
+    authors_str = get_params.get('input')
+
+    if not authors_str:
+        return HttpResponse(json.dumps(''))
+
+    authors = authors_str.split(',')
+    search_author = authors[-1].strip()
+
+    users = User.objects.filter(
+        Q(username__istartswith=search_author) | Q(
+        first_name__istartswith=search_author) | Q(
+        last_name__istartswith=search_author))
+
+    results = [{'id': '',
+                'info': 'plugin_header',
+                'value': 'User Names'
+              }]
+    
+    for user in users:
+        results.append(
+            {'id': 'author_name',
+             'info': str(user.get_full_name()),
+             'value': str(user.username)
+            })
+
+    json_response = {'results': results}
+
+    return HttpResponse(json.dumps(json_response))
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/static/css/autosuggest_inquisitor.css	Thu Apr 01 11:59:35 2010 +0530
@@ -0,0 +1,208 @@
+/* 
+================================================
+autosuggest, inquisitor style
+================================================
+*/
+
+div.autosuggest
+{
+	position: absolute;
+	background-position: top;
+	background-repeat: no-repeat;
+	padding: 0px 0 0 0;
+}
+
+/* IEXX compatinility */
+* html div.autosuggest {
+	padding-top:1px; 
+}
+
+/* Only IE7 compatibility */
+*+html div.autosuggest {
+	margin-top:12px;
+	padding:0px;
+}
+
+div.autosuggest div.as_header
+{
+	margin-top:5px;
+	position: relative;
+	height: 3px;
+	padding: 1px 0 0 0 ;
+	border-top:1px solid #95a5c6;
+	border-left:1px solid #95a5c6;
+	border-right:1px solid #95a5c6;
+	background-color:#ffffff;
+	background-position: top right;
+	background-repeat: no-repeat;
+	overflow: hidden;
+}
+div.autosuggest div.as_footer
+{
+	position: relative;
+	height: 3px;
+	padding: 1px 0 0 0 ;
+	border-bottom:1px solid #95a5c6;
+	border-left:1px solid #95a5c6;
+	border-right:1px solid #95a5c6;
+	background-color:#ffffff;
+	background-position: top right;
+	background-repeat: no-repeat;
+	overflow: hidden;
+}
+/* Only IE7 compatibility */
+*+html div.autosuggest div.as_header { margin-top:0px; }
+* html div.autosuggest div.as_header { margin-top:5px; }
+
+div.autosuggest div.as_footer
+{
+	/* border-bottom:1px solid #95a5c6; */
+}
+
+div.autosuggest div.as_header div.as_corner,
+div.autosuggest div.as_footer div.as_corner
+{
+	position: absolute;
+	top: 0;
+	left: 0;
+}
+div.autosuggest div.as_footer div.as_corner
+{
+	
+}
+div.autosuggest div.as_header div.as_bar,
+div.autosuggest div.as_footer div.as_bar
+{
+	height: 0px;
+	overflow: hidden;
+	background-color: #ffffff;
+}
+
+
+div.autosuggest ul
+{
+	list-style: none;
+	margin: 0 0 -4px 0;
+	padding: 0;
+	overflow: hidden;
+	background-color: #ffffff;
+	border-left:1px solid #95a5c6;
+	border-right:1px solid #95a5c6;
+}
+
+div.autosuggest ul li
+{
+	color: #5776ae;
+	padding: 0;
+	margin: 0 4px 4px;
+	text-align: left;
+}
+
+div.autosuggest ul li a
+{
+	color: #000000;
+	display: block;
+	text-decoration: none;
+	background-color: transparent;
+	text-shadow: #000 0px 0px 5px;
+	position: relative;
+	padding: 0;
+	width: 100%;
+}
+div.autosuggest ul li a:hover
+{
+	background-color: #3b5998;
+	text-decoration:none;
+}
+div.autosuggest ul li.as_highlight a:hover
+{
+	background-color: #3b5998;
+	text-decoration:none;
+}
+
+div.autosuggest ul li a span
+{
+	display: block;
+	padding: 3px 6px;
+	font-weight: normal;
+}
+
+div.autosuggest ul li a span small
+{
+	font-weight: normal;
+	color: #999;
+}
+
+div.autosuggest ul li.as_highlight a span small
+{
+	color: #ccc;
+}
+
+div.autosuggest ul li.as_highlight a
+{
+	color: #fff;
+	background-color: #3b5998;
+	background-position: bottom right;
+	background-repeat: no-repeat;
+	text-decoration:none;
+}
+
+div.autosuggest ul li.as_highlight a span
+{
+	background-position: bottom left;
+	background-repeat: no-repeat;
+}
+
+div.autosuggest ul li a .tl,
+div.autosuggest ul li a .tr
+{
+	background-image: transparent;
+	background-repeat: no-repeat;
+	width: 6px;
+	height: 6px;
+	position: absolute;
+	top: 0;
+	padding: 0;
+	margin: 0;
+}
+div.autosuggest ul li a .tr
+{
+	right: 0;
+}
+
+div.autosuggest ul li.as_highlight a .tl
+{
+	left: 0;
+	background-position: bottom left;
+}
+
+div.autosuggest ul li.as_highlight a .tr
+{
+	right: 0;
+	background-position: bottom right;
+}
+
+div.autosuggest ul li.as_warning
+{
+	font-weight: bold;
+	text-align: center;
+}
+
+div.autosuggest ul li.as_header
+{
+	font-weight: bold;
+	font-size:14px;
+	color:#FFFFFF;
+	background:#999;
+	padding-left:6px;
+	padding-top:2px;
+	padding-bottom:2px;
+}
+
+div.autosuggest ul em
+{
+	font-style: normal;
+	font-weight:bold;
+	color: #000000;
+	background-color:#d8dfea;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/static/jquery/jquery.autosuggest.js	Thu Apr 01 11:59:35 2010 +0530
@@ -0,0 +1,17 @@
+<!-- Init AutoSuggest -->
+/** AutoSuggest Packed JS **/
+if(typeof(bsn)=="undefined")_b=bsn={};if(typeof(_b.Autosuggest)=="undefined")_b.Autosuggest={};else alert("Autosuggest is already set!");_b.AutoSuggest=function(id,param){if(!document.getElementById)return 0;this.fld=_b.DOM.gE(id);if(!this.fld)return 0;this.sInp="";this.nInpC=0;this.aSug=[];this.iHigh=0;this.oP=param?param:{};var k,def={minchars:1,meth:"get",varname:"input",className:"autosuggest",timeout:2500,delay:500,offsety:-5,shownoresults:true,noresults:"No results!",maxheight:250,cache:true,maxentries:25};for(k in def){if(typeof(this.oP[k])!=typeof(def[k]))this.oP[k]=def[k]}var p=this;this.fld.onkeypress=function(ev){return p.onKeyPress(ev)};this.fld.onkeyup=function(ev){return p.onKeyUp(ev)};this.fld.setAttribute("autocomplete","off")};_b.AutoSuggest.prototype.onKeyPress=function(ev){var key=(window.event)?window.event.keyCode:ev.keyCode;var RETURN=13;var TAB=9;var ESC=27;var bubble=1;switch(key){case RETURN:this.setHighlightedValue();bubble=0;break;case ESC:this.clearSuggestions();break}return bubble};_b.AutoSuggest.prototype.onKeyUp=function(ev){var key=(window.event)?window.event.keyCode:ev.keyCode;var ARRUP=38;var ARRDN=40;var bubble=1;switch(key){case ARRUP:this.changeHighlight(key);bubble=0;break;case ARRDN:this.changeHighlight(key);bubble=0;break;default:this.getSuggestions(this.fld.value)}return bubble};_b.AutoSuggest.prototype.getSuggestions=function(val){if(val==this.sInp)return 0;_b.DOM.remE(this.idAs);this.sInp=val;if(val.length<this.oP.minchars){this.aSug=[];this.nInpC=val.length;return 0}var ol=this.nInpC;this.nInpC=val.length?val.length:0;var l=this.aSug.length;if(this.nInpC>ol&&l&&l<this.oP.maxentries&&this.oP.cache){var arr=[];for(var i=0;i<l;i++){if(this.aSug[i].value.substr(0,val.length).toLowerCase()==val.toLowerCase()||this.aSug[i].info=='as_header')arr.push(this.aSug[i])}this.aSug=arr;this.createList(this.aSug);return false}else{var pointer=this;var input=this.sInp;clearTimeout(this.ajID);this.ajID=setTimeout(function(){pointer.doAjaxRequest(input)},this.oP.delay)}return false};_b.AutoSuggest.prototype.doAjaxRequest=function(input){if(input!=this.fld.value)return false;var pointer=this;if(typeof(this.oP.script)=="function")var url=this.oP.script(encodeURIComponent(this.sInp));else var url=this.oP.script+this.oP.varname+"="+encodeURIComponent(this.sInp);if(!url)return false;var meth=this.oP.meth;var input=this.sInp;var onSuccessFunc=function(req){pointer.setSuggestions(req,input)};var onErrorFunc=function(status){alert("AJAX error: "+status)};var myAjax=new _b.Ajax();myAjax.makeRequest(url,meth,onSuccessFunc,onErrorFunc)};_b.AutoSuggest.prototype.setSuggestions=function(req,input){if(input!=this.fld.value)return false;this.aSug=[];if(this.oP.json){var jsondata=eval('('+req.responseText+')');for(var i=0;i<jsondata.results.length;i++){this.aSug.push({'id':jsondata.results[i].id,'value':jsondata.results[i].value,'info':jsondata.results[i].info})}}else{var xml=req.responseXML;var results=xml.getElementsByTagName('results')[0].childNodes;for(var i=0;i<results.length;i++){if(results[i].hasChildNodes())this.aSug.push({'id':results[i].getAttribute('id'),'value':results[i].childNodes[0].nodeValue,'info':results[i].getAttribute('info')})}}this.idAs="as_"+this.fld.id;this.createList(this.aSug)};_b.AutoSuggest.prototype.createList=function(arr){var pointer=this;_b.DOM.remE(this.idAs);this.killTimeout();if(arr.length==0&&!this.oP.shownoresults)return false;var div=_b.DOM.cE("div",{id:this.idAs,className:this.oP.className});var hcorner=_b.DOM.cE("div",{className:"as_corner"});var hbar=_b.DOM.cE("div",{className:"as_bar"});var header=_b.DOM.cE("div",{className:"as_header"});header.appendChild(hcorner);header.appendChild(hbar);div.appendChild(header);var ul=_b.DOM.cE("ul",{id:"as_ul"});for(var i=0;i<arr.length;i++){if(arr[i].info=="plugin_header"){var li=_b.DOM.cE("li",{className:"as_header"},arr[i].value);ul.appendChild(li);i++}var val=arr[i].value;var st=val.toLowerCase().indexOf(this.sInp.toLowerCase());var output=val.substring(0,st)+"<em>"+val.substring(st,st+this.sInp.length)+"</em>"+val.substring(st+this.sInp.length);var span=_b.DOM.cE("span",{},output,true);if(arr[i].info!=""){var br=_b.DOM.cE("br",{});span.appendChild(br);var small=_b.DOM.cE("small",{},arr[i].info);span.appendChild(small)}var a=_b.DOM.cE("a",{href:"#"});var tl=_b.DOM.cE("span",{className:"tl"}," ");var tr=_b.DOM.cE("span",{className:"tr"}," ");a.appendChild(tl);a.appendChild(tr);a.appendChild(span);a.name=i+1;a.onclick=function(){pointer.setHighlightedValue();return false};a.onmouseover=function(){pointer.setHighlight(this.name)};var li=_b.DOM.cE("li",{},a);ul.appendChild(li)}if(arr.length==0&&this.oP.shownoresults){var li=_b.DOM.cE("li",{className:"as_warning"},this.oP.noresults);ul.appendChild(li)}div.appendChild(ul);var fcorner=_b.DOM.cE("div",{className:"as_corner"});var fbar=_b.DOM.cE("div",{className:"as_bar"});var footer=_b.DOM.cE("div",{className:"as_footer"});footer.appendChild(fcorner);footer.appendChild(fbar);div.appendChild(footer);var pos=_b.DOM.getPos(this.fld);div.style.left=pos.x+"px";div.style.top=(pos.y+this.fld.offsetHeight+this.oP.offsety)+"px";div.style.width=this.fld.offsetWidth+"px";div.onmouseover=function(){pointer.killTimeout()};div.onmouseout=function(){pointer.resetTimeout()};document.getElementsByTagName("body")[0].appendChild(div);this.iHigh=0;var pointer=this;this.toID=setTimeout(function(){pointer.clearSuggestions()},this.oP.timeout)};_b.AutoSuggest.prototype.changeHighlight=function(key){var list=_b.DOM.gE("as_ul");if(!list)return false;var n;if(key==40)n=this.iHigh+1;else if(key==38)n=this.iHigh-1;if(n>list.childNodes.length)n=list.childNodes.length;if(n<1)n=1;this.setHighlight(n)};_b.AutoSuggest.prototype.setHighlight=function(n){var list=_b.DOM.gE("as_ul");if(!list)return false;if(this.iHigh>0)this.clearHighlight();this.iHigh=Number(n);if(list.childNodes[this.iHigh-1].className!="as_header")list.childNodes[this.iHigh-1].className="as_highlight";this.killTimeout()};_b.AutoSuggest.prototype.clearHighlight=function(){var list=_b.DOM.gE("as_ul");if(!list)return false;if(this.iHigh>0){if(list.childNodes[this.iHigh-1].className!="as_header")list.childNodes[this.iHigh-1].className="";this.iHigh=0}};
+_b.AutoSuggest.prototype.setHighlightedValue=function(){
+	var value = this.fld.value;
+	var new_val = value.split(', ');
+	if(this.iHigh){
+		this.sInp=this.fld.value=this.aSug[this.iHigh-1].value;
+		this.fld.focus();
+		if(this.fld.selectionStart)
+			this.fld.setSelectionRange(this.sInp.length,this.sInp.length);
+		this.clearSuggestions();
+		if(typeof(this.oP.callback)=="function")
+			this.oP.callback(this.aSug[this.iHigh-1])
+			}
+	};
+_b.AutoSuggest.prototype.killTimeout=function(){clearTimeout(this.toID)};_b.AutoSuggest.prototype.resetTimeout=function(){clearTimeout(this.toID);var pointer=this;this.toID=setTimeout(function(){pointer.clearSuggestions()},1000)};_b.AutoSuggest.prototype.clearSuggestions=function(){this.killTimeout();var ele=_b.DOM.gE(this.idAs);var pointer=this;if(ele){var fade=new _b.Fader(ele,1,0,250,function(){_b.DOM.remE(pointer.idAs)})}};if(typeof(_b.Ajax)=="undefined")_b.Ajax={};_b.Ajax=function(){this.req={};this.isIE=false};_b.Ajax.prototype.makeRequest=function(url,meth,onComp,onErr){if(meth!="POST")meth="GET";this.onComplete=onComp;this.onError=onErr;var pointer=this;if(window.XMLHttpRequest){this.req=new XMLHttpRequest();this.req.onreadystatechange=function(){pointer.processReqChange()};this.req.open("GET",url,true);this.req.send(null)}else if(window.ActiveXObject){this.req=new ActiveXObject("Microsoft.XMLHTTP");if(this.req){this.req.onreadystatechange=function(){pointer.processReqChange()};this.req.open(meth,url,true);this.req.send()}}};_b.Ajax.prototype.processReqChange=function(){if(this.req.readyState==4){if(this.req.status==200){this.onComplete(this.req)}else{this.onError(this.req.status)}}};if(typeof(_b.DOM)=="undefined")_b.DOM={};_b.DOM.cE=function(type,attr,cont,html){var ne=document.createElement(type);if(!ne)return 0;for(var a in attr)ne[a]=attr[a];var t=typeof(cont);if(t=="string"&&!html)ne.appendChild(document.createTextNode(cont));else if(t=="string"&&html)ne.innerHTML=cont;else if(t=="object")ne.appendChild(cont);return ne};_b.DOM.gE=function(e){var t=typeof(e);if(t=="undefined")return 0;else if(t=="string"){var re=document.getElementById(e);if(!re)return 0;else if(typeof(re.appendChild)!="undefined")return re;else return 0}else if(typeof(e.appendChild)!="undefined")return e;else return 0};_b.DOM.remE=function(ele){var e=this.gE(ele);if(!e)return 0;else if(e.parentNode.removeChild(e))return true;else return 0};_b.DOM.getPos=function(e){var e=this.gE(e);var obj=e;var curleft=0;if(obj.offsetParent){while(obj.offsetParent){curleft+=obj.offsetLeft;obj=obj.offsetParent}}else if(obj.x)curleft+=obj.x;var obj=e;var curtop=0;if(obj.offsetParent){while(obj.offsetParent){curtop+=obj.offsetTop;obj=obj.offsetParent}}else if(obj.y)curtop+=obj.y;return{x:curleft,y:curtop}};if(typeof(_b.Fader)=="undefined")_b.Fader={};_b.Fader=function(ele,from,to,fadetime,callback){if(!ele)return 0;this.e=ele;this.from=from;this.to=to;this.cb=callback;this.nDur=fadetime;this.nInt=50;this.nTime=0;var p=this;this.nID=setInterval(function(){p._fade()},this.nInt)};_b.Fader.prototype._fade=function(){this.nTime+=this.nInt;var ieop=Math.round(this._tween(this.nTime,this.from,this.to,this.nDur)*100);var op=ieop/100;if(this.e.filters){try{this.e.filters.item("DXImageTransform.Microsoft.Alpha").opacity=ieop}catch(e){this.e.style.filter='progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')'}}else{this.e.style.opacity=op}if(this.nTime==this.nDur){clearInterval(this.nID);if(this.cb!=undefined)this.cb()}};_b.Fader.prototype._tween=function(t,b,c,d){return b+((c-b)*(t/d))};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/static/jquery/jquery.watermarkinput.js	Thu Apr 01 11:59:35 2010 +0530
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2007 Josh Bush (digitalbush.com)
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE. 
+ */
+ 
+/*
+ * Version: Beta 1
+ * Release: 2007-06-01
+ */ 
+(function($) {
+	var map=new Array();
+	$.Watermark = {
+		ShowAll:function(){
+			for (var i=0;i<map.length;i++){
+				if(map[i].obj.val()==""){
+					map[i].obj.val(map[i].text);					
+					map[i].obj.css("color",map[i].WatermarkColor);
+				}else{
+				    map[i].obj.css("color",map[i].DefaultColor);
+				}
+			}
+		},
+		HideAll:function(){
+			for (var i=0;i<map.length;i++){
+				if(map[i].obj.val()==map[i].text)
+					map[i].obj.val("");					
+			}
+		}
+	};
+	
+	$.fn.Watermark = function(text,color) {
+		if(!color)
+			color="#cccccc";
+		return this.each(
+			function(){		
+				var input=$(this);
+				var defaultColor=input.css("color");
+				map[map.length]={text:text,obj:input,DefaultColor:defaultColor,WatermarkColor:color};
+				function clearMessage(){
+					if(input.val()==text)
+						input.val("");
+					input.css("color",defaultColor);
+				}
+
+				function insertMessage(){
+					if(input.val().length==0 || input.val()==text){
+						input.val(text);
+						input.css("color",color);	
+					}else
+						input.css("color",defaultColor);				
+				}
+
+				input.focus(clearMessage);
+				input.blur(insertMessage);								
+				input.change(insertMessage);
+				
+				insertMessage();
+			}
+		);
+	};
+})(jQuery);
\ No newline at end of file
--- a/project/templates/proceedings/submit.html	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/templates/proceedings/submit.html	Thu Apr 01 11:59:35 2010 +0530
@@ -2,12 +2,37 @@
 {% block title %}Submit Paper for Proceedings{% endblock %}
 
 {% block addscripts %}
-  <script type="text/javascript" src="/static/jquery/jquery-ui-1.7.2.custom.min.js"></script>
-  <script type="text/javascript" src="/static/jquery/jquery-dynamic-form.js"></script>
+  <script type="text/javascript" src="/static/jquery/jquery.watermarkinput.js"></script>
+  <link rel="stylesheet" href="/static/css/autosuggest_inquisitor.css" type="text/css" media="screen" charset="utf-8">
+  <script type="text/javascript" src="/static/jquery/jquery.autosuggest.js"></script>
   <script type="text/javascript">
-    $(document).ready(function(){	
-	  $("#author").dynamicForm("#plus", "#minus", {createColor: 'yellow',removeColor: 'red'});
-	});
+  /** Init autosuggest on Search Input **/
+  jQuery(function() {
+
+    // Set autosuggest options with all plugins activated
+    var options = {
+      script:"{% url kiwipycon_get_usernames %}?limit=10&",
+      varname:"input",
+      json:true,            // Returned response type
+      shownoresults:true,       // If disable, display nothing if no results
+      noresults:"No Results",     // String displayed when no results
+      maxresults:8,         // Max num results displayed
+      cache:false,          // To enable cache
+      minchars:2,           // Start AJAX request with at leat 2 chars
+      timeout:100000,         // AutoHide in XX ms
+      callback: function (obj) {    // Callback after click or selection   
+        // => TO submit form (general use)
+        //$('#id_authors').val('sucks'); 
+        //$('#form_search_country').submit(); 
+      }
+    };
+    
+    // Init autosuggest
+    var as_json = new bsn.AutoSuggest('id_authors', options);
+    
+    // Display a little watermak  
+    $("#id_authors").Watermark("Ex : alex, guido, travis");
+  });
   </script>
 {% endblock %}
 
@@ -16,7 +41,7 @@
 
   {% include '_errors.html' %}
 
-  <form action="{% url kiwipycon_submit_proceedings %}" method="post">
+  <form action="{% if id %}{% url kiwipycon_submit_proceedings id %}{% else %}{% url kiwipycon_submit_proceedings %}{% endif %}" method="post">
     {% if not user.is_authenticated %}
     <fieldset>
       <legend>Are you a member of this site?</legend>
@@ -26,7 +51,8 @@
     </fieldset>
   </form>
   <br />
-  <form action="{% url kiwipycon_submit_talk %}" enctype="multipart/form-data" method="post">
+  <form action="{% url kiwipycon_submit_proceedings id %}" 
+    enctype="multipart/form-data" method="post">
     <fieldset>
       <legend>User Registration</legend>
       <table class="kiwipycon-default required">{{ register_form }}</table>
@@ -53,16 +79,13 @@
         </tr>
         <tr>
           <th>{{ proceedings_form.rst_file.label }}</th>
-          <td>{{ proceedings_form.rst_file.errors }}{{ proceedings_form.rst_file }}</td>
+          <td>{{ proceedings_form.rst_file.errors }}
+              {{ proceedings_form.rst_file }}</td>
         </tr>
         <tr>
           <th>{{ proceedings_form.authors.label }}</th>
-          <td id="author">
-            {{ proceedings_form.authors.errors }}
-            {{ proceedings_form.authors }}
-            <span><a id="minus" href="">[Remove]</a><a id="plus" href="">[Add]</a></span>
-            <br />
-          </td>
+          <td>{{ proceedings_form.authors.errors }}
+              {{ proceedings_form.authors }}</td>
         </tr>
       </table>
       <button class="button left" type="submit">Submit Paper</button>
--- a/project/urls.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/urls.py	Thu Apr 01 11:59:35 2010 +0530
@@ -54,12 +54,17 @@
     url(r'^password/$', 'password', name='kiwipycon_password'), # change pwd
     url(r'^username/$', 'username', name='kiwipycon_username'), # change uname
     url(r'^edit-profile/$', 'edit_profile', name='kiwipycon_edit_profile'),
+    url(r'^get-usernames/$', 'get_usernames', name='kiwipycon_get_usernames'),
     )
 
 # Proceedings
 urlpatterns += patterns('project.kiwipycon.proceedings.views',
-    url(r'^proceedings/submit/$',  'submit', name='kiwipycon_submit_proceedings'),
-    url(r'^proceedings/edit/$',  'edit', name='kiwipycon_edit_proceedings'),
+    url(r'^proceedings/submit/$', 'submit',
+        name='kiwipycon_submit_proceedings'),
+    url(r'^proceedings/submit/(?P<id>\d+)/$', 'submit', 
+        name='kiwipycon_submit_proceedings'),
+    url(r'^proceedings/show_paper/(?P<id>\d+)/$', 'show_paper', 
+        name='kiwipycon_show_paper'),
     )
 
 # About pages and all other static html pages