Page Source

from utils.display import Display, Database, Modal
from utils.controls import *
from utils.output import *
from utils.web_exc import WebError
from utils.static_strings import StaticString
from utils import actions, shapes
import queries, debugging
from config import docroot
import string, os, MySQLdb

class MembershipControl(SelectQueryControl):

  """Represent the members of some group.  display.fields[field] is a list
  of pairs (login, name) of members."""

  def __init__(self, field, title=None):
    self.field = field
    self.title = title
    self.comment = ""
    self.multi = 1
    self.nbsppad = 1
    self.size = 5
    self.attrs = {}

  def output_disp(self, display, container):
    # fill up a BulletColumns container with our people
    rv = BulletColumns()
    for login, name in display.fields[self.field]:
      rv.append("""<a href="%(person!login)s">%(!name)s</a>""" \
                % display.urls( { 'login' : login, 'name' : name } ) )
    container.append(rv)

  def output_form(self, display, container):
    self.default = []
    for login, name in display.fields[self.field]:
      self.default.append(login)
    self.query = queries.Select(tables=["people"],
                                columns={'sys_value' :'login',
                                'user_value' : "concat(fname,' ',mname,' ',lname)"},
                                where="pseudo=0 and retired=0",
                                order=["lname"]
                                )
    SelectQueryControl.output_form(self,display,container)
    return


class ProjectsDisplay(Display, Database, StaticString, Modal):

  multiple_container_control = SimpleContainerControl(BulletColumns)

  multiple_controls = [
   CoalesceControl([IfModeControl('edit',
                                  CoalesceControl(["[&nbsp;",
                                                   LinkControl(field='project_id',
                                                               url="%(action:)s&delete=%(!project_id)s",
                                                               subcontrol="Delete"),
                                                   "&nbsp;&nbsp;",
                                                   LinkControl(field='project_id',
                                                               url="projects/%(!project_id)s",
                                                               subcontrol="Edit"),
                                                   "&nbsp;] " ])),
                    LinkControl("project_id",
                                #"%(sect:research)s/projects/%(!project_id)s",
                                "%(!url)s",
                                FieldControl("project_title")
                               )
                   ])]

  single_controls = [
    "<h1>", TextFieldControl("project_title","Name"), "</h1>",
    IfExistsControl("description",
                    [ "<blockquote>",
                      TextAreaControl("description","Description"),
                      "</blockquote>" ] ),
    IfExistsControl("url",
                    [ "<h2>Main Website</h2><blockquote>",
                      URLControl("url","Project WebPage"),
                      "</blockquote>" ] ),
    "<h2>Project Members</h2>",
    MembershipControl('members','Members')]

  def __init__(self, req):
    self.multiple = 1
    Display.__init__(self, req)

  def is_add(self):
    try:
      return self.add
    except:
      self.add = None
      self.process_arguments()
      return self.add

  def process_arguments(self):
    try: return self.processed
    except: self.processed = 1
    # These arguments expected: 'add', '[0-9]+', or nonsense
    args = self.req.url.arguments
    if len(args) != 1: return
    if args[0] != 'add':
      try:
        self.project_id = int(args[0])
        self.multiple = None
      except ValueError, TypeError:
        # if it's not add, and the int() fails, we just ignore it
        return
    elif self.permit_mode('add'):
      self.add = 1
      self.mode = 'add'
      self.multiple = None
 
  def db_delete_row(self,id):
    # lock
    lock = queries.Lock(tables=["projects","project_members"])

    try:
      sel = queries.Select(tables="projects",
                           where="project_id = %s" % queries.represent_value(id))
      sel.execute()
      row = sel.fetch()
      sels = queries.Select(tables="project_members",
                           where="project_id = %s" % queries.represent_value(id))
      sels.execute()
      rows = sels.fetchall()
      if row:
        actions.notify('projects', "User '%s' deleted the following project from the projects table:\n\n%s\n%s" % (self.req.login, row, rows))
  
      dels = queries.Delete(table="project_members",
                           where="project_id = %s" % queries.represent_value(id))
      dels.execute()
      delq = queries.Delete(table="projects",
                            where="project_id = %s" % queries.represent_value(id))
      delq.execute()
 
    finally:
      lock.unlock()

  def perform_action(self):
    self.process_arguments()
    self.prep_database()

    if self.req.url.internal.has_key('delete'):
      if not self.permit_mode('delete'):
        raise WebError("Permission Denied", "You don't have permission to edit this page")
      delete_id = int(self.req.url.internal['delete'][0])
      self.db_delete_row(delete_id)
      return
    elif self.is_add():
      if not self.permit_mode('add'):
        raise WebError("Permission Denied", "You don't have permission to edit this page")
      self.perform_database_insert()
      self.project_id = self.fields['project_id']
      actions.notify('projects', "User '%s' added a record for project '%s'." % (self.req.login, self.project_id))
      return ("%s?mode+display"%self.project_id)
    else: # not delete, not add, must be edit.
      if not self.permit_mode('edit'):
        raise WebError("Permission Denied", "You don't have permission to edit this page")
      self.perform_database_update()
      actions.notify('projects', "User '%s' edited the record for project '%s'." % (self.req.login, self.project_id))
      return ("%s?mode+display"%self.project_id)

  def db_query(self):
    if self.is_add(): return
    self.process_arguments()

    q = queries.Select(tables="projects", order="project_title")
    if not self.multiple:
      q.where = 'project_id = %s' % queries.represent_value(self.project_id)
    q.execute()
    self.query = q
    if not self.db_rows():
      # Couldn't find the project specified, so switch to multiple, try again.
      self.multiple = 1
      q = queries.Select(tables="projects", order="project_title")
      q.execute()
      self.query = q

  def permit_mode(self, mode):
    return (mode == 'display' or perms.may(self.req.login,mode,'projects'))

  def get_multiple_title(self):
    return "Department Projects"

  def get_single_title(self):
    return ("%s: %s" % (self.get_multiple_title(),self.fields["project_title"]))

  def db_rows(self):
    return self.query.count()

  def is_multiple(self):
    return self.multiple

  def make_page(self, page):
    page.set_type("research")
    self.prep_database()
    if not self.is_add():
      self.add_modes_to_page(page)
    if self.is_multiple():
      page.set_title(self.get_multiple_title())
      page.append("<h1>%s</h1>" % self.get_multiple_title())
      page.append(self.GetString(key="research_projects",
                                   display=self,
                                   title_fn=None))
      page.append("<h2>The Projects</h2>")
      page.add_navigation("%(sect:research)s/projects/add" % self.req.urls(),"Add Project")
      page.append(self.multiple_database())
    else:
      page.set_title(self.get_single_title())
      page.add_navigation("%(sect:research)s/projects" % self.req.urls(),"Projects")
      if self.get_mode() == 'edit' or self.is_add():
	self.shape = shapes.FORM
      page.append(self.single_database())

  def db_update(self):
    sqlid = queries.represent_value(self.project_id)

    # Remove 'members' list from form_fields
    try:
      members = self.form_fields['members']
      del self.form_fields['members']
    except:
      debugging.log("there are no members")
      members = []

    # Delete all the project members for this project in project_members table
    delq = queries.Delete(table="project_members",where="project_id = %s" % sqlid)
    try:
      delq.execute()
    except MySQLdb.Error,e:
      raise WebError("Database Error",e)

    # Add the new set of project members, if any
    if members:
      rows = []
      for mem in members:
        rows.append({'login' : mem, 'project_id' : self.project_id}) # SQLification done automagically
      ins = queries.Insert(table="project_members",rows=rows)
      try:
        ins.execute()
      except MySQLdb.Error,e:
        raise WebError("Database Error",e)

    # Update the other values in the projects table
    u = queries.Update(table="projects",
                       where="project_id = %s" % self.project_id,
                       sets=self.form_fields)
    try:
      u.execute()
    except MySQLdb.Error,e:
      self.SQL_Error("update",e)

  def db_insert(self):
    self.form_fields['project_id'] = self.fields['project_id']

    # Remove 'members' from form_fields
    try:
      members = self.form_fields['members']
      del self.form_fields['members']
    except:
      debugging.log("there are no members")
      members = []

    try:
      lock = queries.Lock(tables=["projects","project_members"])
      # first add an entry to the projects table
      ins = queries.Insert(table="projects",rows=[self.form_fields])
      ins.execute()
      rows = []
      if members:
        for m in members:
          rows.append({'login':m,'project_id':self.form_fields['project_id']}) 
        mem = queries.Insert(table="project_members",rows=rows)
        mem.execute()
    finally:
      lock.unlock()

  def db_defaults(self):
    s = queries.Select(tables = 'projects',
                       columns = [ 'project_id' ],
                       order = 'project_id desc',
                       limit = 1
                       )
    s.execute()
    row = s.fetch()
    project_id = int(row['project_id'] + 1)
    self.fields = { 'project_title' : 'New Project',
                    'url' : 'http://',
                    'project_id' : project_id,
                    'members' : [],
                    'description' : '' }
    return self.fields

  def db_fetch(self):
    # if this is an Add, return the defaults.
    if self.is_add(): return self.db_defaults()

    # Fetch from the database
    self.fields = self.query.fetch()
    
    if not self.fields:
      self.multiple = 1
      try: del self.project_id
      except: pass # project_id must not be set
      return self.fields

    # Fetch project members if necessary
    if not self.multiple:
      q = queries.Select(tables=["project_members", "people"],
                         columns={'name' : queries.SQL("concat(fname, ' ', lname)"),
                                  'login' : 'project_members.login' },
                         order='name',
                         where="""project_id = %s AND
                                  project_members.login = people.login""" \
                                  % queries.represent_value(self.project_id))
      q.execute()
      self.fields['members'] = []
      for member in q.fetchall():
        self.fields['members'].append((member['login'], member['name']))

    return self.fields


def new(req):
  return ProjectsDisplay(req)