Source

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"

mungers = ["xtext", "dave", "txtr", "markov", "burroughs"]

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()

        #TODO: is this an edit or a new chunk
        var = random.random()
        if (var > 0.666):
            chunks = sqlsession.query(Chunk).filter(Chunk.text != "").all()
            chunk = random.choice(chunks)
        elif chunkid:
            chunk = sqlsession.query(Chunk).filter(Chunk.id==chunkid).first()
        else:
            ant = sqlsession.query(Chunk).filter(Chunk.descendent == None).first()
            name = cherrypy.session.get(USER_KEY)
            author = sqlsession.query(User).filter(User.name==name).first()
            chunk = Chunk("", author, corp, round)

            if ant:
                chunk.antecedent = ant

            sqlsession.add(chunk)
            sqlsession.flush()
 
            if ant:
                ant.descendent = [chunk]

        if corp.current_round_index < 2:
            lasttext = "no text written yet"
        else:
            lasttext = chunk.antecedent.text

        if len(chunk.descendent):
            print "Desc EXISTS!"
            nexttext = chunk.descendent[0].text
        else:
            nexttext = None
            
        page = Template(file=template)
        page.corpus = corp
        page.text = chunk.text
        page.chunkid = chunk.id
        page.lastchunk = lasttext
        #TODO: find next chunk based on descendent
        page.nextchunk = nexttext
        
        sqlsession.commit()

        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.corpus==corp, Round.round_index==rnd)).first()
        #TODO: use params for time

        #munge and update prompts
        chunks = sqlsession.query(Chunk).filter(Chunk.round==round).all()
       
        for chunk in chunks: 
            #very hacky but allows for dynamic creation of new munge functs
            var = random.random()
            if var > 0.666:
                algorithm = random.choice(mungers)
                mungefunction = eval("munger."+algorithm)
                munged_output = mungefunction(chunks)
                chunk.text_out = munged_output
            txtout = open("out.txt", "a")
            txtout.write(chunk.text)
            txtout.close()
        
        corp.current_round_index = corp.current_round_index + 1
        sqlsession.commit()
        raise cherrypy.HTTPRedirect("/corpus?cid="+cid)
    
            
    @cherrypy.expose
    @require()
    def addchunk(self, text, cid, chunkid):

        #TODO: add logic to stop naughty hackers from submitting twice/round
        #      also don't allow edits outside of current round participants
        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 = sqlsession.query(Chunk).filter(Chunk.id==chunkid).first()
        chunk.text = text
        #TODO: add git tracking of chunk revisions
        #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()
        
        name = cherrypy.session.get(USER_KEY)
        user = sqlsession.query(User).filter(User.name==name).first()
        owner = corpus.creator
        if user == owner:
            isowner = True
        else:
            isowner = False
        #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
        page.owner = isowner
        
        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)