The Maggot / src / main.py

#    This file is part of exquisite_code.
#    copyright 2010 Brendan Howell.
#
#    exquisite_code is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    exquisite_code is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with exquisite_code.  If not, see <http://www.gnu.org/licenses/>.


import cherrypy
import os, random, glob
from Cheetah.Template import Template

from auth import AuthController, require, member_of, name_is
import auth

from model import *
import munger
import testchunks

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import and_
from sqlalchemy.orm.exc import NoResultFound


#session vars
USER_KEY = "_cp_username"
ROLE_KEY = "_excd_role"
CUR_EX_SESSION = "_excd_session"

class Index:
    _cp_config = {
        'tools.sessions.on': True,
        'tools.auth.on': True
    }
    
    auth = AuthController()
    sqlengine = create_engine('sqlite:///excode.db')
    SqlSession = sessionmaker()
    sqlmeta = Base.metadata
    sqlmeta.create_all(sqlengine)
    SqlSession.configure(bind=sqlengine)
    
    def __init__(self):
        auth.SqlSession = self.SqlSession

    @cherrypy.expose
    @require()
    def index(self):
        template = tmpldir + "/index.tmpl"
        page = Template(file=template)
        
        sqlsession = self.SqlSession()
        page.corpora = sqlsession.query(Corpus).all()
        page.old_corpora = []
        
        return unicode(page)
        
    @cherrypy.expose
    def newuser(self):
        template = tmpldir + "/adduser.tmpl"
        page = Template(file=template)
        
        return unicode(page)
        
    @cherrypy.expose
    def addnewuser(self, name, password):
        newuser = User(name, password)
        
        sqlsession = self.SqlSession()
        sqlsession.add(newuser)
        sqlsession.commit()
        raise cherrypy.HTTPRedirect("/")
        

    @cherrypy.expose
    @require()
    def newsession(self):
        template = tmpldir + "/newsession.tmpl"
        page = Template(file=template)
        page.creator = cherrypy.session.get(USER_KEY)
        
        return unicode(page)
  
        
    @cherrypy.expose
    @require()
    def addnewcorpus(self, name, creator, total_rounds):
        sqlsession = self.SqlSession()
        creator_user = sqlsession.query(User).filter(User.name==creator).first()
        
        newcorpus = Corpus(name, creator_user, total_rounds)
        
        sqlsession.add(newcorpus)
        sqlsession.commit()
        raise cherrypy.HTTPRedirect("/")   

    
    @cherrypy.expose
    @require()
    def corpus(self, cid, chunkid=None):
        template = tmpldir + "/corpus.tmpl"
        sqlsession = self.SqlSession()
        corp = sqlsession.query(Corpus).filter(Corpus.id==cid).first()
        rnd = corp.current_round_index
        round = sqlsession.query(Round).filter(
            and_(Round.corpus==corp, Round.round_index==rnd)).first()
        
        if chunkid:
            chunk = sqlsession.query(Chunk).filter(Chunk.id==chunkid).first()
        else:
            #TODO: create new chunk and pass the id 
            chunk = Chunk("", author, corp, rnd)
            sqlsession.add(chunk)
            sqlsession.flush()
            #TODO: set lastchunk to query antecedent
            pass

        if corp.current_round_index < 2:
            lasttext = "no text written yet"
        else:
            lastround = sqlsession.query(Round).filter(
                and_(Round.session==sess, Round.round_index==(
                sess.current_round_index-1))).first()

            lastchunk = sqlsession.query(Chunk).filter(
                and_(Chunk.round==lastround, Chunk.selected==True)).first()

            
        page = Template(file=template)
        page.corpus = corp
        page.chunkid = chunk.id
        page.lastchunk = lasttext
        #TODO: find next chunk based on descendent
        page.nextchunk = None
        
        return unicode(page)


    @cherrypy.expose
    @require()
    def advanceround(self, cid, algorithm="roundrobin"):
        sqlsession = self.SqlSession()
        corp = sqlsession.query(Corpus).filter(Corpus.id==cid).first()
        rnd = corp.current_round_index
        round = sqlsession.query(Round).filter(
            and_(Round.session==corp, Round.round_index==rnd)).first()
        #TODO: use params for time

        #TODO: munge all texts not just 1
        #munge and update prompts
        chunks = sqlsession.query(Chunk).filter(Chunk.round==round).all()
        
        #this is very hacky but allows for dynamic creation of new munge functs
        mungefunction = eval("munger."+algorithm)
        munged_output = mungefunction(chunks)
        round.text_out = munged_output
        txtout = open("out.txt", "a")
        txtout.write(munged_output)
        txtout.close()
        
        corp.current_round_index = corp.current_round_index + 1
        sqlsession.commit()
        raise cherrypy.HTTPRedirect("/session?cid="+cid)
    
            
    @cherrypy.expose
    @require()
    def addchunk(self, text, cid, chunkid):

        #TODO: add logic to stop naughty hackers from submitting twice/round
        #TODO: add refs to antecedent
        #TODO: add git tracking of chunk revisions
        sqlsession = self.SqlSession()
        corpus = sqlsession.query(Corpus).filter(Corpus.id==cid).first()
        rnd = corpus.current_round_index
        round = sqlsession.query(Round).filter(
            and_(Round.corpus==corpus, Round.round_index==rnd)).first()
        name = cherrypy.session.get(USER_KEY)
        author = sqlsession.query(User).filter(User.name==name).first()
        
        chunk = Chunk(text, author, corpus, round)
        
        sqlsession.add(chunk)
        sqlsession.commit()

        raise cherrypy.HTTPRedirect("/wait?cid="+cid+"&round="+str(rnd))
        
        
    @cherrypy.expose
    @require()
    def wait(self, cid, round):
        sqlsession = self.SqlSession()
        corpus = sqlsession.query(Corpus).filter(Corpus.id==cid).first()
        
        #check if round has advanced
        #  then redirect to corpus edit page
        if(int(round) < corpus.current_round_index):
            raise cherrypy.HTTPRedirect("/session?cid="+cid)

        #TODO: add js reload on 5 second interval to template
        template = tmpldir + "/wait.tmpl"
        page = Template(file=template)
        page.cid = cid
        
        return unicode(page)
        
    @cherrypy.expose
    def mungetest(self):
        pass
    
    @cherrypy.expose
    def domungetest(self, algorithm):
        sqlsession = self.SqlSession()
        round = sqlsession.query(Round).filter(Round.id==1).first()
        chunks = testchunks.testchunks
        #Achtung! hacky and insecure
        mungefunction = eval("munger."+algorithm)
        munged_output = mungefunction(chunks)
        return munged_output


current_dir = os.path.dirname(os.path.abspath(__file__))    
tmpldir = os.path.join(current_dir, "templates")
auth.tmpldir = tmpldir
datadir = os.path.join(current_dir, "data")

root = Index()

conf = { "/static" : { "tools.staticdir.on": True, 
                    "tools.staticdir.dir": os.path.join(current_dir, 'static')}}

cherrypy.config.update({ "server.socket_host": "::",
                        "server.socket_port": 8080 })

cherrypy.quickstart(root,config=conf)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.