aboutsummaryrefslogtreecommitdiff
path: root/cwp/bartlett/server.py
blob: f6b35361052b78ef5dd3d84ef3bd9adfcc4e4749 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/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()