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.
Files changed (55) hide show
  1. cantools/__init__.py +24 -0
  2. cantools/_db.py +142 -0
  3. cantools/_memcache.py +76 -0
  4. cantools/_pay.py +46 -0
  5. cantools/admin.py +31 -0
  6. cantools/cfg.py +347 -0
  7. cantools/config.py +131 -0
  8. cantools/db/__init__.py +18 -0
  9. cantools/db/admin.py +27 -0
  10. cantools/db/gae/__init__.py +0 -0
  11. cantools/db/gae/model.py +127 -0
  12. cantools/db/gae/properties.py +35 -0
  13. cantools/db/wp.py +99 -0
  14. cantools/geo.py +188 -0
  15. cantools/hooks.py +13 -0
  16. cantools/scripts/__init__.py +0 -0
  17. cantools/scripts/bench.py +167 -0
  18. cantools/scripts/builder.py +272 -0
  19. cantools/scripts/deploy.py +154 -0
  20. cantools/scripts/doc.py +239 -0
  21. cantools/scripts/index.py +226 -0
  22. cantools/scripts/init.py +345 -0
  23. cantools/scripts/migrate.py +593 -0
  24. cantools/scripts/pubsub/__init__.py +28 -0
  25. cantools/scripts/pubsub/actor.py +13 -0
  26. cantools/scripts/pubsub/bots.py +143 -0
  27. cantools/scripts/pubsub/channel.py +85 -0
  28. cantools/scripts/pubsub/ps.py +145 -0
  29. cantools/scripts/pubsub/user.py +51 -0
  30. cantools/scripts/start.py +53 -0
  31. cantools/scripts/util.py +24 -0
  32. cantools/util/__init__.py +78 -0
  33. cantools/util/admin.py +620 -0
  34. cantools/util/data.py +109 -0
  35. cantools/util/media.py +303 -0
  36. cantools/util/package.py +125 -0
  37. cantools/util/system.py +73 -0
  38. cantools/web/__init__.py +9 -0
  39. cantools/web/dez_server/__init__.py +1 -0
  40. cantools/web/dez_server/controller.py +129 -0
  41. cantools/web/dez_server/cron.py +115 -0
  42. cantools/web/dez_server/daemons.py +64 -0
  43. cantools/web/dez_server/mail.py +24 -0
  44. cantools/web/dez_server/response.py +63 -0
  45. cantools/web/dez_server/routes.py +21 -0
  46. cantools/web/dez_server/server.py +229 -0
  47. cantools/web/dez_server/sms.py +12 -0
  48. cantools/web/gae_server.py +68 -0
  49. cantools/web/util.py +552 -0
  50. ct-0.10.8.114.dist-info/LICENSE +9 -0
  51. ct-0.10.8.114.dist-info/METADATA +25 -0
  52. ct-0.10.8.114.dist-info/RECORD +55 -0
  53. ct-0.10.8.114.dist-info/WHEEL +5 -0
  54. ct-0.10.8.114.dist-info/entry_points.txt +10 -0
  55. 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
+ }