普通文本  |  154行  |  5.61 KB

#!/usr/bin/python
# Copyright 2012 Google Inc. All Rights Reserved.
# Author: mrdmnd@ (Matt Redmond)
# Based off of code in //depot/google3/experimental/mobile_gwp
"""Code to transport profile data between a user's machine and the CWP servers.
    Pages:
    "/": the main page for the app, left blank so that users cannot access
         the file upload but left in the code for debugging purposes
    "/upload": Updates the datastore with a new file. the upload depends on
               the format which is templated on the main page ("/")
               input includes:
                    profile_data: the zipped file containing profile data
                    board:  the architecture we ran on
                    chromeos_version: the chromeos_version
    "/serve": Lists all of the files in the datastore. Each line is a new entry
              in the datastore. The format is key~date, where key is the entry's
              key in the datastore and date is the file upload time and date.
              (Authentication Required)
    "/serve/([^/]+)?": For downloading a file of profile data, ([^/]+)? means
                       any character sequence so to download the file go to
                       '/serve/$key' where $key is the datastore key of the file
                       you want to download.
                       (Authentication Required)
    "/del/([^/]+)?": For deleting an entry in the datastore. To use go to
                     '/del/$key' where $key is the datastore key of the entry
                     you want to be deleted form the datastore.
                     (Authentication Required)
    TODO: Add more extensive logging"""

import cgi
import logging
import md5
import urllib

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

logging.getLogger().setLevel(logging.DEBUG)


class FileEntry(db.Model):
  profile_data = db.BlobProperty()  # The profile data
  date = db.DateTimeProperty(auto_now_add=True)  # Date it was uploaded
  data_md5 = db.ByteStringProperty()  # md5 of the profile data
  board = db.StringProperty()  # board arch
  chromeos_version = db.StringProperty()  # ChromeOS version


class MainPage(webapp.RequestHandler):
  """Main page only used as the form template, not actually displayed."""

  def get(self, response=''):  # pylint: disable-msg=C6409
    if response:
      self.response.out.write('<html><body>')
      self.response.out.write("""<br>
        <form action="/upload" enctype="multipart/form-data" method="post">
          <div><label>Profile Data:</label></div>
          <div><input type="file" name="profile_data"/></div>
          <div><label>Board</label></div>
          <div><input type="text" name="board"/></div>
          <div><label>ChromeOS Version</label></div>
          <div><input type="text" name="chromeos_version"></div>
          <div><input type="submit" value="send" name="submit"></div>
        </form>
      </body>
      </html>""")


class Upload(webapp.RequestHandler):
  """Handler for uploading data to the datastore, accessible by anyone."""

  def post(self):  # pylint: disable-msg=C6409
    """Takes input based on the main page's form."""
    getfile = FileEntry()
    f1 = self.request.get('profile_data')
    getfile.profile_data = db.Blob(f1)
    getfile.data_md5 = md5.new(f1).hexdigest()
    getfile.board = self.request.get('board')
    getfile.chromeos_version = self.request.get('chromeos_version')
    getfile.put()
    self.response.out.write(getfile.key())
    #self.redirect('/')


class ServeHandler(webapp.RequestHandler):
  """Given the entry's key in the database, output the profile data file. Only
      accessible from @google.com accounts."""

  def get(self, resource):  # pylint: disable-msg=C6409
    if Authenticate(self):
      file_key = str(urllib.unquote(resource))
      request = db.get(file_key)
      self.response.out.write(request.profile_data)


class ListAll(webapp.RequestHandler):
  """Displays all files uploaded. Only accessible by @google.com accounts."""

  def get(self):  # pylint: disable-msg=C6409
    """Displays all information in FileEntry, ~ delimited."""
    if Authenticate(self):
      query_str = 'SELECT * FROM FileEntry ORDER BY date ASC'
      query = db.GqlQuery(query_str)
      delimiter = '~'

      for item in query:
        display_list = [item.key(), item.date, item.data_md5, item.board,
                        item.chromeos_version]
        str_list = [cgi.escape(str(i)) for i in display_list]
        self.response.out.write(delimiter.join(str_list) + '</br>')


class DelEntries(webapp.RequestHandler):
  """Deletes entries. Only accessible from @google.com accounts."""

  def get(self, resource):  # pylint: disable-msg=C6409
    """A specific entry is deleted, when the key is given."""
    if Authenticate(self):
      fkey = str(urllib.unquote(resource))
      request = db.get(fkey)
      if request:
        db.delete(fkey)


def Authenticate(webpage):
  """Some urls are only accessible if logged in with a @google.com account."""
  user = users.get_current_user()
  if user is None:
    webpage.redirect(users.create_login_url(webpage.request.uri))
  elif user.email().endswith('@google.com'):
    return True
  else:
    webpage.response.out.write('Not Authenticated')
    return False


def main():
  application = webapp.WSGIApplication(
      [
          ('/', MainPage),
          ('/upload', Upload),
          ('/serve/([^/]+)?', ServeHandler),
          ('/serve', ListAll),
          ('/del/([^/]+)?', DelEntries),
      ],
      debug=False)
  run_wsgi_app(application)


if __name__ == '__main__':
  main()