Page Source

from utils.display import Display, FileCopy, 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 LaboratoriesDisplay(Display, Database, StaticString, Modal):

  multiple_container_control = SimpleContainerControl(BulletColumns)

  multiple_controls = [
   CoalesceControl([IfModeControl('edit',
                                  CoalesceControl(["[&nbsp;",
                                                   LinkControl(field='lab_id',
                                                               url="%(action:)s&delete=%(!lab_id)s",
                                                               subcontrol="Delete"),
                                                   "&nbsp;] " ])),
                    LinkControl("lab_id",
                                "%(sect:research)s/labs/%(!lab_id)s",
                                FieldControl("lab_name")
                               )
                   ])]

  single_controls = [
    "<h1>", TextFieldControl("lab_name","Name"), "</h1>",
    IfExistsControl("description",
                    [ "<blockquote>",
                      TextAreaControl("description","Description"),
                      "</blockquote>" ] ),
    IfExistsControl("url",
                    [ "<h2>Main Website</h2><blockquote>",
                      URLControl("url","Lab WebPage"),
                      "</blockquote>" ] ),
    "<h2>Lab 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.lab_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=["labs","lab_members"])

    try:
      sel = queries.Select(tables="labs",
                           where="lab_id = %s" % queries.represent_value(id))
      sel.execute()
      row = sel.fetch()
      sels = queries.Select(tables="lab_members",
                           where="lab_id = %s" % queries.represent_value(id))
      sels.execute()
      rows = sels.fetchall()
      if row:
        actions.notify('labs', "User '%s' deleted the following lab from the labs table:\n\n%s\n%s" % (self.req.login, row, rows))
  
      dels = queries.Delete(table="lab_members",
                           where="lab_id = %s" % queries.represent_value(id))
      dels.execute()
      delq = queries.Delete(table="labs",
                            where="lab_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.lab_id = self.fields['lab_id']
      actions.notify('labs', "User '%s' added a record for lab '%s'." % (self.req.login, self.lab_id))
      return ("%s?mode+display"%self.lab_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('labs', "User '%s' edited the record for lab '%s'." % (self.req.login, self.lab_id))
      return ("%s?mode+display"%self.lab_id)

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

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

  def permit_mode(self, mode):
    #debugging.log (mode)                                                                               
    #debugging.log ("%s" % perms.may(self.req.login,mode,'labs')) 
    return (mode == 'display' or perms.may(self.req.login,mode,'labs'))

  def get_multiple_title(self):
    return "Department Laboratories"

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

  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_labs",
                                   display=self,
                                   title_fn=None))
      page.append("<h2>The Laboratories</h2>")
      page.add_navigation("%(sect:research)s/labs/add" % self.req.urls(),"Add Lab")
      page.append(self.multiple_database())
    else:
      page.set_title(self.get_single_title())
      page.add_navigation("%(sect:research)s/labs" % self.req.urls(),"Labs")
      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.lab_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 lab members for this lab in lab_members table
    delq = queries.Delete(table="lab_members",where="lab_id = %s" % sqlid)
    try:
      delq.execute()
    except MySQLdb.Error,e:
      raise WebError("Database Error",e)

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

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

  def db_insert(self):
    self.form_fields['lab_id'] = self.fields['lab_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=["labs","lab_members"])
      # first add an entry to the labs table
      ins = queries.Insert(table="labs",rows=[self.form_fields])
      ins.execute()
      rows = []
      if members:
        for m in members:
          rows.append({'login':m,'lab_id':self.form_fields['lab_id']}) 
        mem = queries.Insert(table="lab_members",rows=rows)
        mem.execute()
    finally:
      lock.unlock()

  def db_defaults(self):
    s = queries.Select(tables = 'labs',
                       columns = [ 'lab_id' ],
                       order = 'lab_id desc',
                       limit = 1
                       )
    s.execute()
    row = s.fetch()
    lab_id = int(row['lab_id'] + 1)
    self.fields = { 'lab_name' : 'New Lab',
                    'url' : 'http://',
                    'lab_id' : lab_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.lab_id
      except: pass # lab_id must not be set
      return self.fields

    # Fetch lab members if necessary
    if not self.multiple:
      q = queries.Select(tables=["lab_members", "people"],
                         columns={'name' : queries.SQL("concat(fname, ' ', lname)"),
                                  'login' : 'lab_members.login' },
                         order='name',
                         where="""lab_id = %s AND
                                  lab_members.login = people.login""" \
                                  % queries.represent_value(self.lab_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 LaboratoriesDisplay(req)