ct 0.10.8.114__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cantools/__init__.py +24 -0
- cantools/_db.py +142 -0
- cantools/_memcache.py +76 -0
- cantools/_pay.py +46 -0
- cantools/admin.py +31 -0
- cantools/cfg.py +347 -0
- cantools/config.py +131 -0
- cantools/db/__init__.py +18 -0
- cantools/db/admin.py +27 -0
- cantools/db/gae/__init__.py +0 -0
- cantools/db/gae/model.py +127 -0
- cantools/db/gae/properties.py +35 -0
- cantools/db/wp.py +99 -0
- cantools/geo.py +188 -0
- cantools/hooks.py +13 -0
- cantools/scripts/__init__.py +0 -0
- cantools/scripts/bench.py +167 -0
- cantools/scripts/builder.py +272 -0
- cantools/scripts/deploy.py +154 -0
- cantools/scripts/doc.py +239 -0
- cantools/scripts/index.py +226 -0
- cantools/scripts/init.py +345 -0
- cantools/scripts/migrate.py +593 -0
- cantools/scripts/pubsub/__init__.py +28 -0
- cantools/scripts/pubsub/actor.py +13 -0
- cantools/scripts/pubsub/bots.py +143 -0
- cantools/scripts/pubsub/channel.py +85 -0
- cantools/scripts/pubsub/ps.py +145 -0
- cantools/scripts/pubsub/user.py +51 -0
- cantools/scripts/start.py +53 -0
- cantools/scripts/util.py +24 -0
- cantools/util/__init__.py +78 -0
- cantools/util/admin.py +620 -0
- cantools/util/data.py +109 -0
- cantools/util/media.py +303 -0
- cantools/util/package.py +125 -0
- cantools/util/system.py +73 -0
- cantools/web/__init__.py +9 -0
- cantools/web/dez_server/__init__.py +1 -0
- cantools/web/dez_server/controller.py +129 -0
- cantools/web/dez_server/cron.py +115 -0
- cantools/web/dez_server/daemons.py +64 -0
- cantools/web/dez_server/mail.py +24 -0
- cantools/web/dez_server/response.py +63 -0
- cantools/web/dez_server/routes.py +21 -0
- cantools/web/dez_server/server.py +229 -0
- cantools/web/dez_server/sms.py +12 -0
- cantools/web/gae_server.py +68 -0
- cantools/web/util.py +552 -0
- ct-0.10.8.114.dist-info/LICENSE +9 -0
- ct-0.10.8.114.dist-info/METADATA +25 -0
- ct-0.10.8.114.dist-info/RECORD +55 -0
- ct-0.10.8.114.dist-info/WHEEL +5 -0
- ct-0.10.8.114.dist-info/entry_points.txt +10 -0
- ct-0.10.8.114.dist-info/top_level.txt +1 -0
cantools/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
__version__ = "0.10.8.114"
|
|
2
|
+
|
|
3
|
+
from . import util, hooks
|
|
4
|
+
from . import config as cfgmod
|
|
5
|
+
config = cfgmod.config
|
|
6
|
+
include_plugin = cfgmod.include_plugin
|
|
7
|
+
mods_and_repos = cfgmod.mods_and_repos
|
|
8
|
+
|
|
9
|
+
if config.web.server == "gae":
|
|
10
|
+
util.init_gae()
|
|
11
|
+
else:
|
|
12
|
+
util.init_basic()
|
|
13
|
+
from . import geo
|
|
14
|
+
from .scripts import builder, deploy, init, pubsub, start, index, migrate, doc, bench, util
|
|
15
|
+
|
|
16
|
+
ctstart = start.go
|
|
17
|
+
ctdeploy = deploy.run
|
|
18
|
+
ctpubsub = pubsub.get_addr_and_start
|
|
19
|
+
ctinit = init.parse_and_make
|
|
20
|
+
ctindex = index.go
|
|
21
|
+
ctmigrate = migrate.go
|
|
22
|
+
ctdoc = doc.build
|
|
23
|
+
ctbench = bench.run
|
|
24
|
+
ctutil = util.run
|
cantools/_db.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from cantools.web import respond, succeed, fail, send_file, send_text, cgi_get, cgi_dump, read_file, getmem, setmem, clearmem
|
|
3
|
+
from cantools.db import get, get_model, get_schema, get_blobs, get_page, get_bulker, get_multi, put_multi, edit, dprep, admin, BlobWrapper
|
|
4
|
+
from cantools.util.data import props, spreadsheet
|
|
5
|
+
from cantools.util import getxls
|
|
6
|
+
from cantools import config
|
|
7
|
+
import model # load up all models (for schema)
|
|
8
|
+
|
|
9
|
+
def response():
|
|
10
|
+
action = cgi_get("action", choices=["schema", "blobs", "get", "blob", "edit", "edits", "delete", "put", "index", "bulk", "spreadsheet", "credcheck"])
|
|
11
|
+
|
|
12
|
+
# edit/delete/put/index/bulk always require credentials; getters do configurably
|
|
13
|
+
if not config.db.public or action in ["blobs", "edit", "edits", "delete", "put", "index", "bulk", "spreadsheet", "credcheck"]:
|
|
14
|
+
pw = cgi_get("pw")
|
|
15
|
+
if pw != config.admin.pw:
|
|
16
|
+
if not pw or pw != config.apikey:
|
|
17
|
+
fail("wrong")
|
|
18
|
+
|
|
19
|
+
# clear cache!
|
|
20
|
+
if (config.memcache.db or config.memcache.dbclear) and action in ["edit", "delete", "put", "bulk"]:
|
|
21
|
+
clearmem()
|
|
22
|
+
|
|
23
|
+
if action == "schema":
|
|
24
|
+
succeed(get_schema())
|
|
25
|
+
elif action == "blobs":
|
|
26
|
+
succeed(get_blobs(cgi_get("variety")))
|
|
27
|
+
elif action == "bulk":
|
|
28
|
+
rawd = read_file(cgi_get("data"))
|
|
29
|
+
mname = cgi_get("modelName")
|
|
30
|
+
fixed = json.loads(cgi_get("fixed", default="{}"))
|
|
31
|
+
mod = get_model(mname)
|
|
32
|
+
bulker = get_bulker(mname)
|
|
33
|
+
if bulker:
|
|
34
|
+
bulker(rawd, fixed)
|
|
35
|
+
else:
|
|
36
|
+
data = getxls(rawd) # add: csv, etc
|
|
37
|
+
schema = get_schema(mname)
|
|
38
|
+
smap = {}
|
|
39
|
+
headers = data.pop(0)
|
|
40
|
+
puts = []
|
|
41
|
+
for index in range(len(headers)):
|
|
42
|
+
header = headers[index]
|
|
43
|
+
if header in schema:
|
|
44
|
+
smap[header] = index
|
|
45
|
+
for properties in data:
|
|
46
|
+
kwargs = {}
|
|
47
|
+
for p in smap:
|
|
48
|
+
kwargs[p] = properties[smap[p]]
|
|
49
|
+
for p in fixed:
|
|
50
|
+
kwargs[p] = fixed[p]
|
|
51
|
+
puts.append(mod(**kwargs))
|
|
52
|
+
put_multi(puts)
|
|
53
|
+
elif action == "spreadsheet":
|
|
54
|
+
ssform = cgi_get("format", default="csv")
|
|
55
|
+
mname = cgi_get("modelName")
|
|
56
|
+
mod = get_model(mname)
|
|
57
|
+
fkey = cgi_get("fixed_key", required=False)
|
|
58
|
+
fval = cgi_get("fixed_value", required=False)
|
|
59
|
+
q = mod.query()
|
|
60
|
+
if fkey:
|
|
61
|
+
q.filter(getattr(mod, fkey) == fval)
|
|
62
|
+
mname = "%s_%s"%(mname, fval)
|
|
63
|
+
send_text(spreadsheet(ssform, q.all(), props(mod)), ssform, mname)
|
|
64
|
+
elif action == "get":
|
|
65
|
+
sig = cgi_dump()
|
|
66
|
+
res = config.memcache.db and getmem(sig, False) or None
|
|
67
|
+
if not res:
|
|
68
|
+
mname = cgi_get("modelName", required=False)
|
|
69
|
+
keys = cgi_get("keys", required=False)
|
|
70
|
+
exporter = cgi_get("exporter", default="export")
|
|
71
|
+
if mname:
|
|
72
|
+
order = cgi_get("order", default="index")
|
|
73
|
+
if config.web.server == "gae":
|
|
74
|
+
order = getattr(get_model(mname), order)
|
|
75
|
+
res = get_page(mname, int(cgi_get("limit")), int(cgi_get("offset")), order,
|
|
76
|
+
cgi_get("filters", default={}), count=cgi_get("count", required=False), exporter=exporter)
|
|
77
|
+
elif keys:
|
|
78
|
+
res = [getattr(d, exporter)() for d in get_multi(keys)]
|
|
79
|
+
else:
|
|
80
|
+
res = getattr(get(cgi_get("key")), exporter)()
|
|
81
|
+
if config.memcache.db and config.web.server == "dez":
|
|
82
|
+
setmem(sig, res, False)
|
|
83
|
+
succeed(res)
|
|
84
|
+
elif action == "blob":
|
|
85
|
+
value = cgi_get("value", required=False) # fastest way
|
|
86
|
+
data = cgi_get("data", required=False)
|
|
87
|
+
prop = cgi_get("property", required=False)
|
|
88
|
+
entkey = cgi_get("key", required=False)
|
|
89
|
+
setter = cgi_get("setter", required=False)
|
|
90
|
+
ent = entkey and get(entkey)
|
|
91
|
+
blob = value and BlobWrapper(value=value) or (ent and prop and getattr(ent, prop))
|
|
92
|
+
if cgi_get("delBlob", default=False):
|
|
93
|
+
blob.delete()
|
|
94
|
+
setattr(ent, prop, None)
|
|
95
|
+
ent.put()
|
|
96
|
+
elif data:
|
|
97
|
+
if config.memcache.db:
|
|
98
|
+
clearmem()
|
|
99
|
+
# if False:#value: # screw this -- doesn't update entity
|
|
100
|
+
# blob.set(read_file(data))
|
|
101
|
+
# else: # going by key, property -- must update index
|
|
102
|
+
if ent:
|
|
103
|
+
if prop:
|
|
104
|
+
setattr(ent, prop, read_file(data))
|
|
105
|
+
ent.put()
|
|
106
|
+
blob = getattr(ent, prop)
|
|
107
|
+
elif setter:
|
|
108
|
+
getattr(ent, setter)(read_file(data))
|
|
109
|
+
succeed(ent.data())
|
|
110
|
+
else:
|
|
111
|
+
blob = BlobWrapper(data=read_file(data))
|
|
112
|
+
succeed(blob.urlsafe())
|
|
113
|
+
else:
|
|
114
|
+
if not value and hasattr(ent, "getBlob"): # for custom blob construction (such as split up gae blobs)
|
|
115
|
+
blob = ent.getBlob()
|
|
116
|
+
if config.web.server == "gae":
|
|
117
|
+
send_file(blob) # no magic :'(
|
|
118
|
+
else:
|
|
119
|
+
if hasattr(blob, "get"): # if not getBlob(), essentially
|
|
120
|
+
blob = blob.get()
|
|
121
|
+
send_file(blob, detect=True)
|
|
122
|
+
elif action == "edit":
|
|
123
|
+
eres = edit(cgi_get("data"), blobifier=cgi_get("blobifier", required=False))
|
|
124
|
+
if type(eres) == str:
|
|
125
|
+
fail(eres)
|
|
126
|
+
else:
|
|
127
|
+
succeed(getattr(eres, cgi_get("exporter", default="data"))())
|
|
128
|
+
elif action == "edits":
|
|
129
|
+
items = cgi_get("data")
|
|
130
|
+
blobifier = cgi_get("blobifier", required=False)
|
|
131
|
+
exporter = cgi_get("exporter", default="data")
|
|
132
|
+
for item in items:
|
|
133
|
+
edit(item, blobifier=blobifier)
|
|
134
|
+
elif action == "put":
|
|
135
|
+
put_multi([get_model(d["modelName"])(**dprep(d)) for d in cgi_get("data")])
|
|
136
|
+
elif action == "delete":
|
|
137
|
+
get(cgi_get("key")).rm()
|
|
138
|
+
elif action == "index":
|
|
139
|
+
setmem("last_index", admin.index(cgi_get("kind", default="*"),
|
|
140
|
+
getmem("last_index", False) or int(cgi_get("index", default=0))), False)
|
|
141
|
+
|
|
142
|
+
respond(response)
|
cantools/_memcache.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from cantools.web import respond, succeed, cgi_get, getmem, setmem, delmem, clearmem, read_file, send_file, fetch
|
|
3
|
+
from cantools.util import token, transcode, resizep2
|
|
4
|
+
from cantools.hooks import memhook
|
|
5
|
+
from cantools import config
|
|
6
|
+
|
|
7
|
+
def prox():
|
|
8
|
+
url = cgi_get("url")
|
|
9
|
+
data = getmem(url, False)
|
|
10
|
+
if not data:
|
|
11
|
+
data = fetch(url, timeout=config.memcache.prox.timeout, fakeua=True)
|
|
12
|
+
if cgi_get("p2", default=False):
|
|
13
|
+
data = resizep2(data)
|
|
14
|
+
setmem(url, data, False)
|
|
15
|
+
send_file(data, detect=True)
|
|
16
|
+
|
|
17
|
+
def response():
|
|
18
|
+
action = cgi_get("action", choices=["get", "set", "forget", "prox", "clear"])
|
|
19
|
+
if action == "clear":
|
|
20
|
+
if cgi_get("pw") != config.admin.pw:
|
|
21
|
+
fail("wrong")
|
|
22
|
+
clearmem()
|
|
23
|
+
succeed()
|
|
24
|
+
if action == "prox":
|
|
25
|
+
return prox()
|
|
26
|
+
key = cgi_get("key")
|
|
27
|
+
json = cgi_get("json", default=False)
|
|
28
|
+
mode = cgi_get("mode", default="normal")
|
|
29
|
+
value = cgi_get("value", required=False) # set only
|
|
30
|
+
countdown_list = getmem("_countdown_list", False)
|
|
31
|
+
meta = cgi_get("meta", default={})
|
|
32
|
+
if action == "forget":
|
|
33
|
+
delmem(key)
|
|
34
|
+
elif action == "get":
|
|
35
|
+
data = getmem(key, json)
|
|
36
|
+
if mode == "countdown":
|
|
37
|
+
if key == "_countdown_list":
|
|
38
|
+
succeed(list(countdown_list or set()))
|
|
39
|
+
elif data:
|
|
40
|
+
succeed({
|
|
41
|
+
"ttl": (data["ttl"] - datetime.datetime.now()).total_seconds(),
|
|
42
|
+
"token": data["token"],
|
|
43
|
+
"meta": data["meta"]
|
|
44
|
+
})
|
|
45
|
+
elif mode == "blob":
|
|
46
|
+
send_file(data, detect=True)
|
|
47
|
+
succeed(data)
|
|
48
|
+
elif action == "set":
|
|
49
|
+
if mode == "countdown":
|
|
50
|
+
cdl = countdown_list or set()
|
|
51
|
+
cdl.add(key);
|
|
52
|
+
setmem("_countdown_list", cdl, False)
|
|
53
|
+
setmem(key, {
|
|
54
|
+
"ttl": datetime.datetime.now() + datetime.timedelta(0, value),
|
|
55
|
+
"token": token(),
|
|
56
|
+
"meta": meta
|
|
57
|
+
}, json)
|
|
58
|
+
elif mode == "blob":
|
|
59
|
+
value = read_file(value)
|
|
60
|
+
if cgi_get("transcode", default=False):
|
|
61
|
+
value = transcode(value, True)
|
|
62
|
+
setmem(key, value, False) # JSON disallowed
|
|
63
|
+
json = False # for memhook
|
|
64
|
+
else:
|
|
65
|
+
setmem(key, value, json)
|
|
66
|
+
cgi_get("nohook", default=False) or memhook({ # actions: set, forget
|
|
67
|
+
"action": action,
|
|
68
|
+
"key": key,
|
|
69
|
+
"mode": mode,
|
|
70
|
+
"json": json,
|
|
71
|
+
"meta": meta,
|
|
72
|
+
"value": value,
|
|
73
|
+
"countdown_list": countdown_list
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
respond(response)
|
cantools/_pay.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from cantools.web import respond, succeed, fail, cgi_get
|
|
2
|
+
from cantools import config, util
|
|
3
|
+
from model import *
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
import braintree
|
|
7
|
+
except:
|
|
8
|
+
util.error("please install braintree >= 0.4.5")
|
|
9
|
+
try:
|
|
10
|
+
gateway = braintree.BraintreeGateway(braintree.Configuration(
|
|
11
|
+
environment=getattr(braintree.Environment, config.pay.environment),
|
|
12
|
+
merchant_id=config.pay.merchant,
|
|
13
|
+
public_key=config.pay.public,
|
|
14
|
+
private_key=config.pay.private
|
|
15
|
+
))
|
|
16
|
+
except:
|
|
17
|
+
util.error("please install braintree >= 0.4.5 and check your PAY config values")
|
|
18
|
+
|
|
19
|
+
def response():
|
|
20
|
+
nonce = cgi_get("nonce", required=False)
|
|
21
|
+
if nonce:
|
|
22
|
+
amount = cgi_get("amount")
|
|
23
|
+
user = db.get(cgi_get("user"))
|
|
24
|
+
onsale = getattr(user, "onsale", None)
|
|
25
|
+
emsg = None
|
|
26
|
+
result = gateway.transaction.sale({
|
|
27
|
+
"amount": amount,
|
|
28
|
+
"payment_method_nonce": nonce,
|
|
29
|
+
"options": {
|
|
30
|
+
"submit_for_settlement": True
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
util.log(result)
|
|
34
|
+
if not result.is_success:
|
|
35
|
+
msg = result.errors.deep_errors
|
|
36
|
+
if not msg:
|
|
37
|
+
msg = "%s: %s"%(result.transaction.processor_settlement_response_code,
|
|
38
|
+
result.transaction.processor_settlement_response_text)
|
|
39
|
+
emsg = "%s (%s)"%(result.message, msg)
|
|
40
|
+
onsale and onsale(amount, emsg)
|
|
41
|
+
fail(emsg)
|
|
42
|
+
onsale and succeed(onsale(amount))
|
|
43
|
+
else:
|
|
44
|
+
succeed(gateway.client_token.generate())
|
|
45
|
+
|
|
46
|
+
respond(response)
|
cantools/admin.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from cantools.web import respond, succeed, fail, cgi_get, getcache, clearmem
|
|
3
|
+
from cantools import config
|
|
4
|
+
|
|
5
|
+
def response():
|
|
6
|
+
action = cgi_get("action", choices=["db", "memcache", "mcclear", "monitor", "pubsub"])
|
|
7
|
+
if cgi_get("pw") != config.admin.pw:
|
|
8
|
+
fail("wrong");
|
|
9
|
+
if action == "memcache":
|
|
10
|
+
succeed(getcache())
|
|
11
|
+
elif action == "mcclear":
|
|
12
|
+
clearmem()
|
|
13
|
+
succeed()
|
|
14
|
+
else:
|
|
15
|
+
obj = { "host": config.pubsub.host, "port": config.pubsub.port }
|
|
16
|
+
if action == "monitor": # vs pubsub
|
|
17
|
+
if config.admin.monitor.geo:
|
|
18
|
+
obj["geo"] = config.admin.monitor.geo
|
|
19
|
+
p = os.path.join("logs", "monitor")
|
|
20
|
+
if config.admin.monitor.log and os.path.isdir(p):
|
|
21
|
+
obj["logs"] = logs = []
|
|
22
|
+
for year in os.listdir(p):
|
|
23
|
+
yp = os.path.join(p, year)
|
|
24
|
+
for month in os.listdir(yp):
|
|
25
|
+
mp = os.path.join(yp, month)
|
|
26
|
+
for day in os.listdir(mp):
|
|
27
|
+
dp = os.path.join(mp, day)
|
|
28
|
+
logs.append((dp, os.listdir(dp)))
|
|
29
|
+
succeed(obj)
|
|
30
|
+
|
|
31
|
+
respond(response)
|
cantools/cfg.py
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
cfg = {
|
|
4
|
+
"log": {
|
|
5
|
+
"deep": False,
|
|
6
|
+
"flush": False,
|
|
7
|
+
"timestamp": True,
|
|
8
|
+
"openfiles": False,
|
|
9
|
+
"tracemalloc": False,
|
|
10
|
+
"allow": ["info", "log", "warn", "error"] # access,info,log,warn,error,detail,db,query,kernel
|
|
11
|
+
},
|
|
12
|
+
"mempad": 0, # 0 = unset (uses dez's default)
|
|
13
|
+
"rel": { # 0 = unset (uses rel's default)
|
|
14
|
+
"sleep": 0,
|
|
15
|
+
"turbo": 0,
|
|
16
|
+
"verbose": False,
|
|
17
|
+
"loudlisten": False
|
|
18
|
+
},
|
|
19
|
+
"plugin": {
|
|
20
|
+
"modules": [],
|
|
21
|
+
"path": "%s/.ctplug"%(os.environ.get("HOME") or os.environ.get("USERPROFILE"),),
|
|
22
|
+
"base": "bubbleboy14", # change to 'cantools' account or something
|
|
23
|
+
},
|
|
24
|
+
"geo": {
|
|
25
|
+
"test": False,
|
|
26
|
+
"where": {
|
|
27
|
+
"nom": True,
|
|
28
|
+
"ua": "cantools geo query"
|
|
29
|
+
},
|
|
30
|
+
"zip": "google", # google|geonames
|
|
31
|
+
"user": {
|
|
32
|
+
"geonames": ["demo"],
|
|
33
|
+
"google": [""]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"memcache": {
|
|
37
|
+
"request": False,
|
|
38
|
+
"db": False,
|
|
39
|
+
"prox": {
|
|
40
|
+
"timeout": 5
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"cron": {
|
|
44
|
+
"catchup": False
|
|
45
|
+
},
|
|
46
|
+
"admin": {
|
|
47
|
+
"host": "localhost",
|
|
48
|
+
"port": 8002,
|
|
49
|
+
"protocol": "http",
|
|
50
|
+
"log": None,
|
|
51
|
+
"contacts": [],
|
|
52
|
+
"reportees": [],
|
|
53
|
+
"whitelist": [],
|
|
54
|
+
"monitor": {
|
|
55
|
+
"interval": 5,
|
|
56
|
+
"log": False,
|
|
57
|
+
"geo": [],
|
|
58
|
+
"proxy": None,
|
|
59
|
+
"thresholds": {
|
|
60
|
+
"cpu": 80
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"web": {
|
|
65
|
+
"server": "dez",
|
|
66
|
+
"domain": "your.web.domain",
|
|
67
|
+
"host": "0.0.0.0",
|
|
68
|
+
"port": 8080,
|
|
69
|
+
"protocol": "http",
|
|
70
|
+
"xorigin": False,
|
|
71
|
+
"shield": False,
|
|
72
|
+
"csp": None,
|
|
73
|
+
"log": None,
|
|
74
|
+
"errlog": None,
|
|
75
|
+
"report": False,
|
|
76
|
+
"rollz": {},
|
|
77
|
+
"eflags": [],
|
|
78
|
+
"blacklist": [],
|
|
79
|
+
"whitelist": []
|
|
80
|
+
},
|
|
81
|
+
"ssl": {
|
|
82
|
+
"verify": True,
|
|
83
|
+
"certfile": None,
|
|
84
|
+
"keyfile": None,
|
|
85
|
+
"cacerts": None,
|
|
86
|
+
"pubsubcert": None, # pubsub-only cert!!
|
|
87
|
+
"pubsubcacerts": None, # pubsub-only cacert!!
|
|
88
|
+
"pubsubkey": None # pubsub-only key!! (use pubsubs when running web/admin behind ssl drp)
|
|
89
|
+
},
|
|
90
|
+
"db": { # switch on web backend (override w/ DB)
|
|
91
|
+
"cache": True,
|
|
92
|
+
"refcount": False,
|
|
93
|
+
"gae": "data.db",
|
|
94
|
+
"dez": "sqlite:///data.db",
|
|
95
|
+
"test": "sqlite:///data_test.db",
|
|
96
|
+
"blob": "blob",
|
|
97
|
+
"alter": False, # add new columns to tables - sqlite only!
|
|
98
|
+
"echo": False,
|
|
99
|
+
"public": True, # read from db without credentials via _db.py web handler
|
|
100
|
+
"pool": {
|
|
101
|
+
"null": True,
|
|
102
|
+
"size": 10,
|
|
103
|
+
"recycle": 30,
|
|
104
|
+
"overflow": 20
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"pay": {
|
|
108
|
+
"merchant": None,
|
|
109
|
+
"public": None,
|
|
110
|
+
"private": None,
|
|
111
|
+
"environment": "Sandbox"
|
|
112
|
+
},
|
|
113
|
+
"scrambler": "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/=_",
|
|
114
|
+
"encode": False,
|
|
115
|
+
"gmailer": False,
|
|
116
|
+
"mailer": None, # (override w/ MAILER)
|
|
117
|
+
"mailhtml": True,
|
|
118
|
+
"mailoud": False,
|
|
119
|
+
"mailscantick": 2,
|
|
120
|
+
"pubsub": {
|
|
121
|
+
"host": "localhost",
|
|
122
|
+
"port": 8888,
|
|
123
|
+
"history": 10,
|
|
124
|
+
"botnames": [],
|
|
125
|
+
"bots": {},
|
|
126
|
+
"echo": True,
|
|
127
|
+
"log": None,
|
|
128
|
+
"meta": False,
|
|
129
|
+
"b64": False
|
|
130
|
+
},
|
|
131
|
+
"parse_error_segment_length": 100,
|
|
132
|
+
"build": {
|
|
133
|
+
"dependencies": [],
|
|
134
|
+
"include": [],
|
|
135
|
+
"exclude": [],
|
|
136
|
+
"notjs": [],
|
|
137
|
+
"prod": {
|
|
138
|
+
"b64": False,
|
|
139
|
+
"closure": False
|
|
140
|
+
},
|
|
141
|
+
"web": {
|
|
142
|
+
"dynamic": "html",
|
|
143
|
+
"compiled": {
|
|
144
|
+
"static": "html-static",
|
|
145
|
+
"production": "html-production"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"admin": {
|
|
149
|
+
"dynamic": "dynamic",
|
|
150
|
+
"compiled": {
|
|
151
|
+
"static": "static",
|
|
152
|
+
"production": "production"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"js": {
|
|
157
|
+
"path": "js",
|
|
158
|
+
"flag": '<script src="/',
|
|
159
|
+
"offset": len('<script src="'),
|
|
160
|
+
"endoffset": len('"></script>')
|
|
161
|
+
},
|
|
162
|
+
"yaml": {
|
|
163
|
+
"path": "app.yaml",
|
|
164
|
+
"start": "# START mode: ",
|
|
165
|
+
"end": "# END mode: "
|
|
166
|
+
},
|
|
167
|
+
"py": {
|
|
168
|
+
"path": "ct.cfg",
|
|
169
|
+
"enc": "ENCODE = %s",
|
|
170
|
+
"mode": "MODE = %s"
|
|
171
|
+
},
|
|
172
|
+
"noscript": """
|
|
173
|
+
<noscript>
|
|
174
|
+
<div style="position: absolute; left:0px; top:0px;">
|
|
175
|
+
This site requires Javascript to function properly. To enable Javascript in your browser, please follow <a href="http://www.google.com/support/bin/answer.py?answer=23852">these instructions</a>. Thank you, and have a nice day.
|
|
176
|
+
</div>
|
|
177
|
+
</noscript>
|
|
178
|
+
""",
|
|
179
|
+
"init": {
|
|
180
|
+
"core": ['CT.require("core.config");', 'CT.require("core.util");'],
|
|
181
|
+
"config": {
|
|
182
|
+
"log": {
|
|
183
|
+
"include": [],
|
|
184
|
+
"exclude": []
|
|
185
|
+
},
|
|
186
|
+
"header": {
|
|
187
|
+
"logo": "Your Logo",
|
|
188
|
+
"right": []
|
|
189
|
+
},
|
|
190
|
+
"spinner": True,
|
|
191
|
+
"borderbox": True,
|
|
192
|
+
"css": [],
|
|
193
|
+
"keys": {},
|
|
194
|
+
"mobile": {
|
|
195
|
+
"scale": False
|
|
196
|
+
},
|
|
197
|
+
"modals": {
|
|
198
|
+
"escape": True,
|
|
199
|
+
"transition": "slide"
|
|
200
|
+
},
|
|
201
|
+
"softclosure": False,
|
|
202
|
+
"CC": {
|
|
203
|
+
"gateway": "https://care-coin.net/comp/api.js",
|
|
204
|
+
"membership": None,
|
|
205
|
+
"agent": None,
|
|
206
|
+
"pod": None
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
"util": {
|
|
210
|
+
"main": {},
|
|
211
|
+
"post": "",
|
|
212
|
+
"template": "core.util = %s;\r\n\r\nCT.log.grep(core.config.log.include, core.config.log.exclude);%s"
|
|
213
|
+
},
|
|
214
|
+
"dirs": ["js", "css", "img", "logs", "blob", "html", "html-static", "html-production"],
|
|
215
|
+
"vcignore": {
|
|
216
|
+
".": ["*pyc", "*~", ".ctp", "_", "admin.py", "_db.py", "_memcache.py", "_pay.py", "logs", "blob"],
|
|
217
|
+
"css": ["ct.css"],
|
|
218
|
+
"js": ["CT"]
|
|
219
|
+
},
|
|
220
|
+
"yaml": {
|
|
221
|
+
"gae": """application: %s
|
|
222
|
+
version: 1
|
|
223
|
+
runtime: python27
|
|
224
|
+
api_version: 1
|
|
225
|
+
threadsafe: false
|
|
226
|
+
|
|
227
|
+
handlers:
|
|
228
|
+
- url: /remote_api
|
|
229
|
+
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
|
|
230
|
+
login: admin""",
|
|
231
|
+
"core": """
|
|
232
|
+
- url: /css
|
|
233
|
+
static_dir: css
|
|
234
|
+
|
|
235
|
+
- url: /img
|
|
236
|
+
static_dir: img
|
|
237
|
+
|
|
238
|
+
- url: /blob
|
|
239
|
+
static_dir: blob
|
|
240
|
+
|
|
241
|
+
- url: /_db
|
|
242
|
+
script: _db.py
|
|
243
|
+
|
|
244
|
+
- url: /_memcache
|
|
245
|
+
script: _memcache.py
|
|
246
|
+
|
|
247
|
+
- url: /_pay
|
|
248
|
+
script: _pay.py
|
|
249
|
+
|
|
250
|
+
## MODE SWITCHING -- DON'T MESS WITH (unless you know what you're doing)!
|
|
251
|
+
# START mode: dynamic
|
|
252
|
+
- url: /js
|
|
253
|
+
static_dir: js
|
|
254
|
+
- url: /.*\.html
|
|
255
|
+
static_dir: html
|
|
256
|
+
# END mode: dynamic
|
|
257
|
+
# START mode: static
|
|
258
|
+
#- url: /js
|
|
259
|
+
# static_dir: js
|
|
260
|
+
#- url: /.*\.html
|
|
261
|
+
# static_dir: html-static
|
|
262
|
+
# END mode: static
|
|
263
|
+
# START mode: production
|
|
264
|
+
#- url: /.*\.html
|
|
265
|
+
# static_dir: html-production
|
|
266
|
+
# END mode: production"""
|
|
267
|
+
},
|
|
268
|
+
"cron": "cron:",
|
|
269
|
+
"html": """<!doctype html>
|
|
270
|
+
<html>
|
|
271
|
+
<head>
|
|
272
|
+
<title>%s</title>
|
|
273
|
+
<link rel="stylesheet" href="/css/ct.css">
|
|
274
|
+
<script src="/js/CT/ct.js"></script>
|
|
275
|
+
</head>
|
|
276
|
+
<body>
|
|
277
|
+
Hello World
|
|
278
|
+
</body>
|
|
279
|
+
</html>""",
|
|
280
|
+
"ctcfg": os.linesep.join(['ENCODE = False', 'MODE = dynamic', 'WEB_SERVER = %s']),
|
|
281
|
+
"model": "from cantools import db"
|
|
282
|
+
},
|
|
283
|
+
"about": """# cantools %s
|
|
284
|
+
This portable modern web framework is the application-neutral backbone of Civil Action Network. It includes: a pubsub WebSocket server and bot platform; swappable web backends capable of targeting high-concurrency standalone or cloud platforms; a variable-mode application compiler; a broad-spectrum ORM and database migration tools; a built in administrative interface; and a rich modular JavaScript library.
|
|
285
|
+
|
|
286
|
+
- Docs: http://ct.mkult.co
|
|
287
|
+
- License: MIT (see LICENSE)
|
|
288
|
+
|
|
289
|
+
## Repository Installation (full)
|
|
290
|
+
- upside: includes full codebase (not just Python)
|
|
291
|
+
- site: https://github.com/bubbleboy14/cantools
|
|
292
|
+
- steps
|
|
293
|
+
- git clone https://github.com/bubbleboy14/cantools.git
|
|
294
|
+
- cd cantools
|
|
295
|
+
- pip3 install -e .
|
|
296
|
+
|
|
297
|
+
If you're running Debian or Fedora or BSD or OSX, you may consider running (probably as root or sudoer):
|
|
298
|
+
|
|
299
|
+
./bootstrap.sh
|
|
300
|
+
|
|
301
|
+
Instead of the pip3 install line. This will also install various dependencies that
|
|
302
|
+
may not already be present on your system (some systems don't even come with Python).
|
|
303
|
+
|
|
304
|
+
## Production Installation (transparent)
|
|
305
|
+
- upside
|
|
306
|
+
- cantools and all dependencies installed in one line
|
|
307
|
+
- hidden away like any standard system library
|
|
308
|
+
- cleanest way to deploy your applications
|
|
309
|
+
- downside
|
|
310
|
+
- no easy access to ct source -- aren't you curious?
|
|
311
|
+
- OSX or Debian (especially Ubuntu) -only (until you add support for your system!)
|
|
312
|
+
- command: curl https://raw.githubusercontent.com/bubbleboy14/cantools/master/bootstrap.sh | cat | sh
|
|
313
|
+
|
|
314
|
+
## Package Installation (limited -- not recommended)
|
|
315
|
+
- downside
|
|
316
|
+
- does _not_ include full package (such as client-side web files)
|
|
317
|
+
- enough to mess around with cantools -- not enough to develop end-to-end applications
|
|
318
|
+
- package: https://pypi.python.org/pypi/ct
|
|
319
|
+
- command: easy_install ct
|
|
320
|
+
|
|
321
|
+
## Hello World
|
|
322
|
+
This takes less than a moment. Pop open a terminal in your home directory:
|
|
323
|
+
|
|
324
|
+
~$ git clone https://github.com/bubbleboy14/cantools.git
|
|
325
|
+
~$ cd cantools/
|
|
326
|
+
~/cantools$ pip3 install -e .
|
|
327
|
+
~/cantools$ cd ..
|
|
328
|
+
~$ ctinit hello_world
|
|
329
|
+
~$ cd hello_world/
|
|
330
|
+
~/hello_world$ ctstart
|
|
331
|
+
|
|
332
|
+
And that's it. Open http://localhost:8080/ in your browser and call it a day.
|
|
333
|
+
|
|
334
|
+
## Deployment Steps
|
|
335
|
+
You just found out that you need to deploy a cantools project to a fresh, naked
|
|
336
|
+
Ubuntu system that doesn't even have Python or git. Oh no, what do you do? This
|
|
337
|
+
(as root or sudoer for first and last commands):
|
|
338
|
+
|
|
339
|
+
~$ curl https://raw.githubusercontent.com/bubbleboy14/cantools/master/bootstrap.sh | cat | sh
|
|
340
|
+
~$ git clone https://github.com/your_organization/your_project.git
|
|
341
|
+
~$ cd your_project
|
|
342
|
+
~/your_project$ ctinit -r
|
|
343
|
+
~/your_project$ ctstart -p80
|
|
344
|
+
|
|
345
|
+
Now just make sure port 80 is open, and you're good to go. Also, you should probably
|
|
346
|
+
run ctstart in a screen or something (so that you can eventually log out) - that's it!"""
|
|
347
|
+
}
|