コード例 #1
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def update_notes():
  """ Updates the notes field of a specific record ; redirects to GET /hours """
  #######################################################
  
  # get index of completed record
  # TODO: ensure this is good, in case of template changes
  index = int(bottle.request.forms.get("index"))
  
  name = Cookies.get.name(bottle.request)
  date = Cookies.get.date(bottle.request)
  
  # TODO: again, check after template changes
  newNotes = bottle.request.forms.get("notesDisplay")
  # replace <br> with " " in case of enter button being pressed
  newNotes = newNotes.replace("<br>", " ").strip()

  # set the anchor cookie ; if the record's notes are successfully changed, it gets deleted
  Cookies.set.anchor(bottle.response, index)

  #######################################################

  if newNotes:
    records = recorder.parseRecordsFromFile(name, date)
    
    records[index].notes = newNotes
    
    recorder.writeRecords(name, date, records)
    
    # delete cookie if task completed
    Cookies.delete.anchor(bottle.response)
  
  #######################################################

  bottle.redirect('hours')
コード例 #2
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def delete_single_record():
  """ Deletes one record from the list of records currently displayed at GET /hours ; redirects to GET /hours """
  #######################################################
  
  # get index based on which delete button was clicked / which form was submitted
  # TODO: ensure this is good, in case of template changes
  index = int(bottle.request.forms.get('index'))
  
  # get name and date cookies
  name = Cookies.get.name(bottle.request)
  date = Cookies.get.date(bottle.request)
    
  # read and parse records from file
  records = recorder.parseRecordsFromFile(name, date)
  
  #######################################################
  
  # upon redirect, anchor to where the record was deleted
  # open that form and insert notes from the deleted record
  Cookies.set.anchor(bottle.response, index)
  Cookies.set.notes(bottle.response, records[index].notes)

  #######################################################

  # delete record
  del records[index]
  
  # write back updated records
  recorder.writeRecords(name, date, records)
  
  #######################################################
  
  bottle.redirect('hours')
コード例 #3
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def hours():
  """ GET /hours ; Main page ; serves up base template ; other routes redirect to here
  1) check for message from logging server
  2) get and manipulate cookies
  3) get subtotal and total
  4) read records from file
  5) return base template with appropriate values passed to it
  """
  # used to send all the required data to the template in one variable
  TEMPLATE = argparse.Namespace()
  
  #######################################################
  
  # if an encrypted message was returned from the logging server, get it and decrypt it
  TEMPLATE.msg = ""
#  try:
#    TEMPLATE.msg = crypto.getDecodedString(bottle.request.query['msg'])
#  except KeyError:
#    pass

  #######################################################
  
  # get name and date cookies
  TEMPLATE.name = Cookies.get.name(bottle.request)
  TEMPLATE.date = Cookies.get.date(bottle.request)
  
  # get anchor cookie in case a record has been just edited
  TEMPLATE.anchor = Cookies.get.anchor(bottle.request)
  # delete anchor cookie after getting it
  Cookies.delete.anchor(bottle.response)
  
  # get notes cookie ; in the case a record was just deleted, this cookie tracks the notes the record had
  TEMPLATE.notes = Cookies.get.notes(bottle.request)
  # delete notes cookie after getting it
  Cookies.delete.notes(bottle.response)
  
  #######################################################
  
  # parses through the saved records and counts the hours worked for the day / pay period
  TEMPLATE.subtotal = recorder.getSubtotalForDay(TEMPLATE.name, TEMPLATE.date)
  TEMPLATE.total = recorder.getTotalForPayPeriod(TEMPLATE.name, TEMPLATE.date)

  #######################################################
  
  # try to read and parse saved records corresponding to the name and date provided
  TEMPLATE.records = recorder.parseRecordsFromFile(TEMPLATE.name, TEMPLATE.date)
  
  #######################################################
  
  # additional data to send to template
  TEMPLATE.month = recorder.getPayPeriodMonth(TEMPLATE.date)
  TEMPLATE.LABELS = ENV.LABELS
  TEMPLATE.SENDER = ENV.SENDER
  TEMPLATE.RECEIVERS = ENV.RECEIVERS
  TEMPLATE.LOGGING_SERVER_ADDRESS = ENV.LOGGING_SERVER_ADDRESS
  TEMPLATE.LOGGING_SERVER_PORT = ENV.LOGGING_SERVER_PORT
  
  #######################################################

  return bottle.template('hours', DATA=TEMPLATE)
コード例 #4
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def email_records():
  """ Sends an SMTP email from ENV.SENDER to ENV.RECEIVERS containing records pulled with the name and date cookies ;
    redirects to GET /hours
  """
  #######################################################
  
  # get name and date cookies
  name = Cookies.get.name(bottle.request)
  date = Cookies.get.date(bottle.request)
  
  # sets flag based on user's confirmation / denial from popup alert
  emailConfirm = (bottle.request.forms.get("emailConfirm") == "true")
  
  #######################################################

  total = recorder.getTotalForPayPeriod(name, date)
  
  #######################################################
  
  currentTimeShort = time.strftime("%m/%d")
  
  subject = "Hours {0} (Total: {1})".format(currentTimeShort, str(total))
  
  #######################################################
  
  if all((emailConfirm, name, ENV.SENDER, ENV.RECEIVERS)):
    
    # get records corresponding to name and date
    records = recorder.parseRecordsFromFile(name, date)
    
    #TODO: check to make sure this works instead of the old commented line (make sure "\n" isn't needed at the end)
    body = "\n".join([record.emailFormat() for record in records])
    # for record in records:
    #   body += record.emailFormat() + "\n"
    
    # message = "Subject: %s\n\n%s" % (subject, body)
    # TODO: check to make sure this works instead of the old commented line
    message = "Subject: {subject}\n\n{body}".format(subject=subject, body=body)
      
    try:
      mail = smtplib.SMTP(ENV.HOST)
      mail.sendmail(ENV.SENDER, ENV.RECEIVERS, message)
      mail.quit()
      
      # if in debug mode, print info on successful email
      if ENV.DEBUG:
        cp.printOk("SENDER: {sender}".format(sender=ENV.SENDER))
        cp.printOk("RECEIVERS: {receivers}".format(receivers=ENV.RECEIVERS))
        cp.printOk("-- MESSAGE --\n{message}".format(message=message))
    
    except smtplib.SMTPException as e:
      # TODO: make sure this works
      cp.printFail(e)
  
  bottle.redirect('hours')
コード例 #5
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def send_records():
  """ Uses modu.crypto to encrypt and send records pulled with the name and date cookies ; redirects to GET /hours """
  # TODO: test this ; not sure if it's going to be used
  #######################################################

  name = Cookies.get.name(bottle.request)
  date = Cookies.get.date(bottle.request)
  
  confirm = (bottle.request.forms.get('confirm') == "true")
  
  # will use form-supplied values but defaults to values read from config file
  address = bottle.request.forms.get('address').strip() or ENV.LOGGING_SERVER_ADDRESS
  port = bottle.request.forms.get('port').strip() or ENV.LOGGING_SERVER_PORT
  
  #######################################################
  
  if all((confirm, name, address, port)):
        
    # parse records from file
    records = recorder.parseRecordsFromFile(name, date)
    
    # turn records into a '\n'-separated string
    recordString = '\n'.join([r.emailFormat() for r in records])
    
    # if in debug mode and about to send records, display info
    if ENV.DEBUG:
      cp.printOk("SENDING TO: {0}:{1}".format(address, port))
      cp.printOK("-- RECORDS --\n{records}".format(records=recordString))
    
    try:
      # encrypt and encode recordString
      encryptedRecords = crypto.getEncodedString(recordString)
      
      address = "/".join(bottle.request.url.split("/")[:-1]) + "/ack"
      
      # encrypts and encodes host address for rerouting back to hours
      encryptedAddress = crypto.getEncodedString(address)
      
      # send name, date, and encoded records to receiving server
      bottle.redirect('http://{address}:{port}/receive?n={name}&d={date}&r={encryptedRecords}&a={encryptedAddress}'
        .format(address=address, port=port,
                name=name, date=date,
                encryptedRecords=encryptedRecords, encryptedAddress=encryptedAddress))
    
    # thrown if config/crypto not found
    # TODO: is this error too specific or even accurate?
    except TypeError as e:
      cp.printFail(e)

  bottle.redirect('hours')
コード例 #6
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def complete_end_time():
  """ Completes a pending record by supplying an end time ; redirects to GET /hours """
  #######################################################
  
  # get index of completed record
  # TODO: ensure this is good, in case of template changes
  index = int(bottle.request.forms.get('index'))
  
  # get the submitted end time (which has already been pattern matched) OR get current rounded time
  # TODO: ensure this is good, in case of template changes
  end = recorder.parseTime(bottle.request.forms.get('completeEnd')) or recorder.getCurrentRoundedTime()
  
  # get name and date cookies
  name = Cookies.get.name(bottle.request)
  date = Cookies.get.date(bottle.request)

  # set the anchor cookie ; if the record is successfully completed, it gets deleted
  Cookies.set.anchor(bottle.response, index)
  
  #######################################################
  
  # get records from file
  records = recorder.parseRecordsFromFile(name, date)
  
  # get particular record to complete
  record = records[index]
  
  # set the end time - THEN check if it is valid
  record.setEnd(end)
  
  # don't accept an invalid or invalidly placed record
  if recorder.checkIfValid(records, record, index):
    
    if not record.durationLocked:
      # calculate and set duration
      record.calculateAndSetDuration()
    
    # write back record
    records[index] = record
    recorder.writeRecords(name, date, records)
    
    # delete cookie if task completed
    Cookies.delete.anchor(bottle.response)
  
  #######################################################

  bottle.redirect('hours')
コード例 #7
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def toggle_emergency():
  """ Toggles a single record's Y/N emergency field ; writes to file ; redirects to GET /hours """
  ##############################################

  name = Cookies.get.name(bottle.request)
  date = Cookies.get.date(bottle.request)
  
  ##############################################

  # TODO: ensure this is good, in case of template changes
  index = int(bottle.request.forms.get('index'))
  # don't delete on task completion (stay anchored to edited record to easily view the change)
  Cookies.set.anchor(bottle.response, index)
  
  ##############################################
  
  records = recorder.parseRecordsFromFile(name, date)

  records[index].emergency = "N" if records[index].emergency == "Y" else "Y"
  
  recorder.writeRecords(name, date, records)

  bottle.redirect('hours')
コード例 #8
0
ファイル: app.py プロジェクト: lgardner462/hoursapp
def hours_post():
  """ POST /hours ; Main page post ; parses form data ; reads/writes files ; redirects to GET /hours
  Extra explicit because of logical complexity
  1) get name, date, and index from the request
  2) parse the new record from the request
  3) read records on file for the user and date
  4) using the name and date cookies, check if the user has seen any records for that date
  5) check that the new record is valid and fits in the record list at the index and that no records have gone unseen
  if true:
    5.1) insert the new record at the index
    5.2) adjust adjacent records
    5.3) write the new record list to file
    5.4) delete the anchor cookie (successful POST means anchor back to the top of the page)
    5.5) delete the notes cookies (since it pertains to the inserted record only)
  else:
    5.1) save the index as the anchor cookie for GET /hours
    5.2) save the new (invalid) record's notes to a cookie
  6) set the name and date cookies to the values pulled from the request
  7) redirect to GET /hours
  """
  #######################################################
  
  # name of user
  name = bottle.request.forms.get("name").strip()
  # date : either picked by user or default today
  date = Cookies.get.date(bottle.request)
  # index for inserting new Record into the list of records
  index = int(bottle.request.forms.get("index"))
  
  #######################################################
  
  # parses form data and returns a Record obj
  newRecord = recorder.parseRecordFromHTML(bottle.request)
  
  # reads and parses Records on file
  records = recorder.parseRecordsFromFile(name, date)
  
  #######################################################

  # if the name cookie is equal to the name pulled from the request
  # and the date cookie is equal to the date pulled from the request
  # then any records on file have already been pulled, and it is safe to insert into the list
  recordsPulled = ((Cookies.get.name(bottle.request) == name) and (Cookies.get.date(bottle.request) == date))
  
  # checks if newRecord.start < newRecord.end
  # and that newRecord doesn't exceed the outer limits of adjacent records
  # also ensures that the user has seen any records that exist
  if recorder.checkIfValid(records, newRecord, index) and (recordsPulled or not records):
      
    # insert new record at index provided from template form
    records.insert(index, newRecord)
    
    # adjust timings of adjacent records in case of overlap
    recorder.adjustAdjacentRecords(records, index)
    
    # write back updated list
    recorder.writeRecords(name, date, records)
    
    # after posting a new record, delete the anchor and notes cookies
    Cookies.delete.anchor(bottle.response)
    Cookies.delete.notes(bottle.response)
  
  else:
    # if the record was invalid
    # or there were records the user hadn't seen
    # then save the index to anchor to the correct record form upon reload
    # and save the notes to avoid retyping
    Cookies.set.anchor(bottle.response, index)
    Cookies.set.notes(bottle.response, newRecord.notes)
  
  #######################################################
  
  # set name cookie with most recently used name (for insurance mostly)
  Cookies.set.name(bottle.response, name)
  Cookies.set.date(bottle.response, date)
  
  bottle.redirect('hours')