A web framework for aspiring media terrorists – PRE-ALPHA – DO NOT DEPLOY!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
11KB

  1. #!/usr/bin/env python
  2. import math
  3. import random
  4. import json
  5. import requests
  6. import datetime
  7. import flask
  8. import numpy
  9. import pandas
  10. import poobrains
  11. from flask import redirect
  12. app = poobrains.app
  13. @app.route('/')
  14. def front():
  15. return redirect(News.url())
  16. class TestSubForm(poobrains.form.Fieldset):
  17. oink = poobrains.form.fields.Text(label="OMGWTF")
  18. foo = poobrains.form.fields.Text(label="SUBfoo")
  19. submit = poobrains.form.Button('submit', label="SUBSUBMIT")
  20. @app.expose('/form')
  21. class TestForm(poobrains.form.Form):
  22. foo = poobrains.form.fields.Text()
  23. bar = TestSubForm()
  24. optin = poobrains.form.fields.Checkbox(label="Opt-in", default=False, required=True, choices=[(True, None)])
  25. radio = poobrains.form.fields.Radio(type=poobrains.form.types.INT, choices=[(1, 'One'), (5, 'Five'), (23, 'Twentythree'), (42, 'Fortytwo')])
  26. multicheck = poobrains.form.fields.Checkbox(label="Check 'em", type=poobrains.form.types.STRING, choices=[('dubs', 'dubs'), ('trips', 'TRIPS'), ('quads', 'QUADS!1!!!!')], multi=True)
  27. completeme = poobrains.form.fields.Text(label="Lookit me, I can autocomplete without JS!", choices=[('Mr. Foo', 'foo'), ('Mr. Florb', 'florb'), ('Ms. Bar', 'bar')])
  28. ranged = poobrains.form.fields.Range()
  29. trigger = poobrains.form.Button('submit', label='Hit me!')
  30. def process(self, submit):
  31. flask.flash('TestForm.process called!')
  32. return self
  33. @app.expose('/news', mode='full')
  34. class News(poobrains.commenting.Commentable):
  35. """ This is the news class docstring """
  36. class Meta:
  37. search_fields = ['title', 'name', 'text']
  38. title = poobrains.storage.fields.CharField()
  39. text = poobrains.md.MarkdownField()
  40. @app.expose('/paste', mode='full', title='Copypasta')
  41. class Paste(poobrains.tagging.Taggable):
  42. type = poobrains.storage.fields.CharField()
  43. text = poobrains.storage.fields.TextField()
  44. @app.site.box('menu_main')
  45. def menu_main():
  46. menu = poobrains.rendering.Menu('main')
  47. try:
  48. News.permissions['read'].check(flask.g.user)
  49. menu.append(News.url(), 'News')
  50. except poobrains.auth.AccessDenied:
  51. pass
  52. try:
  53. Paste.permissions['read'].check(flask.g.user)
  54. menu.append(Paste.url(), 'Pastes')
  55. except poobrains.auth.AccessDenied:
  56. pass
  57. for url, caption in poobrains.auth.Page.main_menu_entries():
  58. menu.append(url, caption)
  59. return menu
  60. class NonExposed(poobrains.auth.Administerable):
  61. text = poobrains.storage.fields.TextField()
  62. class NonExposedB(NonExposed):
  63. pass
  64. class AVeryVeryLongNameToTestMenuPositioning(poobrains.auth.Administerable):
  65. florp = poobrains.storage.fields.BooleanField()
  66. #class MultiPK(poobrains.auth.Administerable):
  67. #
  68. # class Meta:
  69. # primary_key = peewee.CompositeKey('pk_a', 'pk_b')
  70. #
  71. # pk_a = poobrains.storage.fields.IntegerField()
  72. # pk_b = poobrains.storage.fields.IntegerField()
  73. #
  74. #
  75. #class NestedHandle(poobrains.auth.Administerable):
  76. #
  77. # class Meta:
  78. # primary_key = peewee.CompositeKey('foreign', 'local')
  79. #
  80. # foreign = poobrains.storage.fields.ForeignKeyField(MultiPK)
  81. # local = poobrains.storage.fields.CharField()
  82. @app.site.listing(NonExposedB, '/custom', mode='full', title='Custom Listing')
  83. def list_nonexposed(listing):
  84. return listing
  85. class NEO_Approaches(poobrains.analysis.EphemeralDataset):
  86. title='NASA Near Earth Orbits'
  87. @classmethod
  88. def load(cls, spkid: int = 2099942): # default spkid for apophis
  89. try:
  90. spkid = int(spkid)
  91. except ValueError:
  92. raise poobrains.errors.ValidationError("Invalid SPK ID; must be an integer.")
  93. response = requests.get('https://api.nasa.gov/neo/rest/v1/neo/%d?api_key=DEMO_KEY' % spkid)
  94. if response.status_code != 200:
  95. raise poobrains.errors.ValidationError("NASA API responded with error code %d." % response.status_code)
  96. data = json.loads(response.text)
  97. ds = cls()
  98. ds.title = "Close approaches of %s" % (data['name_limited'] if 'name_limited' in data else data['name'])
  99. ds.description: "**%s** belongs to orbit class **%s**; %s" % (data['name'], data['orbital_data']['orbit_class']['orbit_class_type'], data['orbital_data']['orbit_class']['orbit_class_description'])
  100. ds.plot_data = {
  101. 'kind': 'line',
  102. 'layers': {
  103. 'approaches': {
  104. 'x': 'time',
  105. 'y': 'distance'
  106. }
  107. }
  108. }
  109. ds['time'] = {
  110. 'title': 'Time',
  111. 'dtype': 'datetime64',
  112. 'color': None,
  113. 'observations': {},
  114. }
  115. ds['distance'] = {
  116. 'title': 'Distance (km)',
  117. 'dtype': 'float64',
  118. 'color': None,
  119. 'observations': {},
  120. }
  121. for index, observation in enumerate(data['close_approach_data']):
  122. observation_time = datetime.datetime.fromtimestamp(observation['epoch_date_close_approach'] / 1000)
  123. observation_distance = float(observation['miss_distance']['kilometers'])
  124. ds['time']['observations'][index] = {
  125. 'value': observation_time
  126. }
  127. ds['distance']['observations'][index] = {
  128. 'value': observation_distance
  129. }
  130. return ds
  131. class Stock_Weekly(poobrains.analysis.EphemeralDataset):
  132. title = 'Stock (weekly)'
  133. @classmethod
  134. def load(cls, symbol='FB'):
  135. response = requests.get('https://www.alphavantage.co/query?function=TIME_SERIES_WEEKLY&symbol=%s&apikey=%s' % (symbol, app.config['ALPHAVANTAGE_API_KEY']))
  136. if response.status_code != 200:
  137. raise poobrains.errors.ValidationError("AlphaVantage API responded with error code %d." % response.status_code)
  138. data = json.loads(response.text)
  139. dates = [x for x in data['Weekly Time Series'].keys()]
  140. first_date = dates[-1]
  141. last_date = dates[0]
  142. ds = cls()
  143. ds.title = symbol
  144. ds.description = f"Data for stock symbol **{symbol}** from *{first_date}* to *{last_date}*."
  145. ds.plot_data = {
  146. 'kind': 'line',
  147. 'layers': {
  148. symbol: {
  149. 'x': 'time',
  150. 'y': 'price'
  151. }
  152. }
  153. }
  154. ds['time'] = {
  155. 'title': 'Time',
  156. 'description': f"Data for stock symbol **{symbol}** from *{first_date}* to *{last_date}*.",
  157. 'dtype': 'float64',
  158. 'color': None,
  159. 'observations': {}
  160. }
  161. ds['price'] = {
  162. 'title': 'Price ($)',
  163. 'description': f"Data for stock symbol **{symbol}** from *{first_date}* to *{last_date}*.",
  164. 'dtype': 'float64',
  165. 'color': None,
  166. 'observations': {}
  167. }
  168. for index, (datestring, datapoint) in enumerate(data['Weekly Time Series'].items()):
  169. y, m, d = [int(x) for x in datestring.split('-')]
  170. date = datetime.datetime(y, m, d)
  171. ds['time']['observations'][index] = {'value': date.timestamp()}
  172. ds['price']['observations'][index] = {'value': float(datapoint['4. close'])}
  173. #error_lower = y - float(datapoint['3. low'])
  174. #error_upper = y - float(datapoint['2. high'])
  175. return ds
  176. class ConstrainedRandom(poobrains.analysis.EphemeralDataset):
  177. title = 'Constrained random'
  178. @classmethod
  179. def load(cls, magnitude: int = 2, length: int = 16):
  180. magnitude, length = int(magnitude), int(length)
  181. ranges = []
  182. for i in range(0, magnitude):
  183. ranges.append(sorted((random.random(), random.random())))
  184. ds = cls()
  185. ds.title = f"Constrained random ({magnitude}, {length})"
  186. ds.description = f"ConstrainedRandom of magnitude {magnitude} and length {length}."
  187. ds.plot_data = {
  188. 'kind': 'line',
  189. 'layers': {
  190. 'plot': {
  191. 'x': 'x',
  192. 'y': 'y'
  193. }
  194. }
  195. }
  196. ds['x'] = {
  197. 'title': "X",
  198. 'description': "Equidistant steps for X-axis.",
  199. 'dtype': 'int64',
  200. 'color': None,
  201. 'observations': {},
  202. }
  203. ds['y'] = {
  204. 'title': "Y",
  205. 'description': "Random values for Y-axis.",
  206. 'dtype': 'float64',
  207. 'color': None,
  208. 'observations': {},
  209. }
  210. for index, x in enumerate(range(0, length)):
  211. y = random.random()
  212. for r in ranges:
  213. y = r[0] + (r[1] - r[0]) * y
  214. r = ranges[round((len(ranges) - 1) * random.random())] # select random range
  215. y = r[0] + (r[1] - r[0]) * y
  216. y *= math.sin(2 * math.pi * float(i) / length)
  217. ds['x']['observations'][index] = {'value': x}
  218. ds['y']['observations'][index] = {'value': y}
  219. return ds
  220. class Sine(poobrains.analysis.EphemeralDataset):
  221. title = 'Sine'
  222. @classmethod
  223. def load(cls, length: int=10):
  224. ds = cls()
  225. ds.title = f"Sine ({length})"
  226. ds.description = f"A full sine wave out of {length} points."
  227. ds.plot_data = {
  228. 'kind': 'line',
  229. 'layers': {
  230. 'plot': {
  231. 'x': 'x',
  232. 'y': 'y'
  233. }
  234. }
  235. }
  236. inc = (2 * math.pi) / (length - 1)
  237. ds['x'] = {
  238. 'title': "X",
  239. 'description': f"x for `sin(x)`; spaced at equidistance intervals of {inc}.",
  240. 'dtype': 'float64',
  241. 'color': None,
  242. 'observations': {}
  243. }
  244. ds['y'] = {
  245. 'title': "Y",
  246. 'description': "Result of `sin(x)`",
  247. 'dtype': 'float64',
  248. 'color': None,
  249. 'observations': {}
  250. }
  251. x = 0
  252. for index in range(0, length):
  253. ds['x']['observations'][index] = {'value': x}
  254. ds['y']['observations'][index] = {'value': math.sin(x)}
  255. x += inc
  256. return ds
  257. class RandomMap(poobrains.analysis.geo.EphemeralGeoData):
  258. @classmethod
  259. def load(cls):
  260. ds = cls()
  261. data = poobrains.analysis.geo.geojson.MultiPolygon()
  262. for poly_num in range(0, random.randrange(1, 8)):
  263. points = []
  264. for point_num in range(0, random.randrange(3, 7)):
  265. points.append((random.randrange(-180, 181),random.randrange(-75, 76)))
  266. data.coordinates.append([points])
  267. ds.data = poobrains.analysis.geo.geojson.dumps(data)
  268. return ds
  269. if __name__ == '__main__':
  270. #app.run()
  271. poobrains.app.main()