Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge in develop, update to 1.5

  • Loading branch information...
commit b1a0f1d36a6294bdc9f1352af7b919db9de08705 2 parents 5a66ba6 + 55b059b
@kyleconroy kyleconroy authored
Showing with 8,986 additions and 3,773 deletions.
  1. +30 −5 .gitignore
  2. +23 −0 ChangeLog
  3. +31 −21 README.md
  4. +0 −56 app.yaml
  5. +0 −49 config.py
  6. +130 −0 docs/Makefile
  7. +79 −0 docs/_static/examples/example.php
  8. +64 −0 docs/_static/examples/example.py
  9. +50 −0 docs/_static/examples/example.rb
  10. +216 −0 docs/conf.py
  11. +22 −0 docs/examples.rst
  12. +20 −0 docs/help.rst
  13. +29 −0 docs/index.rst
  14. +170 −0 docs/make.bat
  15. +30 −0 docs/quickstart.rst
  16. +634 −0 docs/restapi.rst
  17. +0 −80 examples/stashboard.php
  18. +0 −142 examples/stashboard.py
  19. +0 −50 examples/stashboard.rb
  20. +0 −11 examples/widget/example.html
  21. +0 −35 examples/widget/output.html
  22. +0 −492 handlers/api.py
  23. +0 −205 handlers/restful.py
  24. +0 −403 handlers/site.py
  25. +0 −105 main.py
  26. +0 −17 markdown/convert.py
  27. +0 −215 markdown/examples.markdown
  28. +0 −38 markdown/overview.markdown
  29. +0 −686 markdown/restapi.markdown
  30. +0 −302 models.py
  31. +6 −0 requirements.txt
  32. +0 −75 runner.py
  33. +69 −0 scripts/gen_fixture.py
  34. +1 −0  stashboard/__init__.py
  35. +65 −0 stashboard/app.yaml
  36. +20 −0 stashboard/appengine_config.py
  37. 0  {utils/external/oauth2/clients → stashboard/contrib}/__init__.py
  38. 0  {utils/external → stashboard/contrib}/dateutil/__init__.py
  39. 0  {utils/external → stashboard/contrib}/dateutil/easter.py
  40. 0  {utils/external → stashboard/contrib}/dateutil/parser.py
  41. 0  {utils/external → stashboard/contrib}/dateutil/relativedelta.py
  42. 0  {utils/external → stashboard/contrib}/dateutil/rrule.py
  43. 0  {utils/external → stashboard/contrib}/dateutil/tz.py
  44. 0  {utils/external → stashboard/contrib}/dateutil/tzwin.py
  45. 0  {utils/external → stashboard/contrib}/dateutil/zoneinfo/__init__.py
  46. 0  {utils/external → stashboard/contrib}/dateutil/zoneinfo/zoneinfo-2010g.tar.gz
  47. +1,275 −0 stashboard/contrib/httplib2/__init__.py
  48. 0  {utils/external → stashboard/contrib}/httplib2/iri2uri.py
  49. +440 −0 stashboard/contrib/httplib2/socks.py
  50. 0  {utils/external → stashboard/contrib/httplib2/test}/__init__.py
  51. +1 −0  stashboard/contrib/httplib2/test/brokensocket/socket.py
  52. +88 −0 stashboard/contrib/httplib2/test/functional/test_proxies.py
  53. +100 −0 stashboard/contrib/httplib2/test/miniserver.py
  54. +23 −0 stashboard/contrib/httplib2/test/smoke_test.py
  55. +24 −0 stashboard/contrib/httplib2/test/test_no_socket.py
  56. +860 −0 stashboard/contrib/oauth2/__init__.py
  57. +18 −0 stashboard/contrib/oauth2/_version.py
  58. 0  {utils/django_libs → stashboard/contrib/oauth2/clients}/__init__.py
  59. 0  {utils/external → stashboard/contrib}/oauth2/clients/imap.py
  60. 0  {utils/external → stashboard/contrib}/oauth2/clients/smtp.py
  61. 0  {utils/external → stashboard/contrib}/status_images.py
  62. +4 −0 stashboard/cron.yaml
  63. +562 −0 stashboard/fixtures/images.json
  64. +12 −0 stashboard/fixtures/statuses.json
  65. +14 −0 stashboard/handlers/__init__.py
  66. +371 −0 stashboard/handlers/admin.py
  67. +511 −0 stashboard/handlers/api.py
  68. +208 −0 stashboard/handlers/restful.py
  69. +209 −0 stashboard/handlers/site.py
  70. 0  { → stashboard}/index.yaml
  71. +102 −0 stashboard/main.py
  72. +106 −0 stashboard/migrations.py
  73. +281 −0 stashboard/models.py
  74. +14 −0 stashboard/settings.py
  75. +388 −0 stashboard/static/css/gh-buttons.css
  76. BIN  stashboard/static/css/gh-icons.png
  77. 0  { → stashboard}/static/css/prettify.css
  78. +48 −0 stashboard/static/css/reset.css
  79. +469 −0 stashboard/static/css/style.css
  80. 0  { → stashboard}/static/favicon.ico
  81. 0  {static/images/status → stashboard/static/images/icons/fugue}/broom.png
  82. 0  {static/images/status → stashboard/static/images/icons/fugue}/bug.png
  83. 0  {static/images/status → stashboard/static/images/icons/fugue}/clock.png
  84. 0  {static/images/status → stashboard/static/images/icons/fugue}/cross-circle.png
  85. 0  {static/images/status → stashboard/static/images/icons/fugue}/exclamation.png
  86. 0  {static/images/status → stashboard/static/images/icons/fugue}/flag.png
  87. 0  {static/images/status → stashboard/static/images/icons/fugue}/hard-hat.png
  88. 0  {static/images/status → stashboard/static/images/icons/fugue}/heart.png
  89. 0  {static/images/status → stashboard/static/images/icons/fugue}/information-small.png
  90. 0  {static/images/status → stashboard/static/images/icons/fugue}/information-white.png
  91. 0  {static/images/status → stashboard/static/images/icons/fugue}/information.png
  92. 0  {static/images/status → stashboard/static/images/icons/fugue}/lock.png
  93. 0  {static/images/status → stashboard/static/images/icons/fugue}/plug.png
  94. 0  {static/images/status → stashboard/static/images/icons/fugue}/plus-circle.png
  95. 0  {static/images/status → stashboard/static/images/icons/fugue}/question-white.png
  96. 0  {static/images/status → stashboard/static/images/icons/fugue}/question.png
  97. 0  {static/images/status → stashboard/static/images/icons/fugue}/tick-circle.png
  98. 0  {static/images/status → stashboard/static/images/icons/fugue}/traffic-cone.png
  99. 0  {static/images/status → stashboard/static/images/icons/fugue}/wrench.png
  100. BIN  stashboard/static/images/icons/iconic/arrow_down.png
  101. BIN  stashboard/static/images/icons/iconic/arrow_down_alt1.png
  102. BIN  stashboard/static/images/icons/iconic/arrow_down_alt2.png
  103. BIN  stashboard/static/images/icons/iconic/arrow_left.png
  104. BIN  stashboard/static/images/icons/iconic/arrow_left_alt1.png
  105. BIN  stashboard/static/images/icons/iconic/arrow_left_alt2.png
  106. BIN  stashboard/static/images/icons/iconic/arrow_right.png
  107. BIN  stashboard/static/images/icons/iconic/arrow_right_alt1.png
  108. BIN  stashboard/static/images/icons/iconic/arrow_right_alt2.png
  109. BIN  stashboard/static/images/icons/iconic/arrow_up.png
  110. BIN  stashboard/static/images/icons/iconic/arrow_up_alt1.png
  111. BIN  stashboard/static/images/icons/iconic/arrow_up_alt2.png
  112. BIN  stashboard/static/images/icons/iconic/article.png
  113. BIN  stashboard/static/images/icons/iconic/at.png
  114. BIN  stashboard/static/images/icons/iconic/bolt.png
  115. BIN  stashboard/static/images/icons/iconic/book.png
  116. BIN  stashboard/static/images/icons/iconic/book_alt.png
  117. BIN  stashboard/static/images/icons/iconic/box.png
  118. BIN  stashboard/static/images/icons/iconic/calendar.png
  119. BIN  stashboard/static/images/icons/iconic/calendar_alt_fill.png
  120. BIN  stashboard/static/images/icons/iconic/calendar_alt_stroke.png
  121. BIN  stashboard/static/images/icons/iconic/cd.png
  122. BIN  stashboard/static/images/icons/iconic/chat.png
  123. BIN  stashboard/static/images/icons/iconic/chat_alt_fill.png
  124. BIN  stashboard/static/images/icons/iconic/chat_alt_stroke.png
  125. BIN  stashboard/static/images/icons/iconic/check_alt.png
  126. BIN  stashboard/static/images/icons/iconic/clock.png
  127. BIN  stashboard/static/images/icons/iconic/cog.png
  128. BIN  stashboard/static/images/icons/iconic/cog_alt.png
  129. BIN  stashboard/static/images/icons/iconic/comment_alt1_fill.png
  130. BIN  stashboard/static/images/icons/iconic/comment_alt1_stroke.png
  131. BIN  stashboard/static/images/icons/iconic/compass.png
  132. BIN  stashboard/static/images/icons/iconic/cursor.png
  133. BIN  stashboard/static/images/icons/iconic/denied.png
  134. BIN  stashboard/static/images/icons/iconic/denied_alt.png
  135. BIN  stashboard/static/images/icons/iconic/dial.png
  136. BIN  stashboard/static/images/icons/iconic/document_fill.png
  137. BIN  stashboard/static/images/icons/iconic/document_stroke.png
  138. BIN  stashboard/static/images/icons/iconic/eject.png
  139. BIN  stashboard/static/images/icons/iconic/equalizer.png
  140. BIN  stashboard/static/images/icons/iconic/eyedropper.png
  141. BIN  stashboard/static/images/icons/iconic/first.png
  142. BIN  stashboard/static/images/icons/iconic/folder_fill.png
  143. BIN  stashboard/static/images/icons/iconic/folder_stroke.png
  144. BIN  stashboard/static/images/icons/iconic/fullscreen.png
  145. BIN  stashboard/static/images/icons/iconic/fullscreen_alt.png
  146. BIN  stashboard/static/images/icons/iconic/fullscreen_exit.png
  147. BIN  stashboard/static/images/icons/iconic/fullscreen_exit_alt.png
  148. BIN  stashboard/static/images/icons/iconic/home.png
  149. BIN  stashboard/static/images/icons/iconic/image.png
  150. BIN  stashboard/static/images/icons/iconic/information.png
  151. BIN  stashboard/static/images/icons/iconic/key_fill.png
  152. BIN  stashboard/static/images/icons/iconic/key_stroke.png
  153. BIN  stashboard/static/images/icons/iconic/last.png
  154. BIN  stashboard/static/images/icons/iconic/left_quote.png
  155. BIN  stashboard/static/images/icons/iconic/left_quote_alt.png
  156. BIN  stashboard/static/images/icons/iconic/link.png
  157. BIN  stashboard/static/images/icons/iconic/loop.png
  158. BIN  stashboard/static/images/icons/iconic/magnifying_glass.png
  159. BIN  stashboard/static/images/icons/iconic/magnifying_glass_alt.png
  160. BIN  stashboard/static/images/icons/iconic/map_pin_fill.png
  161. BIN  stashboard/static/images/icons/iconic/map_pin_stroke.png
  162. BIN  stashboard/static/images/icons/iconic/minus_alt.png
  163. BIN  stashboard/static/images/icons/iconic/moon_fill.png
  164. BIN  stashboard/static/images/icons/iconic/moon_stroke.png
  165. BIN  stashboard/static/images/icons/iconic/move.png
  166. BIN  stashboard/static/images/icons/iconic/move_alt1.png
  167. BIN  stashboard/static/images/icons/iconic/move_alt2.png
  168. BIN  stashboard/static/images/icons/iconic/move_horizontal_alt2.png
  169. BIN  stashboard/static/images/icons/iconic/move_vertical_alt2.png
  170. BIN  stashboard/static/images/icons/iconic/movie.png
  171. BIN  stashboard/static/images/icons/iconic/new_window.png
  172. BIN  stashboard/static/images/icons/iconic/pen.png
  173. BIN  stashboard/static/images/icons/iconic/pen_alt_fill.png
  174. BIN  stashboard/static/images/icons/iconic/pen_alt_stroke.png
  175. BIN  stashboard/static/images/icons/iconic/pin.png
  176. BIN  stashboard/static/images/icons/iconic/play_alt.png
  177. BIN  stashboard/static/images/icons/iconic/plus.png
  178. BIN  stashboard/static/images/icons/iconic/plus_alt.png
  179. BIN  stashboard/static/images/icons/iconic/read_more.png
  180. BIN  stashboard/static/images/icons/iconic/right_quote.png
  181. BIN  stashboard/static/images/icons/iconic/right_quote_alt.png
  182. BIN  stashboard/static/images/icons/iconic/rss.png
  183. BIN  stashboard/static/images/icons/iconic/rss_alt.png
  184. BIN  stashboard/static/images/icons/iconic/spin_alt.png
  185. BIN  stashboard/static/images/icons/iconic/star.png
  186. BIN  stashboard/static/images/icons/iconic/stop.png
  187. BIN  stashboard/static/images/icons/iconic/sun.png
  188. BIN  stashboard/static/images/icons/iconic/tag_fill.png
  189. BIN  stashboard/static/images/icons/iconic/tag_stroke.png
  190. BIN  stashboard/static/images/icons/iconic/trash_fill.png
  191. BIN  stashboard/static/images/icons/iconic/trash_stroke.png
  192. BIN  stashboard/static/images/icons/iconic/undo.png
  193. BIN  stashboard/static/images/icons/iconic/x_alt.png
  194. 0  { → stashboard}/static/images/logo.png
  195. BIN  stashboard/static/images/mustacheman.png
  196. BIN  stashboard/static/images/oauth_logo.jpg
  197. 0  { → stashboard}/static/images/poweredbystash.png
  198. 0  { → stashboard}/static/images/small-information.png
  199. 0  { → stashboard}/static/images/sub-nav-selected-arrow.png
  200. 0  { → stashboard}/static/images/widget/blue.png
  201. 0  { → stashboard}/static/images/widget/green.png
  202. 0  { → stashboard}/static/images/widget/red.png
  203. 0  { → stashboard}/static/images/widget/yellow.png
  204. +37 −0 stashboard/static/js/admin.js
  205. +27 −0 stashboard/static/js/backbone.js
  206. 0  { → stashboard}/static/js/prettify.js
  207. +65 −0 stashboard/static/js/stashboard.js
  208. +26 −0 stashboard/static/js/underscore.js
  209. 0  {static → stashboard/static/js}/widget/statusalert.js
  210. +15 −0 stashboard/templates/404.html
  211. +11 −0 stashboard/templates/_legend.html
  212. +27 −0 stashboard/templates/admin/admin.html
  213. +51 −0 stashboard/templates/admin/credentials.html
  214. +30 −0 stashboard/templates/admin/events_create.html
  215. +17 −0 stashboard/templates/admin/events_delete.html
  216. +24 −0 stashboard/templates/admin/events_note.html
  217. +23 −0 stashboard/templates/admin/migrations.html
  218. +21 −0 stashboard/templates/admin/services.html
  219. +30 −0 stashboard/templates/admin/services_create.html
  220. +17 −0 stashboard/templates/admin/services_delete.html
  221. +60 −0 stashboard/templates/admin/services_instance.html
  222. +15 −0 stashboard/templates/admin/setup.html
  223. +21 −0 stashboard/templates/admin/status.html
  224. +45 −0 stashboard/templates/admin/status_create.html
  225. +17 −0 stashboard/templates/admin/status_delete.html
  226. +45 −0 stashboard/templates/admin/status_edit.html
  227. 0  {views/default → stashboard/templates}/authentication.html
  228. +49 −0 stashboard/templates/base.html
  229. 0  {views/default → stashboard/templates}/basic/_legend.html
  230. 0  {views/default → stashboard/templates}/basic/base.html
  231. 0  {views/default → stashboard/templates}/basic/index.html
  232. 0  {views/default → stashboard/templates}/basic/service.html
  233. +39 −0 stashboard/templates/documentation.html
  234. +241 −0 stashboard/templates/examples.html
  235. +45 −0 stashboard/templates/index.html
  236. 0  {views/default → stashboard/templates}/notfound.html
  237. 0  {views/default → stashboard/templates}/overview.html
  238. 0  {views/default → stashboard/templates}/post.html
  239. 0  {views/default → stashboard/templates}/profile.html
  240. 0  {views/default → stashboard/templates}/restapi.html
  241. +53 −0 stashboard/templates/service.html
  242. 0  {views/default → stashboard/templates}/statusform.html
  243. 0  {views/default → stashboard/templates}/unauthorized.html
  244. 0  { → stashboard}/utils/__init__.py
  245. +118 −0 stashboard/utils/authorized.py
  246. 0  { → stashboard}/utils/slugify.py
  247. BIN  static/css/images/button_bg.png
  248. BIN  static/css/images/datepicker.gif
  249. BIN  static/css/images/icon_sprite.png
  250. BIN  static/css/images/progress_bar.gif
  251. BIN  static/css/images/slider_h_bg.gif
  252. BIN  static/css/images/slider_handles.png
  253. BIN  static/css/images/slider_v_bg.gif
  254. BIN  static/css/images/tab_bg.gif
  255. BIN  static/css/images/the_gradient.gif
  256. BIN  static/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png
  257. BIN  static/css/images/ui-bg_diagonals-thick_20_666666_40x40.png
  258. BIN  static/css/images/ui-bg_flat_10_000000_40x100.png
  259. BIN  static/css/images/ui-bg_glass_100_f6f6f6_1x400.png
  260. BIN  static/css/images/ui-bg_glass_100_fdf5ce_1x400.png
  261. BIN  static/css/images/ui-bg_glass_65_ffffff_1x400.png
  262. BIN  static/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png
  263. BIN  static/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
  264. BIN  static/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
  265. BIN  static/css/images/ui-icons_222222_256x240.png
  266. BIN  static/css/images/ui-icons_228ef1_256x240.png
  267. BIN  static/css/images/ui-icons_ef8c08_256x240.png
  268. BIN  static/css/images/ui-icons_ffd27a_256x240.png
  269. BIN  static/css/images/ui-icons_ffffff_256x240.png
  270. +0 −519 static/css/jqueryui.css
  271. +0 −53 static/css/reset.css
  272. +0 −214 static/css/style.css
  273. BIN  static/images/status/address-book--arrow.png
  274. BIN  static/images/status/address-book--exclamation.png
  275. BIN  static/images/status/address-book--minus.png
  276. BIN  static/images/status/address-book--pencil.png
  277. BIN  static/images/status/address-book--plus.png
  278. BIN  static/images/status/address-book-blue.png
  279. BIN  static/images/status/address-book-open.png
  280. BIN  static/images/status/address-book.png
  281. BIN  static/images/status/alarm-clock--arrow.png
  282. BIN  static/images/status/alarm-clock--exclamation.png
  283. BIN  static/images/status/alarm-clock--minus.png
  284. BIN  static/images/status/alarm-clock--pencil.png
  285. BIN  static/images/status/alarm-clock--plus.png
  286. BIN  static/images/status/alarm-clock-blue.png
  287. BIN  static/images/status/alarm-clock-select-remain.png
  288. BIN  static/images/status/alarm-clock-select.png
  289. BIN  static/images/status/alarm-clock.png
  290. BIN  static/images/status/anchor.png
  291. BIN  static/images/status/application--arrow.png
  292. BIN  static/images/status/application--exclamation.png
  293. BIN  static/images/status/application--minus.png
  294. BIN  static/images/status/application--pencil.png
  295. BIN  static/images/status/application--plus.png
  296. BIN  static/images/status/application-block.png
  297. BIN  static/images/status/application-blog.png
  298. BIN  static/images/status/application-blue.png
  299. BIN  static/images/status/application-browser.png
  300. BIN  static/images/status/application-detail.png
Sorry, we could not display the entire diff because too many files (2,926) changed.
View
35 .gitignore
@@ -1,5 +1,30 @@
-*.pyc
-.DS_Store
-.project
-.pydevproject
-*~
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+#Sphnix
+docs/_build
View
23 ChangeLog
@@ -1,4 +1,25 @@
+ChangeLog
+===========
+
+
+2011.11.27, Version 1.5
+-------------------------
+
+* Rewrite frontend to use memcache and templating instead of client-side javascript
+
+* Add test coverage for REST API
+
+* Add a new admin section
+
+* All destructive API calls now must go through the "/admin/api/v1" endpoint
+
+* Add a "Report Incident" button
+
+
+
2010.07.22, Version 1.1.4
+--------------------------
+
* Changed the front page to use the proper date range for events
* Fix the rfc1123() to handle -ve timezone offset (Barnaby Gray)
@@ -8,3 +29,5 @@
* Fix small spelling error in common.js
* Added a favicon
+
+
View
52 README.md
@@ -1,43 +1,53 @@
# Stashboard
-## About
-
-Stashboard was written by Twilio to provide status information on our phone, SMS, and Communication APIs. We open sourced the code and to provide a generic status page designed to be customized by any hosted services company to provide customers up-to-date status information. The code can be downloaded, customized with your logo, and run on any Google App Engine account.
+Stashboard was written by Twilio to provide status information on our phone, SMS, and Communication APIs. We open sourced the code to provide a generic status page designed to be customized by any hosted services company to provide customers up-to-date status information. The code can be downloaded, customized with your logo, and run on any Google App Engine account.
## Installation
-First, install the App Engine SDK for Python.
+1. Download and install the [App Engine SDK for Python][appengine]
+2. `git clone git://github.com/twilio/stashboard.git`
+3. Add your application id to `app.yaml`
+4. Open the SDK, choose `File > Add Existing Application...` and select the `stashboard` folder inside the cloned repository
+5. Update the settings in `settings.py`
+6. Visit http://your-app-id.appspot.com/admin/setup to complete the installation
-Next, download and extract Stashboard to your computer.
+From here you can either run Stashboard locally in the [App Engine development environment][local] or [deploy to Appspot][deploy].
+See the [Getting Started](http://code.google.com/appengine/docs/python/gettingstarted) guide for a basic overview of the App Engine platform.
-### Run Locally
+[local]: http://code.google.com/appengine/docs/python/gettingstarted/devenvironment.html
+[deploy]: http://code.google.com/appengine/docs/python/gettingstarted/uploading.html
+[appengine]: http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Python
-Open the SDK, choose File > Add Existing Application..., select the stashboard folder you downloaded above and choose a port. Press Run and navigate to http://localhost:{port} to see your Stashboard installation.
+## Demo
-### Deploy to AppSpot
+The most recent version of Stashboard lives at http://stashboard.appspot.com
-Before you can deploy Stashboard, you will need to create an application on App Engine.
+## Documentation
-Once your application is registered, open app.yaml in the Stashboard directory and change application-id to the name of your newly created application.
+Full documentation can be found on [Read The Docs](http://readthedocs.org/docs/stashboard/en/latest)
-Hit the 'Deploy' button, wait a couple of seconds, and then naviagate to http://{app-name}.appspot.com to enjoy your new status dashboard
+## Community
-## Basic View
+All Stashboard development and discussion happens in the [Stashboard google group](https://groups.google.com/forum/#!forum/stashboard)
-By default, Stashboard exposes a rich client, utilizing AJAX and jQuery. If instead you just want a basic read only view, change the `rich_client` attribute to `False` in `config.py`.
+To keep up to date, you can follow [@stashboard](http://twitter.com/stashboard) on Twitter or join the [#stashboard](irc://irc.freenode.net/stashboard) channel on freenode
-## REST API
+## Development
-Full documentation of the REST API can be found at <http://stashboard.appspot.com/documentation/rest>
+You'll need to install a couple more packages to hack on Stashboard
+
+ pip install -r requirements.txt
-## Community
+To run the unit tests,
-All Stashboard development and discussion happens in the [Stashboard google group](https://groups.google.com/forum/#!forum/stashboard)
-
-To keep up to date, you can follow [@stashboard](http://twitter.com/stashboard) on Twitter or join the [#stashboard](irc://irc.freenode.net/stashboard) channel on freenode
+ python tests/runner.py tests
## Future
-Future plans include RSS feeds, Web Hook integration, and a richer support for different status page views.
-
+The [roadmap](https://github.com/twilio/stashboard/wiki/Roadmap) details future plans for Stashboard.
+## Acknowledgements
+* Buttons by [Necolas](https://github.com/necolas/css3-github-buttons)
+* Fugue icons by [Yusuke Kamiyamane](http://p.yusukekamiyamane.com/)
+* Iconic icons by [P.J. Onori](http://somerandomdude.com/projects/iconic/)
+* OAuth support via [simplegeo/python-oauth2](https://github.com/simplegeo/python-oauth2)
View
56 app.yaml
@@ -1,56 +0,0 @@
-application: stashboard
-version: 1
-runtime: python
-api_version: 1
-
-derived_file_type:
-- python_precompiled
-
-handlers:
-# URLS for testing
-#- url: /tests
-# static_dir: testing
-# login: required
-
-#- url: /runner
-# script: runner.py
-# login: required
-
-- url: /css
- static_dir: static/css
-
-- url: /images
- static_dir: static/images
-
-- url: /js
- static_dir: static/js
-
-- url: /widget
- static_dir: static/widget
-
-- url: /favicon\.ico
- static_files: static/favicon.ico
- upload: static/favicon.ico
-
-- url: /robots\.txt
- static_files: static/robots.txt
- upload: static/robots.txt
-
-- url: .*
- script: main.py
- secure: optional
-
-skip_files: |
- ^(.*/)?(
- (#.*#)|
- (.*~)|
- (.*\.py[co])|
- (.*/RCS/.*)|
- (\..*)|
- (dev/.*)|
- (tests/.*)|
- (docs/.*)|
- (.*\.markdown)|
- (license\.txt)|
- (setup.py)
- )$
View
49 config.py
@@ -1,49 +0,0 @@
-# Copyright (c) 2010 Twilio Inc.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-import os
-import logging
-
-from google.appengine.dist import use_library
-use_library('django', '1.2')
-
-APP_ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
-
-#Stashboard version
-VERSION = "1.1.6"
-
-# If we're debugging, turn the cache off, etc.
-# Set to true if we want to have our webapp print stack traces, etc
-DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev')
-logging.info("Starting application in DEBUG mode: %s", DEBUG)
-
-SITE = {
- "html_type": "text/html",
- "charset": "utf-8",
- "title": "Stashboard",
- "author": "Kyle Conroy",
- # This must be the email address of a registered administrator for the
- # application due to mail api restrictions.
- "email": "kyle.j.conroy@gmail.com",
- "description": "A RESTful Status Tracker on top of App Engine.",
- "root_url": "http://stashboard.appspot.com",
- "template_path": os.path.join(APP_ROOT_DIR, "views/default"),
- "rich_client": True, #If false, the website will go into a simplified read-only view
-}
View
130 docs/Makefile
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Stashboard.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Stashboard.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Stashboard"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Stashboard"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
View
79 docs/_static/examples/example.php
@@ -0,0 +1,79 @@
+<?php
+
+require_once('OAuth.php');
+
+$consumer_key = 'anonymous';
+$consumer_secret = 'anonymous';
+$oauth_key = 'ACCESS_TOKEN';
+$oauth_secret = 'ACCESS_SECRET';
+$app_id = "stashboard";
+
+$consumer = new OAuthConsumer($consumer_key, $consumer_secret);
+$token = new OAuthToken($oauth_key, $oauth_secret);
+
+// Set up a request function
+function request($consumer, $token, $url, $method = "GET", $data = null) {
+
+ $sign = new OAuthSignatureMethod_HMAC_SHA1();
+ $request = OAuthRequest::from_consumer_and_token(
+ $consumer, $token, $method, $url, $data
+ );
+
+ $request->sign_request($sign, $consumer, $token);
+ $ch = curl_init($request->get_normalized_http_url());
+
+ if ($method == "POST") {
+ curl_setopt($ch, CURLOPT_POST ,1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS , $request->to_postdata());
+ }
+
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION ,1);
+ curl_setopt($ch, CURLOPT_HEADER ,0); // DO NOT RETURN HTTP HEADERS
+
+ return curl_exec($ch);
+}
+
+// Fill in your website
+$base_url = "https://$app_id.appspot.com/api/v1";
+
+$data = array(
+ "name" => "An Example Service",
+ "description" => "An example service, created "
+ . "using the StashBoard API",
+ );
+
+$r = request($consumer, $token, $base_url . "/services", "POST", $data);
+$service = json_decode($r);
+
+// GET the list of possible status images
+$r = request($consumer, $token, $base_url . "/status-images", "GET");
+$data = json_decode($r);
+$images = $data->images;
+
+// Pick a the first image
+$image = $images[0];
+
+// POST to the Statuses Resources to create a new Status
+$data = array(
+ "name" => "Example Status",
+ "description" => "An example status, means nothing",
+ "severity" => 10000,
+ "image" => $image->name,
+ );
+
+$r = request($consumer, $token, $base_url . "/statuses", "POST", $data);
+$status = json_decode($r);
+
+// Create a new event with the given status and given service
+$data = array(
+ "message" => "Our first event! So exciting",
+ "status" => $status->id,
+ );
+
+$r = request($consumer, $token, $service->url . "/events", "POST", $data);
+$event = json_decode($r);
+
+print_r($event);
+
View
64 docs/_static/examples/example.py
@@ -0,0 +1,64 @@
+import oauth2 as oauth
+import json
+import urllib
+import unittest
+import random
+
+# Stashboard application id
+app_id = "stashboard"
+
+# These keys can be found at /admin/credentials
+consumer_key = 'anonymous'
+consumer_secret = 'anonymous'
+oauth_key = 'ACCESS_TOKEN'
+oauth_secret = 'ACCESS_SECRET'
+
+# Create your consumer with the proper key/secret.
+# If you register your application with google, these values won't be
+# anonymous and anonymous.
+consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
+token = oauth.Token(oauth_key, oauth_secret)
+
+# Create our client.
+client = oauth.Client(consumer, token=token)
+
+# Base url for all rest requests
+base_url = "https://%s.appspot.com/api/v1" % app_id
+
+
+# CREATE a new service
+data = urllib.urlencode({
+ "name": "Generic Web Service",
+ "description": "An example web service or REST API",
+ })
+
+resp, content = client.request(base_url + "/services",
+ "POST", body=data)
+service = json.loads(content)
+
+# GET the list of possible status images
+resp, content = client.request(base_url + "/status-images", "GET")
+data = json.loads(content)
+images = data["images"]
+
+# Pick a random image for our status
+image = random.choice(images)
+
+# POST to the Statuses Resources to create a new Status
+data = urllib.urlencode({
+ "name": "Up",
+ "description": "The web service is up and running",
+ "image": image["name"],
+})
+
+resp, content = client.request(base_url + "/statuses", "POST", body=data)
+status = json.loads(content)
+
+# Create a new event with the given status and given service
+data = urllib.urlencode({
+ "message": "Our first event! So exciting",
+ "status": status["id"],
+})
+
+resp, content = client.request(service["url"] + "/events", "POST", body=data)
+event = json.loads(content)
View
50 docs/_static/examples/example.rb
@@ -0,0 +1,50 @@
+require 'rubygems'
+require 'oauth'
+require 'json'
+
+oauth_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
+oauth_secret = 'YYYYYYYYYYYYYYYYYYYYYYYY'
+
+# Fill in your website
+base = "https://stashboard.appspot.com"
+
+@consumer=OAuth::Consumer.new "anonymous",
+ "anonymous",
+ {:site=>base}
+
+@token = OAuth::AccessToken.new(@consumer, oauth_key, oauth_secret)
+
+# POST to the Services Resource to create a new service. Save the response for
+# later
+@response = @token.post("/api/v1/services", {
+ :name => "An Example Service",
+ :description => "An example service, created using the StashBoard API",
+})
+srvice = JSON.parse(@response.body)
+
+# GET the list of possible status images
+@response = @token.get("/api/v1/status-images")
+data = JSON.parse(@response.body)
+images = data['images']
+
+# Pick a random image for our status
+image = images[rand(images.length)]
+
+
+# POST to the Statuses Resources to create a new Status
+@response = @token.post("/api/v1/statuses", {
+ :name => "Example Status",
+ :description => "An example status, means nothing",
+ :severity => 10000,
+ :image => image["name"],
+})
+
+status = JSON.parse(@response.body)
+
+@response = @token.post("/api/v1/services/" + srvice["id"] + "/events", {
+ :message => "Our first event! So exciting",
+ :status => status["id"],
+})
+event = JSON.parse(@response.body)
+
+puts event
View
216 docs/conf.py
@@ -0,0 +1,216 @@
+# -*- coding: utf-8 -*-
+#
+# Stashboard documentation build configuration file, created by
+# sphinx-quickstart on Thu May 19 00:03:13 2011.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Stashboard'
+copyright = u'2011, Twilio'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.5'
+# The full version, including alpha/beta/rc tags.
+release = '1.5.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Stashboarddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Stashboard.tex', u'Stashboard Documentation',
+ u'Twilio', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'stashboard', u'Stashboard Documentation',
+ [u'Twilio'], 1)
+]
View
22 docs/examples.rst
@@ -0,0 +1,22 @@
+========================
+REST API Examples
+========================
+
+PHP
+-------
+
+.. literalinclude:: _static/examples/example.php
+ :language: php
+
+Ruby
+--------
+
+.. literalinclude:: _static/examples/example.rb
+ :language: ruby
+
+Python
+--------
+
+.. literalinclude:: _static/examples/example.py
+ :language: python
+
View
20 docs/help.rst
@@ -0,0 +1,20 @@
+Community
+=============
+
+Can't seem to get Stashboard up and running? We're always here to help
+
+Google Group
+-------------
+All Stashboard development and discussion happens in the `Stashboard google group <https://groups.google.com/forum/#!forum/stashboard>`_
+
+IRC
+----
+Join the `#stashboard <irc://irc.freenode.net/stashboard>`_ channel on freenode
+
+Twitter
+---------
+To keep up to date, you can follow `@stashboard <http://twitter.com/stashboard>`_ on Twitter
+
+Wiki and Issue Tracker
+----------------------
+Hosted on the `stashboard Github repository <http://github.com/twilio/stashboard>`_.
View
29 docs/index.rst
@@ -0,0 +1,29 @@
+.. Stashboard documentation master file, created by
+ sphinx-quickstart on Thu May 19 00:03:13 2011.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+==========
+Stashboard
+==========
+
+About
+=====
+
+Stashboard was written by Twilio to provide status information on our phone, SMS, and Communication APIs. We open sourced the code and to provide a generic status page designed to be customized by any hosted services company to provide customers up-to-date status information. The code can be downloaded, customized with your logo, and run on any Google App Engine account.
+
+User's Guide
+=============
+
+A complete guide to installing, running, and developing Stashboard
+
+.. toctree::
+ :maxdepth: 2
+
+ quickstart
+ help
+ restapi
+ examples
+
+
+
View
170 docs/make.bat
@@ -0,0 +1,170 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Stashboard.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Stashboard.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
View
30 docs/quickstart.rst
@@ -0,0 +1,30 @@
+Getting Started
+=================
+
+Running Locally
+----------------
+
+Download and install the `App Engine SDK for Python <http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Python>`_.
+
+You'll then need to checkout the Stashboard repository.
+
+.. code-block:: bash
+
+ git clone git://github.com/twilio/stashboard.git`
+
+Open the SDK, choose ``File > Add Existing Application...`` and select the ``stashboard`` folder inside the cloned repository. Then click the green "Run" button to start the application.
+
+Visit http://localhost:8080/admin/setup to complete the installation.
+
+Customzing
+-------------
+Open the ``settings.py`` file and change the ``SITE_NAME``, ``SITE_URL``, and ``REPORT_URL`` options to the desired values. The ``CONSUMER_KEY`` and ``CONSUMER_SECRET`` values don't need to be changed
+
+Deploying
+-------------
+
+Before you can deploy to Appspot, you'll need to `create an application on App Engine <https://appengine.google.com/start/createapp>`_. Once you've done that, update the ``app.yaml`` with your application id.
+
+Hit the "Deploy" button, wait a couple of seconds, and then naviagate to ``http://{application-id}.appspot.com`` to enjoy your new status dashboard.
+
+**REMINDER:** You need to go to ``http://{application-id}.appspot.com/admin/setup`` to complete your installation.
View
634 docs/restapi.rst
@@ -0,0 +1,634 @@
+========================
+REST API Documentation
+========================
+
+The Stashboard REST API is split in two portions. The public facing REST API only responds to GET and lives at the ``/api/v1/`` endpoint. This API requires no authentication.
+
+The admin-only REST API lives at the ``/admin/api/v1/`` endpoint and responsds to GET, POST, PUT, and DELETE. You'll need to authenticate via OAuth. You can obtain your OAuth keys on the OAuth Credentials page at ``https://{application-id}.appspot.com/admin/credentials``
+
+Services
+----------
+
+The Services resource represents all web services currently tracked via Stashboard.
+
+============== ===============
+Property Description
+============== ===============
+id The unique identifier by which to identify the service
+name The name of the service, defined by the user
+description The description of the web service
+current-event The current event for the service
+url The URL of the specific service resource
+============== ===============
+
+List Resource
+~~~~~~~~~~~~~~~
+
+.. code-block:: text
+
+ /admin/api/v1/services
+
+GET
++++++
+
+Returns a list of all current services tracked by Stashboard
+
+.. code-block:: bash
+
+ GET /admin/api/v1/services HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "services": [
+ {
+ "name": "Example Foo",
+ "id": "example-foo",
+ "description": "An explanation of this service"
+ "url": "/api/v1/services/example-foo",
+ "current-event": {
+ 'message': 'What an event!',
+ 'sid': 'ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M',
+ 'status': {
+ 'description': 'Hey, dude',
+ 'id': 'up',
+ 'image': '/images/status/tick-circle.png',
+ 'level': 'NORMAL',
+ 'name': 'Up',
+ 'url': '/statuses/up'
+ },
+ 'timestamp': 'Mon, 28 Jun 2010 22:17:06 GMT',
+ 'url': '/services/twilio/events/ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M'},
+
+ },
+ {
+ "name": "Example Bar",
+ "id": "example-bar",
+ "description": "An explanation of this service"
+ "url": "/api/v1/services/example-bar",
+ "current-event": null,
+ }
+ ]
+ }
+
+
+POST
+++++++
+
+Creates a new service (or updates an existing service) and returns the new service object.
+
+============== ===============
+Param Description
+============== ===============
+name Name of the service
+description Description of service
+============== ===============
+
+.. code-block:: text
+
+ POST /admin/api/v1/services HTTP/1.1 name=New%20Service&description=A%20great%20service
+
+.. code-block:: js
+
+ {
+ "name": "New Service",
+ "id": "new-service",
+ "description": "A great service"
+ "url": "/api/v1/services/new-service",
+ "current-event": null,
+ }
+
+
+
+Instance Resource
+~~~~~~~~~~~~~~~~~~
+
+.. code-block:: text
+
+ /admin/api/v1/services/{service}
+
+The Service Instance resources represents an individual web service tracked by StashBoard
+
+GET
+++++
+
+.. code-block:: bash
+
+ GET /admin/api/v1/services/{service} HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "name": "Example Service",
+ "id": "example-service",
+ "description": "An explanation of what this service represents"
+ "url": "/api/v1/services/example-service",
+ "current-event": null,
+ }
+
+POST
++++++
+
+Updates a service's description and returns the updated service object. All the listed parameters are optional.
+
+============== ===============
+Param Description
+============== ===============
+name Name of the service
+description Description of service
+============== ===============
+
+.. code-block:: text
+
+ POST /admin/api/v1/services/{service} description=System%20is%20now%20operational
+
+.. code-block:: js
+
+ {
+ "name": "Example Service",
+ "id": "example-service",
+ "description": "System is now operational",
+ "url": "/api/v1/services/example-service",
+ "current-event": null,
+ }
+
+
+DELETE
++++++++
+
+Deletes a service and returns the deleted service object
+
+.. code-block:: text
+
+ DELETE /admin/api/v1/services/{service} HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "name": "Example Service",
+ "id": "example-service",
+ "description": "System is now operational",
+ "url": "/api/v1/services/example-service",
+ "current-event": null,
+ }
+
+Events
+-----------
+
+The Events List resource represents all event associated with a given service
+
+
+============== ===============
+Property Description
+============== ===============
+sid The unique identifier by which to identify the event
+message The message associated with this event
+timestamp The time at which this event occurred, given in RFC 1132 format.
+url The URL of the specific event resource
+status The status of this event, as described by the Statuses resource
+============== ===============
+
+
+List Resource
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: text
+
+ /admin/api/v1/services/{service}/events
+
+GET
+++++
+
+Returns all events associated with a given service in reverse chronological order.
+
+.. code-block:: text
+
+ GET /admin/api/v1/services/{service}/events HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "events": [
+ {
+ "timestamp": "Mon, 28 Jun 2010 22:17:06 GMT",
+ "message": "Problem fixed",
+ "sid": "ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GBAM",
+ "url": "/api/v1/services/example-service/events/ahJpc215d2Vic2VydmljZWRvd2",
+ "status": {
+ "id": "down",
+ "name": "Down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ },
+ },
+ {
+ "timestamp": "Mon, 28 Jun 2010 22:18:06 GMT",
+ "message": "Might be up",
+ "sid": "ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "url": "/api/v1/services/example-service/events/ahJpc215d2Vic..."
+ "status": {
+ "id": "down",
+ "name": "Down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ },
+ }
+ ]
+ }
+
+The Events List resource also supports filtering events via dates. To filter events, place on of the following options into the query string for a GET request
+
+While the format of these parameters is very flexible, we suggested either the RFC 2822 or RFC 1123 format due to their support for encoding timezone information.
+
+Events List URL Filtering Options
+
+======= ============
+Option Description
+======= ============
+start Only show events which started after this date, inclusive.
+end Only show events which started before date, inclusive.
+======= ============
+
+.. code-block:: text
+
+ GET /admin/api/v1/services/{service}/events?start=2010-06-10 HTTP/1.1
+
+would return all events starting after June 6, 2010.
+
+Similarly, both "start" and "end" can be used to create date ranges
+
+.. code-block:: text
+
+ GET /admin/api/v1/services/{service}/events?end=2010-06-17&start=2010-06-01 HTTP/1.1
+
+would return all events between June 6, 2010 and June 17, 2010
+
+
+
+POST
++++++
+
+Creates a new event for the given service and returns the newly created event object. All arguments are required.
+
+======== ==============
+Param Description
+======== ==============
+status The system status for the event. This must be a valid system status identifier found in the Statuses List resource
+message The message for the event
+======== ==============
+
+.. code-block:: text
+
+ POST /admin/api/v1/services/{service}/events HTTP/1.1 status=AVAILABLE&message=System%20is%20now%20operational
+
+.. code-block:: js
+
+ {
+ "timestamp": "Mon, 28 Jun 2010 22:18:06 GMT"
+ "message": "Might be up",
+ "sid": "ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "url": "/api/v1/services/example-service/events/ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "status": {
+ "id": "down",
+ "name": "Down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ },
+ }
+
+Current Event
+~~~~~~~~~~~~~~~~~
+
+The Current Service Event resource simply returns the current event for a given service.
+
+.. code-block:: text
+
+ /admin/api/v1/services/{service}/events/current
+
+GET
+++++
+
+Returns the current event for a given service.
+
+.. code-block:: text
+
+ GET /admin/api/v1/services/{service}/events/current HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "timestamp": "Mon, 28 Jun 2010 22:17:06 GMT",
+ "message": "Might be up",
+ "sid": "ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "url": "/api/v1/services/example-service/events/ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "status": {
+ "id": "down",
+ "name": "Down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ },
+ }
+
+Instance Resource
+~~~~~~~~~~~~~~~~~~~~
+
+The Event Instance resource represents an individual event for a given service.
+
+.. code-block:: text
+
+ /admin/api/v1/services/{service}/events/{sid}
+
+GET
+++++
+
+Returns a service event with the given event sid. The event's status object is also returned as well.
+
+.. code-block:: text
+
+ GET /admin/api/v1/services/{service}/events/{sid} HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "timestamp": "Mon, 28 Jun 2010 22:17:06 GMT",
+ "message": "Might be up",
+ "sid": "ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "url": "/api/v1/services/example-service/events/ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "status": {
+ "id": "down",
+ "name": "Down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ }
+ }
+
+
+DELETE
+++++++++
+
+Deletes the given event and returns the deleted event
+
+.. code-block:: text
+
+ DELETE /admin/api/v1/services/{service}/events/{sid} HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "timestamp": "Mon, 28 Jun 2010 22:17:06 GMT",
+ "message": "Might be up",
+ "sid": "ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "url": "/api/v1/services/example-service/events/ahJpc215d2Vic2VydmljZWRvd25yCwsSBUV2ZW50GA8M",
+ "status": {
+ "id": "down",
+ "name": "Down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/statuses/down",
+ },
+ }
+
+Statuses
+-----------
+The Status resource represents a possible status for a service.
+
+============== ===============
+Property Description
+============== ===============
+id The unique identifier by which to identify the status
+name The name of the status, defined by the user
+description The description of the status
+url The URL of the specific status resource
+level The level of this status. Can be any value listed in the Levels List resource
+image The URL of the image for this status
+============== ===============
+
+List Resource
+~~~~~~~~~~~~~~~~
+
+.. code-block:: text
+
+ /admin/api/v1/statuses
+
+
+The Status List resource represents all possible systems statuses.
+
+
+GET
++++++
+
+Returns all service statuses
+
+.. code-block:: text
+
+ GET /admin/api/v1/statuses HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "statuses": [
+ {
+ "name": "Available",
+ "id": "available",
+ "description": "An explanation of what this status represents",
+ "level": "NORMAL",
+ "image": "/images/status/tick-circle.png",
+ "url": "api/v1/statuses/up",
+ },
+ {
+ "name": "Down",
+ "id": "down",
+ "description": "An explanation of what this status represents",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "api/v1/statuses/down",
+ },
+ ]
+ }
+
+POST
+++++++
+
+Creates a new status and returns this newly created status. All parameters are required.
+
+============ ==============
+Param Description
+============ ==============
+name The name of the status
+description The description of the status
+level The level of the status. lues listed in the rce
+image The filename of the image, with no extension. See the status-images resource
+============ ==============
+
+.. code-block:: text
+
+ POST /admin/api/v1/statuses HTTP/1.1 name=Down&description=A%20new%20status&severity=1000&image=cross-circle.png
+
+.. code-block:: js
+
+ {
+ "name": "Down",
+ "id": "down"
+ "description": "A new status",
+ "level": "ERROR",
+ "image": "cross-circle",
+ "url": "/api/v1/statuses/down",
+ }
+
+Instance Resource
+~~~~~~~~~~~~~~~~~~~~~
+
+The Status Instance resource represents a single service status
+
+.. code-block:: text
+
+ /admin/api/v1/statuses/{name}
+
+
+GET
++++++
+
+Returns a status object
+
+.. code-block:: text
+
+ GET /admin/api/v1/services HTTP/1.1
+
+.. code-block:: js
+
+ {
+ "name": "Down",
+ "id": "down",
+ "description": "A new status",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ }
+
+POST
+++++++
+
+Update the given status. All the following parameters are optional.
+
+============ ==============
+Param Description
+============ ==============
+name The name of the status
+description The description of the status
+level The level of the status. lues listed in the rce
+image The filename of the image, with no extension. See the status-images resource
+============ ==============
+
+.. code-block:: text
+
+ POST /admin/api/v1/statuses HTTP/1.1 description=A%20new%20status&severity=1010&image=cross-circle.png
+
+.. code-block:: js
+
+ {
+ "name": "Down",
+ "id": "down",
+ "description": "A new status",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ }
+
+DELETE
++++++++++
+
+Delete the given status and return the deleted status
+
+
+.. code-block:: text
+
+ DELETE /admin/api/v1/statuses/{name}
+
+.. code-block:: js
+
+ {
+ "name": "Down",
+ "id": "down",
+ "description": "A new status",
+ "level": "ERROR",
+ "image": "/images/status/cross-circle.png",
+ "url": "/api/v1/statuses/down",
+ }
+
+Status Levels
+----------------
+The Status Levels resource is a read-only resource which lists the possible levels for a status.
+
+List Resource
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: text
+
+ /admin/api/v1/levels
+
+GET
++++++
+Returns a list of possible status levels in increasing severity
+
+.. code-block:: text
+
+ GET /admin/api/v1/levels
+
+.. code-block:: js
+
+ {
+ "levels": [
+ "INFO",
+ "NORMAL",
+ "WARNING",
+ "ERROR",
+ "CRITICAL",
+ ]
+ }
+
+
+Status Images
+----------------
+The Status Images resource is a read-only resource which lists the icons available to use for statuses
+
+List Resource
+~~~~~~~~~~~~~~~
+
+.. code-block:: text
+
+ /admin/api/v1/status-images
+
+GET
+++++++
+
+Returns a list of status images.
+
+.. code-block:: text
+
+ GET /admin/api/v1/status-images
+
+.. code-block:: js
+
+ {
+ "images": [
+ {
+ "name": "sample-image",
+ "url": "/status-images/sample-image.png",
+ },
+ {
+ "name": "sample-image",
+ "url": "/status-images/sample-image.png",
+ },
+ ]
+ }
View
80 examples/stashboard.php
@@ -1,80 +0,0 @@
-<?php
-
- require_once('OAuth.php');
-
- $consumer_key = 'anonymous';
- $consumer_secret = 'anonymous';
- $oauth_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
- $oauth_secret = 'YYYYYYYYYYYYYYYYYYYYYYYY'
-
- $consumer = new OAuthConsumer($consumer_key, $consumer_secret);
- $token = new OAuthToken($oauth_key, $oauth_secret);
-
-
- // Set up a request function
- function request($consumer, $token, $url, $method = "GET", $data = null){
-
- $sign = new OAuthSignatureMethod_HMAC_SHA1();
- $request = OAuthRequest::from_consumer_and_token(
- $consumer, $token, $method, $url, $data);
- $request->sign_request($sign, $consumer, $token);
-
- $ch = curl_init($request->get_normalized_http_url());
-
- if ($method == "POST") {
- curl_setopt($ch, CURLOPT_POST ,1);
- curl_setopt($ch, CURLOPT_POSTFIELDS , $request->to_postdata());
- }
-
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION ,1);
- curl_setopt($ch, CURLOPT_HEADER ,0); // DO NOT RETURN HTTP HEADERS
-
- return curl_exec($ch);
- }
-
- // Fill in your website
- $base_url = "https://stashboard.appspot.com/api/v1";
-
- $data = array(
- "name" => "An Example Service",
- "description" => "An example service, created using the StashBoard API",
- );
-
- $r = request($consumer, $token, $base_url . "/services", "POST", $data);
- $service = json_decode($r);
-
- // GET the list of possible status images
- $r = request($consumer, $token, $base_url . "/status-images", "GET");
- $data = json_decode($r);
- $images = $data->images;
-
-
-
- // Pick a the first image
- $image = $images[0];
-
- // POST to the Statuses Resources to create a new Status
- $data = array(
- "name" => "Example Status",
- "description" => "An example status, means nothing",
- "severity" => 10000,
- "image" => $image->name,
- );
-
- $r = request($consumer, $token, $base_url . "/statuses", "POST", $data);
- $status = json_decode($r);
-
- // Create a new event with the given status and given service
- $data = array(
- "message" => "Our first event! So exciting",
- "status" => $status->id,
- );
-
- $r = request($consumer, $token, $service->url . "/events", "POST", $data);
- $event = json_decode($r);
-
- print_r($event);
-
-
View
142 examples/stashboard.py
@@ -1,142 +0,0 @@
-import oauth2 as oauth
-import json
-import urllib
-import unittest
-
-oauth_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
-oauth_secret = 'YYYYYYYYYYYYYYYYYYYYYYYY'
-
-# Create your consumer with the proper key/secret.
-# If you register your application with google, these values won't be
-# anonymous and anonymous.
-consumer = oauth.Consumer(key='anonymous', secret='anonymous')
-token = oauth.Token(oauth_key, oauth_secret)
-
-# Fill in your website
-base_url = "https://stashboard.appspot.com/api/v1"
-
-# Create our client.
-client = oauth.Client(consumer, token=token)
-
-class ServicesTest(unittest.TestCase):
-
- def testMissingServiceName(self):
- "should return 400 Bad Data"
- data = urllib.urlencode({
- "description": "An example service API",
- })
-
- resp, content = client.request(base_url + "/services",
- "POST", body=data)
-
- self.assertEquals(resp.status, 400)
-
- def testMissingServiceDescription(self):
- "should return 400 Bad Data"
- data = urllib.urlencode({
- "name": "Some Random Name",
- })
-
- resp, content = client.request(base_url + "/services",
- "POST", body=data)
-
- self.assertEquals(resp.status, 400)
-
- def testMissingServiceData(self):
- "should return 400 Bad Data"
- resp, content = client.request(base_url + "/services", "POST")
- self.assertEquals(resp.status, 400)
-
- def testDelete(self):
- "should return 405 Method Not Allowed"
- resp, content = client.request(base_url + "/services", "DELETE")
- self.assertEquals(resp.status, 405)
-
- def testPut(self):
- "should return 411 Content Length Required"
- resp, content = client.request(base_url + "/services", "PUT")
- self.assertEquals(resp.status, 411)
-
- def testPutWithData(self):
- "should return 405 Method Not Allowed"
- data = urllib.urlencode({
- "name": "Some Random Name",
- })
- resp, content = client.request(base_url + "/services",
- "PUT", body=data)
- self.assertEquals(resp.status, 405)
-
- def testServiceLifeCycle(self):
- "should return 200 and a newly created status"
- data = urllib.urlencode({
- "name": "What a service",
- "description": "An example service API",
- })
-
- resp, content = client.request(base_url + "/services", "POST", body=data)
- service = json.loads(content)
-
- self.assertEquals(resp.status, 200)
- self.assertEquals(service["name"], "What a service")
- self.assertEquals(service["description"], "An example service API")
-
- resp, content = client.request(base_url + "/services/" + service["id"], "GET")
- service = json.loads(content)
-
- self.assertEquals(resp.status, 200)
- self.assertEquals(service["name"], "What a service")
- self.assertEquals(service["description"], "An example service API")
-
- # Update service
- data = urllib.urlencode({
- "description": "An example service API woohoo",
- })
-
- resp, content = client.request(base_url + "/services/" + service["id"],
- "POST", body=data)
- service = json.loads(content)
-
- self.assertEquals(resp.status, 200)
- self.assertEquals(service["name"], "What a service")
- self.assertEquals(service["description"], "An example service API woohoo")
-
- # Delete service
- resp, content = client.request(base_url + "/services/" + service["id"],
- "DELETE")
- service = json.loads(content)
-
- self.assertEquals(resp.status, 200)
- self.assertEquals(service["name"], "What a service")
- self.assertEquals(service["description"], "An example service API woohoo")
-
-if __name__ == '__main__':
- unittest.main()
-
-# GET the list of possible status images
-resp, content = client.request(base_url + "/status-images", "GET")
-data = json.loads(content)
-images = data["images"]
-
-# Pick a random image for our status
-image = images[0]
-
-# POST to the Statuses Resources to create a new Status
-data = urllib.urlencode({
- "name": "Example Status",
- "description": "An example status, means nothing",
- "severity": 10000,
- "image": image["name"],
-})
-
-resp, content = client.request(base_url + "/statuses", "POST", body=data)
-status = json.loads(content)
-
-# Create a new event with the given status and given service
-data = urllib.urlencode({
- "message": "Our first event! So exciting",
- "status": status["id"],
-})
-
-resp, content = client.request(service["url"] + "/events", "POST", body=data)
-event = json.loads(content)
-
View
50 examples/stashboard.rb
@@ -1,50 +0,0 @@
-require 'rubygems'
-require 'oauth'
-require 'json'
-
-oauth_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
-oauth_secret = 'YYYYYYYYYYYYYYYYYYYYYYYY'
-
-# Fill in your website
-base = "https://stashboard.appspot.com"
-
-@consumer=OAuth::Consumer.new "anonymous",
- "anonymous",
- {:site=>base}
-
-@token = OAuth::AccessToken.new(@consumer, oauth_key, oauth_secret)
-
-# POST to the Services Resource to create a new service. Save the response for
-# later
-@response = @token.post("/api/v1/services", {
- :name => "An Example Service",
- :description => "An example service, created using the StashBoard API",
-})
-srvice = JSON.parse(@response.body)
-
-# GET the list of possible status images
-@response = @token.get("/api/v1/status-images")
-data = JSON.parse(@response.body)
-images = data['images']
-
-# Pick a random image for our status
-image = images[rand(images.length)]
-
-
-# POST to the Statuses Resources to create a new Status
-@response = @token.post("/api/v1/statuses", {
- :name => "Example Status",
- :description => "An example status, means nothing",
- :severity => 10000,
- :image => image["name"],
-})
-
-status = JSON.parse(@response.body)
-
-@response = @token.post("/api/v1/services/" + srvice["id"] + "/events", {
- :message => "Our first event! So exciting",
- :status => status["id"],
-})
-event = JSON.parse(@response.body)
-
-puts event
View
11 examples/widget/example.html
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
-
- <head>
- <title>HellO!</title>
- <script type="text/javascript" src="../static/js/stashboard.js"></script>
- </head>
- <body>
- </body>
-
-</html>
View
35 examples/widget/output.html
@@ -1,35 +0,0 @@
-<!DOCTYPE html>
-<html>
-
- <head>
- <title>HellO!</title>
- <style>
- #outer {
- position: absolute;
- top: 0px;
- height: 45px;
- right: 20px;
- padding: 0px 105px 0 15px;
- line-height: 45px;
- -moz-box-shadow: 0px 0px 8px rgb(204, 204, 204);
- -moz-border-radius-bottomleft: 15px;
- -moz-border-radius-bottomright: 15px;
- border-bottom: 1px solid #ccc;
- border-left: 1px solid #ccc;
- border-right: 1px solid #ccc;
- background: #eee;
- z-index: 99;
- }
- </style>
- </head>
- <body>
- <div id="outer">
- <img style="float: left; margin: 14px 15px 0 0;"src="http://localhost:8080/images/status/cross.png" />
- <strong>Service:</strong> message
- </div>
- <div style="width: 65px; height: 70px; position: absolute; top: 0px; right: 45px; background: none repeat scroll 0% 0% rgb(204, 204, 204); -moz-border-radius-bottomleft: 15px; -moz-border-radius-bottomright: 15px; border-