# HG changeset patch # User Madhusudan.C.S # Date 1270103375 -19800 # Node ID e86755df35daaf45afbd6bcc5c51aac0224abe8c # Parent 3743275f7291a055e10b578665a17eb4f5f9e2bd Add admin interface and views for proceedings. Booklet is also setup to generate paper. diff -r 3743275f7291 -r e86755df35da buildout.cfg --- 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 diff -r 3743275f7291 -r e86755df35da development.cfg --- 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 diff -r 3743275f7291 -r e86755df35da project/kiwipycon/proceedings/admin.py --- /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) diff -r 3743275f7291 -r e86755df35da project/kiwipycon/proceedings/booklet/__init__.py diff -r 3743275f7291 -r e86755df35da project/kiwipycon/proceedings/booklet/mk_booklet.py --- /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) diff -r 3743275f7291 -r e86755df35da project/kiwipycon/proceedings/booklet/mk_scipy_paper.py --- /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() diff -r 3743275f7291 -r e86755df35da project/kiwipycon/proceedings/forms.py --- 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).') diff -r 3743275f7291 -r e86755df35da project/kiwipycon/proceedings/views.py --- 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 diff -r 3743275f7291 -r e86755df35da project/kiwipycon/user/views.py --- 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 diff -r 3743275f7291 -r e86755df35da project/static/css/autosuggest_inquisitor.css --- /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 diff -r 3743275f7291 -r e86755df35da project/static/jquery/jquery.autosuggest.js --- /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 @@ + +/** 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.lengthol&&l&&l"+val.substring(st,st+this.sInp.length)+""+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))}; diff -r 3743275f7291 -r e86755df35da project/static/jquery/jquery.watermarkinput.js --- /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 - + + + {% endblock %} @@ -16,7 +41,7 @@ {% include '_errors.html' %} -
+ {% if not user.is_authenticated %}
Are you a member of this site? @@ -26,7 +51,8 @@

-
+
User Registration {{ register_form }}
@@ -53,16 +79,13 @@ {{ proceedings_form.rst_file.label }} - {{ proceedings_form.rst_file.errors }}{{ proceedings_form.rst_file }} + {{ proceedings_form.rst_file.errors }} + {{ proceedings_form.rst_file }} {{ proceedings_form.authors.label }} - - {{ proceedings_form.authors.errors }} - {{ proceedings_form.authors }} - [Remove][Add] -
- + {{ proceedings_form.authors.errors }} + {{ proceedings_form.authors }} diff -r 3743275f7291 -r e86755df35da project/urls.py --- 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\d+)/$', 'submit', + name='kiwipycon_submit_proceedings'), + url(r'^proceedings/show_paper/(?P\d+)/$', 'show_paper', + name='kiwipycon_show_paper'), ) # About pages and all other static html pages