-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
219 lines (165 loc) · 6.44 KB
/
main.py
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/usr/bin/env python
###
### This web service is used in conjunction with App
### Inventor for Android. It stores and retrieves data as instructed by an App Inventor app and its TinyWebDB component.
### It also provides a web interface to the database for administration
### Author: Dave Wolber via template of Hal Abelson and incorporating changes of Dean Sanvitale
### Note-- updated for use with Python2.7 in App Engine, June 2013
import webapp2
import logging
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.ext.db import Key
from django.utils import simplejson as json
# DWW
import os
from google.appengine.ext.webapp import template
import urllib
# DEAN
import logging
import re
max_entries = 1000
class StoredData(db.Model):
tag = db.StringProperty()
value = db.TextProperty()
date = db.DateTimeProperty(required=True, auto_now=True)
class StoreAValue(webapp2.RequestHandler):
def store_a_value(self, tag, value):
store(tag, value)
# call trimdb if you want to limit the size of db
# trimdb()
## Send back a confirmation message. The TinyWebDB component ignores
## the message (other than to note that it was received), but other
## components might use this.
result = ["STORED", tag, value]
## When I first implemented this, I used json.JSONEncoder().encode(value)
## rather than json.dump. That didn't work: the component ended up
## seeing extra quotation marks. Maybe someone can explain this to me.
if self.request.get('fmt') == "html":
WriteToWeb(self,tag,value)
else:
WriteToPhoneAfterStore(self,tag,value)
def post(self):
tag = self.request.get('tag')
value = self.request.get('value')
self.store_a_value(tag, value)
class DeleteEntry(webapp2.RequestHandler):
def post(self):
logging.debug('/deleteentry?%s\n|%s|' %
(self.request.query_string, self.request.body))
entry_key_string = self.request.get('entry_key_string')
key = db.Key(entry_key_string)
tag = self.request.get('tag')
if tag.startswith("http"):
DeleteUrl(tag)
db.run_in_transaction(dbSafeDelete,key)
self.redirect('/')
class GetValueHandler(webapp2.RequestHandler):
def get_value(self, tag):
entry = db.GqlQuery("SELECT * FROM StoredData where tag = :1", tag).get()
if entry:
value = entry.value
else: value = ""
if self.request.get('fmt') == "html":
WriteToWeb(self,tag,value )
else:
WriteToPhone(self,tag,value)
def post(self):
tag = self.request.get('tag')
self.get_value(tag)
# there is a web ui for this as well, here is the get
def get(self):
# this did pump out the form
template_values={}
path = os.path.join(os.path.dirname(__file__),'index.html')
self.response.out.write(template.render(path,template_values))
class MainPage(webapp2.RequestHandler):
def get(self):
entries = db.GqlQuery("SELECT * FROM StoredData ORDER BY date desc")
template_values = {"entryList":entries}
# render the page using the template engine
path = os.path.join(os.path.dirname(__file__),'index.html')
self.response.out.write(template.render(path,template_values))
#### Utilty procedures for generating the output
def WriteToPhone(handler,tag,value):
handler.response.headers['Content-Type'] = 'application/jsonrequest'
json.dump(["VALUE", tag, value], handler.response.out)
def WriteToWeb(handler, tag,value):
entries = db.GqlQuery("SELECT * FROM StoredData ORDER BY date desc")
template_values={"result": value,"entryList":entries}
path = os.path.join(os.path.dirname(__file__),'index.html')
handler.response.out.write(template.render(path,template_values))
def WriteToPhoneAfterStore(handler,tag, value):
handler.response.headers['Content-Type'] = 'application/jsonrequest'
json.dump(["STORED", tag, value], handler.response.out)
# db utilities from Dean
### A utility that guards against attempts to delete a non-existent object
def dbSafeDelete(key):
if db.get(key) : db.delete(key)
def store(tag, value, bCheckIfTagExists=True):
if bCheckIfTagExists:
# There's a potential readers/writers error here :(
entry = db.GqlQuery("SELECT * FROM StoredData where tag = :1", tag).get()
if entry:
entry.value = value
else: entry = StoredData(tag = tag, value = value)
else:
entry = StoredData(tag = tag, value = value)
entry.put()
def trimdb():
## If there are more than the max number of entries, flush the
## earliest entries.
entries = db.GqlQuery("SELECT * FROM StoredData ORDER BY date")
if (entries.count() > max_entries):
for i in range(entries.count() - max_entries):
db.delete(entries.get())
from htmlentitydefs import name2codepoint
def replace_entities(match):
try:
ent = match.group(1)
if ent[0] == "#":
if ent[1] == 'x' or ent[1] == 'X':
return unichr(int(ent[2:], 16))
else:
return unichr(int(ent[1:], 10))
return unichr(name2codepoint[ent])
except:
return match.group()
entity_re = re.compile(r'&(#?[A-Za-z0-9]+?);')
def html_unescape(data):
return entity_re.sub(replace_entities, data)
def ProcessNode(node, sPath):
entries = []
if node.nodeType == minidom.Node.ELEMENT_NODE:
value = ""
for childNode in node.childNodes:
if (childNode.nodeType == minidom.Node.TEXT_NODE) or (childNode.nodeType == minidom.Node.CDATA_SECTION_NODE):
value += childNode.nodeValue
value = value.strip()
value = html_unescape(value)
if len(value) > 0:
entries.append(StoredData(tag = sPath, value = value))
for attr in node.attributes.values():
if len(attr.value.strip()) > 0:
entries.append(StoredData(tag = sPath + ">" + attr.name, value = attr.value))
childCounts = {}
for childNode in node.childNodes:
if childNode.nodeType == minidom.Node.ELEMENT_NODE:
sTag = childNode.tagName
try:
childCounts[sTag] = childCounts[sTag] + 1
except:
childCounts[sTag] = 1
if (childCounts[sTag] <= 5):
entries.extend(ProcessNode(childNode, sPath + ">" + sTag + str(childCounts[sTag])))
return entries
def DeleteUrl(sUrl):
entries = StoredData.all().filter('tag >=', sUrl).filter('tag <', sUrl + u'\ufffd')
db.delete(entries[:500])
### Assign the classes to the URL's
app = webapp2.WSGIApplication ([('/', MainPage),
('/getvalue', GetValueHandler),
('/storeavalue', StoreAValue),
('/deleteentry', DeleteEntry)
])