flapjack 1.6.0 → 2.0.0b1

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 (301) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -6
  3. data/.gitmodules +1 -1
  4. data/.rspec +1 -1
  5. data/.ruby-version +1 -1
  6. data/.travis.yml +12 -13
  7. data/CHANGELOG.md +2 -9
  8. data/CONTRIBUTING.md +7 -2
  9. data/Gemfile +4 -13
  10. data/LICENCE +1 -0
  11. data/README.md +8 -2
  12. data/Rakefile +2 -2
  13. data/bin/flapjack +3 -12
  14. data/build.sh +4 -2
  15. data/etc/flapjack_config.toml.example +273 -0
  16. data/features/ack_after_sched_maint.feature +18 -21
  17. data/features/cli.feature +11 -71
  18. data/features/cli_flapjack-feed-events.feature +14 -15
  19. data/features/cli_flapjack-nagios-receiver.feature +12 -41
  20. data/features/cli_flapper.feature +12 -41
  21. data/features/cli_purge.feature +5 -6
  22. data/features/cli_receive-events.feature +6 -7
  23. data/features/cli_simulate-failed-check.feature +5 -6
  24. data/features/events.feature +206 -181
  25. data/features/events_check_names.feature +4 -7
  26. data/features/notification_rules.feature +144 -223
  27. data/features/notifications.feature +65 -57
  28. data/features/rollup.feature +45 -47
  29. data/features/steps/cli_steps.rb +4 -5
  30. data/features/steps/events_steps.rb +163 -373
  31. data/features/steps/notifications_steps.rb +408 -264
  32. data/features/steps/packaging-lintian_steps.rb +0 -4
  33. data/features/steps/time_travel_steps.rb +0 -26
  34. data/features/support/daemons.rb +6 -31
  35. data/features/support/env.rb +65 -74
  36. data/flapjack.gemspec +22 -24
  37. data/lib/flapjack.rb +14 -7
  38. data/lib/flapjack/cli/flapper.rb +74 -173
  39. data/lib/flapjack/cli/maintenance.rb +278 -109
  40. data/lib/flapjack/cli/migrate.rb +950 -0
  41. data/lib/flapjack/cli/purge.rb +19 -22
  42. data/lib/flapjack/cli/receiver.rb +150 -326
  43. data/lib/flapjack/cli/server.rb +8 -235
  44. data/lib/flapjack/cli/simulate.rb +42 -57
  45. data/lib/flapjack/configuration.rb +51 -37
  46. data/lib/flapjack/coordinator.rb +138 -129
  47. data/lib/flapjack/data/acknowledgement.rb +177 -0
  48. data/lib/flapjack/data/alert.rb +97 -158
  49. data/lib/flapjack/data/check.rb +611 -0
  50. data/lib/flapjack/data/condition.rb +70 -0
  51. data/lib/flapjack/data/contact.rb +226 -456
  52. data/lib/flapjack/data/event.rb +96 -184
  53. data/lib/flapjack/data/extensions/associations.rb +59 -0
  54. data/lib/flapjack/data/extensions/short_name.rb +25 -0
  55. data/lib/flapjack/data/medium.rb +428 -0
  56. data/lib/flapjack/data/metrics.rb +194 -0
  57. data/lib/flapjack/data/notification.rb +22 -281
  58. data/lib/flapjack/data/rule.rb +473 -0
  59. data/lib/flapjack/data/scheduled_maintenance.rb +244 -0
  60. data/lib/flapjack/data/state.rb +221 -0
  61. data/lib/flapjack/data/statistic.rb +112 -0
  62. data/lib/flapjack/data/tag.rb +277 -0
  63. data/lib/flapjack/data/test_notification.rb +182 -0
  64. data/lib/flapjack/data/unscheduled_maintenance.rb +159 -0
  65. data/lib/flapjack/data/validators/id_validator.rb +20 -0
  66. data/lib/flapjack/exceptions.rb +6 -0
  67. data/lib/flapjack/filters/acknowledgement.rb +23 -16
  68. data/lib/flapjack/filters/base.rb +0 -5
  69. data/lib/flapjack/filters/delays.rb +53 -43
  70. data/lib/flapjack/filters/ok.rb +23 -14
  71. data/lib/flapjack/filters/scheduled_maintenance.rb +3 -3
  72. data/lib/flapjack/filters/unscheduled_maintenance.rb +12 -3
  73. data/lib/flapjack/gateways/aws_sns.rb +65 -49
  74. data/lib/flapjack/gateways/aws_sns/alert.text.erb +2 -2
  75. data/lib/flapjack/gateways/aws_sns/alert_subject.text.erb +2 -2
  76. data/lib/flapjack/gateways/aws_sns/rollup_subject.text.erb +1 -1
  77. data/lib/flapjack/gateways/email.rb +107 -90
  78. data/lib/flapjack/gateways/email/alert.html.erb +19 -18
  79. data/lib/flapjack/gateways/email/alert.text.erb +20 -14
  80. data/lib/flapjack/gateways/email/alert_subject.text.erb +2 -1
  81. data/lib/flapjack/gateways/email/rollup.html.erb +14 -13
  82. data/lib/flapjack/gateways/email/rollup.text.erb +13 -10
  83. data/lib/flapjack/gateways/jabber.rb +679 -671
  84. data/lib/flapjack/gateways/jabber/alert.text.erb +9 -6
  85. data/lib/flapjack/gateways/jsonapi.rb +164 -350
  86. data/lib/flapjack/gateways/jsonapi/data/join_descriptor.rb +44 -0
  87. data/lib/flapjack/gateways/jsonapi/data/method_descriptor.rb +21 -0
  88. data/lib/flapjack/gateways/jsonapi/helpers/headers.rb +63 -0
  89. data/lib/flapjack/gateways/jsonapi/helpers/miscellaneous.rb +136 -0
  90. data/lib/flapjack/gateways/jsonapi/helpers/resources.rb +227 -0
  91. data/lib/flapjack/gateways/jsonapi/helpers/serialiser.rb +313 -0
  92. data/lib/flapjack/gateways/jsonapi/helpers/swagger_docs.rb +322 -0
  93. data/lib/flapjack/gateways/jsonapi/methods/association_delete.rb +115 -0
  94. data/lib/flapjack/gateways/jsonapi/methods/association_get.rb +288 -0
  95. data/lib/flapjack/gateways/jsonapi/methods/association_patch.rb +178 -0
  96. data/lib/flapjack/gateways/jsonapi/methods/association_post.rb +116 -0
  97. data/lib/flapjack/gateways/jsonapi/methods/metrics.rb +71 -0
  98. data/lib/flapjack/gateways/jsonapi/methods/resource_delete.rb +119 -0
  99. data/lib/flapjack/gateways/jsonapi/methods/resource_get.rb +186 -0
  100. data/lib/flapjack/gateways/jsonapi/methods/resource_patch.rb +239 -0
  101. data/lib/flapjack/gateways/jsonapi/methods/resource_post.rb +197 -0
  102. data/lib/flapjack/gateways/jsonapi/middleware/array_param_fixer.rb +27 -0
  103. data/lib/flapjack/gateways/jsonapi/{rack → middleware}/json_params_parser.rb +7 -6
  104. data/lib/flapjack/gateways/jsonapi/middleware/request_timestamp.rb +18 -0
  105. data/lib/flapjack/gateways/oobetet.rb +222 -170
  106. data/lib/flapjack/gateways/pager_duty.rb +388 -0
  107. data/lib/flapjack/gateways/pager_duty/alert.text.erb +13 -0
  108. data/lib/flapjack/gateways/slack.rb +56 -48
  109. data/lib/flapjack/gateways/slack/alert.text.erb +1 -1
  110. data/lib/flapjack/gateways/slack/rollup.text.erb +1 -1
  111. data/lib/flapjack/gateways/sms_aspsms.rb +155 -0
  112. data/lib/flapjack/gateways/sms_aspsms/alert.text.erb +7 -0
  113. data/lib/flapjack/gateways/sms_aspsms/rollup.text.erb +2 -0
  114. data/lib/flapjack/gateways/sms_messagenet.rb +77 -57
  115. data/lib/flapjack/gateways/sms_messagenet/alert.text.erb +3 -2
  116. data/lib/flapjack/gateways/sms_nexmo.rb +53 -51
  117. data/lib/flapjack/gateways/sms_nexmo/alert.text.erb +2 -2
  118. data/lib/flapjack/gateways/sms_nexmo/rollup.text.erb +1 -1
  119. data/lib/flapjack/gateways/sms_twilio.rb +79 -62
  120. data/lib/flapjack/gateways/sms_twilio/alert.text.erb +3 -2
  121. data/lib/flapjack/gateways/web.rb +437 -345
  122. data/lib/flapjack/gateways/web/middleware/request_timestamp.rb +18 -0
  123. data/lib/flapjack/gateways/web/public/css/bootstrap.css +3793 -4340
  124. data/lib/flapjack/gateways/web/public/css/bootstrap.css.map +1 -0
  125. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
  126. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +273 -214
  127. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  128. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
  129. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  130. data/lib/flapjack/gateways/web/public/js/bootstrap.js +1637 -1607
  131. data/lib/flapjack/gateways/web/public/js/self_stats.js +1 -2
  132. data/lib/flapjack/gateways/web/views/_pagination.html.erb +19 -0
  133. data/lib/flapjack/gateways/web/views/check.html.erb +159 -121
  134. data/lib/flapjack/gateways/web/views/checks.html.erb +82 -41
  135. data/lib/flapjack/gateways/web/views/contact.html.erb +59 -71
  136. data/lib/flapjack/gateways/web/views/contacts.html.erb +32 -8
  137. data/lib/flapjack/gateways/web/views/index.html.erb +2 -2
  138. data/lib/flapjack/gateways/web/views/{layout.erb → layout.html.erb} +7 -23
  139. data/lib/flapjack/gateways/web/views/self_stats.html.erb +32 -33
  140. data/lib/flapjack/gateways/web/views/tag.html.erb +32 -0
  141. data/lib/flapjack/gateways/web/views/tags.html.erb +51 -0
  142. data/lib/flapjack/logger.rb +34 -3
  143. data/lib/flapjack/notifier.rb +180 -112
  144. data/lib/flapjack/patches.rb +8 -63
  145. data/lib/flapjack/pikelet.rb +185 -143
  146. data/lib/flapjack/processor.rb +323 -191
  147. data/lib/flapjack/record_queue.rb +33 -0
  148. data/lib/flapjack/redis_proxy.rb +66 -0
  149. data/lib/flapjack/utility.rb +21 -15
  150. data/lib/flapjack/version.rb +2 -1
  151. data/libexec/httpbroker.go +218 -14
  152. data/libexec/oneoff.go +13 -10
  153. data/spec/lib/flapjack/configuration_spec.rb +286 -0
  154. data/spec/lib/flapjack/coordinator_spec.rb +103 -157
  155. data/spec/lib/flapjack/data/check_spec.rb +175 -0
  156. data/spec/lib/flapjack/data/contact_spec.rb +26 -349
  157. data/spec/lib/flapjack/data/event_spec.rb +76 -291
  158. data/spec/lib/flapjack/data/medium_spec.rb +19 -0
  159. data/spec/lib/flapjack/data/rule_spec.rb +43 -0
  160. data/spec/lib/flapjack/data/scheduled_maintenance_spec.rb +976 -0
  161. data/spec/lib/flapjack/data/unscheduled_maintenance_spec.rb +34 -0
  162. data/spec/lib/flapjack/gateways/aws_sns_spec.rb +111 -60
  163. data/spec/lib/flapjack/gateways/email_spec.rb +194 -161
  164. data/spec/lib/flapjack/gateways/jabber_spec.rb +961 -162
  165. data/spec/lib/flapjack/gateways/jsonapi/methods/check_links_spec.rb +155 -0
  166. data/spec/lib/flapjack/gateways/jsonapi/methods/checks_spec.rb +426 -0
  167. data/spec/lib/flapjack/gateways/jsonapi/methods/contact_links_spec.rb +217 -0
  168. data/spec/lib/flapjack/gateways/jsonapi/methods/contacts_spec.rb +425 -0
  169. data/spec/lib/flapjack/gateways/jsonapi/methods/events_spec.rb +271 -0
  170. data/spec/lib/flapjack/gateways/jsonapi/methods/media_spec.rb +257 -0
  171. data/spec/lib/flapjack/gateways/jsonapi/methods/medium_links_spec.rb +163 -0
  172. data/spec/lib/flapjack/gateways/jsonapi/methods/metrics_spec.rb +8 -0
  173. data/spec/lib/flapjack/gateways/jsonapi/methods/rule_links_spec.rb +212 -0
  174. data/spec/lib/flapjack/gateways/jsonapi/methods/rules_spec.rb +289 -0
  175. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenance_links_spec.rb +49 -0
  176. data/spec/lib/flapjack/gateways/jsonapi/methods/scheduled_maintenances_spec.rb +242 -0
  177. data/spec/lib/flapjack/gateways/jsonapi/methods/tag_links_spec.rb +274 -0
  178. data/spec/lib/flapjack/gateways/jsonapi/methods/tags_spec.rb +302 -0
  179. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenance_links_spec.rb +49 -0
  180. data/spec/lib/flapjack/gateways/jsonapi/methods/unscheduled_maintenances_spec.rb +339 -0
  181. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +1 -1
  182. data/spec/lib/flapjack/gateways/oobetet_spec.rb +151 -79
  183. data/spec/lib/flapjack/gateways/pager_duty_spec.rb +353 -0
  184. data/spec/lib/flapjack/gateways/slack_spec.rb +53 -53
  185. data/spec/lib/flapjack/gateways/sms_aspsms_spec.rb +106 -0
  186. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +111 -54
  187. data/spec/lib/flapjack/gateways/sms_nexmo_spec.rb +50 -51
  188. data/spec/lib/flapjack/gateways/sms_twilio_spec.rb +108 -48
  189. data/spec/lib/flapjack/gateways/web_spec.rb +144 -216
  190. data/spec/lib/flapjack/notifier_spec.rb +132 -1
  191. data/spec/lib/flapjack/pikelet_spec.rb +111 -50
  192. data/spec/lib/flapjack/processor_spec.rb +210 -40
  193. data/spec/lib/flapjack/redis_proxy_spec.rb +45 -0
  194. data/spec/lib/flapjack/utility_spec.rb +11 -15
  195. data/spec/service_consumers/fixture_data.rb +547 -0
  196. data/spec/service_consumers/pact_helper.rb +21 -32
  197. data/spec/service_consumers/pacts/flapjack-diner_v2.0.json +4652 -0
  198. data/spec/service_consumers/provider_states_for_flapjack-diner.rb +279 -322
  199. data/spec/service_consumers/provider_support.rb +8 -0
  200. data/spec/spec_helper.rb +34 -44
  201. data/spec/support/erb_view_helper.rb +1 -1
  202. data/spec/support/factories.rb +58 -0
  203. data/spec/support/jsonapi_helper.rb +15 -26
  204. data/spec/support/mock_logger.rb +43 -0
  205. data/spec/support/xmpp_comparable.rb +24 -0
  206. data/src/flapjack/transport_test.go +30 -1
  207. data/tasks/dump_keys.rake +82 -0
  208. data/tasks/events.rake +7 -7
  209. data/tasks/support/flapjack_config_benchmark.toml +28 -0
  210. data/tasks/support/flapjack_config_benchmark.yaml +0 -2
  211. metadata +175 -222
  212. data/Guardfile +0 -14
  213. data/etc/flapjack_config.yaml.example +0 -477
  214. data/features/cli_flapjack-populator.feature +0 -90
  215. data/features/support/silent_system.rb +0 -4
  216. data/lib/flapjack/cli/import.rb +0 -108
  217. data/lib/flapjack/data/entity.rb +0 -652
  218. data/lib/flapjack/data/entity_check.rb +0 -1044
  219. data/lib/flapjack/data/message.rb +0 -56
  220. data/lib/flapjack/data/migration.rb +0 -234
  221. data/lib/flapjack/data/notification_rule.rb +0 -425
  222. data/lib/flapjack/data/semaphore.rb +0 -44
  223. data/lib/flapjack/data/tagged.rb +0 -48
  224. data/lib/flapjack/gateways/jsonapi/check_methods.rb +0 -206
  225. data/lib/flapjack/gateways/jsonapi/check_presenter.rb +0 -221
  226. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +0 -186
  227. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +0 -223
  228. data/lib/flapjack/gateways/jsonapi/medium_methods.rb +0 -185
  229. data/lib/flapjack/gateways/jsonapi/metrics_methods.rb +0 -132
  230. data/lib/flapjack/gateways/jsonapi/notification_rule_methods.rb +0 -141
  231. data/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods.rb +0 -139
  232. data/lib/flapjack/gateways/jsonapi/report_methods.rb +0 -146
  233. data/lib/flapjack/gateways/pagerduty.rb +0 -318
  234. data/lib/flapjack/gateways/pagerduty/alert.text.erb +0 -10
  235. data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +0 -87
  236. data/lib/flapjack/gateways/web/public/css/select2.css +0 -615
  237. data/lib/flapjack/gateways/web/public/css/tablesort.css +0 -67
  238. data/lib/flapjack/gateways/web/public/img/select2-spinner.gif +0 -0
  239. data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
  240. data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
  241. data/lib/flapjack/gateways/web/public/js/backbone.js +0 -1581
  242. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +0 -322
  243. data/lib/flapjack/gateways/web/public/js/flapjack.js +0 -82
  244. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.js +0 -1640
  245. data/lib/flapjack/gateways/web/public/js/jquery.tablesorter.widgets.js +0 -1390
  246. data/lib/flapjack/gateways/web/public/js/modules/contact.js +0 -520
  247. data/lib/flapjack/gateways/web/public/js/modules/entity.js +0 -28
  248. data/lib/flapjack/gateways/web/public/js/modules/medium.js +0 -40
  249. data/lib/flapjack/gateways/web/public/js/select2.js +0 -3397
  250. data/lib/flapjack/gateways/web/public/js/tablesort.js +0 -44
  251. data/lib/flapjack/gateways/web/public/js/underscore.js +0 -1276
  252. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +0 -173
  253. data/lib/flapjack/gateways/web/views/entities.html.erb +0 -30
  254. data/lib/flapjack/gateways/web/views/entity.html.erb +0 -51
  255. data/lib/flapjack/rack_logger.rb +0 -47
  256. data/lib/flapjack/redis_pool.rb +0 -42
  257. data/spec/lib/flapjack/data/entity_check_spec.rb +0 -1418
  258. data/spec/lib/flapjack/data/entity_spec.rb +0 -872
  259. data/spec/lib/flapjack/data/message_spec.rb +0 -30
  260. data/spec/lib/flapjack/data/migration_spec.rb +0 -104
  261. data/spec/lib/flapjack/data/notification_rule_spec.rb +0 -232
  262. data/spec/lib/flapjack/data/notification_spec.rb +0 -53
  263. data/spec/lib/flapjack/data/semaphore_spec.rb +0 -24
  264. data/spec/lib/flapjack/filters/acknowledgement_spec.rb +0 -6
  265. data/spec/lib/flapjack/filters/delays_spec.rb +0 -6
  266. data/spec/lib/flapjack/filters/ok_spec.rb +0 -6
  267. data/spec/lib/flapjack/filters/scheduled_maintenance_spec.rb +0 -6
  268. data/spec/lib/flapjack/filters/unscheduled_maintenance_spec.rb +0 -6
  269. data/spec/lib/flapjack/gateways/jsonapi/check_methods_spec.rb +0 -315
  270. data/spec/lib/flapjack/gateways/jsonapi/check_presenter_spec.rb +0 -223
  271. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +0 -131
  272. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +0 -389
  273. data/spec/lib/flapjack/gateways/jsonapi/medium_methods_spec.rb +0 -231
  274. data/spec/lib/flapjack/gateways/jsonapi/notification_rule_methods_spec.rb +0 -169
  275. data/spec/lib/flapjack/gateways/jsonapi/pagerduty_credential_methods_spec.rb +0 -114
  276. data/spec/lib/flapjack/gateways/jsonapi/report_methods_spec.rb +0 -590
  277. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +0 -249
  278. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +0 -21
  279. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +0 -24
  280. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +0 -16
  281. data/spec/lib/flapjack/redis_pool_spec.rb +0 -29
  282. data/spec/service_consumers/pacts/flapjack-diner_v1.0.json +0 -4702
  283. data/tasks/entities.rake +0 -151
  284. data/tasks/profile.rake +0 -282
  285. data/tmp/acknowledge.rb +0 -13
  286. data/tmp/create_config_yaml.rb +0 -16
  287. data/tmp/create_event_ok.rb +0 -30
  288. data/tmp/create_event_unknown.rb +0 -30
  289. data/tmp/create_events_failure.rb +0 -34
  290. data/tmp/create_events_ok.rb +0 -32
  291. data/tmp/create_events_ok_fail_ack_ok.rb +0 -53
  292. data/tmp/create_events_ok_failure.rb +0 -41
  293. data/tmp/create_events_ok_failure_ack.rb +0 -53
  294. data/tmp/dummy_contacts.json +0 -43
  295. data/tmp/dummy_entities.json +0 -37
  296. data/tmp/generate_nagios_test_hosts.rb +0 -16
  297. data/tmp/notification_rules.rb +0 -73
  298. data/tmp/parse_config_yaml.rb +0 -7
  299. data/tmp/redis_find_spurious_unknown_states.rb +0 -52
  300. data/tmp/test_json_post.rb +0 -19
  301. data/tmp/test_notification_rules_api.rb +0 -171
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sinatra/base'
4
+
5
+ module Flapjack
6
+ module Gateways
7
+ class JSONAPI < Sinatra::Base
8
+ module Methods
9
+ module AssociationDelete
10
+
11
+ def self.registered(app)
12
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Headers
13
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Miscellaneous
14
+
15
+ Flapjack::Gateways::JSONAPI::RESOURCE_CLASSES.each do |resource_class|
16
+ resource = resource_class.short_model_name.plural
17
+
18
+ jsonapi_links = if resource_class.respond_to?(:jsonapi_associations)
19
+ resource_class.jsonapi_associations || {}
20
+ else
21
+ {}
22
+ end
23
+
24
+ delete_links = jsonapi_links.select {|n, jd|
25
+ jd.link.is_a?(TrueClass) && jd.delete.is_a?(TrueClass) && :multiple.eql?(jd.number)
26
+ }
27
+
28
+ unless delete_links.empty?
29
+
30
+ app.class_eval do
31
+ single = resource.singularize
32
+
33
+ delete_links.each_pair do |link_name, link_data|
34
+ link_type = link_data.data_klass.short_model_name.name
35
+
36
+ swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do
37
+ operation :delete do
38
+ key :description, link_data.descriptions[:delete]
39
+ key :operationId, "remove_#{single}_#{link_name}"
40
+ key :consumes, [JSONAPI_MEDIA_TYPE]
41
+ parameter do
42
+ key :name, "#{single}_id".to_sym
43
+ key :in, :path
44
+ key :description, "Id of a #{single}"
45
+ key :required, true
46
+ key :type, :string
47
+ end
48
+ parameter do
49
+ key :name, :data
50
+ key :in, :body
51
+ key :description, "#{link_name} to remove from the #{single}"
52
+ key :required, true
53
+ schema do
54
+ key :type, :array
55
+ items do
56
+ key :"$ref", "#{link_type}Reference".to_sym
57
+ end
58
+ end
59
+ end
60
+ response 204 do
61
+ key :description, 'No Content; link deletion success'
62
+ end
63
+ response 403 do
64
+ key :description, "Forbidden; no link ids"
65
+ schema do
66
+ key :'$ref', :Errors
67
+ end
68
+ end
69
+ response 404 do
70
+ key :description, "Not Found"
71
+ schema do
72
+ key :'$ref', :Errors
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ id_patt = if Flapjack::Data::Tag.eql?(resource_class)
82
+ "\\S+"
83
+ else
84
+ Flapjack::UUID_RE
85
+ end
86
+
87
+ assoc_patt = jsonapi_links.keys.map(&:to_s).join("|")
88
+
89
+ app.delete %r{^/#{resource}/(#{id_patt})/relationships/(#{assoc_patt})$} do
90
+ resource_id = params[:captures][0]
91
+ assoc_name = params[:captures][1].to_sym
92
+
93
+ halt(404) unless delete_links.has_key?(assoc_name)
94
+
95
+ status 204
96
+
97
+ assoc = delete_links[assoc_name]
98
+
99
+ assoc_ids, _ = wrapped_link_params(:association => assoc)
100
+
101
+ halt(err(403, 'No relationship ids')) if assoc_ids.empty?
102
+
103
+ resource_class.lock(*assoc.lock_klasses) do
104
+ resource_obj = resource_class.find_by_id!(resource_id)
105
+ assoc = resource_obj.send(assoc_name)
106
+ assoc.remove_ids(*assoc_ids)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sinatra/base'
4
+
5
+ module Flapjack
6
+ module Gateways
7
+ class JSONAPI < Sinatra::Base
8
+ module Methods
9
+ module AssociationGet
10
+
11
+ def self.registered(app)
12
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Headers
13
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Miscellaneous
14
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Serialiser
15
+
16
+ Flapjack::Gateways::JSONAPI::RESOURCE_CLASSES.each do |resource_class|
17
+
18
+ jsonapi_links = if resource_class.respond_to?(:jsonapi_associations)
19
+ resource_class.jsonapi_associations || {}
20
+ else
21
+ {}
22
+ end
23
+
24
+ singular_links = jsonapi_links.select {|n, jd|
25
+ jd.link.is_a?(TrueClass) && jd.get.is_a?(TrueClass) && :singular.eql?(jd.number)
26
+ }
27
+
28
+ multiple_links = jsonapi_links.select {|n, jd|
29
+ jd.link.is_a?(TrueClass) && jd.get.is_a?(TrueClass) && :multiple.eql?(jd.number)
30
+ }
31
+
32
+ resource = resource_class.short_model_name.plural
33
+
34
+ unless singular_links.empty? && multiple_links.empty?
35
+
36
+ app.class_eval do
37
+ # GET and PATCH duplicate a lot of swagger code, but swagger-blocks
38
+ # make it difficult to DRY things due to the different contexts in use
39
+ single = resource.singularize
40
+
41
+ singular_links.each_pair do |link_name, link_data|
42
+ link_type = link_data.data_klass.short_model_name.name
43
+
44
+ swagger_path "/#{resource}/{#{single}_id}/#{link_name}" do
45
+ operation :get do
46
+ key :description, link_data.descriptions[:get]
47
+ key :operationId, "get_#{single}_#{link_name}"
48
+ key :produces, [Flapjack::Gateways::JSONAPI.media_type_produced]
49
+ parameter do
50
+ key :name, "#{single}_id".to_sym
51
+ key :in, :path
52
+ key :description, "Id of a #{single}"
53
+ key :required, true
54
+ key :type, :string
55
+ end
56
+ response 200 do
57
+ key :description, "GET #{resource} #{link_name} success"
58
+ schema do
59
+ key :"$ref", "#{link_type}Reference".to_sym
60
+ end
61
+ end
62
+ response 403 do
63
+ key :description, "Forbidden; invalid request"
64
+ schema do
65
+ key :'$ref', :Errors
66
+ end
67
+ end
68
+ response 404 do
69
+ key :description, "Not Found"
70
+ schema do
71
+ key :'$ref', :Errors
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do
78
+ operation :get do
79
+ key :description, link_data.descriptions[:get]
80
+ key :operationId, "get_#{single}_#{link_name}"
81
+ key :produces, [JSONAPI_MEDIA_TYPE]
82
+ parameter do
83
+ key :name, "#{single}_id".to_sym
84
+ key :in, :path
85
+ key :description, "Id of a #{single}"
86
+ key :required, true
87
+ key :type, :string
88
+ end
89
+ response 200 do
90
+ key :description, "GET #{resource} success"
91
+ schema do
92
+ key :"$ref", "#{link_type}Reference".to_sym
93
+ end
94
+ end
95
+ response 403 do
96
+ key :description, "Forbidden; invalid request"
97
+ schema do
98
+ key :'$ref', :Errors
99
+ end
100
+ end
101
+ response 404 do
102
+ key :description, "Not Found"
103
+ schema do
104
+ key :'$ref', :Errors
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ multiple_links.each_pair do |link_name, link_data|
112
+ link_type = link_data.data_klass.short_model_name.name
113
+ swagger_path "/#{resource}/{#{single}_id}/#{link_name}" do
114
+ operation :get do
115
+ key :description, link_data.descriptions[:get]
116
+ key :operationId, "get_#{single}_#{link_name}"
117
+ key :produces, [Flapjack::Gateways::JSONAPI.media_type_produced]
118
+ parameter do
119
+ key :name, "#{single}_id".to_sym
120
+ key :in, :path
121
+ key :description, "Id of a #{single}"
122
+ key :required, true
123
+ key :type, :string
124
+ end
125
+ response 200 do
126
+ key :description, "GET #{resource} response"
127
+ schema do
128
+ key :type, :array
129
+ items do
130
+ key :"$ref", "#{link_type}Reference".to_sym
131
+ end
132
+ end
133
+ end
134
+ response 403 do
135
+ key :description, "Forbidden; invalid request"
136
+ schema do
137
+ key :'$ref', :Errors
138
+ end
139
+ end
140
+ response 404 do
141
+ key :description, "Not Found"
142
+ schema do
143
+ key :'$ref', :Errors
144
+ end
145
+ end
146
+ end
147
+ end
148
+ swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do
149
+ operation :get do
150
+ key :description, link_data.descriptions[:get]
151
+ key :operationId, "get_#{single}_links_#{link_name}"
152
+ key :produces, [Flapjack::Gateways::JSONAPI.media_type_produced]
153
+ parameter do
154
+ key :name, "#{single}_id".to_sym
155
+ key :in, :path
156
+ key :description, "Id of a #{single}"
157
+ key :required, true
158
+ key :type, :string
159
+ end
160
+ response 200 do
161
+ key :description, "GET #{resource} response"
162
+ schema do
163
+ key :type, :array
164
+ items do
165
+ key :"$ref", "#{link_type}Reference".to_sym
166
+ end
167
+ end
168
+ end
169
+ response 403 do
170
+ key :description, "Forbidden; invalid request"
171
+ schema do
172
+ key :'$ref', :Errors
173
+ end
174
+ end
175
+ response 404 do
176
+ key :description, "Not Found"
177
+ schema do
178
+ key :'$ref', :Errors
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ assoc_patt = jsonapi_links.keys.map(&:to_s).join("|")
188
+
189
+ app.get %r{^/#{resource}/(#{Flapjack::UUID_RE})/(?:relationships/)?(#{assoc_patt})(\?.+)?} do
190
+ resource_id = params[:captures][0]
191
+ assoc_name = params[:captures][1].to_sym
192
+
193
+ halt(404) unless singular_links.has_key?(assoc_name) ||
194
+ multiple_links.has_key?(assoc_name)
195
+
196
+ fields = params[:fields]
197
+ incl = params[:include].nil? ? nil : params[:include].split(',')
198
+
199
+ assoc = jsonapi_links[assoc_name]
200
+
201
+ extra_locks = incl.nil? ? [] : lock_for_include_clause(resource_class,
202
+ :include => incl.dup)
203
+
204
+ locks = assoc.lock_klasses | extra_locks
205
+ locks.sort_by!(&:name)
206
+
207
+ status 200
208
+
209
+ halt(err(404, 'Unknown relationship')) if assoc.nil?
210
+
211
+ empty = false
212
+ included = nil
213
+ result = nil
214
+ meta = nil
215
+
216
+ resource_class.lock(*locks) do
217
+ res = resource_class.intersect(:id => resource_id)
218
+ empty = res.empty?
219
+
220
+ unless empty
221
+ associated = res.all.first.send(assoc_name)
222
+
223
+ result = case assoc.number
224
+ when :multiple
225
+
226
+ unless params[:filter].nil?
227
+ unless params[:filter].is_a?(Array)
228
+ halt(err(403, "Filter parameters must be passed as an Array"))
229
+ end
230
+
231
+ bad = params[:filter].detect {|f| f !~ /^#{assoc_name}\.(?:[^,]+)$/ }
232
+ unless bad.nil?
233
+ halt(err(403, "Filter params must start with '#{assoc_name}.', not contain comma: '#{bad}'"))
234
+ end
235
+
236
+ filters = params[:filter].collect do |f|
237
+ f.sub(/^#{assoc_name}\./, '')
238
+ end
239
+
240
+ filter_ops = filter_params(assoc.data_klass, filters)
241
+
242
+ associated = associated.intersect(filter_ops)
243
+ end
244
+
245
+ associated = associated.sort(:id => :asc)
246
+
247
+ resources, _, meta = paginate_get(associated, :page => params[:page],
248
+ :per_page => params[:per_page])
249
+
250
+ result = resources.eql?([]) ? [] : resources.ids
251
+ when :singular
252
+ result = associated.id
253
+ end
254
+
255
+ unless incl.nil?
256
+ included = as_jsonapi_included(resource_class, res,
257
+ :include => incl, :fields => fields, :query_type => :association)
258
+ end
259
+ end
260
+ end
261
+ raise ::Zermelo::Records::Errors::RecordNotFound.new(resource_class, resource_id) if empty
262
+
263
+ links = {
264
+ :self => "#{request.base_url}/#{resource}/#{resource_id}/relationships/#{assoc_name}",
265
+ :related => "#{request.base_url}/#{resource}/#{resource_id}/#{assoc_name}"
266
+ }
267
+
268
+ data = case result
269
+ when Array, Set
270
+ result.map {|assoc_id| {:type => assoc.type, :id => assoc_id} }
271
+ when String
272
+ {:type => assoc.type, :id => result}
273
+ else
274
+ nil
275
+ end
276
+
277
+ ret = {:data => data, :links => links}
278
+ ret[:included] = included unless included.nil?
279
+ ret[:meta] = meta unless meta.nil?
280
+ Flapjack.dump_json(ret)
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sinatra/base'
4
+
5
+ module Flapjack
6
+ module Gateways
7
+ class JSONAPI < Sinatra::Base
8
+ module Methods
9
+ module AssociationPatch
10
+
11
+ def self.registered(app)
12
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Headers
13
+ app.helpers Flapjack::Gateways::JSONAPI::Helpers::Miscellaneous
14
+
15
+ Flapjack::Gateways::JSONAPI::RESOURCE_CLASSES.each do |resource_class|
16
+ resource = resource_class.short_model_name.plural
17
+
18
+ jsonapi_links = if resource_class.respond_to?(:jsonapi_associations)
19
+ resource_class.jsonapi_associations || {}
20
+ else
21
+ {}
22
+ end
23
+
24
+ singular_links = jsonapi_links.select {|n, jd|
25
+ jd.link.is_a?(TrueClass) && jd.patch.is_a?(TrueClass) && :singular.eql?(jd.number)
26
+ }
27
+
28
+ multiple_links = jsonapi_links.select {|n, jd|
29
+ jd.link.is_a?(TrueClass) && jd.patch.is_a?(TrueClass) && :multiple.eql?(jd.number)
30
+ }
31
+
32
+ unless singular_links.empty? && multiple_links.empty?
33
+
34
+ app.class_eval do
35
+ # GET and PATCH duplicate a lot of swagger code, but swagger-blocks
36
+ # make it difficult to DRY things due to the different contexts in use
37
+
38
+ single = resource.singularize
39
+
40
+ singular_links.each_pair do |link_name, link_data|
41
+ link_type = link_data.data_klass.short_model_name.name
42
+ swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do
43
+ operation :patch do
44
+ key :description, link_data.descriptions[:patch]
45
+ key :operationId, "replace_#{single}_#{link_name}"
46
+ key :consumes, [JSONAPI_MEDIA_TYPE]
47
+ parameter do
48
+ key :name, "#{single}_id".to_sym
49
+ key :in, :path
50
+ key :description, "Id of a #{single}"
51
+ key :required, true
52
+ key :type, :string
53
+ end
54
+ parameter do
55
+ key :name, :data
56
+ key :in, :body
57
+ key :description, "#{link_name} association to replace for the #{single}"
58
+ key :required, true
59
+ schema do
60
+ key :"$ref", "#{link_type}Reference".to_sym
61
+ end
62
+ end
63
+ response 204 do
64
+ key :description, 'No Content; link update success'
65
+ end
66
+ response 403 do
67
+ key :description, "Forbidden; no link id"
68
+ schema do
69
+ key :'$ref', :Errors
70
+ end
71
+ end
72
+ response 404 do
73
+ key :description, "Not Found"
74
+ schema do
75
+ key :'$ref', :Errors
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ multiple_links.each_pair do |link_name, link_data|
83
+ link_type = link_data.data_klass.short_model_name.name
84
+ swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do
85
+ operation :patch do
86
+ key :description, link_data.descriptions[:patch]
87
+ key :operationId, "replace_#{single}_#{link_name}"
88
+ key :consumes, [JSONAPI_MEDIA_TYPE]
89
+ parameter do
90
+ key :name, "#{single}_id".to_sym
91
+ key :in, :path
92
+ key :description, "Id of a #{single}"
93
+ key :required, true
94
+ key :type, :string
95
+ end
96
+ parameter do
97
+ key :name, :data
98
+ key :in, :body
99
+ key :description, "#{link_name} associations to replace for the #{single}"
100
+ key :required, true
101
+ schema do
102
+ key :type, :array
103
+ items do
104
+ key :"$ref", "#{link_type}Reference".to_sym
105
+ end
106
+ end
107
+ end
108
+ response 204 do
109
+ key :description, 'No Content; link update succeeded'
110
+ end
111
+ response 403 do
112
+ key :description, "Forbidden; no link ids"
113
+ schema do
114
+ key :'$ref', :Errors
115
+ end
116
+ end
117
+ response 404 do
118
+ key :description, "Not Found"
119
+ schema do
120
+ key :'$ref', :Errors
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+ id_patt = if Flapjack::Data::Tag.eql?(resource_class)
131
+ "\\S+"
132
+ else
133
+ Flapjack::UUID_RE
134
+ end
135
+
136
+ assoc_patt = jsonapi_links.keys.map(&:to_s).join("|")
137
+
138
+ app.patch %r{^/#{resource}/(#{id_patt})/relationships/(#{assoc_patt})$} do
139
+ resource_id = params[:captures][0]
140
+ assoc_name = params[:captures][1].to_sym
141
+
142
+ halt(404) unless singular_links.has_key?(assoc_name) ||
143
+ multiple_links.has_key?(assoc_name)
144
+
145
+ status 204
146
+
147
+ assoc = jsonapi_links[assoc_name]
148
+
149
+ assoc_ids, _ = wrapped_link_params(:association => assoc,
150
+ :allow_nil => true)
151
+
152
+ resource_class.lock(*assoc.lock_klasses) do
153
+ resource = resource_class.find_by_id!(resource_id)
154
+
155
+ if :multiple.eql?(assoc.number)
156
+ current_assoc_ids = resource.send(assoc_name).ids.to_a
157
+ to_remove = current_assoc_ids - assoc_ids
158
+ to_add = assoc_ids - current_assoc_ids
159
+ resource.send(assoc_name).remove_ids(*to_remove) unless to_remove.empty?
160
+ resource.send(assoc_name).add_ids(*to_add) unless to_add.empty?
161
+ elsif :singular.eql?(assoc.number)
162
+ if assoc_ids.nil?
163
+ resource.send("#{assoc_name}=".to_sym, nil)
164
+ else
165
+ halt(err(403, "Trying to add multiple records to singular association '#{assoc_name}'")) if assoc_ids.size > 1
166
+ value = assoc_ids.first.nil? ? nil : assoc.data_klass.find_by_id!(assoc_ids.first)
167
+ resource.send("#{assoc_name}=".to_sym, value)
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end