[pysignup] / trunk / cgi / index.py Repository:
ViewVC logotype

View of /trunk/cgi/index.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 105 - (download) (as text) (annotate)
Mon May 11 04:59:31 2009 UTC (16 months ago) by pinky
File size: 33324 byte(s)
Fix bug where removing someone that wasn't there would error
#!/usr/bin/python
##### ^ if python is not installed at /usr/bin/python (i.e. on a
# windows system) change the above to the file path to python, 
# i.e. #!C:/path/to/python/python.exe

"""Main file for PySignup.

It shows all of the signup data and is where people can signup
for the event.

@copyright: 2008 by Nathaniel Herman
@license: GNU GPLv3, see COPYING for full details
"""

### 
# Copyright (C) 2008 Nathaniel Herman
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
###


import os, re, cgi, sys
import recaptcha, functions
from configobj import ConfigObj
#import cgitb; cgitb.enable() # only enable when developing

__version__ = '1.3'
__author__ = "Nathaniel Herman"

class Html:
    '''Class for retrieving HTML'''
    
    def __init__(self, inithtml='', errormsg=''):
        self.html = inithtml
        self.errormsg = errormsg
 
    def makelocation(self):
        """Reads the config file and creates html for the next event's location. 

        if usegooglemaps is true, it will include a link to a Google map of the
        location."""

        # most config values besides location/fulllocation should not have list 
        # values, so instead of turning list_values on for everything, just use
        # a custom parselist() function for these values (which is based on the
        # configobj code)
        locat = config["required"]["location"]
        locat = functions.parselist(locat)
        if functions.checkboolean(config["googlemaps"]["usegooglemaps"]):
            if config["googlemaps"]["full-location"]:
                fulllocation = config["googlemaps"]["full-location"]
                fulllocation = functions.parselist(fulllocation)
            else: # if no fulllocation is specified, normal location will do
                fulllocation = locat

            # check if the location is a list
            if type(locat) == type([]):
                htmllocation = "<ol>\n"
                if type(fulllocation) == type([]):
                    for indlocation, indfulllocation in zip(locat, fulllocation):
                        htmllocation += """\
 <li><a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;q=%s">%s</a></li>
""" % (cgi.escape(indfulllocation), cgi.escape(indlocation))
                # on the off chance that location is a list, but fulllocation 
                # is not
                else: 
                    for indlocation in locat:
                        htmllocation += """\
 <li><a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;q=%s">%s</a></li>
""" % (cgi.escape(fulllocation), cgi.escape(indlocation))
                htmllocation += "</ol>"

            else:
                htmllocation = """\
<a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;q=%s">%s</a>""" \
% (cgi.escape(fulllocation), cgi.escape(locat))

        else: 
            # if they don't want to use google maps, just display the location 
            # with no hyperlink
            if type(locat) == type([]):
                htmllocation = "<ol>\n"
                for indlocation in locat:
                    htmllocation += "<li>%s</li>\n" % cgi.escape(indlocation)
                htmllocation += "</ol>\n"
            else:
                htmllocation = cgi.escape(locat)
        return htmllocation

    def displaymessage(self):
        """Displays a user-specified message below the location."""
        if config["required"]["message"]:
            message = config["required"]["message"]
        else:
            message = ''
        html = """\
 <tr>
  <td id="message">%s</td>
 </tr>
""" % message
        return html

    def tableheader(self):
        """Returns HTML for table header."""
        html = '''\
 <tr>
  <th>In/Out</th>'''
        for field in datafields:
            fieldname = field[0]
            html += '  <th>%s</th>' % fieldname
        
        html += '\n </tr>'
        return html

    def formfieldhtml(self):
        """Returns the HTML for displaying the user enterable form fields.

        Displays all of the form fields listed in the datafields config
        variable. This will not include things like a CAPTCHA or password field."""

        html = ''
        for field in datafields:
            fieldval = ''
            fieldname = field[0]
            if self.errormsg:
                if fieldname.lower() in form:
                    fieldval = form[fieldname.lower()].value
            if fieldname.lower() == 'name':
                length = 40
            elif fieldname.lower() == 'comment':
                length = 100
            else:
                length = 50
            html += '''\
  <tr>
   <td>%(field)s:</td>
   <td><input type="text" name="%(fieldlow)s" maxlength="%(length)s"
   size="%(length)s" value="%(fieldval)s" /></td>
  </tr>''' % {'field': fieldname, 'fieldlow': fieldname.lower(),
              'length': length, 'fieldval': fieldval}

        return html

    def passhtml(self):
        """Returns the HTML for displaying a password field."""
        html = """  <tr>
   <td>Password:</td>
   <td><input type="password" name="passwd" maxlength="20" size="20" />
If you enter a password, it will be required to later change your entry.</td>
  </tr>"""

        if userpass.lower() == 'optional':
            return html
        elif userpass.lower() == 'required':
            return html
        else:
            return ''

    def signupinfo(self):
        """Returns information for signing up.

        i.e. what forms to fill in, etc."""

        sinfo = "Fill in your "

        for item in datafields:
            name = item[0].lower()
            if item[1].lower() in ('req', 'pri'):
                sinfo += '%s, ' % name
            else:
                sinfo += '%s (optional), ' % name

        if functions.checkboolean(userecaptcha):
            sinfo += "the CAPTCHA, "

        if userpass.lower() == 'required':
            sinfo += 'a password, '
        elif userpass.lower() == 'optional':
            sinfo += 'a password (optional), '

        sinfo += 'and then click "In", "Out", or "Remove".'
        return sinfo

    def recaptchahtml(self):
        """Returns all the necessary html for adding a reCaptcha."""
        if not functions.checkboolean(userecaptcha):
            # they don't want to use recaptcha
            return ''

        captchahtml = ''
        # print out the required HTML if they want to use custom reCAPTCHA
        if functions.checkboolean(config['captcha']['recaptcha']['usecustom']):
            captchahtml += """<div id="recaptcha_widget" style="display:none">
<div id="recaptcha_image"></div>
Enter the words above: <input type="text" id="recaptcha_response_field"
name="recaptcha_response_field" />
<br />
<a href="javascript:Recaptcha.reload()">Reload CAPTCHA</a>
<br />
<a href="javascript:Recaptcha.switch_type('audio')" class="recaptcha_only_if_image">Audio CAPTCHA</a>
<a href="javascript:Recaptcha.switch_type('image')" class="recaptcha_only_if_audio">Image CAPTCHA</a>
<br />
<span id="recaptcha_word">reCAPTCHA</span>
<a id="recaptcha_help" href="javascript:Recaptcha.showhelp()">Help</a>
</div>
"""
        captchahtml += recaptcha.displayhtml(recaptcha_pub_key)
        return captchahtml

    def load(self):
        '''Open HTML template, and substitute proper variables into self.html'''
        # if there's a user-specified theme, load all CSS, etc. for it
        theme = config['required']['theme']
        if theme:
            skinhtml = functions.loadtheme(theme)
        else:
            skinhtml = ''
        indhtml = 'Content-type: text/html\n\n'
        indhtml += functions.read("indextmpl.html") % {'sitename': sitename,
                                             'skinspecific': skinhtml,
                                             'nextevent': nextevent,
                                             'locat': self.makelocation(),
                                             'message': self.displaymessage(),
                                             'data': DB.getdata(),
                                             'signupinfo': self.signupinfo(),
                                             'tableheader': self.tableheader(),
                                             'errormsg': self.errormsg,
                                             'formfields': self.formfieldhtml(),
                                             'captcha': self.recaptchahtml(),
                                             'passhtml': self.passhtml(),
                                             'version': __version__}

        self.html += indhtml

    def display(self):
        """Displays whatever HTML is in self.html"""
        print self.html

class FileSto:
    '''Class for all file storage functions.
    
    when storagemethod = file, this class will be used, saving all user data
    directly to a file.'''
    
    def __init__(self, file):
        self.file = file

    def getdata(self):
        """Parses data from file and returns it as html.
                
        Reads the contents of a given data file line by line, and parses it
        into html, if the the file does not exist, an error message is returned,
        otherwise html of the parsed data is returned. The data file is
        specifically formatted, with each field of an entry being seperated by a
        ">", and each entry being seperated by a new line. A typical entry will
        look like "In>name>comment>optionalpassword" """

        errormessage = """\
 <tr>
  <td id="nosignup" colspan="%s">No one has signed up yet</td>
 </tr>
""" % (len(datafields) + 1)

        incount = 0
        tabledata = ''
        try: # in case the file doesn't exist
            f = open(self.file, 'r')
            # read the data file line by line, which will seperate it entry by
            # entry
            thedata = f.readlines()
            f.close()
            if not thedata: # check if file exists, but is empty
                tabledata = errormessage
            for entry in thedata: # going through each line of the date file
                # each value is seperated by a ">", so split it by each
                # occurence of ">"
                datalist = entry.split('>')
                inorout = datalist[0]
                formdata = datalist[1:-1]
                if inorout == 'In': # if this entry is "in" for the event
                    incount += 1 # increase the amount of people that are "in"
                    num = '%s(%d)' % (inorout, incount)
                else:
                    # don't need to count number of people who won't be there
                    num = '%s' % inorout
                datahtml = ''
                for field in formdata:
                    datahtml += '<td>%s</td>' % field
                # parsing the data as html for a table
                tabledata += \
""" <tr>
  <td><b>%(num)s</b></td>%(datahtml)s
 </tr>
""" % {'num': num, 'datahtml': datahtml}
        except IOError: # same as if the file is blank
            tabledata = errormessage
        try:
            alert = int(alerton)
        except ValueError:
            return tabledata
        if incount >= alert:
            if functions.checkboolean(htmlalert):
                htmltext = cgi.escape(config['alerts']['htmltext'])
                tabledata += '<h1 id="htmlalert">%s</h1>' % htmltext
        return tabledata

    def add(self, status):
        """Handles the viewer pressing the "In" or "Out" button.

        Adds or modifies an entry in the data file using the user filled in
        fields, status argument should be "In" or "Out" based on which button
        was pressed by the viewer."""

        savecode = "%(inorout)s>%(prikey)s>%(data)s%(passwd)s\n"
        formdata = ''
        # create a variable that is the opposite of the button they clicked
        if status == "In":
            notstatus = "Out"
        elif status == "Out":
            notstatus = "In"
        else:
            return # status argument was incorrect, so don't do anything

        prikey = False
        # datafields is a list of tuples, so go through each tuple in the list
        for field in datafields:
            fieldname = field[0].lower() # 1st item of each tuple is the name
            fieldtype = field[1].lower() # 2nd item is the type (opt, req, or pri)
            if fieldname in form:
                fieldval = form[fieldname].value
                # if for some reason the length of the field is higher than
                # allowed, just return and don't save anything. No error message
                # or anything is printed, as the only way to do this is usually
                # to deliberately try, and they're given a 10 character cushion
                if fieldname == 'name' and len(fieldval) > 50:
                    return
                elif fieldname == 'comment' and len(fieldval) > 110:
                    return
                elif len(fieldval) > 60:
                    return
                fieldval = cgi.escape(fieldval)
            else:
                if fieldtype in ('pri', 'req'):
                    indexhtml.errormsg += '<span class="error-msg">%s must be \
entered!</span>' % fieldname.capitalize()
                    return
                fieldval = '&nbsp;'

            if fieldtype == 'pri':
                prikey = fieldval
                continue
            # the primary key must be the first key, so if there's no primary
            # key set yet, settings.conf is wrong somewhere
            if prikey is False:
                indexhtml.errormsg += '<span class="error-msg">No primary key \
was set!</span>'
                return
    
            formdata += fieldval + '>'

        if "passwd" in form: # did they enter a password
            passwd = form["passwd"].value
            if len(passwd) > 20:
                return
            passwdhash = functions.makehash(passwd)
            nopass = False  
        else:
            if userpass.lower() == 'required':
                indexhtml.errormsg += '''<span class="error-msg">You must \
enter a password!</span>'''
                return
            nopass = userpass.lower() != 'optional'
            passwd = ''
            passwdhash = ''
        # opening data file
        data = functions.read(self.file)
        # if data file doesn't exist already or is empty
        if not data:
            # create the data file now with user-inputted values
            tosave = savecode % {'inorout': status,
                             'prikey': prikey,
                             'data': formdata,
                             'passwd': passwdhash}
            didwrite = functions.save(self.file, tosave)
            # make sure it wrote to the data file
            if not didwrite:
                indexhtml.errormsg += '<span class="error-msg">Unable to write \
to the data file!\n<p>Check permissions</p></span>'
            return
        # regex to check if someone with the inputted name was already added
        reg1 = re.compile("(In|Out)>%s>" % re.escape(prikey))
        if reg1.search(data):

            # regex for matching their stored password hash if there is one
            passreg = re.compile(r'(>%s>.*>)(.*)\n' % re.escape(prikey))
            storedhash = passreg.search(data).group(2)
            if storedhash:
                # check that the supplied password matches the stored password
                if not functions.checkhash(storedhash, passwd) and not nopass:
                    indexhtml.errormsg += '<span class="error-msg">Password \
was incorrect!</span>'
                    return

            # just in case the person was previously out and is clicking "in",
            # or was previously in and is clicking "out", change their
            # status based on which button they clicked
            reg2 = re.compile("%s(?=>%s>)" % (notstatus, re.escape(prikey)))
            data = reg2.sub(status, data)

            # lets also replace their old data with new
            reg3 = re.compile("((?:In|Out)>%s>)(.*>)(.*\n)" % re.escape(prikey))
            replace = r'\1%s\3' % functions.escapebackslash(formdata)
            tosave = reg3.sub(replace, data)

            didwrite = functions.write(self.file, tosave) # write changes
            if not didwrite:
                indexhtml.errormsg += '''<span class="error-msg">Unable to \
write to the data file!\n<p>Check permissions</p></span>'''
        else: # if the person's inputted name wasn't added yet
            tosave = savecode % {'inorout': status, 'prikey': prikey,
                             'data': formdata,
                             'passwd': passwdhash}
            # just append their data to the file, since they're not there yet
            didwrite = functions.save(self.file, tosave)
            if not didwrite:
                indexhtml.errormsg += '''<span class="error-msg">Unable to \
write to the data file!\n<p>Check permissions</p></span>'''

    def remove(self):
        """Handles the viewer pressing the "Remove" button.
  
        Searches the data for someone with the given name and removes that
        entry completely"""
    
        field = datafields[0]
        if field[1].lower() != 'pri':
            indexhtml.errormsg += '<span class="error-msg">\
The first data field <b>must</b> be the primary data field!</span>'
            return
        prikeyname = field[0].lower()

        if prikeyname in form:
            data = functions.read(self.file)
            if not data:
                return # if data file doesn't exist or is blank, return None
            prikey = cgi.escape(form[prikeyname].value)
            if "passwd" in form:
                passwd = form['passwd'].value
                nopass = False
            else:
                nopass = userpass.lower() not in ('optional', 'required')
                passwd = ''

            # regex for matching their stored password hash if there is one
            passreg = re.compile(r'((?:In|Out)>%s>.*>)(.*)\n' % re.escape(prikey))
            storedhash = passreg.search(data).group(2)
            if storedhash:
                # check that the supplied password matches the stored password
                if not functions.checkhash(storedhash, passwd) and not nopass:
                    indexhtml.errormsg += '<span class="error-msg">Password \
was incorrect!</span>'
                    return

            # this regex should catch their entire entry, but no one elses
            reg = re.compile("(In|Out)>%s>.*\n" % re.escape(prikey))
            data = reg.sub('', data)
            functions.write(self.file, data)

    def incount(self):
        '''Returns number of people marked as "in"'''
        try:
            open(self.file, 'r')
        except IOError:
            return
        count = 0
        for line in open(self.file, 'r'):
            if line[:2] == 'In':
                count += 1

        return count


class Sqlite:
    '''Class for storing data using an SQLite database.'''
    
    def __init__(self, dbfile):
        try:
            import pysqlite2.dbapi2 as sqlite
            self.sqlite = sqlite
        except ImportError:
            indexhtml.html = 'Content-type: text/html\n\n'
            indexhtml.html += 'PySQLite 2 is not installed!\n<br />\n'
            indexhtml.html += 'You can download it <a href="http://oss.itsyst'
            indexhtml.html += 'ementwicklung.de/trac/pysqlite/wiki/WikiStart'
            indexhtml.html += '#Downloads">here</a>'
            indexhtml.display()
            sys.exit()

        self.dbfile = dbfile
        try:
            self.conn = sqlite.connect(self.dbfile)
        except sqlite.OperationalError:
            indexhtml.html = 'Content-type: text/html\n\n'
            indexhtml.html += 'Error reading SQLite database file.<br />'
            indexhtml.html += 'Check permissions.'
            indexhtml.display()
            sys.exit()

    def getdata(self):
        '''Gets data from SQLite db and returns parsed as HTML.'''
        c = self.conn.cursor()
        errormessage = """\
 <tr>
  <td id="nosignup" colspan="%s">No one has signed up yet</td>
 </tr>
""" % (len(datafields) + 1)

        incount = 0
        tabledata = ''

        try:
            c.execute('select * from signup')
            data = c.fetchall()
            c.close()
        except self.sqlite.OperationalError:
            # table hasn't been created, so just display the errormsg
            data = False
        if not data:
            return errormessage
        for entry in data:
            inorout = entry[0]
            formdata = entry[1:-1]
            if inorout == 'In': # entry is "in"
                incount += 1
                num = '%s(%d)' % (inorout, incount)
            else:
                # don't count number of people who won't be there
                num = '%s' % inorout
            datahtml = ''
            for field in formdata:
                datahtml += '<td>%s</td>' % field
            # parsing data as HTML
            tabledata += \
''' <tr>
  <td><b>%(num)s</b></td>%(datahtml)s
 </tr>
''' % {'num': num, 'datahtml': datahtml}

        try:
            alert = int(alerton)
        except ValueError:
            return tabledata
        if incount >= alert:
            if functions.checkboolean(htmlalert):
                htmltext = cgi.escape(config['alerts']['htmltext'])
                tabledata += '<h1 id="htmlalert">%s</h1>' % htmltext
        return tabledata

    def add(self, status):
        '''Handles viewer pressing "In" or "Out" button.'''
        # open dbfile in append mode, to make sure we can write to the db
        try:
            open(self.dbfile, 'a')
        except IOError:
            indexhtml.errormsg += '''<span class="error-msg">Could not 
write to the SQLite DB, check permissions.</span>'''
            return

        c = self.conn.cursor()
        fnames = []
        fvalues = []
        if status == "In":
            notstatus = "Out"
        elif status == "Out":
            notstatus = "In"
        else:
            return
        
        prikey = False
        # datafields is a list of tuples, so go through each tuple in list
        for field in datafields:
            fieldname = field[0].lower() # 1st item of tuple is name
            fieldtype = field[1].lower() # 2nd item is type (opt, req, pri)
            if fieldname in form:
                fieldval = form[fieldname].value
                # if for some reason the length of the field is higher than
                # allowed, just return and don't save anything. No error message
                # or anything is printed, as the only way to do this is usually$
                # deliberately try, and they're given a 10 character cushion
                if fieldname == 'name' and len(fieldval) > 50:
                    return
                elif fieldname == 'comment' and len(fieldval) > 110:
                    return
                elif len(fieldval) > 60:
                    return
                fieldval = cgi.escape(fieldval)
            else:
                if fieldtype in ('pri', 'req'):
                    indexhtml.errormsg += '<span class="error-msg">%s must be \
entered!</span>' % fieldname.capitalize()
                    return
                fieldval = '&nbsp;'

            if fieldtype == 'pri':
                prikey = fieldname
                prikeyval = fieldval

            fnames.append(fieldname)
            fvalues.append(fieldval)

        if prikey is False:
            indexhtml.errormsg += '<span class="error-msg">No primary key \
was set!</span>'
            return

        if "passwd" in form:
            passwd = form["passwd"].value
            if len(passwd) > 20:
                return
            passwdhash = functions.makehash(passwd)
            nopass = False
        else:
            if userpass.lower() == 'required':
                indexhtml.errormsg += '''<span class="error-msg">You must \
enter a password!</span>'''
                return
            nopass = userpass.lower() != 'optional'
            passwd = ''
            passwdhash = ''

        # combining status, fvalues, and passwdhash into one list
        values = [status] + fvalues + [passwdhash]
        # SQL query wants a tuple, so convert the list to a tuple
        values = tuple(values)
        statement = 'select * from signup where %s=?' % prikey
        try:
            c.execute(statement, (prikeyval,))
        except self.sqlite.OperationalError:
            # table doesn't exist yet, so create it
            functions.createsqlite(self.conn, tuple(fnames))
            c.execute(statement, (prikeyval,))
        data = c.fetchall()
        if not data: # nothing in signup table matches user's prikey
            length = len(values) - 1
            # make sure it has a ? for every item in values
            statement = 'insert into signup values (%s?)' % ('?, ' * length)
            c.execute(statement, values)
            c.close()
            self.conn.commit()
            return

        else:
            statement = 'select passwd from signup where %s=?' % prikey
            c.execute(statement, (prikeyval,))
            storedhash = c.fetchone()[0]
            if not functions.checkhash(storedhash, passwd) and not nopass:
                    indexhtml.errormsg += '<span class="error-msg">Password \
was incorrect!</span>'
                    return

            # change status to be correct 
            statement = 'update signup set status=? where %s=?' % prikey
            c.execute(statement, (status, prikeyval))

            # change other data fields to be newly entered data
            length = len(fnames) - 1
            set = '%s%%s=?' % ('%s=?, ' * length)
            set %= tuple(fnames)
            statement = 'update signup set %s where %s=?' % (set, prikey)
            args = tuple(fvalues) + (prikeyval,)
            c.execute(statement, args)
            self.conn.commit()
            c.close()

    def remove(self):
        '''Handles viewer pressing the "Remove" button.'''
        # open a file in append mode to make sure we can write to the db,
        # and just display an error message if we can't
        try:
            open(self.dbfile, 'a')
        except IOError:
            indexhtml.errormsg += '''<span class="error-msg">Couldn't write to
SQLite database, check permissions.'''
            return
        for field in datafields:
            if field[1].lower() == 'pri':
                prikeyname = field[0].lower()
                break

        if prikeyname in form:
            c = self.conn.cursor()
            prikeyval = cgi.escape(form[prikeyname].value)
            if "passwd" in form:
                passwd = form['passwd'].value
                nopass = False
            else:
                nopass = userpass.lower() not in ('optional', 'required')
                passwd = ''

            statement = 'select passwd from signup where %s=?' % prikeyname
            c.execute(statement, (prikeyval,))
            if not c.fetchone():
                return
            storedhash = c.fetchone()[0]
            if storedhash:
                if not functions.checkhash(storedhash, passwd) and not nopass:
                    indexhtml.errormsg += '<span class="error-msg">Password \
was incorrect!</span>'
                    return

            statement = 'delete from signup where %s=?' % prikeyname
            c.execute(statement, (prikeyval,))
            c.close()
            self.conn.commit()

    def incount(self):
        '''Returns an integer of how many people are signed up as "in".'''
        c = self.conn.cursor()
        try:
            c.execute("select * from signup where status='In'")
        except self.sqlite.OperationalError:
            return
        count = len(c.fetchall())
        
        return count


def recaptchacheck():
    """Checks the user's captcha against reCaptcha's server.
    
    Returns a class depending on whether the captcha is correct or incorrect,
    whether the captcha is correct can be checked using .is_valid, which will
    return either true or false, and .error_code will return the error code
    if .is_valid is false."""
        
    # get the viewer's IP for reCaptcha
    if functions.checkboolean(config['captcha']['recaptcha']['reverseproxy']):
        # if using a reverseproxy, we want to get HTTP_X_FORWARDED_FOR
        ip = os.environ["HTTP_X_FORWARDED_FOR"]
    else:
        # otherwise, we want REMOTE_ADDR
        ip = os.environ["REMOTE_ADDR"]
    
    try:
        challenge = form["recaptcha_challenge_field"].value
    except KeyError: # this means the captcha was never displayed
        challenge = ''
    try:
        response = form["recaptcha_response_field"].value
    except KeyError: # in case no captcha was inputted at all   
        # ideally, if no captcha was entered, it would alert the user and
        # not submit the form, however that would probably require ajax
        response = '' # user's response is blank, since nothing was entered
    return recaptcha.submit(challenge, response, recaptcha_priv_key, ip)

def sendmail(incount):
    '''Sends an e-mail (if mailalert is true) using configuration info.
        
    incount is an integer of how many people are "in"'''
        
    if not functions.checkboolean(mailalert):
        return
    try:
        alert = int(alerton)
    except ValueError:
        return
    if incount != alert:
        return
    server = config['mail']['smtpserver']
    user = config['mail']['mailuser']
    passwd = config['mail']['mailpass']
    
    toadd = config['alerts']['toaddress']
    fromadd = config['alerts']['fromaddress']
    subject = config['alerts']['mailsubject']
    body = config['alerts']['mailbody']
    functions.mail(server, fromadd, toadd, subject, body, user, passwd)


indexhtml = Html()

# open up config file
try:
    userconf = ConfigObj('settings.conf', file_error=True, list_values=False)
# if settings.conf doesn't exist, change.py was probably never used
except IOError:
    indexhtml.html = '''Content-type: text/html\n
No settings file! <a href="change.py">Go to change.py</a> to
create a settings file'''
    indexhtml.display()
    sys.exit()

defaultconf = ConfigObj('defaultsettings.conf', list_values=False)
# merge user conf with default, user overrides default
defaultconf.merge(userconf)
# to reduce confusion, as defaultconf is now a combo of user and default conf
config = defaultconf

# loading up configuration
nextevent = cgi.escape(config["required"]["nextevent"])
stomethod = config['required']['storage']
datafile = config["file"]["data-file"]
sqlitedb = config['sqlite']['sqlitedb']
sitename = cgi.escape(config["required"]["sitename"])
userpass = config['required']['userpass']
userecaptcha = cgi.escape(config["captcha"]["recaptcha"]["userecaptcha"])
recaptcha_pub_key = cgi.escape(config["captcha"]["recaptcha"]["publickey"])
recaptcha_priv_key = cgi.escape(config["captcha"]["recaptcha"]["privatekey"])
datafields = functions.parsedict(config['required']['datafields'])
alerton = config['alerts']['alerton']
htmlalert = config['alerts']['htmlalert']
mailalert = config['alerts']['mailalert']

if stomethod == 'sqlite':
    DB = Sqlite(sqlitedb)
else:
    DB = FileSto(datafile)

form = cgi.FieldStorage()


def main():
    """Main function that is called on a page load.

    It checks to see if any data has been filled in and if so handles it,
    and then prints the page's html"""
    errormessage = """\
 <tr>
  <td id="nosignup" colspan="%s">No one has signed up yet</td>
 </tr>
""" % (len(datafields) + 1)
    # attempt to create .htaccess if the user wants/it isn't there already
    functions.createhtaccess(config)
    # if they've hit in, out, or remove
    if "action" in form:
        submit = True
        if functions.checkboolean(userecaptcha):
            checkvalid = recaptchacheck()
            # make sure recaptcha is valid before continuing
            if not checkvalid.is_valid:
                indexhtml.errormsg += """\
<span class="error-msg">Incorrect CAPTCHA entered, try again</span>"""
                submit = False
        if submit:
            # figure out what button they clicked and call the appropriate
            # function
            if form["action"].value == "In":
                DB.add("In")
                sendmail(DB.incount())
            elif form["action"].value == "Out":
                DB.add("Out")
            elif form["action"].value == "Remove":
                DB.remove()

    indexhtml.load() # load HTML up
    
    indexhtml.display()

if __name__ == '__main__':
    main()

Report a bug
ViewVC Help
Powered by ViewVC 1.0.5