Exemple #1
0
def main(id, qdict):

    # Open database connection.

    cnx = dbconfig.connect(readonly=True, devel=qdict['dev'])

    # Get project name.

    name = dbutil.get_project_name(cnx, id)

    # Generate html document header.

    print 'Content-type: text/plain'
    print

    # Generate main part of html document.

    if id == 0 or name == '':
        print 'No such project.'
    else:

        # Generate POMS ini file.

        ini = StringIO.StringIO()
        dbutil.export_poms_project(cnx, id, qdict['dev'], ini)
        print ini.getvalue()
def main(id, qdict):

    # Open database connection.

    cnx = dbconfig.connect(readonly=True, devel=qdict['dev'])

    # Get project name.

    name = dbutil.get_project_name(cnx, id)

    # Generate document header.

    print 'Content-type: text/plain'
    print

    # Generate main part of text document.

    if id == 0 or name == '':
        print 'No such project.'
    else:

        # Generate text.

        cfg = StringIO.StringIO()
        dbutil.export_fife_project(cnx, id, cfg)
        print cfg.getvalue()
def main(project_id, qdict):

    # Open database connection.

    cnx = dbconfig.connect(readonly=False, devel=qdict['dev'])

    # Get original project name.

    project_name = dbutil.get_project_name(cnx, project_id)
    clone_id = 0

    if project_name != '':

        # Generate first candidate clone project name.

        clone_project_name = 'Clone of %s' % project_name

        # Check whether this project name is already used.

        dup_id = dbutil.get_project_id(cnx, clone_project_name)

        # Modify project name until we find one that isn't alrady used.

        ntry = 1
        while dup_id > 0:
            ntry += 1
            clone_project_name = 'Clone %d of %s' % (ntry, project_name)
            dup_id = dbutil.get_project_id(cnx, clone_project_name)

        # Now clone the project.

        clone_id = dbutil.clone_project(cnx, project_id, clone_project_name)

    # Generate redirect html document header to invoke the project editor for
    # the newly created document.

    url = ''
    if clone_id > 0:
        url = '%s/edit_project.py?id=%d&%s' % \
              (dbconfig.base_url, clone_id, dbargs.convert_args(qdict))
    else:
        url = '%s/query_projects.py?%s' % \
              (dbconfig.base_url, dbargs.convert_args(qdict))

    print 'Content-type: text/html'
    print 'Status: 303 See Other'
    print 'Location: %s' % url
    print
    print '<!DOCTYPE html>'
    print '<html>'
    print '<body>'
    url = ''
    if clone_id > 0:
        print 'Cloned project %s' % project_name
    else:
        print 'Project not cloned.'
    print '<br><br>'
    print 'If page does not automatically reload click this <a href=%s>link</a>' % url
    print '</body>'
    print '</html>'
def override_form(cnx, id, qdict):

    # Construct global disabled option for restricted controls.

    disabled = ''
    if not dbconfig.restricted_access_allowed() and dbutil.restricted_access(
            cnx, 'overrides', id):
        disabled = 'disabled'

    # Query override from database.

    c = cnx.cursor()
    q = 'SELECT stage_id,name,override_type,value FROM overrides WHERE id=%s'
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) == 0:
        raise IOError('Unable to fetch override id %d' % id)
    row = rows[0]
    stage_id = row[0]
    name = row[1]
    override_type = row[2]
    value = row[3]

    # Query stage name and project id.

    q = 'SELECT id, name, project_id FROM stages WHERE id=%s'
    c.execute(q, (stage_id, ))
    stage_rows = c.fetchall()
    if len(stage_rows) == 0:
        raise IOError('Unable to fetch stage id %d' % stage_id)
    stage_row = stage_rows[0]
    stage_name = stage_row[1]
    project_id = stage_row[2]
    project_name = dbutil.get_project_name(cnx, project_id)

    # Generate form.

    print '<h2>Project %s</h2>' % project_name
    print '<h2>Stage %s</h2>' % stage_name
    print '<h2>Override %s</h2>' % name
    print '<form action="%s/dbhandler.py" method="post">' % dbconfig.rel_url

    # Add hidden input field to store table name.

    print '<input type="hidden" id="table" name="table" value="overrides">'

    # Add hidden input field to store save url (parent of this page).

    print '<input type="hidden" id="saveurl" name="saveurl" value="%s/edit_stage.py?id=%d&%s">' % \
        (dbconfig.base_url, stage_id, dbargs.convert_args(qdict))

    # Add hidden qdict input fields.

    for key in qdict:
        print '<input type="hidden" name="%s" value="%s">' % (
            dbutil.convert_str(key), dbutil.convert_str(qdict[key]))
    # Add form fields in a table.

    print '<table border=1 style="border-collapse:collapse">'

    print '<tr>'
    print '<td>'
    print '<label for="id">ID:</label>'
    print '</td>'
    print '<td>'
    print '<input type="number" id="id" name="id" value="%d" readonly>' % id
    print '</td>'
    print '</tr>'

    print '<tr>'
    print '<td>'
    print '<label for="stage_id">Stage ID:</label>'
    print '</td>'
    print '<td>'
    print '<input type="number" id="stage_id" name="stage_id" value="%d" readonly>' % stage_id
    print '</td>'
    print '</tr>'

    print '<tr>'
    print '<td>'
    print '<label for="name">Name:</label>'
    print '</td>'
    print '<td>'
    print '<input type="text" id="name" name="name" value="%s">' % name
    print '</td>'
    print '</tr>'

    print '<tr>'
    print '<td>'
    print '<label for="override_type">Type:</label>'
    print '</td>'
    print '<td>'
    print '<select id="override_type" name="override_type" size=0>'
    pulldown_list = pulldowns['override_type']
    for override_value in pulldown_list:
        sel = ''
        if override_value == override_type:
            sel = 'selected'
        print '<option value="%s" %s>%s</option>' % (override_value, sel,
                                                     override_value)
    print '</select>'
    print '</td>'
    print '</tr>'

    print '<tr>'
    print '<td>'
    print '<label for="value">Value:</label>'
    print '</td>'
    print '<td>'
    print '<input type="text" id="value" name="value" value="%s">' % value
    print '</td>'
    print '</tr>'

    # Finish table.

    print '</table>'

    # Add "Save" and "Back" buttons.

    print '<input type="submit" name="submit" value="Save" %s>' % disabled
    print '<input type="submit" name="submit" value="Update" %s>' % disabled
    print '<input type="submit" name="submit" value="Back">'
    print '</form>'
def project_form(cnx, id, qdict):

    # Construct global disabled option for restricted controls.

    disabled = ''
    if not dbconfig.restricted_access_allowed() and dbutil.restricted_access(
            cnx, 'projects', id):
        disabled = 'disabled'

    # Construct disable option that applies only to status options.

    option_disabled = ''
    if not dbconfig.restricted_access_allowed():
        option_disabled = 'disabled'

    # Get project name.

    name = dbutil.get_project_name(cnx, id)

    # Get experiment.

    experiment = dbutil.get_project_experiment(cnx, id)

    # Generate form.

    print '<h2>Project %s</h2>' % name

    # Add button to insert another stage.

    print '<h2>Stages</h2>'
    print '<form action="%s/add_stage.py?id=%d&%s" method="post" target="_self">' % \
        (dbconfig.rel_url, id, dbargs.convert_args(qdict))
    print '<input type="submit" value="Add Stage" %s>' % disabled
    print '</form>'
    print '<br>'

    # Query stage ids belonging to this project.

    c = cnx.cursor()
    q = 'SELECT id, name FROM stages WHERE project_id=%s ORDER BY seqnum'
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) > 0:

        # Add links to edit project stages.

        print '<table border=1 style="border-collapse:collapse">'
        print '<tr>'
        print '<th>&nbsp;Stage ID&nbsp;</th>'
        print '<th>&nbsp;Stage Name&nbsp;</th>'
        print '</tr>'

        for row in rows:
            print '<tr>'
            stage_id = row[0]
            stage_name = row[1]
            print '<td align="center">%d</td>' % stage_id
            print '<td>&nbsp;<a target="_self" href="%s/edit_stage.py?id=%d&%s">%s</a>&nbsp;</td>' % \
                (dbconfig.base_url, stage_id, dbargs.convert_args(qdict), stage_name)

            # Add Edit button/column

            print '<td>'
            print '<form target="_self" action="%s/edit_stage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, stage_id, dbargs.convert_args(qdict))
            print '<div title="Edit stage">'
            print '<input type="submit" value="&#x270e;">'
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Clone button/column

            print '<td>'
            print '<form target="_self" action="%s/clone_stage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, stage_id, dbargs.convert_args(qdict))
            print '<div title="Clone stage">'
            print '<input type="submit" value="&#x2398;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Delete button/column

            print '<td>'
            print '<form action="%s/delete_stage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, stage_id, dbargs.convert_args(qdict))
            print '<div title="Delete stage">'
            print '<input type="submit" value="&#x1f5d1;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Up button/column

            print '<td>'
            print '<form action="%s/up_stage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, stage_id, dbargs.convert_args(qdict))
            print '<div title="Move up">'
            print '<input type="submit" value="&#x25b2;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Down button/column

            print '<td>'
            print '<form action="%s/down_stage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, stage_id, dbargs.convert_args(qdict))
            print '<div title="Move down">'
            print '<input type="submit" value="&#x25bc;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Finish row.

            print '</tr>'

        # Finish table.

        print '</table>'

    print '<h2>Project Data</h2>'

    # Query full project from database.

    q = 'SELECT %s FROM projects WHERE id=%%s' % dbutil.columns('projects')
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) == 0:
        raise IOError('Unable to fetch project id %d' % id)
    row = rows[0]

    print '<form action="%s/dbhandler.py" method="post">' % dbconfig.rel_url

    # Add hidden input field to store table name.

    print '<input type="hidden" id="table" name="table" value="projects">'

    # Add hidden input field to store save url (parent of this page).

    print '<input type="hidden" id="saveurl" name="saveurl" value="%s/query_projects.py?%s">' % \
        (dbconfig.base_url, dbargs.convert_args(qdict))

    # Add hidden qdict input fields.

    for key in qdict:
        print '<input type="hidden" name="%s" value="%s">' % (
            dbutil.convert_str(key), dbutil.convert_str(qdict[key]))
    # Loop over fields of this project.
    # Put fields in a table.

    print '<table border=1 style="border-collapse:collapse">'
    cols = databaseDict['projects']
    for n in range(len(cols)):
        coltup = cols[n]
        colname = coltup[0]
        coltype = coltup[2]
        colarray = coltup[3]
        coldesc = coltup[4]

        if colname != '':

            # Set readonly attribute

            readonly = ''
            if colname == 'id':
                readonly = 'readonly'
            elif disabled != '':
                readonly = 'readonly'

            print '<tr>'
            print '<td>'
            print '<label for="%s">%s: </label>' % (colname, coldesc)
            print '</td>'
            print '<td>'
            if colarray == 0:

                # Scalar column.

                if coltype[0:3] == 'INT':
                    print '<input type="number" id="%s" name="%s" size=10 value="%d" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:6] == 'DOUBLE':
                    print '<input type="text" id="%s" name="%s" size=10 value="%8.6f" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:7] == 'VARCHAR':
                    if colname in pulldowns:
                        print '<select id="%s" name="%s" size=0 %s>' % (
                            colname, colname, disabled)
                        pulldown_list = pulldowns[colname]
                        if type(pulldown_list) == type({}):
                            if experiment in pulldown_list:
                                pulldown_list = pulldowns[colname][experiment]
                            else:
                                pulldown_list = ['']
                        for value in pulldown_list:
                            sel = ''
                            if value == row[n]:
                                sel = 'selected'
                            if value == '' or value == 'Requested':
                                print '<option value="%s" %s>%s</option>' % (
                                    value, sel, value)
                            else:
                                print '<option value="%s" %s %s>%s</option>' % (
                                    value, sel, option_disabled, value)
                        print '</select>'
                    else:
                        print '<input type="text" id="%s" name="%s" size=100 value="%s" %s>' % \
                            (colname, colname, row[n], readonly)

            else:

                # Array columns.
                # Display using multiline <textarea>.

                strs = dbutil.get_strings(cnx, row[n])
                print '<textarea id="%s" name="%s" rows=%d cols=80 %s>' % \
                    (colname, colname, max(len(strs),1), readonly)
                print '\n'.join(strs)
                print '</textarea>'

            print '</td>'
            print '</tr>'

    # Finish table.

    print '</table>'

    # Add "Save" and "Back" buttons.

    print '<input type="submit" name="submit" value="Save" %s>' % disabled
    print '<input type="submit" name="submit" value="Update" %s>' % disabled
    print '<input type="submit" name="submit" value="Back">'
    print '</form>'
Exemple #6
0
def substage_form(cnx, id, qdict):

    # Construct global disabled option for restricted controls.

    disabled = ''
    if not dbconfig.restricted_access_allowed() and dbutil.restricted_access(
            cnx, 'substages', id):
        disabled = 'disabled'

    # Query substage from database.

    c = cnx.cursor()
    q = 'SELECT %s FROM substages WHERE id=%%s' % dbutil.columns('substages')
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) == 0:
        raise IOError('Unable to fetch substage id %d' % id)
    row = rows[0]
    fclname = row[1]
    stage_id = row[2]

    # Query stage name and project id.

    q = 'SELECT id, name, project_id FROM stages WHERE id=%s'
    c.execute(q, (stage_id, ))
    stage_rows = c.fetchall()
    if len(stage_rows) == 0:
        raise IOError('Unable to fetch stage id %d' % stage_id)
    stage_row = stage_rows[0]
    stage_name = stage_row[1]
    project_id = stage_row[2]
    project_name = dbutil.get_project_name(cnx, project_id)

    # Generate form.

    print '<h2>Project %s</h2>' % project_name
    print '<h2>Stage %s</h2>' % stage_name
    print '<h2>FCL %s</h2>' % fclname
    print '<form action="%s/dbhandler.py" method="post">' % dbconfig.rel_url

    # Add hidden input field to store table name.

    print '<input type="hidden" id="table" name="table" value="substages">'

    # Add hidden input field to store save url (parent of this page).

    print '<input type="hidden" id="saveurl" name="saveurl" value="%s/edit_stage.py?id=%d&%s">' % \
        (dbconfig.base_url, stage_id, dbargs.convert_args(qdict))

    # Add hidden qdict input fields.

    for key in qdict:
        print '<input type="hidden" name="%s" value="%s">' % (
            dbutil.convert_str(key), dbutil.convert_str(qdict[key]))
    # Loop over fields of this stage.
    # Put fields in a table.

    print '<table border=1 style="border-collapse:collapse">'
    cols = databaseDict['substages']
    for n in range(len(cols)):
        coltup = cols[n]
        colname = coltup[0]
        coltype = coltup[2]
        colarray = coltup[3]
        coldesc = coltup[4]

        if colname != '':

            # Set readonly attribute

            readonly = ''
            if colname == 'id' or colname == 'stage_id':
                readonly = 'readonly'
            elif disabled != '':
                readonly = 'readonly'

            print '<tr>'
            print '<td>'
            print '<label for="%s">%s: </label>' % (colname, coldesc)
            print '</td>'
            print '<td>'
            if colarray == 0:

                # Scalar column.

                if coltype[0:3] == 'INT':
                    print '<input type="number" id="%s" name="%s" size=10 value="%d" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:6] == 'DOUBLE':
                    print '<input type="text" id="%s" name="%s" size=100 value="%8.6f" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:7] == 'VARCHAR':
                    print '<input type="text" id="%s" name="%s" size=100 value="%s" %s>' % \
                        (colname, colname, row[n], readonly)

            else:

                # Array columns.
                # Display using multiline <textarea>.

                strs = dbutil.get_strings(cnx, row[n])
                print '<textarea id="%s" name="%s" rows=%d cols=80 %s>' % \
                    (colname, colname, max(len(strs), 1), readonly)
                print '\n'.join(strs)
                print '</textarea>'

            print '</td>'
            print '</tr>'

    # Finish table.

    print '</table>'

    # Add "Save" and "Back" buttons.

    print '<input type="submit" name="submit" value="Save" %s>' % disabled
    print '<input type="submit" name="submit" value="Update" %s>' % disabled
    print '<input type="submit" name="submit" value="Back">'
    print '</form>'
Exemple #7
0
def group_form(cnx, id, qdict):

    # Construct global disabled option for restricted controls.

    disabled = ''
    if not dbconfig.restricted_access_allowed():
        disabled = 'disabled'

    # Get group name.

    name = dbutil.get_group_name(cnx, id)

    # Generate form.

    print '<h2>Group %s</h2>' % name

    # Query full group from database.

    c = cnx.cursor()
    q = 'SELECT %s FROM groups WHERE id=%%s' % dbutil.columns('groups')
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) == 0:
        raise IOError('Unable to fetch group id %d' % id)
    row = rows[0]

    print '<form action="%s/dbhandler.py" method="post">' % dbconfig.rel_url

    # Add hidden input field to store table name.

    print '<input type="hidden" id="table" name="table" value="groups">'

    # Add hidden input field to store save url (parent of this page).

    print '<input type="hidden" id="saveurl" name="saveurl" value="%s/query_groups.py?%s">' % \
        (dbconfig.base_url, dbargs.convert_args(qdict))

    # Add hidden qdict input fields.

    for key in qdict:
        print '<input type="hidden" name="%s" value="%s">' % (
            dbutil.convert_str(key), dbutil.convert_str(qdict[key]))
    # Loop over fields of this group.
    # Put fields in a table.

    print '<table border=1 style="border-collapse:collapse">'
    cols = databaseDict['groups']
    for n in range(len(cols)):
        coltup = cols[n]
        colname = coltup[0]
        coltype = coltup[2]
        colarray = coltup[3]
        coldesc = coltup[4]

        if colname != '':

            # Set readonly attribute

            readonly = ''
            if colname == 'id':
                readonly = 'readonly'
            elif disabled != '':
                readonly = 'readonly'

            print '<tr>'
            print '<td>'
            print '<label for="%s">%s: </label>' % (colname, coldesc)
            print '</td>'
            print '<td>'
            if colarray == 0:

                # Scalar column.

                if coltype[0:3] == 'INT':
                    print '<input type="number" id="%s" name="%s" size=10 value="%d" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:6] == 'DOUBLE':
                    print '<input type="text" id="%s" name="%s" size=10 value="%8.6f" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:7] == 'VARCHAR':
                    if colname in pulldowns:
                        print '<select id="%s" name="%s" size=0 %s>' % (
                            colname, colname, disabled)
                        for value in pulldowns[colname]:
                            sel = ''
                            if value == row[n]:
                                sel = 'selected'
                            if value == '' or value == 'Requested':
                                print '<option value="%s" %s>%s</option>' % (
                                    value, sel, value)
                            else:
                                print '<option value="%s" %s %s>%s</option>' % (
                                    value, sel, option_disabled, value)
                        print '</select>'
                    else:
                        print '<input type="text" id="%s" name="%s" size=100 value="%s" %s>' % \
                            (colname, colname, row[n], readonly)

            else:

                # Array columns.
                # Display using multiline <textarea>.

                strs = dbutil.get_strings(cnx, row[n])
                print '<textarea id="%s" name="%s" rows=%d cols=80 %s>' % \
                    (colname, colname, max(len(strs),1), readonly)
                print '\n'.join(strs)
                print '</textarea>'

            print '</td>'
            print '</tr>'

    # Finish table.

    print '</table>'

    # Projects section.

    print '<h3>Projects</h3>'

    # Query all projects.

    project_ids = []
    q = 'SELECT id,name FROM projects ORDER BY name'
    c.execute(q, ())
    rows = c.fetchall()
    for row in rows:
        project_id = row[0]
        project_ids.append(project_id)

    # Query all projects in this group.

    project_group_ids = set()
    q = 'SELECT project_id FROM group_project WHERE group_id=%s'
    c.execute(q, (id, ))
    rows = c.fetchall()
    for row in rows:
        project_id = row[0]
        project_group_ids.add(project_id)

    # Projects table.

    print '<table border=1 style="border-collapse:collapse">'
    print '<tr>'
    print '<th>Group Projects</th>'
    print '<th>Available Projects</th>'
    print '</tr>'

    # Generate project lists.

    print '<td>'

    # Generate selection list for projects in group.
    # Loop over project ids in name order.

    print '<select id="ingroup" name="remove" size=20 multiple>'
    for project_id in project_ids:
        if project_id in project_group_ids:
            project_name = dbutil.get_project_name(cnx, project_id)
            print '<option value="%d">%s</option>' % (project_id, project_name)
    print '</select>'
    print '</td>'
    print '<td>'

    # Generate selection list for projects not in group.
    # Loop over project ids in name order.

    print '<select id="available" name="add" size=20 multiple>'
    for project_id in project_ids:
        if not project_id in project_group_ids:
            project_name = dbutil.get_project_name(cnx, project_id)
            print '<option value="%d">%s</option>' % (project_id, project_name)
    print '</select>'
    print '</td>'

    # Finish datasets table.

    print '</table>'

    # Add "Save" and "Back" buttons.

    print '<input type="submit" name="submit" value="Save" %s>' % disabled
    print '<input type="submit" name="submit" value="Update" %s>' % disabled
    print '<input type="submit" name="submit" value="Back">'
    print '</form>'
Exemple #8
0
def main(id, confirm, qdict):

    # Open database connection.

    cnx = dbconfig.connect(readonly=False, devel=qdict['dev'])

    # Get project name.

    name = dbutil.get_project_name(cnx, id)

    # Check confirm flag.

    if confirm == 0:

        # If confirm flag is zero, generate a confirmation page.

        print 'Content-type: text/html'
        print
        print '<!DOCTYPE html>'
        print '<html>'
        print '<head>'
        print '<title>Delete Project</title>'
        print '</head>'
        print '<body>'
        if id == 0 or name == '':

            print 'No such project.'

        else:

            print 'Delete project %s?' % name

            # Generate a form with two buttons "Delete" and "Cancel."

            print '<br>'
            print '<form action="%s/delete_project.py?id=%d&confirm=1&%s" method="post">' % \
                (dbconfig.rel_url, id, dbargs.convert_args(qdict))
            print '<input type="submit" value="Delete">'
            print '<input type="submit" value="Cancel" formaction="%s/query_projects.py?%s">' % \
                (dbconfig.rel_url, dbargs.convert_args(qdict))
            print '</form>'

        print '</body>'
        print '</html>'

    else:

        # If confirm flag is nonzero, delete project and redirect to project list.

        dbutil.delete_project(cnx, id)
        url = '%s/query_projects.py?%s' % \
              (dbconfig.base_url, dbargs.convert_args(qdict))

        # Generate redirect page.

        print 'Content-type: text/html'
        print 'Status: 303 See Other'
        print 'Location: %s' % url
        print
        print '<!DOCTYPE html>'
        print '<html>'
        print '<body>'
        print 'Deleted project %s.' % name
        print '<br><br>'
        print 'If page does not automatically reload click this <a href=%s>link</a>' % url
        print '</body>'
        print '</html>'
Exemple #9
0
def stage_form(cnx, id, qdict):

    # Construct global disabled option for restricted controls.

    disabled = ''
    if not dbconfig.restricted_access_allowed() and dbutil.restricted_access(
            cnx, 'stages', id):
        disabled = 'disabled'

    # Query project name and id from database.

    c = cnx.cursor()
    q = 'SELECT id, name, project_id FROM stages WHERE id=%s'
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) == 0:
        raise IOError('Unable to fetch stage id %d' % id)
    row = rows[0]
    name = row[1]
    project_id = row[2]
    project_name = dbutil.get_project_name(cnx, project_id)

    # Generate form.

    print '<h2>Project %s</h2>' % project_name
    print '<h2>Stage %s</h2>' % name

    # Substages section.

    print '<h2>Substages</h2>'

    # Add a button to add a new substage.

    print '<form action="%s/add_substage.py?id=%d&%s" method="post" target="_self">' % \
        (dbconfig.rel_url, id, dbargs.convert_args(qdict))
    print '<input type="submit" value="Add Substage" %s>' % disabled
    print '</form>'
    print '<br>'

    # Query substage ids belonging to this stage.

    q = 'SELECT id, fclname FROM substages WHERE stage_id=%s ORDER BY seqnum'
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) > 0:

        # Add links to edit project stages.

        print '<table border=1 style="border-collapse:collapse">'
        print '<tr>'
        print '<th>&nbsp;Substage ID&nbsp;</th>'
        print '<th>&nbsp;FCL&nbsp;</th>'
        print '</tr>'

        for row in rows:
            print '<tr>'
            substage_id = row[0]
            fclname = row[1]
            print '<td align="center">%d</td>' % substage_id
            print '<td>&nbsp;<a target="_self" href="%s/edit_substage.py?id=%d&%s">%s</a>&nbsp;</td>' % \
                (dbconfig.base_url, substage_id, dbargs.convert_args(qdict), fclname)

            # Add Edit button/column

            print '<td>'
            print '<form target="_self" action="%s/edit_substage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, substage_id, dbargs.convert_args(qdict))
            print '<div title="Edit substage">'
            print '<input type="submit" value="&#x270e;">'
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Clone button/column

            print '<td>'
            print '<form target="_self" action="%s/clone_substage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, substage_id, dbargs.convert_args(qdict))
            print '<div title="Clone substage">'
            print '<input type="submit" value="&#x2398;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Delete button/column

            print '<td>'
            print '<form action="%s/delete_substage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, substage_id, dbargs.convert_args(qdict))
            print '<div title="Delete substage">'
            print '<input type="submit" value="&#x1f5d1;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Up button/column

            print '<td>'
            print '<form action="%s/up_substage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, substage_id, dbargs.convert_args(qdict))
            print '<div title="Move up">'
            print '<input type="submit" value="&#x25b2;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Down button/column

            print '<td>'
            print '<form action="%s/down_substage.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, substage_id, dbargs.convert_args(qdict))
            print '<div title="Move down">'
            print '<input type="submit" value="&#x25bc;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Finish row.

            print '</tr>'

        # Finish table.

        print '</table>'

    # Overrides section.

    print '<h2>Overrides</h2>'

    # Add a button to add a new override.

    print '<form action="%s/add_override.py?id=%d&%s" method="post" target="_self">' % \
        (dbconfig.rel_url, id, dbargs.convert_args(qdict))
    print '<table>'

    print '<tr>'
    print '<td>'
    print '<label for="name">Name:</label>'
    print '</td>'
    print '<td>'
    print '<input type="text" id="name" name="name" value="">'
    print '</td>'
    print '</tr>'

    print '<tr>'
    print '<td>'
    print '<label for="override_type">Type:</label>'
    print '</td>'
    print '<td>'
    print '<select id="override_type" name="override_type" size=0>'
    pulldown_list = pulldowns['override_type']
    sel = 'selected'
    for value in pulldown_list:
        print '<option value="%s" %s>%s</option>' % (value, sel, value)
        sel = ''
    print '</select>'
    print '</td>'
    print '</tr>'

    print '<tr>'
    print '<td>'
    print '<label for="value">Value:</label>'
    print '</td>'
    print '<td>'
    print '<input type="text" id="value" name="value" value="">'
    print '</td>'
    print '</tr>'

    print '</table>'
    print '<input type="submit" value="Add Override" %s>' % disabled
    print '</form>'
    print '<br>'

    # Query override ids belonging to this stage.

    q = 'SELECT id, name, override_type, value FROM overrides WHERE stage_id=%s ORDER BY override_type'
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) > 0:

        # Add links to edit project stages.

        print '<table border=1 style="border-collapse:collapse">'
        print '<tr>'
        print '<th>&nbsp;ID&nbsp;</th>'
        print '<th>&nbsp;Name&nbsp;</th>'
        print '<th>&nbsp;Type&nbsp;</th>'
        print '<th>&nbsp;Value&nbsp;</th>'
        print '</tr>'

        for row in rows:
            print '<tr>'
            override_id = row[0]
            name = row[1]
            override_type = row[2]
            value = row[3]
            print '<td align="center">%d</td>' % override_id
            print '<td align="left">&nbsp;%s&nbsp;</td>' % name
            print '<td align="left">&nbsp;%s&nbsp;</td>' % override_type
            print '<td align="value" >&nbsp;%s&nbsp;</td>' % value

            # Add Edit button/column

            print '<td>'
            print '<form target="_self" action="%s/edit_override.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, override_id, dbargs.convert_args(qdict))
            print '<div title="Edit override">'
            print '<input type="submit" value="&#x270e;">'
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Clone button/column

            print '<td>'
            print '<form target="_self" action="%s/clone_override.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, override_id, dbargs.convert_args(qdict))
            print '<div title="Clone override">'
            print '<input type="submit" value="&#x2398;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Add Delete button/column

            print '<td>'
            print '<form action="%s/delete_override.py?id=%d&%s" method="post">' % \
                (dbconfig.rel_url, override_id, dbargs.convert_args(qdict))
            print '<div title="Delete override">'
            print '<input type="submit" value="&#x1f5d1;" %s>' % disabled
            print '</div>'
            print '</form>'
            print '</td>'

            # Finish row.

            print '</tr>'

        # Finish table.

        print '</table>'

    print '<h2>Stage Data</h2>'

    # Query full stage from database.

    q = 'SELECT %s FROM stages WHERE id=%%s' % dbutil.columns('stages')
    c.execute(q, (id, ))
    rows = c.fetchall()
    if len(rows) == 0:
        raise IOError('Unable to fetch stage id %d' % id)
    row = rows[0]

    print '<form action="%s/dbhandler.py" method="post">' % dbconfig.rel_url

    # Add hidden input field to store table name.

    print '<input type="hidden" id="table" name="table" value="stages">'

    # Add hidden input field to store save url (parent of this page).

    print '<input type="hidden" id="saveurl" name="saveurl" value="%s/edit_project.py?id=%d&%s">' % \
        (dbconfig.base_url, project_id, dbargs.convert_args(qdict))

    # Add hidden qdict input fields.

    for key in qdict:
        print '<input type="hidden" name="%s" value="%s">' % (
            dbutil.convert_str(key), dbutil.convert_str(qdict[key]))
    # Loop over fields of this stage.
    # Put fields in a table.

    print '<table border=1 style="border-collapse:collapse">'
    cols = databaseDict['stages']
    for n in range(len(cols)):
        coltup = cols[n]
        colname = coltup[0]
        coltype = coltup[2]
        colarray = coltup[3]
        coldesc = coltup[4]

        if colname != '':

            # Set readonly attribute

            readonly = ''
            if colname == 'id' or colname == 'project_id':
                readonly = 'readonly'
            elif disabled != '':
                readonly = 'readonly'

            print '<tr>'
            print '<td>'
            print '<label for="%s">%s: </label>' % (colname, coldesc)
            print '</td>'
            print '<td>'
            if colarray == 0:

                # Scalar column.

                if coltype[0:3] == 'INT':
                    print '<input type="number" id="%s" name="%s" size=10 value="%d" %s>' % \
                        (colname, colname, row[n], readonly)
                elif coltype[0:6] == 'DOUBLE':
                    value = row[n]
                    if value == None:
                        value = 0.
                    print '<input type="text" id="%s" name="%s" size=100 value="%8.6f" %s>' % \
                        (colname, colname, value, readonly)
                elif coltype[0:7] == 'VARCHAR':
                    if colname in pulldowns:
                        print '<select id="%s" name="%s" size=0 %s>' % (
                            colname, colname, disabled)
                        pulldown_list = pulldowns[colname]
                        if type(pulldown_list) == type({}):
                            if experiment in pulldown_list:
                                pulldown_list = pulldowns[colname][experiment]
                            else:
                                pulldown_list = ['']
                        for value in pulldown_list:
                            sel = ''
                            if value == row[n]:
                                sel = 'selected'
                            print '<option value="%s" %s>%s</option>' % (
                                value, sel, value)
                        print '</select>'
                    else:
                        print '<input type="text" id="%s" name="%s" size=100 value="%s" %s>' % \
                            (colname, colname, row[n], readonly)

                    # Add datasets.

                    #if (colname == 'defname' or colname == 'ana_defname') and row[n] != '':
                    #    dbutil.add_dataset(cnx, project_id, 'output', row[n])
                    #if colname == 'inputdef' and row[n] != '':
                    #    dbutil.add_dataset(cnx, project_id, 'input', row[n])

            else:

                # Array columns.
                # Display using multiline <textarea>.

                strs = dbutil.get_strings(cnx, row[n])
                print '<textarea id="%s" name="%s" rows=%d cols=80 %s>' % \
                    (colname, colname, max(len(strs), 1), readonly)
                print '\n'.join(strs)
                print '</textarea>'

            print '</td>'
            print '</tr>'

    # Finish table.

    print '</table>'

    # Add "Save" and "Back" buttons.

    print '<input type="submit" name="submit" value="Save" %s>' % disabled
    print '<input type="submit" name="submit" value="Update" %s>' % disabled
    print '<input type="submit" name="submit" value="Back">'
    print '</form>'