mirror of
https://github.com/google/blockly.git
synced 2026-01-09 01:50:11 +01:00
New initial commit with .svn directories and their contents ignored.
This commit is contained in:
34
appengine/README.txt
Normal file
34
appengine/README.txt
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
Running an App Engine server
|
||||
|
||||
This directory contains the files needed to setup the optional Blockly server.
|
||||
Although Blockly itself is 100% client-side, the server enables cloud storage
|
||||
and sharing. Store your programs in Datastore and get a unique URL that allows
|
||||
you to load the program on any computer.
|
||||
|
||||
To run your own App Engine instance you'll need to create this directory
|
||||
structure:
|
||||
|
||||
blockly/
|
||||
|- app.yaml
|
||||
|- index.yaml
|
||||
|- index_redirect.py
|
||||
|- README.txt
|
||||
|- storage.js
|
||||
|- storage.py
|
||||
|- closure-library-read-only/
|
||||
`- static/
|
||||
|- apps/
|
||||
|- core/
|
||||
|- demos/
|
||||
|- generators/
|
||||
|- language/
|
||||
|- media/
|
||||
|- tests/
|
||||
`- blockly_compressed.js
|
||||
|
||||
Instructions for fetching Closure may be found here:
|
||||
http://code.google.com/p/blockly/wiki/Closure
|
||||
|
||||
Finally, upload this directory structure to your App Engine account,
|
||||
wait a minute, then go to http://YOURNAME.appspot.com/
|
||||
99
appengine/app.yaml
Normal file
99
appengine/app.yaml
Normal file
@@ -0,0 +1,99 @@
|
||||
application: blockly-demo
|
||||
version: 1
|
||||
runtime: python27
|
||||
api_version: 1
|
||||
threadsafe: no
|
||||
|
||||
handlers:
|
||||
# Redirect obsolete URLs.
|
||||
# Blockly files moved from /blockly to /static on 5 Dec 2012.
|
||||
- url: /blockly/.*
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Code, Maze and Turtle moved from demos to apps on 29 Dec 2012.
|
||||
- url: /static/demos/(code|maze|turtle)/.*
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Vietnamese apps moved from vn to vi on 9 Jun 2012.
|
||||
- url: /static/apps/.+/vn\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Code moved to index.html on 7 Aug 2013.
|
||||
- url: /static/apps/code/code\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Code became language-agnostic on 20 Jul 2013.
|
||||
- url: /static/apps/code/(de|en|hu|vi|zh_tw)\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Graph moved to index.html on 7 Aug 2013.
|
||||
- url: /static/apps/graph/graph\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Graph became language-agnostic on 20 Jul 2013.
|
||||
- url: /static/apps/graph/(de|en|hu|vi)\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Maze moved to index.html on 7 Aug 2013.
|
||||
- url: /static/apps/maze/maze\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Maze became language-agnostic on 20 Jul 2013.
|
||||
- url: /static/apps/maze/(ca|cs|da|el|en|es|eu|fr|hu|it|lv|nl|pl|pt|ru|sr|sw|th|tr|vi)\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Plane moved to index.html on 7 Aug 2013.
|
||||
- url: /static/apps/plane/plane\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Plane became language-agnostic on 20 Jul 2013.
|
||||
- url: /static/apps/plane/(1_|2_)?(en|hu|vi|vn)\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Puzzle moved to index.html on 30 Jul 2013.
|
||||
- url: /static/apps/puzzle/puzzle\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Puzzle became language-agnostic on 20 Jul 2013.
|
||||
- url: /static/apps/puzzle/(af|cs|de|el|en|gl|hak|he|hu|ia|it|ja|ko|ksh|la|lb|lv|mk|ms|nl|pl|pt-br|ru|sv|sw|tzm|vi|zh-hans)\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Turtle moved to index.html on 7 Aug 2013.
|
||||
- url: /static/apps/turtle/turtle\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
# Turtle became language-agnostic on 20 Jul 2013.
|
||||
- url: /static/apps/turtle/(de|en|hu|vi)\.html
|
||||
static_files: redirect.html
|
||||
upload: redirect.html
|
||||
|
||||
|
||||
# Storage API.
|
||||
- url: /storage
|
||||
script: storage.py
|
||||
- url: /storage\.js
|
||||
static_files: storage.js
|
||||
upload: storage\.js
|
||||
|
||||
# Blockly files.
|
||||
- url: /static
|
||||
static_dir: static
|
||||
|
||||
# Closure library for uncompiled Blockly.
|
||||
- url: /closure-library-read-only
|
||||
static_dir: closure-library-read-only
|
||||
|
||||
# Redirect for root directory.
|
||||
- url: /
|
||||
script: index_redirect.py
|
||||
|
||||
# Favicon.
|
||||
- url: /favicon\.ico
|
||||
static_files: favicon.ico
|
||||
upload: favicon\.ico
|
||||
|
||||
# robot.txt
|
||||
- url: /robots\.txt
|
||||
static_files: robots.txt
|
||||
upload: robots\.txt
|
||||
|
||||
BIN
appengine/favicon.ico
Normal file
BIN
appengine/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
11
appengine/index.yaml
Normal file
11
appengine/index.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
indexes:
|
||||
|
||||
# AUTOGENERATED
|
||||
|
||||
# This index.yaml is automatically updated whenever the dev_appserver
|
||||
# detects that a new type of query is run. If you want to manage the
|
||||
# index.yaml file manually, remove the above marker line (the line
|
||||
# saying "# AUTOGENERATED"). If you want to manage some indexes
|
||||
# manually, move them above the marker line. The index.yaml file is
|
||||
# automatically uploaded to the admin console when you next deploy
|
||||
# your application using appcfg.py.
|
||||
2
appengine/index_redirect.py
Normal file
2
appengine/index_redirect.py
Normal file
@@ -0,0 +1,2 @@
|
||||
print("Status: 302")
|
||||
print("Location: /static/apps/index.html")
|
||||
98
appengine/redirect.html
Normal file
98
appengine/redirect.html
Normal file
@@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
var loc = location.href;
|
||||
|
||||
// Blockly files moved from /blockly to /static on 5 Dec 2012.
|
||||
if (loc.match('/blockly/')) {
|
||||
loc = loc.replace('/blockly/', '/static/');
|
||||
}
|
||||
|
||||
// Code, Maze and Turtle moved from demos to apps on 29 Dec 2012.
|
||||
if (loc.match(/\/demos\/(code|maze|turtle)\//)) {
|
||||
loc = loc.replace('/demos/', '/apps/');
|
||||
}
|
||||
|
||||
// Vietnamese apps moved from vn to vi on 9 Jun 2012.
|
||||
if (loc.match('/vn.html')) {
|
||||
loc = loc.replace('/vn.html', '/vi.html');
|
||||
}
|
||||
|
||||
if (loc.match('/apps/code/code.html')) {
|
||||
// Code moved to index.html on 7 Aug 2013.
|
||||
loc = loc.replace('/code.html', '/index.html');
|
||||
} else if (loc.match('/apps/code/zh_tw.html')) {
|
||||
// Code became language-agnostic on 20 Jul 2013.
|
||||
loc = loc.replace('/zh_tw.html', '/index.html?lang=zh-tw');
|
||||
} else if (loc.match('/apps/code/index.html')) {
|
||||
// NOP.
|
||||
} else if (loc.match(/\/apps\/code\/[-a-z]+\.html/)) {
|
||||
// Code became language-agnostic on 20 Jul 2013.
|
||||
loc = loc.replace(/\/([-a-z]+)\.html/, '/index.html?lang=$1');
|
||||
}
|
||||
|
||||
if (loc.match('/apps/graph/graph.html')) {
|
||||
// Graph moved to index.html on 7 Aug 2013.
|
||||
loc = loc.replace('/graph.html', '/index.html');
|
||||
} else if (loc.match('/apps/graph/index.html')) {
|
||||
// NOP.
|
||||
} else if (loc.match(/\/apps\/graph\/[-a-z]+\.html/)) {
|
||||
// Graph became language-agnostic on 20 Jul 2013.
|
||||
loc = loc.replace(/\/([-a-z]+)\.html/, '/index.html?lang=$1');
|
||||
}
|
||||
|
||||
if (loc.match('/apps/maze/maze.html')) {
|
||||
// Maze moved to index.html on 7 Aug 2013.
|
||||
loc = loc.replace('/maze.html', '/index.html');
|
||||
} else if (loc.match('/apps/maze/index.html')) {
|
||||
// NOP.
|
||||
} else if (loc.match(/\/apps\/maze\/[-a-z]+\.html/)) {
|
||||
// Maze became language-agnostic on 20 Jul 2013.
|
||||
if (location.search) {
|
||||
loc = loc.replace(/\/([-a-z]+)\.html\?/, '/index.html?lang=$1&');
|
||||
} else {
|
||||
loc = loc.replace(/\/([-a-z]+)\.html/, '/index.html?lang=$1');
|
||||
}
|
||||
}
|
||||
|
||||
if (loc.match('/apps/plane/plane.html')) {
|
||||
// Plane moved to index.html on 7 Aug 2013.
|
||||
loc = loc.replace('/plane.html', '/index.html');
|
||||
} else if (loc.match('/apps/code/plane.html')) {
|
||||
// NOP.
|
||||
} else if (loc.match(/\/apps\/plane\/[\d_]*[-a-z]+\.html/)) {
|
||||
// Plane became language-agnostic on 20 Jul 2013.
|
||||
loc = loc.replace('vn.html', 'vi.html');
|
||||
if (location.search) {
|
||||
loc = loc.replace(/\/[\d_]*([-a-z]+)\.html\?/, '/index.html?lang=$1&');
|
||||
} else {
|
||||
loc = loc.replace(/\/[\d_]*([-a-z]+)\.html/, '/index.html?lang=$1');
|
||||
}
|
||||
}
|
||||
|
||||
if (loc.match('/apps/puzzle/puzzle.html')) {
|
||||
// Puzzle moved to index.html on 30 Jul 2013.
|
||||
loc = loc.replace('/puzzle.html', '/index.html');
|
||||
} else if (loc.match('/apps/puzzle/index.html')) {
|
||||
// NOP.
|
||||
} else if (loc.match(/\/apps\/puzzle\/[-a-z]+\.html/)) {
|
||||
// Puzzle became language-agnostic on 20 Jul 2013.
|
||||
loc = loc.replace(/\/([-a-z]+)\.html/, '/index.html?lang=$1');
|
||||
}
|
||||
|
||||
if (loc.match('/apps/turtle/turtle.html')) {
|
||||
// Turtle moved to index.html on 7 Aug 2013.
|
||||
loc = loc.replace('/turtle.html', '/index.html');
|
||||
} else if (loc.match('/apps/turtle/index.html')) {
|
||||
// NOP.
|
||||
} else if (loc.match(/\/apps\/turtle\/[-a-z]+\.html/)) {
|
||||
// Turtle became language-agnostic on 20 Jul 2013.
|
||||
loc = loc.replace(/\/([-a-z]+)\.html/, '/index.html?lang=$1');
|
||||
}
|
||||
|
||||
location = loc;
|
||||
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
53
appengine/report.py
Normal file
53
appengine/report.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Blockly Demo: Report
|
||||
|
||||
Copyright 2012 Google Inc.
|
||||
http://blockly.googlecode.com/
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
"""Store reports about code written by users.
|
||||
"""
|
||||
|
||||
__author__ = "ellen.spertus@gmail.com (Ellen Spertus)"
|
||||
|
||||
import cgi
|
||||
import logging
|
||||
|
||||
from google.appengine.ext import db
|
||||
|
||||
print "Content-type: text/plain\n"
|
||||
|
||||
class Report(db.Model):
|
||||
identifier = db.FloatProperty()
|
||||
application = db.StringProperty()
|
||||
date = db.DateTimeProperty(auto_now_add=True)
|
||||
level = db.IntegerProperty()
|
||||
result = db.IntegerProperty()
|
||||
# StringProperty is limited to 500 characters, so use TextProperty.
|
||||
program = db.TextProperty()
|
||||
|
||||
# Catch errors extracting form fields or converting to numeric types.
|
||||
# Let any other errors propagate up.
|
||||
try:
|
||||
forms = cgi.FieldStorage()
|
||||
identifier = float(forms["id"].value)
|
||||
application = forms["app"].value
|
||||
level = int(forms["level"].value)
|
||||
result = int(forms["result"].value)
|
||||
program = forms["program"].value
|
||||
row = Report(identifier = identifier, application = application,
|
||||
level = level, result = result, program = program)
|
||||
row.put()
|
||||
except ValueError, KeyError:
|
||||
logging.error("Unable to extract all form fields.")
|
||||
2
appengine/robots.txt
Normal file
2
appengine/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /storage
|
||||
180
appengine/storage.js
Normal file
180
appengine/storage.js
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Blockly Demo: Storage
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* http://blockly.googlecode.com/
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Loading and saving blocks with localStorage and cloud storage.
|
||||
* @author q.neutron@gmail.com (Quynh Neutron)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// Create a namespace.
|
||||
var BlocklyStorage = {};
|
||||
|
||||
/**
|
||||
* Backup code blocks to localStorage.
|
||||
* @private
|
||||
*/
|
||||
BlocklyStorage.backupBlocks_ = function() {
|
||||
if ('localStorage' in window) {
|
||||
var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace());
|
||||
// Gets the current URL, not including the hash.
|
||||
var url = window.location.href.split('#')[0];
|
||||
window.localStorage.setItem(url, Blockly.Xml.domToText(xml));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind the localStorage backup function to the unload event.
|
||||
*/
|
||||
BlocklyStorage.backupOnUnload = function() {
|
||||
window.addEventListener('unload', BlocklyStorage.backupBlocks_, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Restore code blocks from localStorage.
|
||||
*/
|
||||
BlocklyStorage.restoreBlocks = function() {
|
||||
var url = window.location.href.split('#')[0];
|
||||
if ('localStorage' in window && window.localStorage[url]) {
|
||||
var xml = Blockly.Xml.textToDom(window.localStorage[url]);
|
||||
Blockly.Xml.domToWorkspace(Blockly.getMainWorkspace(), xml);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Save blocks to database and return a link containing key to XML.
|
||||
*/
|
||||
BlocklyStorage.link = function() {
|
||||
var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace());
|
||||
var data = Blockly.Xml.domToText(xml);
|
||||
BlocklyStorage.makeRequest_('/storage', 'xml', data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve XML text from database using given key.
|
||||
* @param {string} key Key to XML, obtained from href.
|
||||
*/
|
||||
BlocklyStorage.retrieveXml = function(key) {
|
||||
var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace());
|
||||
BlocklyStorage.makeRequest_('/storage', 'key', key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Global reference to current AJAX request.
|
||||
* @type XMLHttpRequest
|
||||
* @private
|
||||
*/
|
||||
BlocklyStorage.httpRequest_ = null;
|
||||
|
||||
/**
|
||||
* Fire a new AJAX request.
|
||||
* @param {string} url URL to fetch.
|
||||
* @param {string} name Name of parameter.
|
||||
* @param {string} content Content of parameter.
|
||||
* @private
|
||||
*/
|
||||
BlocklyStorage.makeRequest_ = function(url, name, content) {
|
||||
if (BlocklyStorage.httpRequest_) {
|
||||
// AJAX call is in-flight.
|
||||
BlocklyStorage.httpRequest_.abort();
|
||||
}
|
||||
BlocklyStorage.httpRequest_ = new XMLHttpRequest();
|
||||
BlocklyStorage.httpRequest_.name = name;
|
||||
BlocklyStorage.httpRequest_.onreadystatechange =
|
||||
BlocklyStorage.handleRequest_;
|
||||
BlocklyStorage.httpRequest_.open('POST', url);
|
||||
BlocklyStorage.httpRequest_.setRequestHeader('Content-Type',
|
||||
'application/x-www-form-urlencoded');
|
||||
BlocklyStorage.httpRequest_.send(name + '=' + encodeURIComponent(content));
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for AJAX call.
|
||||
* @private
|
||||
*/
|
||||
BlocklyStorage.handleRequest_ = function() {
|
||||
if (BlocklyStorage.httpRequest_.readyState == 4) {
|
||||
if (BlocklyStorage.httpRequest_.status != 200) {
|
||||
BlocklyStorage.alert(BlocklyStorage.HTTPREQUEST_ERROR + '\n' +
|
||||
'httpRequest_.status: ' + BlocklyStorage.httpRequest_.status);
|
||||
} else {
|
||||
var data = BlocklyStorage.httpRequest_.responseText.trim();
|
||||
if (BlocklyStorage.httpRequest_.name == 'xml') {
|
||||
window.location.hash = data;
|
||||
BlocklyStorage.alert(BlocklyStorage.LINK_ALERT.replace('%1',
|
||||
window.location.href));
|
||||
} else if (BlocklyStorage.httpRequest_.name == 'key') {
|
||||
if (!data.length) {
|
||||
BlocklyStorage.alert(BlocklyStorage.HASH_ERROR.replace('%1',
|
||||
window.location.hash));
|
||||
} else {
|
||||
BlocklyStorage.loadXml_(data);
|
||||
}
|
||||
}
|
||||
BlocklyStorage.monitorChanges_();
|
||||
}
|
||||
BlocklyStorage.httpRequest_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start monitoring the workspace. If a change is made that changes the XML,
|
||||
* clear the key from the URL. Stop monitoring the workspace once such a
|
||||
* change is detected.
|
||||
* @private
|
||||
*/
|
||||
BlocklyStorage.monitorChanges_ = function() {
|
||||
var startXmlDom = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace());
|
||||
var startXmlText = Blockly.Xml.domToText(startXmlDom);
|
||||
function change() {
|
||||
var xmlDom = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace());
|
||||
var xmlText = Blockly.Xml.domToText(xmlDom);
|
||||
if (startXmlText != xmlText) {
|
||||
window.location.hash = '';
|
||||
Blockly.removeChangeListener(bindData);
|
||||
}
|
||||
}
|
||||
var bindData = Blockly.addChangeListener(change);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load blocks from XML.
|
||||
* @param {string} xml Text representation of XML.
|
||||
* @private
|
||||
*/
|
||||
BlocklyStorage.loadXml_ = function(xml) {
|
||||
try {
|
||||
xml = Blockly.Xml.textToDom(xml);
|
||||
} catch (e) {
|
||||
BlocklyStorage.alert(BlocklyStorage.XML_ERROR + '\nXML: ' + xml);
|
||||
return;
|
||||
}
|
||||
// Clear the workspace to avoid merge.
|
||||
Blockly.getMainWorkspace().clear();
|
||||
Blockly.Xml.domToWorkspace(Blockly.getMainWorkspace(), xml);
|
||||
};
|
||||
|
||||
/**
|
||||
* Present a text message to the user.
|
||||
* Designed to be overridden if an app has custom dialogs, or a butter bar.
|
||||
* @param {string} message Text to alert.
|
||||
*/
|
||||
BlocklyStorage.alert = function(message) {
|
||||
window.alert(message);
|
||||
};
|
||||
85
appengine/storage.py
Normal file
85
appengine/storage.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""Blockly Demo: Storage
|
||||
|
||||
Copyright 2012 Google Inc.
|
||||
http://blockly.googlecode.com/
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
"""Store and retrieve XML with App Engine.
|
||||
"""
|
||||
|
||||
__author__ = "q.neutron@gmail.com (Quynh Neutron)"
|
||||
|
||||
import cgi
|
||||
from random import randint
|
||||
from google.appengine.ext import db
|
||||
from google.appengine.api import memcache
|
||||
import logging
|
||||
|
||||
print "Content-Type: text/plain\n"
|
||||
|
||||
def keyGen():
|
||||
# Generate a random string of length KEY_LEN.
|
||||
KEY_LEN = 6
|
||||
CHARS = "abcdefghijkmnopqrstuvwxyz23456789" # Exclude l, 0, 1.
|
||||
max_index = len(CHARS) - 1
|
||||
return "".join([CHARS[randint(0, max_index)] for x in range(KEY_LEN)])
|
||||
|
||||
class Xml(db.Model):
|
||||
# A row in the database.
|
||||
xml_hash = db.IntegerProperty()
|
||||
xml_content = db.TextProperty()
|
||||
|
||||
forms = cgi.FieldStorage()
|
||||
if "xml" in forms:
|
||||
# Store XML and return a generated key.
|
||||
xml_content = forms["xml"].value
|
||||
xml_hash = hash(xml_content)
|
||||
lookup_query = db.Query(Xml)
|
||||
lookup_query.filter("xml_hash =", xml_hash)
|
||||
lookup_result = lookup_query.get()
|
||||
if lookup_result:
|
||||
xml_key = lookup_result.key().name()
|
||||
else:
|
||||
trials = 0
|
||||
result = True
|
||||
while result:
|
||||
trials += 1
|
||||
if trials == 100:
|
||||
raise Exception("Sorry, the generator failed to get a key for you.")
|
||||
xml_key = keyGen()
|
||||
result = db.get(db.Key.from_path("Xml", xml_key))
|
||||
xml = db.Text(xml_content, encoding="utf_8")
|
||||
row = Xml(key_name = xml_key, xml_hash = xml_hash, xml_content = xml)
|
||||
row.put()
|
||||
print xml_key
|
||||
|
||||
if "key" in forms:
|
||||
# Retrieve stored XML based on the provided key.
|
||||
key_provided = forms["key"].value
|
||||
# Normalize the string.
|
||||
key_provided = key_provided.lower().strip()
|
||||
# Check memcache for a quick match.
|
||||
xml = memcache.get("XML_" + key_provided)
|
||||
if xml is None:
|
||||
# Check datastore for a definitive match.
|
||||
result = db.get(db.Key.from_path("Xml", key_provided))
|
||||
if not result:
|
||||
xml = ""
|
||||
else:
|
||||
xml = result.xml_content
|
||||
# Save to memcache for next hit.
|
||||
if not memcache.add("XML_" + key_provided, xml, 3600):
|
||||
logging.error("Memcache set failed.")
|
||||
print xml.encode("utf-8")
|
||||
Reference in New Issue
Block a user