├── .env ├── Procfile ├── .gitignore ├── aws-package.sh ├── docs ├── icons │ ├── icon_bugsnag.png │ ├── icon_nixstats.png │ ├── icon_opsgenie.png │ ├── icon_aha_256x256.png │ ├── icon_bugsnag_dark.jpg │ ├── icon_bugsnag_512x512.png │ ├── icon_datadog_512x512.png │ ├── icon_enchant_400x400.png │ ├── icon_heroku_512x512.png │ ├── icon_librato_128x128.png │ ├── icon_librato_512x512.png │ ├── icon_librato_570x570.png │ ├── icon_marketo_250x250.png │ ├── icon_marketo_300x300.png │ ├── icon_marketo_728x728.png │ ├── icon_pingdom_512x512.png │ ├── icon_raygun_290x290.jpg │ ├── icon_raygun_512x512.png │ ├── icon_wootric_200x200.png │ ├── icon_appsignal_400x400.png │ ├── icon_circleci_128x128.png │ ├── icon_codeship_512x512.png │ ├── icon_gosquared_128x128.png │ ├── icon_magnumci_400x400.png │ ├── icon_opsgenie_128x128.png │ ├── icon_runscope_400x400.png │ ├── icon_semaphore_512x512.png │ ├── icon_travisci_200x200.png │ ├── icon_travisci_225x225.png │ ├── icon_userlike_512x512.png │ ├── icon_victorops_225x225.png │ ├── icon_webhookrc_512x512.png │ ├── icon_apteligent_496x496.jpg │ ├── icon_apteligent_496x496.png │ ├── icon_chathooks_1024x1024.png │ ├── icon_chathooks_1024x1024.psd │ ├── icon_confluence_256x256.png │ ├── icon_deskdotcom_400x400.png │ ├── icon_papertrail_128x128.png │ ├── icon_semaphore_2000x2000.png │ ├── icon_statuspage_512x512.png │ ├── icon_webhookrc_1550x1550.png │ ├── icon_victorops_blue.svg │ ├── icon_twitter.svg │ ├── icon_statuspage.svg │ ├── icon_circleci.svg │ ├── icon_appsignal.svg │ ├── icon_victorops.svg │ ├── icon_opsgenie.svg │ ├── icon_pingdom.svg │ ├── icon_elasticsearch.svg │ ├── icon_heroku.svg │ ├── icon_codeship.svg │ └── icon_twitter_alt.svg ├── logos │ ├── logo_chathooks_1024x1024.png │ ├── logo_chathooks_1024x1024.psd │ ├── logo_chathooks_long_600x150.png │ ├── logo_chathooks_long_600x150.psd │ ├── logo_chathooks_long_4000x1000.png │ └── logo_chathooks_long_4000x1000.psd ├── images │ ├── glip_webhook_step-3_details.png │ ├── glip_webhook_step-2_add-webhook.png │ └── glip_webhook_step-1_add-integration.png ├── handlers │ ├── sumologic │ │ ├── sumo-logic-logo_100x100.png │ │ ├── sumo-logic-logo_110x110.png │ │ ├── sumo-logic-logo_116x116.png │ │ ├── sumo-logic-logo_120x120.png │ │ └── sumo-logic-logo_150x150.png │ ├── bugsnag │ │ ├── event-example_new-error_slack.png │ │ └── event-example_new-error_update_slack.png │ ├── pingdom │ │ ├── event-example_http-check_demo.png │ │ ├── README.md │ │ ├── event-example_transaction-check.json │ │ ├── event-example_ping-check.json │ │ ├── event-example_tcp-check.json │ │ ├── event-example_imap-check.json │ │ ├── event-example_pop3-check.json │ │ ├── event-example_smtp-check.json │ │ ├── event-example_dns-check.json │ │ ├── event-example_udp-check.json │ │ ├── event-example_http-custom-check.json │ │ ├── event-example_http-check.json │ │ └── event-example_http-check_demo.json │ ├── gosquared │ │ ├── event-example_site-traffic_demo.png │ │ ├── event-example_smart-group-enter_demo.png │ │ └── event-example_live-chat.json │ ├── papertrail │ │ ├── event-example_notifications-array-len-1_demo.png │ │ ├── event-example_notifications-array-len-1.json │ │ ├── event-example_notifications-array-len-1_demo.json │ │ └── event-example_notifications-array.json │ ├── heroku │ │ ├── event-example_build.txt │ │ └── config_heroku.md │ ├── runscope │ │ ├── README.md │ │ └── event-example_notification.json │ ├── librato │ │ ├── event-example_alert-cleared.json │ │ ├── event-example_2.json │ │ └── event-example_alert-triggered.json │ ├── servicenow │ │ └── message-example_incident.json │ ├── appsignal │ │ ├── event-example_marker.json │ │ ├── config_appsignal.md │ │ ├── event-example_performance.json │ │ └── event-example_exception.json │ ├── deskdotcom │ │ ├── event-example_formatted1.json │ │ └── event-example_formatted2.json │ ├── slack │ │ ├── event-example_attachment.json │ │ └── event-example_link-emoji.json │ ├── zendesk │ │ └── event-example_notification.json │ ├── sendgrid │ │ ├── event-example_spamreport.json │ │ ├── event-example_dropped.json │ │ ├── event-example_processed.json │ │ ├── event-example_open.json │ │ ├── event-example_delivered.json │ │ ├── event-example_deferred.json │ │ └── event-example_click.json │ ├── logentries │ │ └── event-example_alert.json │ ├── raygun │ │ ├── config_raygun.md │ │ └── event-example_error.json │ ├── apteligent │ │ ├── event-example_alert-close.json │ │ ├── event-example_alert-open.json │ │ └── event-example_alert.json │ ├── wootric │ │ ├── event-example_decline-created.txt │ │ └── event-example_response-created.txt │ ├── asana │ │ └── event-example_notification.json │ ├── semaphore │ │ ├── config_semaphore.md │ │ ├── event-example_build.json │ │ └── event-example_deploy.json │ ├── datadog │ │ └── event-example_formatted1.json │ ├── userlike │ │ ├── config_userlike.md │ │ ├── event-example_operator_away.json │ │ ├── event-example_operator_back.json │ │ ├── event-example_operator_offline.json │ │ ├── event-example_operator_online.json │ │ ├── event-example_offline-message_receive.json │ │ ├── README.md │ │ ├── event-example_chat-meta_forward.json │ │ └── event-example_chat-meta_start.json │ ├── magnumci │ │ ├── config_magnumci.md │ │ └── event-example_build.json │ ├── victorops │ │ └── event-example_formatted1.json │ ├── codeship │ │ └── event-example_build.json │ ├── opsgenie │ │ ├── event-example_escalate.json │ │ ├── event-example_delete.json │ │ ├── event-example_close.json │ │ ├── event-example_acknowledge.json │ │ ├── event-example_unacknowledge.json │ │ ├── event-example_custom-action-test-action.json │ │ ├── event-example_add-team.json │ │ ├── event-example_add-note.json │ │ ├── event-example_remove-tags.json │ │ ├── event-example_add-recipient.json │ │ ├── event-example_assign-ownership.json │ │ ├── event-example_add-tags.json │ │ ├── event-example_take-ownership.json │ │ └── event-example_create.json │ ├── confluence │ │ ├── event-example_page-created.json │ │ └── event-example_comment-created.json │ ├── marketo │ │ ├── event-example_demo1.json │ │ ├── event-example_formatted2.json │ │ ├── event-example_formatted1.json │ │ └── event-example_formatted1_template.json │ ├── quickbooks │ │ └── example__notification.json │ ├── updown │ │ ├── event-example_recovery.json │ │ └── event-example_down.json │ ├── hubspot │ │ └── event-example_notification.json │ ├── statuspage │ │ ├── event-example_component-updates.json │ │ ├── event-example_incident-updates-create.json │ │ └── event-example_incident-updates.json │ ├── aha │ │ ├── event-example_feature-add-tag.json │ │ ├── event-example_release-ship.json │ │ └── event-example_feature-to-parking-lot.json │ ├── enchant │ │ └── event-example_notification.json │ ├── fabric │ │ └── event-example_notification.json │ ├── airbrake │ │ └── event-example_new-error.json │ ├── kapost │ │ └── event-example_create-content.json │ ├── helpscout │ │ └── event-example_customer-created.json │ ├── trello │ │ └── event-example_notification.json │ ├── paypal │ │ └── event-example_payment-authorization-created.json │ ├── travisci │ │ └── event-example_build.json │ ├── pagerduty │ │ └── event-example_incident_trigger.json │ └── stripe │ │ └── event-example_event.json ├── index.html ├── start.md ├── handlers.md └── slack.md ├── pkg ├── templates │ └── home.go ├── handlers │ ├── travisci │ │ ├── travisci_glip.png │ │ ├── logo_travisci_201x201.png │ │ └── handler_travisci_util.go │ ├── enchant │ │ ├── logo_enchant_400x400.png │ │ └── handler_enchant_util.go │ ├── heroku │ │ ├── logo_heroku_300x300.jpg │ │ ├── handler_heroku_out_util.go │ │ └── handler_heroku_out_test.go │ ├── raygun │ │ ├── logo_raygun_290x290.jpg │ │ └── handler_raygun_out_util.go │ ├── magnumci │ │ ├── logo_magnumci_512x512.png │ │ └── handler_magnumci_util.go │ ├── userlike │ │ ├── logo_userlike_512x512.png │ │ └── util.go │ ├── appsignal │ │ ├── logo_appsignal_400x400.png │ │ └── handler_appsignal_util.go │ ├── confluence │ │ ├── logo_confluence_256x256.png │ │ ├── handler_confluence_util.go │ │ └── handler_confluence_out_test.go │ ├── semaphore │ │ ├── logo_semaphore_2000x2000.png │ │ └── handler_semaphore_util.go │ ├── codeship │ │ └── handler_codeship_util.go │ ├── circleci │ │ └── handler_circleci_out_util.go │ ├── datadog │ │ ├── handler_datadog_out_util.go │ │ └── handler_datadog_out.go │ ├── aha │ │ └── handler_aha_out_util.go │ ├── runscope │ │ └── handler_runscope_out_util.go │ ├── victorops │ │ ├── handler_victorops_out_util.go │ │ └── handler_victorops_out.go │ ├── wootric │ │ └── wootric_examples.go │ ├── bugsnag │ │ └── handler_bugsnag_util.go │ ├── slack │ │ ├── handler_slack_in_util.go │ │ ├── handler_slack_in_test.go │ │ └── handler_slack_in.go │ ├── librato │ │ └── handler_librato_out_util.go │ ├── marketo │ │ ├── handler_marketo_out_util.go │ │ └── handler_marketo_out.go │ ├── pingdom │ │ └── handler_pingdom_out_util.go │ ├── gosquared │ │ └── handler_gosquared_out_util.go │ ├── gosquared2 │ │ └── handler_gosquared2_out_util.go │ ├── opsgenie │ │ └── handler_opsgenie_out_util.go │ ├── apteligent │ │ └── handler_apteligent_out_util.go │ ├── deskdotcom │ │ ├── handler_deskdotcom_out_util.go │ │ └── handler_deskdotcom_out.go │ ├── papertrail │ │ └── handler_papertrail_out_util.go │ ├── statuspage │ │ └── handler_statuspage_out_util.go │ ├── handler_home.go │ └── templated_handler.go ├── adapters │ ├── glip_config.go │ └── adapter.go └── config │ ├── configuration_test.go │ ├── interface_constants.go │ ├── configuration.go │ └── icons.go ├── aws-update.sh ├── heroku.yml ├── .codeclimate.yml ├── .github ├── dependabot.yaml └── workflows │ ├── lint.yaml │ └── ci.yaml ├── examples ├── proxy_send │ ├── sample.env │ └── README.md ├── build_hook_url │ └── build_hook_url.go └── examples.go ├── Makefile ├── Dockerfile ├── CONTRIBUTING.md ├── .golangci.yml ├── main.go ├── LICENSE ├── app.json └── go.mod /.env: -------------------------------------------------------------------------------- 1 | REPEAT=10 -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: chathooks -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | _* 3 | *.tar 4 | handler.so 5 | handler.zip 6 | main 7 | main.zip 8 | -------------------------------------------------------------------------------- /aws-package.sh: -------------------------------------------------------------------------------- 1 | rm main 2 | rm main.zip 3 | GOOS=linux go build -o main main.go 4 | zip main.zip main -------------------------------------------------------------------------------- /docs/icons/icon_bugsnag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_bugsnag.png -------------------------------------------------------------------------------- /docs/icons/icon_nixstats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_nixstats.png -------------------------------------------------------------------------------- /docs/icons/icon_opsgenie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_opsgenie.png -------------------------------------------------------------------------------- /docs/icons/icon_aha_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_aha_256x256.png -------------------------------------------------------------------------------- /docs/icons/icon_bugsnag_dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_bugsnag_dark.jpg -------------------------------------------------------------------------------- /docs/icons/icon_bugsnag_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_bugsnag_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_datadog_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_datadog_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_enchant_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_enchant_400x400.png -------------------------------------------------------------------------------- /docs/icons/icon_heroku_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_heroku_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_librato_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_librato_128x128.png -------------------------------------------------------------------------------- /docs/icons/icon_librato_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_librato_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_librato_570x570.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_librato_570x570.png -------------------------------------------------------------------------------- /docs/icons/icon_marketo_250x250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_marketo_250x250.png -------------------------------------------------------------------------------- /docs/icons/icon_marketo_300x300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_marketo_300x300.png -------------------------------------------------------------------------------- /docs/icons/icon_marketo_728x728.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_marketo_728x728.png -------------------------------------------------------------------------------- /docs/icons/icon_pingdom_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_pingdom_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_raygun_290x290.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_raygun_290x290.jpg -------------------------------------------------------------------------------- /docs/icons/icon_raygun_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_raygun_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_wootric_200x200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_wootric_200x200.png -------------------------------------------------------------------------------- /docs/icons/icon_appsignal_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_appsignal_400x400.png -------------------------------------------------------------------------------- /docs/icons/icon_circleci_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_circleci_128x128.png -------------------------------------------------------------------------------- /docs/icons/icon_codeship_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_codeship_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_gosquared_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_gosquared_128x128.png -------------------------------------------------------------------------------- /docs/icons/icon_magnumci_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_magnumci_400x400.png -------------------------------------------------------------------------------- /docs/icons/icon_opsgenie_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_opsgenie_128x128.png -------------------------------------------------------------------------------- /docs/icons/icon_runscope_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_runscope_400x400.png -------------------------------------------------------------------------------- /docs/icons/icon_semaphore_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_semaphore_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_travisci_200x200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_travisci_200x200.png -------------------------------------------------------------------------------- /docs/icons/icon_travisci_225x225.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_travisci_225x225.png -------------------------------------------------------------------------------- /docs/icons/icon_userlike_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_userlike_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_victorops_225x225.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_victorops_225x225.png -------------------------------------------------------------------------------- /docs/icons/icon_webhookrc_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_webhookrc_512x512.png -------------------------------------------------------------------------------- /pkg/templates/home.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | type HomeData struct { 4 | HomeURL string 5 | WebhookURL string 6 | } 7 | -------------------------------------------------------------------------------- /aws-update.sh: -------------------------------------------------------------------------------- 1 | aws lambda update-function-code --function-name='Chathooks' --zip-file='fileb://main.zip' --publish --region='us-east-1' -------------------------------------------------------------------------------- /docs/icons/icon_apteligent_496x496.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_apteligent_496x496.jpg -------------------------------------------------------------------------------- /docs/icons/icon_apteligent_496x496.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_apteligent_496x496.png -------------------------------------------------------------------------------- /docs/icons/icon_chathooks_1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_chathooks_1024x1024.png -------------------------------------------------------------------------------- /docs/icons/icon_chathooks_1024x1024.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_chathooks_1024x1024.psd -------------------------------------------------------------------------------- /docs/icons/icon_confluence_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_confluence_256x256.png -------------------------------------------------------------------------------- /docs/icons/icon_deskdotcom_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_deskdotcom_400x400.png -------------------------------------------------------------------------------- /docs/icons/icon_papertrail_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_papertrail_128x128.png -------------------------------------------------------------------------------- /docs/icons/icon_semaphore_2000x2000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_semaphore_2000x2000.png -------------------------------------------------------------------------------- /docs/icons/icon_statuspage_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_statuspage_512x512.png -------------------------------------------------------------------------------- /docs/icons/icon_webhookrc_1550x1550.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/icons/icon_webhookrc_1550x1550.png -------------------------------------------------------------------------------- /docs/logos/logo_chathooks_1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/logos/logo_chathooks_1024x1024.png -------------------------------------------------------------------------------- /docs/logos/logo_chathooks_1024x1024.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/logos/logo_chathooks_1024x1024.psd -------------------------------------------------------------------------------- /pkg/handlers/travisci/travisci_glip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/travisci/travisci_glip.png -------------------------------------------------------------------------------- /docs/logos/logo_chathooks_long_600x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/logos/logo_chathooks_long_600x150.png -------------------------------------------------------------------------------- /docs/logos/logo_chathooks_long_600x150.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/logos/logo_chathooks_long_600x150.psd -------------------------------------------------------------------------------- /docs/images/glip_webhook_step-3_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/images/glip_webhook_step-3_details.png -------------------------------------------------------------------------------- /docs/logos/logo_chathooks_long_4000x1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/logos/logo_chathooks_long_4000x1000.png -------------------------------------------------------------------------------- /docs/logos/logo_chathooks_long_4000x1000.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/logos/logo_chathooks_long_4000x1000.psd -------------------------------------------------------------------------------- /pkg/handlers/enchant/logo_enchant_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/enchant/logo_enchant_400x400.png -------------------------------------------------------------------------------- /pkg/handlers/heroku/logo_heroku_300x300.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/heroku/logo_heroku_300x300.jpg -------------------------------------------------------------------------------- /pkg/handlers/raygun/logo_raygun_290x290.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/raygun/logo_raygun_290x290.jpg -------------------------------------------------------------------------------- /docs/images/glip_webhook_step-2_add-webhook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/images/glip_webhook_step-2_add-webhook.png -------------------------------------------------------------------------------- /pkg/handlers/magnumci/logo_magnumci_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/magnumci/logo_magnumci_512x512.png -------------------------------------------------------------------------------- /pkg/handlers/travisci/logo_travisci_201x201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/travisci/logo_travisci_201x201.png -------------------------------------------------------------------------------- /pkg/handlers/userlike/logo_userlike_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/userlike/logo_userlike_512x512.png -------------------------------------------------------------------------------- /pkg/handlers/appsignal/logo_appsignal_400x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/appsignal/logo_appsignal_400x400.png -------------------------------------------------------------------------------- /docs/handlers/sumologic/sumo-logic-logo_100x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/sumologic/sumo-logic-logo_100x100.png -------------------------------------------------------------------------------- /docs/handlers/sumologic/sumo-logic-logo_110x110.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/sumologic/sumo-logic-logo_110x110.png -------------------------------------------------------------------------------- /docs/handlers/sumologic/sumo-logic-logo_116x116.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/sumologic/sumo-logic-logo_116x116.png -------------------------------------------------------------------------------- /docs/handlers/sumologic/sumo-logic-logo_120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/sumologic/sumo-logic-logo_120x120.png -------------------------------------------------------------------------------- /docs/handlers/sumologic/sumo-logic-logo_150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/sumologic/sumo-logic-logo_150x150.png -------------------------------------------------------------------------------- /docs/images/glip_webhook_step-1_add-integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/images/glip_webhook_step-1_add-integration.png -------------------------------------------------------------------------------- /pkg/handlers/confluence/logo_confluence_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/confluence/logo_confluence_256x256.png -------------------------------------------------------------------------------- /pkg/handlers/semaphore/logo_semaphore_2000x2000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/pkg/handlers/semaphore/logo_semaphore_2000x2000.png -------------------------------------------------------------------------------- /docs/handlers/bugsnag/event-example_new-error_slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/bugsnag/event-example_new-error_slack.png -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_http-check_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/pingdom/event-example_http-check_demo.png -------------------------------------------------------------------------------- /docs/handlers/gosquared/event-example_site-traffic_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/gosquared/event-example_site-traffic_demo.png -------------------------------------------------------------------------------- /docs/handlers/bugsnag/event-example_new-error_update_slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/bugsnag/event-example_new-error_update_slack.png -------------------------------------------------------------------------------- /docs/handlers/gosquared/event-example_smart-group-enter_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/gosquared/event-example_smart-group-enter_demo.png -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | # https://devcenter.heroku.com/articles/heroku-yml-build-manifest 2 | # Officially unsupported, but works. 3 | build: 4 | languages: 5 | - go 6 | 7 | run: 8 | web: chathooks -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | gofmt: 3 | enabled: true 4 | golint: 5 | enabled: true 6 | govet: 7 | enabled: true 8 | 9 | ratings: 10 | paths: 11 | - "**.go" 12 | -------------------------------------------------------------------------------- /docs/handlers/papertrail/event-example_notifications-array-len-1_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokify/chathooks/HEAD/docs/handlers/papertrail/event-example_notifications-array-len-1_demo.png -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: / 5 | schedule: 6 | interval: daily 7 | - package-ecosystem: github-actions 8 | directory: / 9 | schedule: 10 | interval: daily 11 | -------------------------------------------------------------------------------- /docs/handlers/heroku/event-example_build.txt: -------------------------------------------------------------------------------- 1 | app=secure-woodland-9775&user=example%40example.com&url=http%3A%2F%2Fsecure-woodland-9775.herokuapp.com&head=4f20bdd&head_long=4f20bdd&prev_head=&git_log=%20%20*%20Michael%20Friis%3A%20add%20bar&release=v7 -------------------------------------------------------------------------------- /docs/handlers/runscope/README.md: -------------------------------------------------------------------------------- 1 | # Runscope Webhook Notes 2 | 3 | * `response_status_code` is a string in webhook, not number 4 | * `,` is needed after `variables` 5 | * `initial_variables` and `variables` have unknown format. Are these `map[string]string`? -------------------------------------------------------------------------------- /examples/proxy_send/sample.env: -------------------------------------------------------------------------------- 1 | CHATHOOKS_REQ_INPUT_TYPE=aha 2 | CHATHOOKS_REQ_OUTPUT_TYPE=glip 3 | CHATHOOKS_REQ_TOKEN=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef 4 | CHATHOOKS_REQ_URL=https://hooks.glip.com/webhook/11112222-3333-4444-5555-666677778888 -------------------------------------------------------------------------------- /pkg/adapters/glip_config.go: -------------------------------------------------------------------------------- 1 | package adapters 2 | 3 | import ( 4 | "github.com/grokify/commonchat/glip/config" 5 | ) 6 | 7 | func GlipConfig() *config.ConverterConfig { 8 | return &config.ConverterConfig{ 9 | UseAttachments: true, 10 | UseFieldExtraSpacing: true, 11 | ConvertTripleBacktick: true, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/handlers/librato/event-example_alert-cleared.json: -------------------------------------------------------------------------------- 1 | { 2 | "alert":{ 3 | "id":6268092, 4 | "name":"a.test.name", 5 | "runbook_url":"", 6 | "version":2 7 | }, 8 | "account":"youremail@yourdomain.com", 9 | "trigger_time":1457040045, 10 | "clear":"normal" 11 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GO_BUILD_ENV := CGO_ENABLED=0 GOOS=linux GOARCH=amd64 2 | DOCKER_BUILD=$(shell pwd)/.docker_build 3 | DOCKER_CMD=$(DOCKER_BUILD)/chathooks 4 | 5 | $(DOCKER_CMD): clean 6 | mkdir -p $(DOCKER_BUILD) 7 | $(GO_BUILD_ENV) go build -v -o $(DOCKER_CMD) . 8 | 9 | clean: 10 | rm -rf $(DOCKER_BUILD) 11 | 12 | heroku: $(DOCKER_CMD) 13 | heroku container:push web -------------------------------------------------------------------------------- /docs/handlers/servicenow/message-example_incident.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Incident was created", 3 | "title":"Incident [INC00100200](https://example.com/) was created", 4 | "text":"**Short Description**\nI cannot login to my account although my username and password are correct", 5 | "icon_url":"http://milindhg.github.io/portfolio/images/SNOW_Icon.png" 6 | } -------------------------------------------------------------------------------- /docs/handlers/appsignal/event-example_marker.json: -------------------------------------------------------------------------------- 1 | { 2 | "marker":{ 3 | "user":"thijs", 4 | "site":"AppSignal", 5 | "environment":"test", 6 | "revision":"3107ddc4bb053d570083b4e3e425b8d62532ddc9", 7 | "repository":"git@github.com:appsignal/appsignal.git", 8 | "url":"https://appsignal.com/test/sites/1385f7e38c5ce90000000000/web/exceptions" 9 | } 10 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/README.md: -------------------------------------------------------------------------------- 1 | # Pingdom Webhook Notes 2 | 3 | * Pingdom webhook message does not include a check URL. 4 | 5 | ## References 6 | 7 | * [Pingdom Detailed Error Description Announcement](http://royal.pingdom.com/2007/09/19/new-pingdom-feature-detailed-error-descriptions/) 8 | * [Pingdom Error Descriptions](https://help.pingdom.com/hc/en-us/articles/214566145-What-will-trigger-an-outage-in-Pingdom-) -------------------------------------------------------------------------------- /docs/handlers/deskdotcom/event-example_formatted1.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Case updated", 3 | "title":"[Help Please!](https://example.desk.com/agent/case/1)", 4 | "attachments":[ 5 | { 6 | "fields":[ 7 | { 8 | "title":"Case Type", 9 | "value":"new email" 10 | } 11 | ] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /docs/handlers/slack/event-example_attachment.json: -------------------------------------------------------------------------------- 1 | { 2 | "username":"updown.io", 3 | "attachments":[ 4 | { 5 | "text":"*World* :+1:", 6 | "fallback":"Hello World :+1:", 7 | "mrkdwn_in":[ 8 | "text", 9 | "pretext", 10 | "fields" 11 | ], 12 | "pretext":"Hello" 13 | } 14 | ], 15 | "icon_url":"https://updown.io/square-logo.png" 16 | } -------------------------------------------------------------------------------- /docs/handlers/zendesk/event-example_notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "devices":[ 3 | { 4 | "identifier":"oiuytrdsdfghjk", 5 | "type":"ios" 6 | }, 7 | { 8 | "identifier":"iuytfrdcvbnmkl", 9 | "type":"android" 10 | } 11 | ], 12 | "notification":{ 13 | "body":"Agent replied something something", 14 | "title":"Agent replied", 15 | "ticket_id":"5" 16 | } 17 | } -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Chathooks URL Builder

5 | 6 |

inputType: 

7 |

outputType: 

8 |

url: 

9 |

token: 

10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_spamreport.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sg_event_id":"sendgrid_internal_event_id", 4 | "sg_message_id":"sendgrid_internal_message_id", 5 | "email":"email@example.com", 6 | "timestamp":1249948800, 7 | "unique_arg_key":"unique_arg_value", 8 | "category":[ 9 | "category1", 10 | "category2" 11 | ], 12 | "event":"spamreport", 13 | "asm_group_id":1 14 | } 15 | ] -------------------------------------------------------------------------------- /docs/handlers/logentries/event-example_alert.json: -------------------------------------------------------------------------------- 1 | { 2 | "alert":{ 3 | "name":"500 error" 4 | }, 5 | "host":{ 6 | "name":"Web", 7 | "hostname":"web.example.com" 8 | }, 9 | "log":{ 10 | "name":"access.log" 11 | }, 12 | "event":"Event", 13 | "context":[ 14 | { 15 | "t":1346202355889, 16 | "s":40634540484, 17 | "m":"[26/Aug/2012:10:58:50 +0100] POST /api..." 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /docs/handlers/appsignal/config_appsignal.md: -------------------------------------------------------------------------------- 1 | Adding AppSignal Notifications to Glip 2 | ====================================== 3 | 4 | 1. To receive a webhook, go to the "Integrations" tab the site's sidebar and fill out the url where you'd like to receive your webhook data. 5 | 1. Selct the notifications you wish to receive. 6 | 1. Enter your Glip webhook URL. 7 | 1. Click submit. 8 | 9 | See the [AppSignal webhook docs](http://docs.appsignal.com/application/integrations/webhooks.html) for more info. 10 | -------------------------------------------------------------------------------- /docs/handlers/raygun/config_raygun.md: -------------------------------------------------------------------------------- 1 | Adding Raygun Notifications to Glip 2 | =================================== 3 | 4 | 1. Open your application in Raygun and go to "Integrations" from the left-hand side menu. 5 | 1. On the Integrations page, click the "Webhook" button. 6 | 1. Specify the endpoint the webhook will be delivered to. 7 | 1. Enable (or disable) the webhook and then click "Save Changes." 8 | 9 | See the [Raygun webhook docs](https://raygun.com/docs/integrations/webhooks) for more info. 10 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: lint 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | lint: 6 | strategy: 7 | matrix: 8 | go-version: [1.x] 9 | platform: [ubuntu-latest] 10 | runs-on: ${{ matrix.platform }} 11 | 12 | steps: 13 | - uses: actions/checkout@v6.0.1 14 | - name: golangci-lint 15 | uses: golangci/golangci-lint-action@v9 16 | with: 17 | skip-go-installation: true 18 | version: latest 19 | args: --timeout 3m --verbose 20 | -------------------------------------------------------------------------------- /pkg/config/configuration_test.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var ConfigurationTests = []struct { 8 | v int 9 | want string 10 | }{ 11 | {8080, ":8080"}} 12 | 13 | func TestConfigurationAddress(t *testing.T) { 14 | for _, tt := range ConfigurationTests { 15 | cfg := Configuration{ 16 | Port: tt.v} 17 | 18 | addr := cfg.Address() 19 | if tt.want != addr { 20 | t.Errorf("Configuration.Address(%v): want %v, got %v", tt.v, tt.want, addr) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/handlers/apteligent/event-example_alert-close.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold_value":"1", 3 | "description":"The Crashes alert on Crittercism was resolved at 06:40 PM UTC.", 4 | "metric":"Crashes", 5 | "crittercism_app_id":"54aab27451de5e9f042ec7ee", 6 | "trigger_id":"54aabecc1787845ae400000f", 7 | "state":"RESOLVED", 8 | "alert_url":"https://app.crittercism.com/developers/alerts/54aab27451de5e9f042ec7ee?alertId=54aabecc1787845ae400000f", 9 | "filters":"{}", 10 | "application_name":"Crittercism" 11 | } -------------------------------------------------------------------------------- /examples/proxy_send/README.md: -------------------------------------------------------------------------------- 1 | # Test Proxy Send 2 | 3 | `proxy_send.go` is a test program which will send a test message to a live Chathooks URL. 4 | 5 | Run it from the command line as follows: 6 | 7 | ``` 8 | $ go run proxy_send.go --url https://hooks.glip.com/webhook/ \ 9 | --input bugsnag --output glip --token -c 10 | ``` 11 | 12 | Using AWS API Gateway, a hook URL can look like the following: 13 | 14 | `https://0123456789.execute-api.us-west-1.amazonaws.com/prod/hook` 15 | -------------------------------------------------------------------------------- /docs/handlers/raygun/event-example_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "event":"error_notification", 3 | "eventType":"NewErrorOccurred", 4 | "error":{ 5 | "url":"http://app.raygun.io/error-url", 6 | "message":"", 7 | "firstOccurredOn":"1970-01-28T01:49:36Z", 8 | "lastOccurredOn":"1970-01-28T01:49:36Z", 9 | "usersAffected":1, 10 | "totalOccurrences":1 11 | }, 12 | "application":{ 13 | "name":"application name", 14 | "url":"http://app.raygun.io/application-url" 15 | } 16 | } -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_dropped.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sg_event_id":"sendgrid_internal_event_id", 4 | "sg_message_id":"sendgrid_internal_message_id", 5 | "email":"email@example.com", 6 | "timestamp":1249948800, 7 | "smtp-id":"", 8 | "unique_arg_key":"unique_arg_value", 9 | "category":[ 10 | "category1", 11 | "category2" 12 | ], 13 | "reason":"Bounced Address", 14 | "event":"dropped" 15 | } 16 | ] -------------------------------------------------------------------------------- /docs/handlers/heroku/config_heroku.md: -------------------------------------------------------------------------------- 1 | Adding Heroku Notifications to Glip 2 | =================================== 3 | 4 | 1. Use the Heroku command line app to add a deployment webhook to your app with the following command, replacing the example `url` with your webhook URL. 5 | 6 | ```bash 7 | $ heroku addons:create deployhooks:http \ 8 | --url=http://example.org 9 | Adding deployhooks:http to myapp...Done. 10 | ``` 11 | 12 | See the [Heroku webhook docs](https://devcenter.heroku.com/articles/deploy-hooks#http-post-hook) for more info. 13 | -------------------------------------------------------------------------------- /docs/handlers/wootric/event-example_decline-created.txt: -------------------------------------------------------------------------------- 1 | decline[id]=19&decline[email]=nps@example.com&decline[external_id]=123abc&decline[ip_address]=127.0.0.1&decline[origin_url]=https%3A%2F%2Fwootric.com%2F&decline[end_user_id]=31&decline[end_user_properties][pricing_plan]=Pro&decline[end_user_properties][product_plan]=Web%20App&decline[survey_id]=1147&decline[created_at]=2016-08-04%2013%3A58%3A21%20-0700&decline[updated_at]=2016-08-04%2013%3A58%3A21%20-0700&event_name=created&account_token=NPS-xxxxxxx&survey_mode=NPS×tamp=2016-08-04%2013%3A58%3A23%20-0700 -------------------------------------------------------------------------------- /pkg/handlers/heroku/handler_heroku_out_util.go: -------------------------------------------------------------------------------- 1 | package heroku 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "build") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/raygun/handler_raygun_out_util.go: -------------------------------------------------------------------------------- 1 | package raygun 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "error") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /docs/handlers/deskdotcom/event-example_formatted2.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"New email case", 3 | "title":"New email case from John Smith from example.com - #36", 4 | "attachments":[ 5 | { 6 | "fields":[ 7 | { 8 | "title":"Assigned To", 9 | "value":"(Unassigned)" 10 | }, 11 | { 12 | "title":"Case Body", 13 | "value":"I can't log into my account" 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /pkg/handlers/codeship/handler_codeship_util.go: -------------------------------------------------------------------------------- 1 | package codeship 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "build") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/magnumci/handler_magnumci_util.go: -------------------------------------------------------------------------------- 1 | package magnumci 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "build") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/travisci/handler_travisci_util.go: -------------------------------------------------------------------------------- 1 | package travisci 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "build") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/userlike/util.go: -------------------------------------------------------------------------------- 1 | package userlike 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /docs/handlers/appsignal/event-example_performance.json: -------------------------------------------------------------------------------- 1 | { 2 | "performance":{ 3 | "site":"AppSignal", 4 | "action":"App::ExceptionsController#index", 5 | "path":"/slow", 6 | "duration":552.7897429999999, 7 | "status":200, 8 | "hostname":"frontend.appsignal.com", 9 | "revision":"3107ddc4bb053d570083b4e3e425b8d62532ddc9", 10 | "user":"thijs", 11 | "url":"https://appsignal.com/test/sites/1385f7e38c5ce90000000000/web/performance/App::ExceptionsController-index", 12 | "environment":"test" 13 | } 14 | } -------------------------------------------------------------------------------- /docs/handlers/asana/event-example_notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "events":[ 3 | { 4 | "action":"changed", 5 | "created_at":"2013-08-21T18:20:37.972Z", 6 | "parent":null, 7 | "resource":1337, 8 | "type":"task", 9 | "user":1123 10 | }, 11 | { 12 | "action":"changed", 13 | "created_at":"2013-08-21T18:22:45.421Z", 14 | "parent":null, 15 | "resource":1338, 16 | "type":"task", 17 | "user":1428 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /pkg/handlers/circleci/handler_circleci_out_util.go: -------------------------------------------------------------------------------- 1 | package circleci 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "build") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/datadog/handler_datadog_out_util.go: -------------------------------------------------------------------------------- 1 | package datadog 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "formatted1") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/enchant/handler_enchant_util.go: -------------------------------------------------------------------------------- 1 | package enchant 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "notification") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/aha/handler_aha_out_util.go: -------------------------------------------------------------------------------- 1 | package aha 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/runscope/handler_runscope_out_util.go: -------------------------------------------------------------------------------- 1 | package runscope 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "notification") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/victorops/handler_victorops_out_util.go: -------------------------------------------------------------------------------- 1 | package victorops 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, "formatted1") 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/wootric/wootric_examples.go: -------------------------------------------------------------------------------- 1 | package wootric 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/bugsnag/handler_bugsnag_util.go: -------------------------------------------------------------------------------- 1 | package bugsnag 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/slack/handler_slack_in_util.go: -------------------------------------------------------------------------------- 1 | package slack 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/appsignal/handler_appsignal_util.go: -------------------------------------------------------------------------------- 1 | package appsignal 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/librato/handler_librato_out_util.go: -------------------------------------------------------------------------------- 1 | package librato 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/marketo/handler_marketo_out_util.go: -------------------------------------------------------------------------------- 1 | package marketo 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/pingdom/handler_pingdom_out_util.go: -------------------------------------------------------------------------------- 1 | package pingdom 2 | 3 | import ( 4 | "github.com/grokify/chathooks/pkg/config" 5 | "github.com/grokify/chathooks/pkg/handlers" 6 | "github.com/grokify/chathooks/pkg/util" 7 | 8 | cc "github.com/grokify/commonchat" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/semaphore/handler_semaphore_util.go: -------------------------------------------------------------------------------- 1 | package semaphore 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/confluence/handler_confluence_util.go: -------------------------------------------------------------------------------- 1 | package confluence 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/gosquared/handler_gosquared_out_util.go: -------------------------------------------------------------------------------- 1 | package gosquared 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/gosquared2/handler_gosquared2_out_util.go: -------------------------------------------------------------------------------- 1 | package gosquared2 2 | 3 | import ( 4 | "github.com/grokify/chathooks/pkg/config" 5 | "github.com/grokify/chathooks/pkg/handlers" 6 | "github.com/grokify/chathooks/pkg/util" 7 | cc "github.com/grokify/commonchat" 8 | ) 9 | 10 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 11 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 12 | if err != nil { 13 | return cc.Message{}, err 14 | } 15 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 16 | } 17 | -------------------------------------------------------------------------------- /pkg/handlers/opsgenie/handler_opsgenie_out_util.go: -------------------------------------------------------------------------------- 1 | package opsgenie 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /docs/handlers/semaphore/config_semaphore.md: -------------------------------------------------------------------------------- 1 | Adding Semaphore CI Notifications to Glip 2 | ========================================= 3 | 4 | 1. Navigate to the project you wish to set up a notification for. 5 | 1. Click on “settings” next to your project on the dashboard. 6 | 1. Open the “Webhooks” tab on project settings page. 7 | 1. Add your Glip URL to receive the payload. 8 | 1. Click on “Test” to receive an example payload and verify that it all works. 9 | 1. Save your settings. 10 | 11 | See the [Semaphore CI webhook docs](https://semaphoreci.com/docs/post-build-webhooks.html) for more info. 12 | -------------------------------------------------------------------------------- /pkg/handlers/apteligent/handler_apteligent_out_util.go: -------------------------------------------------------------------------------- 1 | package apteligent 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/deskdotcom/handler_deskdotcom_out_util.go: -------------------------------------------------------------------------------- 1 | package deskdotcom 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/papertrail/handler_papertrail_out_util.go: -------------------------------------------------------------------------------- 1 | package papertrail 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/handlers/statuspage/handler_statuspage_out_util.go: -------------------------------------------------------------------------------- 1 | package statuspage 2 | 3 | import ( 4 | cc "github.com/grokify/commonchat" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/util" 9 | ) 10 | 11 | func ExampleMessage(cfg config.Configuration, data util.ExampleData, eventSlug string) (cc.Message, error) { 12 | bytes, err := data.ExampleMessageBytes(HandlerKey, eventSlug) 13 | if err != nil { 14 | return cc.Message{}, err 15 | } 16 | return Normalize(cfg, handlers.HandlerRequest{Body: bytes}) 17 | } 18 | -------------------------------------------------------------------------------- /docs/handlers/librato/event-example_2.json: -------------------------------------------------------------------------------- 1 | {"alert":{"id":6799146,"name":"glip.test","runbook_url":"","version":2},"account":"gmafglip@gmail.com","trigger_time":1488887279,"conditions":[{"id":21352240,"type":"above","threshold":50,"summary_function":"average","duration":300},{"id":21363654,"type":"above","threshold":20,"summary_function":"min","duration":300}],"violations":{"test-source":[{"metric":"librato.cpu.percent.idle","value":92,"recorded_at":1488887279,"condition_violated":21352240},{"metric":"librato.memory.memory.used","value":62,"recorded_at":1488887279,"condition_violated":21363654}]},"triggered_by_user_test":true} -------------------------------------------------------------------------------- /docs/icons/icon_victorops_blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/handlers/apteligent/event-example_alert-open.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold_value":"1", 3 | "triggering_value":"4", 4 | "incident_time":"2015-01-05T18:15:56.976000", 5 | "description":"Alert on Crittercism at 06:15 PM UTC. Crashes threshold 4 exceeds 1.", 6 | "metric":"Crashes", 7 | "crittercism_app_id":"54aab27451de5e9f042ec7ee", 8 | "trigger_id":"54aabecc1787845ae400000f", 9 | "state":"TRIGGERED", 10 | "alert_url":"https://app.crittercism.com/developers/alerts/54aab27451de5e9f042ec7ee?incidentId=54aad4dcf39917103e0041b6", 11 | "filters":"{}", 12 | "application_name":"Crittercism" 13 | } -------------------------------------------------------------------------------- /docs/handlers/apteligent/event-example_alert.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold_value":"2", 3 | "triggering_value":"9", 4 | "incident_time":"2014-05-08T01:30:24.230000", 5 | "description":"Alert on Zapier Demo at 01:30 AM UTC. App Loads threshold 9 exceeds 2.", 6 | "metric":"App Loads", 7 | "crittercism_app_id":"5351712740ec921171000003", 8 | "trigger_id":"536add5b0729df3fe9000008", 9 | "state":"TRIGGERED", 10 | "alert_url":"https://app.crittercism.com/developers/alerts/5351712740ec921171000003?incidentId=536ade306f10274d97000008", 11 | "filters":"{}", 12 | "application_name":"Zapier Demo" 13 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM heroku/heroku:16-build as build 2 | 3 | COPY . /app 4 | WORKDIR /app 5 | 6 | # Setup buildpack 7 | RUN mkdir -p /tmp/buildpack/heroku/go /tmp/build_cache /tmp/env 8 | RUN curl https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/go.tgz | tar xz -C /tmp/buildpack/heroku/go 9 | 10 | #Execute Buildpack 11 | RUN STACK=heroku-16 /tmp/buildpack/heroku/go/bin/compile /app /tmp/build_cache /tmp/env 12 | 13 | # Prepare final, minimal image 14 | FROM heroku/heroku:16 15 | 16 | COPY --from=build /app /app 17 | ENV HOME /app 18 | WORKDIR /app 19 | RUN useradd -m heroku 20 | USER heroku 21 | CMD /app/bin/chathooks -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Set your GO env variables 2 | 3 | ``` 4 | GOPATH=~/go 5 | PATH=$PATH:$GOPATH/bin 6 | ``` 7 | 8 | Prepare your workspace 9 | 10 | ``` 11 | mkdir -p ~/go/src/github.com/grokify 12 | ``` 13 | 14 | Clone the project 15 | 16 | ``` 17 | cd ~/go/src/github.com/grokify 18 | clone git@github.com:grokify/chathooks.git 19 | cd chathooks 20 | ``` 21 | 22 | Install godep (dependency manager) 23 | 24 | ``` 25 | go get github.com/tools/godep 26 | ``` 27 | 28 | Download all dependencies 29 | 30 | ``` 31 | godep restore 32 | ``` 33 | 34 | Run the project then visit http://localhost:3000/ 35 | 36 | ``` 37 | go run main.go 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/handlers/datadog/event-example_formatted1.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Event triggered", 3 | "title":"[Event 1234567](https://app.datadoghq.com/event/jump_to?event_id=123456): [Triggered] [Memory Alert]", 4 | "attachments":[ 5 | { 6 | "fields":[ 7 | { 8 | "title":"Priority", 9 | "value":"normal" 10 | }, 11 | { 12 | "title":"Alert", 13 | "value":"system.load.1 over host:my-host was > 0 at least once during the last 1m" 14 | } 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/config_userlike.md: -------------------------------------------------------------------------------- 1 | Adding Userlike Notifications to Glip 2 | ===================================== 3 | 4 | 1. Go to the [Addons section](https://www.userlike.com/en/dashboard/config/addon/overview) and select the API configure option. 5 | 1. Enter the callback URL of your Glip API endpoint. HTTP and HTTPS are supported as protocols. 6 | 1. Select the filtering you wish to receive for Offline Messages and/or Chats. 7 | 1. Select the data you wish to add including detailed user information and/or custom data. 8 | 9 | See the [Userlike webhook docs](https://www.userlike.com/en/public/tutorial/addon/api) for more info. 10 | -------------------------------------------------------------------------------- /docs/start.md: -------------------------------------------------------------------------------- 1 | # Chathooks Developer Guide 2 | 3 | Chathooks is a webhook to chat proxy framework that converts outbound cloud app webhooks to inbound team chat webhooks. 4 | 5 | ## Creating a New Handler 6 | 7 | 1. Select one of the handlers in the `src/handlers` folder and create a duplicate, for example in th dirctory `src/handlers/myapp`. 8 | 1. Add examples `docs/handlers/myapp`. 9 | 1. Add examples filenames to `src/util/example_events.go`. 10 | 1. Add icon to `docs/icons` folder. Add icon reference to `src/config/icons/go`. 11 | 1. Add to `examples/local_send/local_send.go`. 12 | 1. Run `examples/local_send/local_send.go` to test handler. -------------------------------------------------------------------------------- /docs/handlers/wootric/event-example_response-created.txt: -------------------------------------------------------------------------------- 1 | response[id]=1128&response[email]=nps@example.com&response[external_id]=123abc&response[score]=7&response[text]=okay&response[ip_address]=127.0.0.1&response[origin_url]=https%3A%2F%2Fwootric.com%2F&response[end_user_id]=30&response[end_user_properties][pricing_plan]=Enterprise&response[end_user_properties][product_plan]=Web%20App&response[survey_id]=1146&response[created_at]=2016-08-04%2013%3A57%3A26%20-0700&response[updated_at]=2016-08-04%2013%3A57%3A26%20-0700&response[excluded_from_calculations]=false&event_name=created&account_token=NPS-xxxxxxx&survey_mode=NPS×tamp=2016-08-04%2013%3A57%3A31%20-0700 -------------------------------------------------------------------------------- /docs/handlers/magnumci/config_magnumci.md: -------------------------------------------------------------------------------- 1 | Adding Magnum CI Notifications to Glip 2 | ====================================== 3 | 4 | 1. Login to Magnum CI, and then on the Dashboard page, menu, click your project that you want to add a webhook to. 5 | 1. On the Project page menu bar, click Settings. 6 | 1. In the Basic Setup section on the left navigation menu, click Web Hooks. The Web Hooks page is displayed for your project. 7 | 1. In the Add a Web Hook field, enter your Glip webhook URL for the alert, and then click the Add icon. 8 | 9 | See the [Magnum CI webhook docs](https://github.com/magnumci/documentation/blob/master/webhooks.md) for more info. 10 | -------------------------------------------------------------------------------- /docs/handlers/victorops/event-example_formatted1.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Event triggered", 3 | "title":"[Event 1234567](https://portal.victorops.com/client/-/popoutIncident?incidentName=1): [Triggered] [Memory Alert]", 4 | "attachments":[ 5 | { 6 | "fields":[ 7 | { 8 | "title":"Priority", 9 | "value":"normal" 10 | }, 11 | { 12 | "title":"Alert", 13 | "value":"system.load.1 over host:my-host was > 0 at least once during the last 1m" 14 | } 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /docs/handlers/codeship/event-example_build.json: -------------------------------------------------------------------------------- 1 | { 2 | "build":{ 3 | "build_url":"https://www.codeship.com/projects/10213/builds/973711", 4 | "commit_url":"https://github.com/codeship/docs/commit/96943dc5269634c211b6fbb18896ecdcbd40a047", 5 | "project_id":10213, 6 | "build_id":973711, 7 | "status":"testing", 8 | "project_name":"codeship/docs", 9 | "commit_id":"96943dc5269634c211b6fbb18896ecdcbd40a047", 10 | "short_commit_id":"96943", 11 | "message":"Merge pull request #34 from codeship/feature/shallow-clone", 12 | "committer":"beanieboi", 13 | "branch":"master" 14 | } 15 | } -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | enable: 4 | - dogsled 5 | - dupl 6 | - gosec 7 | - misspell 8 | - nakedret 9 | - staticcheck 10 | - unconvert 11 | - unparam 12 | - whitespace 13 | exclusions: 14 | generated: lax 15 | presets: 16 | - comments 17 | - common-false-positives 18 | - legacy 19 | - std-error-handling 20 | paths: 21 | - third_party$ 22 | - builtin$ 23 | - examples$ 24 | formatters: 25 | enable: 26 | - gofmt 27 | - goimports 28 | exclusions: 29 | generated: lax 30 | paths: 31 | - third_party$ 32 | - builtin$ 33 | - examples$ 34 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_escalate.json: -------------------------------------------------------------------------------- 1 | { 2 | "escalationId":"51859f57-7fad-467b-ad79-59acbc69cb6a", 3 | "headers":{ 4 | "foo":"bar" 5 | }, 6 | "integrationName":"Webhook_Test", 7 | "escalationNotify":{ 8 | "name":"test@ifountain.com", 9 | "id":"64818849-71d6-40ce-87c6-ed5e588702fd", 10 | "type":"default", 11 | "entity":"user" 12 | }, 13 | "integrationId":"868be72a-8015-432e-8b23-c1f7f4374baa", 14 | "escalationName":"test_esc", 15 | "alert":{ 16 | "alertId":"7ba97e3a-d328-4b5e-8f9a-39e945a3869a" 17 | }, 18 | "escalationTime":0, 19 | "action":"Escalate", 20 | "repeatCount":0 21 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | workflow_dispatch: 10 | jobs: 11 | test: 12 | strategy: 13 | matrix: 14 | go-version: [1.25.x, 1.24.x] 15 | platform: [ubuntu-latest, macos-latest, windows-latest] 16 | runs-on: ${{ matrix.platform }} 17 | steps: 18 | - name: Install Go 19 | if: success() 20 | uses: actions/setup-go@v6 21 | with: 22 | go-version: ${{ matrix.go-version }} 23 | - name: Checkout code 24 | uses: actions/checkout@v6.0.1 25 | - name: Run tests 26 | run: go test -v -covermode=count ./... 27 | -------------------------------------------------------------------------------- /docs/icons/icon_twitter.svg: -------------------------------------------------------------------------------- 1 | twitter 2 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_delete.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "tinyId":"23", 8 | "alias":"aliastest", 9 | "entity":"", 10 | "message":"test alert", 11 | "updatedAt":1420452374669001603, 12 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 13 | "username":"fili@ifountain.com", 14 | "source":"fili@ifountain.com", 15 | "createdAt":1420452191104, 16 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d" 17 | }, 18 | "action":"Delete", 19 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 20 | "integrationName":"Integration1" 21 | } -------------------------------------------------------------------------------- /docs/handlers/appsignal/event-example_exception.json: -------------------------------------------------------------------------------- 1 | { 2 | "exception":{ 3 | "exception":"ActionView::Template::Error", 4 | "site":"AppSignal", 5 | "message":"undefined method 'encoding' for nil:NilClass", 6 | "action":"App::ErrorController#show", 7 | "path":"/errors", 8 | "revision":"3107ddc4bb053d570083b4e3e425b8d62532ddc9", 9 | "user":"thijs", 10 | "first_backtrace_line":"/usr/local/rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/cgi/util.rb:7:in 'escape'", 11 | "url":"https://appsignal.com/test/sites/1385f7e38c5ce90000000000/web/exceptions/App::SnapshotsController-show/ActionView::Template::Error", 12 | "environment":"test" 13 | } 14 | } -------------------------------------------------------------------------------- /docs/icons/icon_statuspage.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 9 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_processed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sg_event_id":"sendgrid_internal_event_id", 4 | "sg_message_id":"sendgrid_internal_message_id", 5 | "email":"email@example.com", 6 | "timestamp":1249948800, 7 | "smtp-id":"", 8 | "unique_arg_key":"unique_arg_value", 9 | "category":[ 10 | "category1", 11 | "category2" 12 | ], 13 | "event":"processed", 14 | "newsletter":{ 15 | "newsletter_user_list_id":"10557865", 16 | "newsletter_id":"1943530", 17 | "newsletter_send_id":"2308608" 18 | }, 19 | "asm_group_id":1, 20 | "send_at":1249949000 21 | } 22 | ] -------------------------------------------------------------------------------- /docs/handlers/confluence/event-example_page-created.json: -------------------------------------------------------------------------------- 1 | { 2 | "page":{ 3 | "spaceKey":"~admin", 4 | "modificationDate":1471926079631, 5 | "creatorKey":"ff80808154510724015451074c160001", 6 | "creatorName":"admin", 7 | "lastModifierKey":"ff80808154510724015451074c160001", 8 | "self":"https://cloud-development-environment.atlassian.net/wiki/display/~admin/Some+random+test+page", 9 | "lastModifierName":"admin", 10 | "id":16777227, 11 | "title":"Some random test page", 12 | "creationDate":1471926079631, 13 | "version":1 14 | }, 15 | "user":"admin", 16 | "userKey":"ff80808154510724015451074c160001", 17 | "timestamp":1471926079645, 18 | "username":"admin" 19 | } -------------------------------------------------------------------------------- /docs/handlers/magnumci/event-example_build.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":1603, 3 | "project_id":43, 4 | "title":"[PASS] project-name #130 (master - e91e132) by Dan Sosedoff", 5 | "number":130, 6 | "commit":"e91e132612d263d95211aae6de2df9e503f22704", 7 | "author":"Dan Sosedoff", 8 | "committer":"Dan Sosedoff", 9 | "message":"Commit Message", 10 | "branch":"master", 11 | "state":"finished", 12 | "status":"pass", 13 | "result":0, 14 | "duration":158, 15 | "duration_string":"2m 38s", 16 | "commit_url":"http://domain.com/commit/e91e132612d263...", 17 | "compare_url":null, 18 | "build_url":"http://magnum-ci.com/projects/43/builds/1603", 19 | "started_at":"2013-02-14T00:09:01-06:00", 20 | "finished_at":"2013-02-14T00:11:39-06:00" 21 | } -------------------------------------------------------------------------------- /docs/handlers/marketo/event-example_demo1.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Contact Us form fill", 3 | "title":"Marketo", 4 | "attachments":[ 5 | { 6 | "fields":[ 7 | { 8 | "title":"Name", 9 | "value":"Jane Doe" 10 | }, 11 | { 12 | "title":"Email", 13 | "value":"jane.doe@example.com" 14 | }, 15 | { 16 | "title":"Company", 17 | "value":"Example.com" 18 | }, 19 | { 20 | "title":"Message", 21 | "value":"We are glad to see you!" 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /docs/handlers/marketo/event-example_formatted2.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"New lead visit", 3 | "attachments":[ 4 | { 5 | "fields":[ 6 | { 7 | "title":"Name", 8 | "value":"Jane Doe" 9 | }, 10 | { 11 | "title":"Email", 12 | "value":"jane.doe@example.com" 13 | }, 14 | { 15 | "title":"Company", 16 | "value":"Example.com" 17 | }, 18 | { 19 | "title":"Visited URL", 20 | "value":"https://example.com/integrating-glip-with-marketo" 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /docs/handlers/quickbooks/example__notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventNotifications":[ 3 | { 4 | "realmId":"1185883450", 5 | "dataChangeEvent":{ 6 | "entities":[ 7 | { 8 | "name":"Customer", 9 | "id":"1", 10 | "operation":"Create", 11 | "lastUpdated":"2015-10-05T14:42:19-0700" 12 | }, 13 | { 14 | "name":"Vendor", 15 | "id":"1", 16 | "operation":"Create", 17 | "lastUpdated":"2015-10-05T14:42:19-0700" 18 | } 19 | ] 20 | } 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /docs/handlers/updown/event-example_recovery.json: -------------------------------------------------------------------------------- 1 | { 2 | "username":"updown.io", 3 | "attachments":[ 4 | { 5 | "text":"Up since *23:29:36 (UTC)*, after being down for *4 minutes* because: *Bad Gateway*", 6 | "fallback":"RECOVERY: Chathooks Up since 23:29:36 (UTC), after being down for 4 minutes because: Bad Gateway", 7 | "mrkdwn_in":[ 8 | "text", 9 | "pretext", 10 | "fields" 11 | ], 12 | "pretext":"RECOVERY: :sunny:", 13 | "author_name":"Chathooks", 14 | "author_icon":"https://updown.io/checks/wgsw/favicon", 15 | "author_link":"https://chathooks.ngrok.io/about", 16 | "color":"#5c4", 17 | "fields":[ 18 | 19 | ] 20 | } 21 | ], 22 | "icon_url":"https://updown.io/square-logo.png" 23 | } -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_close.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452374669001603, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"" 21 | }, 22 | "action":"Close", 23 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 24 | "integrationName":"Integration1" 25 | } -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/grokify/mogo/config" 8 | "github.com/grokify/sogo/net/http/httpsimple" 9 | 10 | "github.com/grokify/chathooks/pkg/service" 11 | ) 12 | 13 | /* 14 | 15 | Use the `CHATHOOKS_TOKENS` environment variable to load secret 16 | tokens as a comma delimited string. 17 | 18 | */ 19 | 20 | // CHATHOOKS_URL=http://localhost:8080/hook CHATHOOKS_HOME_URL=http://localhost:8080 go run main.go 21 | 22 | func main() { 23 | if _, err := config.LoadDotEnv( 24 | []string{os.Getenv("ENV_PATH"), "./.env"}, 1); err != nil { 25 | panic(err) 26 | } 27 | 28 | svc := service.NewService() 29 | fmt.Printf("Starting on port [%d] with engine [%s].\n", 30 | svc.PortInt(), svc.HTTPEngine()) 31 | httpsimple.Serve(svc) 32 | } 33 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_acknowledge.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452224764002246, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"" 21 | }, 22 | "action":"Acknowledge", 23 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 24 | "integrationName":"Integration1" 25 | } -------------------------------------------------------------------------------- /docs/handlers/marketo/event-example_formatted1.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Contact Us form fill", 3 | "attachments":[ 4 | { 5 | "fields":[ 6 | { 7 | "title":"Name", 8 | "value":"Jane Doe" 9 | }, 10 | { 11 | "title":"Email", 12 | "value":"jane.doe@example.com" 13 | }, 14 | { 15 | "title":"Company", 16 | "value":"Example.com" 17 | }, 18 | { 19 | "title":"Message", 20 | "value":"Hello, I'm looking to speak to someone about buying your product." 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_unacknowledge.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452224764002246, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"" 21 | }, 22 | "action":"UnAcknowledge", 23 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 24 | "integrationName":"Integration1" 25 | } -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_open.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "email":"email@example.com", 4 | "timestamp":1249948800, 5 | "ip":"255.255.255.255", 6 | "sg_event_id":"sendgrid_internal_event_id", 7 | "sg_message_id":"sendgrid_internal_message_id", 8 | "useragent":"Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)", 9 | "event":"open", 10 | "unique_arg_key":"unique_arg_value", 11 | "category":[ 12 | "category1", 13 | "category2" 14 | ], 15 | "newsletter":{ 16 | "newsletter_user_list_id":"10557865", 17 | "newsletter_id":"1943530", 18 | "newsletter_send_id":"2308608" 19 | }, 20 | "asm_group_id":1 21 | } 22 | ] -------------------------------------------------------------------------------- /pkg/handlers/slack/handler_slack_in_test.go: -------------------------------------------------------------------------------- 1 | package slack 2 | 3 | import ( 4 | "testing" 5 | 6 | ccslack "github.com/grokify/commonchat/slack" 7 | ) 8 | 9 | var SlackWebhookMessageFromBytesTests = []struct { 10 | v []byte 11 | want ccslack.Message 12 | }{ 13 | {[]byte(`{"username":"Ghost Bot [bot]"}`), ccslack.Message{Username: "Ghost Bot [bot]"}}} 14 | 15 | func TestSlackWebhookMessageFromBytes(t *testing.T) { 16 | for _, tt := range SlackWebhookMessageFromBytesTests { 17 | msg, err := ccslack.ParseMessageJSON(tt.v) 18 | 19 | if err != nil { 20 | t.Errorf("ParseMessageJSON(%v): want %v, err %v", tt.v, tt.want, err) 21 | } 22 | 23 | if tt.want.Username != msg.Username { 24 | t.Errorf("ParseMessageJSON(%v): want %v, got %v", tt.v, tt.want, msg.Username) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_custom-action-test-action.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452275002000962, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"" 21 | }, 22 | "action":"TestAction", 23 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 24 | "integrationName":"Integration1" 25 | } -------------------------------------------------------------------------------- /docs/handlers/hubspot/event-example_notification.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "objectId":1246965, 4 | "propertyName":"lifecyclestage", 5 | "propertyValue":"subscriber", 6 | "changeSource":"ACADEMY", 7 | "eventId":3816279340, 8 | "subscriptionId":25, 9 | "portalId":33, 10 | "appId":1160452, 11 | "occurredAt":1462216307945, 12 | "subscriptionType":"contact.propertyChange", 13 | "attemptNumber":0 14 | }, 15 | { 16 | "objectId":1246978, 17 | "changeSource":"IMPORT", 18 | "eventId":3816279480, 19 | "subscriptionId":22, 20 | "portalId":33, 21 | "appId":1160452, 22 | "occurredAt":1462216307945, 23 | "subscriptionType":"contact.creation", 24 | "attemptNumber":0 25 | } 26 | ] -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_add-team.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452256147001924, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"", 21 | "team":"team2" 22 | }, 23 | "action":"AddTeam", 24 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 25 | "integrationName":"Integration1" 26 | } -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_add-note.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452275002000962, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"", 21 | "note":"note to test alert" 22 | }, 23 | "action":"AddNote", 24 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 25 | "integrationName":"Integration1" 26 | } -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_remove-tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452275002000962, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "removedTags":"tag3", 13 | "message":"test alert", 14 | "username":"fili@ifountain.com", 15 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 16 | "source":"fili@ifountain.com", 17 | "alias":"aliastest", 18 | "tinyId":"23", 19 | "createdAt":1420452191104, 20 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 21 | "entity":"" 22 | }, 23 | "action":"RemoveTags", 24 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 25 | "integrationName":"Integration1" 26 | } -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_delivered.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "response":"250 OK", 4 | "sg_event_id":"sendgrid_internal_event_id", 5 | "sg_message_id":"sendgrid_internal_message_id", 6 | "event":"delivered", 7 | "email":"email@example.com", 8 | "timestamp":1249948800, 9 | "smtp-id":"", 10 | "unique_arg_key":"unique_arg_value", 11 | "category":[ 12 | "category1", 13 | "category2" 14 | ], 15 | "newsletter":{ 16 | "newsletter_user_list_id":"10557865", 17 | "newsletter_id":"1943530", 18 | "newsletter_send_id":"2308608" 19 | }, 20 | "asm_group_id":1, 21 | "ip":"127.0.0.1", 22 | "tls":"1", 23 | "cert_err":"1" 24 | } 25 | ] -------------------------------------------------------------------------------- /examples/build_hook_url/build_hook_url.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/google/go-querystring/query" 7 | ) 8 | 9 | type Options struct { 10 | InputType string `url:"inputType"` 11 | OutputType string `url:"outputType"` 12 | URL string `url:"url"` 13 | Token string `url:"token"` 14 | } 15 | 16 | func BuildURL(baseUrl string, opts Options) string { 17 | v, _ := query.Values(opts) 18 | return fmt.Sprintf("%v?%v", baseUrl, v.Encode()) 19 | } 20 | 21 | func main() { 22 | baseUrl := "https://12345678.ngrok.io/hook" 23 | opts := Options{ 24 | InputType: "aha", 25 | OutputType: "glip", 26 | URL: "https://hooks.glip.com/webhook/11112222-3333-4444-5555-666677778888", 27 | Token: "deadbeefdeadbeefdeadbeefdeadbeef", 28 | } 29 | fmt.Println(BuildURL(baseUrl, opts)) 30 | } 31 | -------------------------------------------------------------------------------- /docs/handlers/marketo/event-example_formatted1_template.json: -------------------------------------------------------------------------------- 1 | { 2 | "activity":"Contact Us form fill", 3 | "attachments":[ 4 | { 5 | "fields":[ 6 | { 7 | "title":"Name", 8 | "value":"{{lead.First Name:default= }} {{lead.Last Name:default= }}" 9 | }, 10 | { 11 | "title":"Email", 12 | "value":"{{lead.Email Address:default= }}" 13 | }, 14 | { 15 | "title":"Company", 16 | "value":"{{lead.Company:default= }}" 17 | }, 18 | { 19 | "title":"Message", 20 | "value":"{{lead.Message:default= }}" 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_add-recipient.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452274617001925, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"", 21 | "recipient":"team2_escalation" 22 | }, 23 | "action":"AddRecipient", 24 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 25 | "integrationName":"Integration1" 26 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_operator_away.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"away", 3 | "_type":"operator", 4 | "dashboard_url":"https://devel.userlike.local/dashboard/config/operator/edit/5", 5 | "email":"david@userlike.com", 6 | "first_name":"David", 7 | "id":5, 8 | "is_active":true, 9 | "jid":"david@userlike.com", 10 | "lang":"en", 11 | "last_name":"Voswinkel", 12 | "locale":"en_IS", 13 | "name":"David Voswinkel", 14 | "operator_group":{ 15 | "id":14, 16 | "name":"Testing David" 17 | }, 18 | "operator_group_id":14, 19 | "role":"a", 20 | "role_name":"Admin", 21 | "timezone":"Atlantic/Reykjavik", 22 | "url_image":"devel-cdn-operators.s3-eu-west-1.amazonaws.com/306ff79697ad929289f900ee013e8c33a4b7a371e80b5617e197264f953143d7_80x80.jpg", 23 | "username":"david" 24 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_operator_back.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"back", 3 | "_type":"operator", 4 | "dashboard_url":"https://devel.userlike.local/dashboard/config/operator/edit/5", 5 | "email":"david@userlike.com", 6 | "first_name":"David", 7 | "id":5, 8 | "is_active":true, 9 | "jid":"david@userlike.com", 10 | "lang":"en", 11 | "last_name":"Voswinkel", 12 | "locale":"en_IS", 13 | "name":"David Voswinkel", 14 | "operator_group":{ 15 | "id":14, 16 | "name":"Testing David" 17 | }, 18 | "operator_group_id":14, 19 | "role":"a", 20 | "role_name":"Admin", 21 | "timezone":"Atlantic/Reykjavik", 22 | "url_image":"devel-cdn-operators.s3-eu-west-1.amazonaws.com/306ff79697ad929289f900ee013e8c33a4b7a371e80b5617e197264f953143d7_80x80.jpg", 23 | "username":"david" 24 | } -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_assign-ownership.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452374669001603, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "message":"test alert", 13 | "username":"fili@ifountain.com", 14 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 15 | "source":"fili@ifountain.com", 16 | "alias":"aliastest", 17 | "tinyId":"23", 18 | "createdAt":1420452191104, 19 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 20 | "entity":"", 21 | "owner":"user2@ifountain.com" 22 | }, 23 | "action":"AssignOwnership", 24 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 25 | "integrationName":"Integration1" 26 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_operator_offline.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"offline", 3 | "_type":"operator", 4 | "dashboard_url":"https://devel.userlike.local/dashboard/config/operator/edit/5", 5 | "email":"david@userlike.com", 6 | "first_name":"David", 7 | "id":5, 8 | "is_active":true, 9 | "jid":"david@userlike.com", 10 | "lang":"en", 11 | "last_name":"Voswinkel", 12 | "locale":"en_IS", 13 | "name":"David Voswinkel", 14 | "operator_group":{ 15 | "id":14, 16 | "name":"Testing David" 17 | }, 18 | "operator_group_id":14, 19 | "role":"a", 20 | "role_name":"Admin", 21 | "timezone":"Atlantic/Reykjavik", 22 | "url_image":"devel-cdn-operators.s3-eu-west-1.amazonaws.com/306ff79697ad929289f900ee013e8c33a4b7a371e80b5617e197264f953143d7_80x80.jpg", 23 | "username":"david" 24 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_operator_online.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"online", 3 | "_type":"operator", 4 | "dashboard_url":"https://devel.userlike.local/dashboard/config/operator/edit/5", 5 | "email":"david@userlike.com", 6 | "first_name":"David", 7 | "id":5, 8 | "is_active":true, 9 | "jid":"david@userlike.com", 10 | "lang":"en", 11 | "last_name":"Voswinkel", 12 | "locale":"en_IS", 13 | "name":"David Voswinkel", 14 | "operator_group":{ 15 | "id":14, 16 | "name":"Testing David" 17 | }, 18 | "operator_group_id":14, 19 | "role":"a", 20 | "role_name":"Admin", 21 | "timezone":"Atlantic/Reykjavik", 22 | "url_image":"devel-cdn-operators.s3-eu-west-1.amazonaws.com/306ff79697ad929289f900ee013e8c33a4b7a371e80b5617e197264f953143d7_80x80.jpg", 23 | "username":"david" 24 | } -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_add-tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"", 4 | "type":"web" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452275002000962, 8 | "tags":[ 9 | "tag1", 10 | "tag2", 11 | "tag3" 12 | ], 13 | "addedTags":"tag1,tag2,tag3", 14 | "message":"test alert", 15 | "username":"fili@ifountain.com", 16 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 17 | "source":"fili@ifountain.com", 18 | "alias":"aliastest", 19 | "tinyId":"23", 20 | "createdAt":1420452191104, 21 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 22 | "entity":"" 23 | }, 24 | "action":"AddTags", 25 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 26 | "integrationName":"Integration1" 27 | } -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_take-ownership.json: -------------------------------------------------------------------------------- 1 | { 2 | "integrationType":"Integration1", 3 | "alert":{ 4 | "createdAt":1470226893192, 5 | "tinyId":"47", 6 | "alias":"8a745a79-3ed3-4044-8427-98e067c0623c", 7 | "alertId":"8a745a79-3ed3-4044-8427-98e067c0623c", 8 | "source":"test@test.com", 9 | "message":"message test", 10 | "userId":"ac6a9ab7-98fe-4256-8a0e-30dc082a55e7", 11 | "entity":"", 12 | "tags":[ 13 | "tag1", 14 | "tag2" 15 | ], 16 | "updatedAt":1470383477928000335, 17 | "username":"test@test.com" 18 | }, 19 | "integrationName":"Webhook", 20 | "action":"TakeOwnership", 21 | "integrationId":"fd8755c1-7a5e-4829-9ecc-8990e1a2eed3", 22 | "source":{ 23 | "name":"", 24 | "type":"web" 25 | } 26 | } -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_deferred.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "response":"400 Try again", 4 | "sg_event_id":"sendgrid_internal_event_id", 5 | "sg_message_id":"sendgrid_internal_message_id", 6 | "event":"deferred", 7 | "email":"email@example.com", 8 | "timestamp":1249948800, 9 | "smtp-id":"", 10 | "unique_arg_key":"unique_arg_value", 11 | "category":[ 12 | "category1", 13 | "category2" 14 | ], 15 | "attempt":"10", 16 | "newsletter":{ 17 | "newsletter_user_list_id":"10557865", 18 | "newsletter_id":"1943530", 19 | "newsletter_send_id":"2308608" 20 | }, 21 | "asm_group_id":1, 22 | "ip":"127.0.0.1", 23 | "tls":"0", 24 | "cert_err":"0" 25 | } 26 | ] -------------------------------------------------------------------------------- /docs/handlers/statuspage/event-example_component-updates.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta":{ 3 | "unsubscribe":"http://statustest.flyingkleinbrothers.com:5000/?unsubscribe=j0vqr9kl3513", 4 | "documentation":"http://doers.statuspage.io/customer-notifications/webhooks/" 5 | }, 6 | "page":{ 7 | "id":"j2mfxwj97wnj", 8 | "status_indicator":"major", 9 | "status_description":"Partial System Outage" 10 | }, 11 | "component_update":{ 12 | "created_at":"2013-05-29T21:32:28Z", 13 | "new_status":"operational", 14 | "old_status":"major_outage", 15 | "id":"k7730b5v92bv", 16 | "component_id":"rb5wq1dczvbm" 17 | }, 18 | "component":{ 19 | "created_at":"2013-05-29T21:32:28Z", 20 | "id":"rb5wq1dczvbm", 21 | "name":"Some Component", 22 | "status":"operational" 23 | } 24 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_transaction-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of transaction check", 4 | "check_type":"TRANSACTION", 5 | "check_params":{ 6 | "encryption":true, 7 | "port":443, 8 | "url":"https://www.example.com/" 9 | }, 10 | "tags":[ 11 | "example_tag" 12 | ], 13 | "previous_state":"FAILING", 14 | "current_state":"SUCCESS", 15 | "state_changed_timestamp":1451610061, 16 | "state_changed_utc_time":"2016-01-01T01:01:01", 17 | "description":"Error message", 18 | "first_probe":{ 19 | "ip":"123.4.5.6", 20 | "ipv6":"2001:4800:1020:209::5", 21 | "location":"Stockholm, Sweden" 22 | }, 23 | "second_probe":{ 24 | "ip":"123.4.5.6", 25 | "ipv6":"2001:4800:1020:209::5", 26 | "location":"Austin, US" 27 | } 28 | } -------------------------------------------------------------------------------- /docs/handlers/semaphore/event-example_build.json: -------------------------------------------------------------------------------- 1 | { 2 | "branch_name":"gem_updates", 3 | "branch_url":"https://semaphoreci.com/projects/44/branches/50", 4 | "project_name":"base-app", 5 | "project_hash_id":"123-aga-471-6a8", 6 | "build_url":"https://semaphoreci.com/projects/44/branches/50/builds/15", 7 | "build_number":15, 8 | "result":"passed", 9 | "event":"build", 10 | "started_at":"2012-07-09T15:23:53Z", 11 | "finished_at":"2012-07-09T15:30:16Z", 12 | "commit":{ 13 | "id":"dc395381e650f3bac18457909880829fc20e34ba", 14 | "url":"https://github.com/renderedtext/base-app/commit/dc395381e650f3bac18457909880829fc20e34ba", 15 | "author_name":"Vladimir Saric", 16 | "author_email":"vladimir@renderedtext.com", 17 | "message":"Update 'shoulda' gem.", 18 | "timestamp":"2012-07-04T18:14:08Z" 19 | } 20 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_ping-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of Ping check", 4 | "check_type":"PING", 5 | "check_params":{ 6 | "hostname":"www.example.com", 7 | "basic_auth":false, 8 | "ipv6":false 9 | }, 10 | "tags":[ 11 | "example_tag" 12 | ], 13 | "previous_state":"UP", 14 | "current_state":"DOWN", 15 | "state_changed_timestamp":1451610061, 16 | "state_changed_utc_time":"2016-01-01T01:01:01", 17 | "long_description":"Long error message", 18 | "description":"Short error message", 19 | "first_probe":{ 20 | "ip":"123.4.5.6", 21 | "ipv6":"2001:4800:1020:209::5", 22 | "location":"Stockholm, Sweden" 23 | }, 24 | "second_probe":{ 25 | "ip":"123.4.5.6", 26 | "ipv6":"2001:4800:1020:209::5", 27 | "location":"Austin, US" 28 | } 29 | } -------------------------------------------------------------------------------- /docs/handlers.md: -------------------------------------------------------------------------------- 1 | { 2 | "event":"audit", 3 | "audit":{ 4 | "id":"1011112222333344445555666", 5 | "audit_action":"create", 6 | "created_at":"2018-01-24T22:29:16.361Z", 7 | "interesting":false, 8 | "user":{ 9 | "id":"2011112222333344445555666", 10 | "name":"John Wang", 11 | "email":"john.wang@example.com", 12 | "created_at":"2017-11-21T20:09:39.022Z", 13 | "updated_at":"2018-01-24T21:50:03.013Z" 14 | }, 15 | "auditable_type":"tagging", 16 | "auditable_id":"3011112222333344445555666", 17 | "description":"tagged feature API-1 My Awesome Feature - Use Cases", 18 | "auditable_url":"https://example.aha.io/features/API-1", 19 | "changes":[ 20 | { 21 | "field_name":"Tag", 22 | "value":"Awesome" 23 | } 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /docs/handlers/papertrail/event-example_notifications-array-len-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "events":[ 3 | { 4 | "id":7711561783320576, 5 | "received_at":"2011-05-18T20:30:02-07:00", 6 | "display_received_at":"May 18 20:30:02", 7 | "source_ip":"208.75.57.121", 8 | "source_name":"abc", 9 | "source_id":2, 10 | "hostname":"abc", 11 | "program":"CROND", 12 | "severity":"Info", 13 | "facility":"Cron", 14 | "message":"message body" 15 | } 16 | ], 17 | "saved_search":{ 18 | "id":42, 19 | "name":"Important stuff", 20 | "query":"cron OR server1", 21 | "html_edit_url":"https://papertrailapp.com/searches/42/edit", 22 | "html_search_url":"https://papertrailapp.com/searches/42" 23 | }, 24 | "max_id":7711582041804800, 25 | "min_id":7711561783320576 26 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_tcp-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of TCP check", 4 | "check_type":"PORT_TCP", 5 | "check_params":{ 6 | "hostname":"www.example.com", 7 | "basic_auth":false, 8 | "ipv6":false, 9 | "port":80 10 | }, 11 | "tags":[ 12 | "example_tag" 13 | ], 14 | "previous_state":"UP", 15 | "current_state":"DOWN", 16 | "state_changed_timestamp":1451610061, 17 | "state_changed_utc_time":"2016-01-01T01:01:01", 18 | "long_description":"Long error message", 19 | "description":"Short error message", 20 | "first_probe":{ 21 | "ip":"123.4.5.6", 22 | "ipv6":"2001:4800:1020:209::5", 23 | "location":"Stockholm, Sweden" 24 | }, 25 | "second_probe":{ 26 | "ip":"123.4.5.6", 27 | "ipv6":"2001:4800:1020:209::5", 28 | "location":"Austin, US" 29 | } 30 | } -------------------------------------------------------------------------------- /docs/handlers/librato/event-example_alert-triggered.json: -------------------------------------------------------------------------------- 1 | { 2 | "alert":{ 3 | "id":5846005, 4 | "name":"collectd.high.load", 5 | "runbook_url":"http://example.com/runbook.pdf", 6 | "version":2 7 | }, 8 | "account":"m@example.com", 9 | "trigger_time":1444177459, 10 | "conditions":[ 11 | { 12 | "id":1150670, 13 | "type":"above", 14 | "threshold":2, 15 | "duration":300 16 | } 17 | ], 18 | "violations":{ 19 | "example-ubuntu-14.04":[ 20 | { 21 | "metric":"collectd.load.load.shortterm", 22 | "value":7.190000057220459, 23 | "recorded_at":1444177454, 24 | "condition_violated":1150670, 25 | "count":31, 26 | "begin":1444177140, 27 | "end":1444177440 28 | } 29 | ] 30 | } 31 | } -------------------------------------------------------------------------------- /docs/icons/icon_circleci.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_imap-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of IMAP check", 4 | "check_type":"IMAP", 5 | "check_params":{ 6 | "hostname":"www.example.com", 7 | "basic_auth":false, 8 | "encryption":false, 9 | "ipv6":false, 10 | "port":143 11 | }, 12 | "tags":[ 13 | "example_tag" 14 | ], 15 | "previous_state":"UP", 16 | "current_state":"DOWN", 17 | "state_changed_timestamp":1451610061, 18 | "state_changed_utc_time":"2016-01-01T01:01:01", 19 | "long_description":"Long error message", 20 | "description":"Short error message", 21 | "first_probe":{ 22 | "ip":"123.4.5.6", 23 | "ipv6":"2001:4800:1020:209::5", 24 | "location":"Stockholm, Sweden" 25 | }, 26 | "second_probe":{ 27 | "ip":"123.4.5.6", 28 | "ipv6":"2001:4800:1020:209::5", 29 | "location":"Austin, US" 30 | } 31 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_pop3-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of POP3 check", 4 | "check_type":"POP3", 5 | "check_params":{ 6 | "basic_auth":false, 7 | "encryption":false, 8 | "hostname":"www.example.com", 9 | "ipv6":false, 10 | "port":110 11 | }, 12 | "tags":[ 13 | "example_tag" 14 | ], 15 | "previous_state":"UP", 16 | "current_state":"DOWN", 17 | "state_changed_timestamp":1451610061, 18 | "state_changed_utc_time":"2016-01-01T01:01:01", 19 | "long_description":"Long error message", 20 | "description":"Short error message", 21 | "first_probe":{ 22 | "ip":"123.4.5.6", 23 | "ipv6":"2001:4800:1020:209::5", 24 | "location":"Stockholm, Sweden" 25 | }, 26 | "second_probe":{ 27 | "ip":"123.4.5.6", 28 | "ipv6":"2001:4800:1020:209::5", 29 | "location":"Austin, US" 30 | } 31 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_smtp-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":123456, 3 | "check_name":"Name of SMTP check", 4 | "check_type":"SMTP", 5 | "check_params":{ 6 | "basic_auth":false, 7 | "encryption":false, 8 | "hostname":"www.example.com", 9 | "ipv6":false, 10 | "port":25 11 | }, 12 | "tags":[ 13 | "example_tag" 14 | ], 15 | "previous_state":"UP", 16 | "current_state":"DOWN", 17 | "state_changed_timestamp":1451610061, 18 | "state_changed_utc_time":"2016-01-01T01:01:01", 19 | "long_description":"Long error message", 20 | "description":"Short error message", 21 | "first_probe":{ 22 | "ip":"123.4.5.6", 23 | "ipv6":"2001:4800:1020:209::5", 24 | "location":"Stockholm, Sweden" 25 | }, 26 | "second_probe":{ 27 | "ip":"123.4.5.6", 28 | "ipv6":"2001:4800:1020:209::5", 29 | "location":"Austin, US" 30 | } 31 | } -------------------------------------------------------------------------------- /docs/handlers/aha/event-example_feature-add-tag.json: -------------------------------------------------------------------------------- 1 | { 2 | "event":"audit", 3 | "audit":{ 4 | "id":"1011112222333344445555666", 5 | "audit_action":"create", 6 | "created_at":"2018-01-24T22:29:16.361Z", 7 | "interesting":false, 8 | "user":{ 9 | "id":"2011112222333344445555666", 10 | "name":"John Wang", 11 | "email":"john.wang@example.com", 12 | "created_at":"2017-11-21T20:09:39.022Z", 13 | "updated_at":"2018-01-24T21:50:03.013Z" 14 | }, 15 | "auditable_type":"tagging", 16 | "auditable_id":"3011112222333344445555666", 17 | "description":"tagged feature API-1 My Awesome Feature - Use Cases", 18 | "auditable_url":"https://example.aha.io/features/API-1", 19 | "changes":[ 20 | { 21 | "field_name":"Tag", 22 | "value":"Awesome" 23 | } 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_offline-message_receive.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"receive", 3 | "_type":"offline_message", 4 | "browser_name":"Chrome", 5 | "browser_os":"Mac OS X", 6 | "browser_version":"32", 7 | "chat_widget":{ 8 | "id":2, 9 | "name":"Website" 10 | }, 11 | "client_email":"support@userlike.com", 12 | "client_name":"Userlike Support", 13 | "created_at":"2014-12-20 14:50:23", 14 | "custom":{ 15 | 16 | }, 17 | "data_privacy":null, 18 | "id":3, 19 | "loc_city":"Cologne", 20 | "loc_country":"Germany", 21 | "loc_lat":50.9333000183105, 22 | "loc_lon":6.94999980926514, 23 | "marked_read":true, 24 | "message":"We are happy to welcome you as a Userlike user!", 25 | "page_impressions":5, 26 | "screenshot_oid":null, 27 | "screenshot_url":null, 28 | "status":"new", 29 | "topic":"Support", 30 | "url":"http://www.userlike.com", 31 | "visits":1 32 | } -------------------------------------------------------------------------------- /docs/handlers/aha/event-example_release-ship.json: -------------------------------------------------------------------------------- 1 | { 2 | "event":"audit", 3 | "audit":{ 4 | "id":"1011112222333344445555666", 5 | "audit_action":"update", 6 | "created_at":"2018-01-24T23:12:00.903Z", 7 | "interesting":true, 8 | "user":{ 9 | "id":"2011112222333344445555666", 10 | "name":"John Wang", 11 | "email":"john.wang@example.com", 12 | "created_at":"2017-11-21T20:09:39.022Z", 13 | "updated_at":"2018-01-24T21:50:03.013Z" 14 | }, 15 | "auditable_type":"release", 16 | "auditable_id":"3011112222333344445555666", 17 | "description":"updated release API-R-8 8.0", 18 | "auditable_url":"https://example.aha.io/releases/API-R-8", 19 | "changes":[ 20 | { 21 | "field_name":"Workflow status", 22 | "value":"Ready to ship \u0026rarr; Shipped" 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/handlers/enchant/event-example_notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":"7f94629", 3 | "account_id":"a91bb74", 4 | "account_url":"company.enchant.com", 5 | "created_at":"2016-10-17T19:52:43Z", 6 | "type":"ticket.label_added", 7 | "data":{ 8 | "label_id":"97b0a40", 9 | "label_name":"High Priority", 10 | "label_color":"red" 11 | }, 12 | "actor_type":"user", 13 | "actor_id":"a91bb75", 14 | "actor_name":"Michelle Han", 15 | "model_type":"ticket", 16 | "model_id":"a52ec86", 17 | "model":{ 18 | "id":"a52ec86", 19 | "number":53249, 20 | "user_id":"a91bb75", 21 | "state":"open", 22 | "subject":"email from customer", 23 | "label_ids":[ 24 | "97b0a3e", 25 | "97b0a40" 26 | ], 27 | "customer_id":"97b0a43", 28 | "type":"email", 29 | "reply_to":"john@smith.com", 30 | "created_at":"2016-10-14T20:15:46Z" 31 | } 32 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_dns-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of DNS check", 4 | "check_type":"DNS", 5 | "check_params":{ 6 | "hostname":"www.example.com", 7 | "basic_auth":false, 8 | "expected_ip":"123.4.5.6", 9 | "ipv6":false, 10 | "nameserver":"example.com" 11 | }, 12 | "tags":[ 13 | "example_tag" 14 | ], 15 | "previous_state":"UP", 16 | "current_state":"DOWN", 17 | "state_changed_timestamp":1451610061, 18 | "state_changed_utc_time":"2016-01-01T01:01:01", 19 | "long_description":"Long error message", 20 | "description":"Short error message", 21 | "first_probe":{ 22 | "ip":"123.4.5.6", 23 | "ipv6":"2001:4800:1020:209::5", 24 | "location":"Stockholm, Sweden" 25 | }, 26 | "second_probe":{ 27 | "ip":"123.4.5.6", 28 | "ipv6":"2001:4800:1020:209::5", 29 | "location":"Austin, US" 30 | } 31 | } -------------------------------------------------------------------------------- /docs/icons/icon_appsignal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/handlers/opsgenie/event-example_create.json: -------------------------------------------------------------------------------- 1 | { 2 | "source":{ 3 | "name":"web", 4 | "type":"API" 5 | }, 6 | "alert":{ 7 | "updatedAt":1420452193166002000, 8 | "tags":[ 9 | "tag1", 10 | "tag2" 11 | ], 12 | "teams":[ 13 | "team1", 14 | "team2" 15 | ], 16 | "recipients":[ 17 | "recipient1", 18 | "recipient2" 19 | ], 20 | "message":" test alert", 21 | "username":"fili@ifountain.com", 22 | "alertId":"052652ac-5d1c-464a-812a-7dd18bbfba8c", 23 | "source":"fili@ifountain.com", 24 | "alias":"aliastest", 25 | "tinyId":"23", 26 | "createdAt":1420452191104, 27 | "userId":"daed1180-0ce8-438b-8f8e-57e1a5920a2d", 28 | "entity":"" 29 | }, 30 | "action":"Create", 31 | "integrationId":"37c8f316-17c6-49d7-899b-9c7e540c048d", 32 | "integrationName":"Integration1" 33 | } -------------------------------------------------------------------------------- /docs/handlers/papertrail/event-example_notifications-array-len-1_demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "events":[ 3 | { 4 | "id":7711561783320576, 5 | "received_at":"2011-05-18T20:30:02-07:00", 6 | "display_received_at":"May 18 20:30:02", 7 | "source_ip":"208.75.57.121", 8 | "source_name":"abc", 9 | "source_id":2, 10 | "hostname":"localhost", 11 | "program":"sshd", 12 | "severity":"Error", 13 | "facility":"sshd", 14 | "message":"Cound not load host key: /etc/ssh/ssh_host_abc123_key" 15 | } 16 | ], 17 | "saved_search":{ 18 | "id":42, 19 | "name":"SSH key missing", 20 | "query":"Could not load host key", 21 | "html_edit_url":"https://papertrailapp.com/searches/42/edit", 22 | "html_search_url":"https://papertrailapp.com/searches/42" 23 | }, 24 | "max_id":7711582041804800, 25 | "min_id":7711561783320576 26 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_udp-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of UDP check", 4 | "check_type":"UDP", 5 | "check_params":{ 6 | "hostname":"www.example.com", 7 | "basic_auth":false, 8 | "expect":"string to expect", 9 | "ipv6":false, 10 | "port":80, 11 | "send":"string to send" 12 | }, 13 | "tags":[ 14 | "example_tag" 15 | ], 16 | "previous_state":"UP", 17 | "current_state":"DOWN", 18 | "state_changed_timestamp":1451610061, 19 | "state_changed_utc_time":"2016-01-01T01:01:01", 20 | "long_description":"Long error message", 21 | "description":"Short error message", 22 | "first_probe":{ 23 | "ip":"123.4.5.6", 24 | "ipv6":"2001:4800:1020:209::5", 25 | "location":"Stockholm, Sweden" 26 | }, 27 | "second_probe":{ 28 | "ip":"123.4.5.6", 29 | "ipv6":"2001:4800:1020:209::5", 30 | "location":"Austin, US" 31 | } 32 | } -------------------------------------------------------------------------------- /docs/handlers/aha/event-example_feature-to-parking-lot.json: -------------------------------------------------------------------------------- 1 | { 2 | "event":"audit", 3 | "audit":{ 4 | "id":"1011112222333344445555666", 5 | "audit_action":"update", 6 | "created_at":"2018-01-24T22:21:16.155Z", 7 | "interesting":true, 8 | "user":{ 9 | "id":"2011112222333344445555666", 10 | "name":"John Wang", 11 | "email":"john.wang@example.com", 12 | "created_at":"2017-11-21T20:09:39.022Z", 13 | "updated_at":"2018-01-24T21:50:03.013Z" 14 | }, 15 | "auditable_type":"feature", 16 | "auditable_id":"3011112222333344445555666", 17 | "description":"updated feature X-7 Secret and Awesome Feature", 18 | "auditable_url":"https://example.aha.io/features/X-7", 19 | "changes":[ 20 | { 21 | "field_name":"Release", 22 | "value":"X-R-3 Est 18Q2 \u0026rarr; X-R-10 Parking Lot" 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pkg/handlers/heroku/handler_heroku_out_test.go: -------------------------------------------------------------------------------- 1 | package heroku 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | const ( 8 | TestAppName = "secure-woodland-9775" 9 | ) 10 | 11 | var ConfigurationTests = []struct { 12 | v string 13 | want HerokuOutMessage 14 | }{ 15 | {HookData(), HerokuOutMessage{App: "secure-woodland-9775"}}} 16 | 17 | func TestConfluence(t *testing.T) { 18 | for _, tt := range ConfigurationTests { 19 | msg, err := HerokuOutMessageFromQuery([]byte(tt.v)) 20 | if err != nil { 21 | t.Errorf("error %v", err) 22 | continue 23 | } 24 | if msg.App != TestAppName { 25 | t.Errorf("error HerokuOutMessageFromQueryString(%v): want [%v], got [%v]", tt.v, "secure-woodland-9775", tt.want.App) 26 | } 27 | } 28 | } 29 | 30 | func HookData() string { 31 | return `app=secure-woodland-9775&user=example%40example.com&url=http%3A%2F%2Fsecure-woodland-9775.herokuapp.com&head=4f20bdd&head_long=4f20bdd&prev_head=&git_log=%20%20*%20Michael%20Friis%3A%20add%20bar&release=v7 32 | ` 33 | } 34 | -------------------------------------------------------------------------------- /docs/handlers/sendgrid/event-example_click.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sg_event_id":"sendgrid_internal_event_id", 4 | "sg_message_id":"sendgrid_internal_message_id", 5 | "ip":"255.255.255.255", 6 | "useragent":"Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53", 7 | "event":"click", 8 | "email":"email@example.com", 9 | "timestamp":1249948800, 10 | "url":"http://yourdomain.com/blog/news.html", 11 | "url_offset":{ 12 | "index":0, 13 | "type":"html" 14 | }, 15 | "unique_arg_key":"unique_arg_value", 16 | "category":[ 17 | "category1", 18 | "category2" 19 | ], 20 | "newsletter":{ 21 | "newsletter_user_list_id":"10557865", 22 | "newsletter_id":"1943530", 23 | "newsletter_send_id":"2308608" 24 | }, 25 | "asm_group_id":1 26 | } 27 | ] -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_http-custom-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of HTTP Custom check", 4 | "check_type":"HTTP_CUSTOM", 5 | "check_params":{ 6 | "basic_auth":false, 7 | "encryption":false, 8 | "full_url":"https://www.example.com/path", 9 | "hostname":"www.example.com", 10 | "ipv6":false, 11 | "port":80, 12 | "url":"/" 13 | }, 14 | "tags":[ 15 | "example_tag" 16 | ], 17 | "previous_state":"UP", 18 | "current_state":"DOWN", 19 | "state_changed_timestamp":1451610061, 20 | "state_changed_utc_time":"2016-01-01T01:01:01", 21 | "long_description":"Long error message", 22 | "description":"Short error message", 23 | "first_probe":{ 24 | "ip":"123.4.5.6", 25 | "ipv6":"2001:4800:1020:209::5", 26 | "location":"Stockholm, Sweden" 27 | }, 28 | "second_probe":{ 29 | "ip":"123.4.5.6", 30 | "ipv6":"2001:4800:1020:209::5", 31 | "location":"Austin, US" 32 | } 33 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_http-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"Name of HTTP check", 4 | "check_type":"HTTP", 5 | "check_params":{ 6 | "basic_auth":false, 7 | "encryption":true, 8 | "full_url":"https://www.example.com/path", 9 | "header":"User-Agent:Pingdom.com_bot", 10 | "hostname":"www.example.com", 11 | "ipv6":false, 12 | "port":443, 13 | "url":"/path" 14 | }, 15 | "tags":[ 16 | "example_tag" 17 | ], 18 | "previous_state":"UP", 19 | "current_state":"DOWN", 20 | "state_changed_timestamp":1451610061, 21 | "state_changed_utc_time":"2016-01-01T01:01:01", 22 | "long_description":"Long error message", 23 | "description":"Short error message", 24 | "first_probe":{ 25 | "ip":"123.4.5.6", 26 | "ipv6":"2001:4800:1020:209::5", 27 | "location":"Stockholm, Sweden" 28 | }, 29 | "second_probe":{ 30 | "ip":"123.4.5.6", 31 | "ipv6":"2001:4800:1020:209::5", 32 | "location":"Austin, US" 33 | } 34 | } -------------------------------------------------------------------------------- /docs/handlers/pingdom/event-example_http-check_demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "check_id":12345, 3 | "check_name":"My Awesome Website", 4 | "check_type":"HTTP", 5 | "check_params":{ 6 | "basic_auth":false, 7 | "encryption":true, 8 | "full_url":"https://my-awesome-site.com", 9 | "header":"User-Agent:Pingdom.com_bot", 10 | "hostname":"my-awesome-site.com", 11 | "ipv6":false, 12 | "port":443, 13 | "url":"/path" 14 | }, 15 | "tags":[ 16 | "example_tag" 17 | ], 18 | "previous_state":"UP", 19 | "current_state":"DOWN", 20 | "state_changed_timestamp":1451610061, 21 | "state_changed_utc_time":"2016-01-01T01:01:01", 22 | "long_description":"Long error message", 23 | "description":"Timeout (> 30s)", 24 | "first_probe":{ 25 | "ip":"123.4.5.6", 26 | "ipv6":"2001:4800:1020:209::5", 27 | "location":"Stockholm, Sweden" 28 | }, 29 | "second_probe":{ 30 | "ip":"123.4.5.6", 31 | "ipv6":"2001:4800:1020:209::5", 32 | "location":"Austin, US" 33 | } 34 | } -------------------------------------------------------------------------------- /pkg/handlers/marketo/handler_marketo_out.go: -------------------------------------------------------------------------------- 1 | package marketo 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | cc "github.com/grokify/commonchat" 7 | 8 | "github.com/grokify/chathooks/pkg/config" 9 | "github.com/grokify/chathooks/pkg/handlers" 10 | "github.com/grokify/chathooks/pkg/models" 11 | ) 12 | 13 | const ( 14 | DisplayName = "Marketo" 15 | HandlerKey = "marketo" 16 | MessageDirection = "out" 17 | MessageBodyType = models.JSON 18 | ) 19 | 20 | func NewHandler() handlers.Handler { 21 | return handlers.Handler{MessageBodyType: MessageBodyType, Normalize: Normalize} 22 | } 23 | 24 | func Normalize(cfg config.Configuration, hReq handlers.HandlerRequest) (cc.Message, error) { 25 | ccMsg, err := CcMessageFromBytes(hReq.Body) 26 | if err != nil { 27 | return ccMsg, err 28 | } 29 | iconURL, err := cfg.GetAppIconURL(HandlerKey) 30 | if err == nil { 31 | ccMsg.IconURL = iconURL.String() 32 | } 33 | return ccMsg, nil 34 | } 35 | 36 | func CcMessageFromBytes(bytes []byte) (cc.Message, error) { 37 | msg := cc.Message{} 38 | err := json.Unmarshal(bytes, &msg) 39 | return msg, err 40 | } 41 | -------------------------------------------------------------------------------- /pkg/handlers/victorops/handler_victorops_out.go: -------------------------------------------------------------------------------- 1 | package victorops 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | cc "github.com/grokify/commonchat" 7 | 8 | "github.com/grokify/chathooks/pkg/config" 9 | "github.com/grokify/chathooks/pkg/handlers" 10 | "github.com/grokify/chathooks/pkg/models" 11 | ) 12 | 13 | const ( 14 | DisplayName = "VictorOps" 15 | HandlerKey = "victorops" 16 | MessageDirection = "out" 17 | MessageBodyType = models.JSON 18 | ) 19 | 20 | func NewHandler() handlers.Handler { 21 | return handlers.Handler{MessageBodyType: MessageBodyType, Normalize: Normalize} 22 | } 23 | 24 | func Normalize(cfg config.Configuration, hReq handlers.HandlerRequest) (cc.Message, error) { 25 | ccMsg, err := CcMessageFromBytes(hReq.Body) 26 | if err != nil { 27 | return ccMsg, err 28 | } 29 | 30 | iconURL, err := cfg.GetAppIconURL(HandlerKey) 31 | if err == nil { 32 | ccMsg.IconURL = iconURL.String() 33 | } 34 | 35 | return ccMsg, nil 36 | } 37 | 38 | func CcMessageFromBytes(bytes []byte) (cc.Message, error) { 39 | var msg cc.Message 40 | return msg, json.Unmarshal(bytes, &msg) 41 | } 42 | -------------------------------------------------------------------------------- /docs/handlers/semaphore/event-example_deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_name":"heroku-deploy-test", 3 | "project_hash_id":"123-aga-471-6a8", 4 | "result":"passed", 5 | "event":"deploy", 6 | "server_name":"server-heroku-master-automatic-2", 7 | "number":2, 8 | "created_at":"2013-07-30T13:52:33Z", 9 | "updated_at":"2013-07-30T13:53:21Z", 10 | "started_at":"2013-07-30T13:52:38Z", 11 | "finished_at":"2013-07-30T13:53:21Z", 12 | "html_url":"https://semaphoreci.com/projects/2420/servers/81/deploys/2", 13 | "build_number":10, 14 | "branch_name":"master", 15 | "branch_html_url":"https://semaphoreci.com/projects/2420/branches/58394", 16 | "build_html_url":"https://semaphoreci.com/projects/2420/branches/58394/builds/7", 17 | "commit":{ 18 | "author_email":"rastasheep3@gmail.com", 19 | "author_name":"Aleksandar Diklic", 20 | "id":"43ddb7516ecc743f0563abd7418f0bd3617348c4", 21 | "message":"One more time", 22 | "timestamp":"2013-07-19T12:56:25Z", 23 | "url":"https://github.com/rastasheep/heroku-deploy-test/commit/43ddb7516ecc743f0563abd7418f0bd3617348c4" 24 | } 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-2025 grokify 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/handlers/fabric/event-example_notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_name":"heroku-deploy-test", 3 | "project_hash_id":"123-aga-471-6a8", 4 | "result":"passed", 5 | "event":"deploy", 6 | "server_name":"server-heroku-master-automatic-2", 7 | "number":2, 8 | "created_at":"2013-07-30T13:52:33Z", 9 | "updated_at":"2013-07-30T13:53:21Z", 10 | "started_at":"2013-07-30T13:52:38Z", 11 | "finished_at":"2013-07-30T13:53:21Z", 12 | "html_url":"https://semaphoreci.com/projects/2420/servers/81/deploys/2", 13 | "build_number":10, 14 | "branch_name":"master", 15 | "branch_html_url":"https://semaphoreci.com/projects/2420/branches/58394", 16 | "build_html_url":"https://semaphoreci.com/projects/2420/branches/58394/builds/7", 17 | "commit":{ 18 | "author_email":"rastasheep3@gmail.com", 19 | "author_name":"Aleksandar Diklic", 20 | "id":"43ddb7516ecc743f0563abd7418f0bd3617348c4", 21 | "message":"One more time", 22 | "timestamp":"2013-07-19T12:56:25Z", 23 | "url":"https://github.com/rastasheep/heroku-deploy-test/commit/43ddb7516ecc743f0563abd7418f0bd3617348c4" 24 | } 25 | } -------------------------------------------------------------------------------- /docs/handlers/airbrake/event-example_new-error.json: -------------------------------------------------------------------------------- 1 | { 2 | "error":{ 3 | "id":37463546, 4 | "error_message":"KitchenException: You are all out of bacon!", 5 | "error_class":"KitchenException", 6 | "file":"[PROJECT_ROOT]/app/controllers/bacon_controller.rb", 7 | "line_number":35, 8 | "project":{ 9 | "id":1111, 10 | "name":"Baconator" 11 | }, 12 | "last_notice":{ 13 | "id":4505303522, 14 | "request_method":null, 15 | "request_url":"http://airbrake.io:445/bacon/cook", 16 | "backtrace":[ 17 | "[PROJECT_ROOT]/app/controllers/bacon_controller.rb:35:in `cook'", 18 | "[PROJECT_ROOT]/app/middleware/kitchen.rb:19:in `oven'", 19 | "[PROJECT_ROOT]/app/middleware/kitchen.rb:33:in `chef'", 20 | "[PROJECT_ROOT]/app/middleware/salumi.rb:23:in `store'" 21 | ] 22 | }, 23 | "environment":"avocado", 24 | "first_occurred_at":"2012-02-23T22:03:03Z", 25 | "last_occurred_at":"2012-03-21T08:37:15Z", 26 | "times_occurred":118 27 | }, 28 | "airbrake_error_url":"https://airbrake.io/airbrake-error-url" 29 | } -------------------------------------------------------------------------------- /pkg/handlers/slack/handler_slack_in.go: -------------------------------------------------------------------------------- 1 | package slack 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | "github.com/grokify/chathooks/pkg/handlers" 8 | "github.com/grokify/chathooks/pkg/models" 9 | cc "github.com/grokify/commonchat" 10 | "github.com/valyala/fasthttp" 11 | 12 | ccslack "github.com/grokify/commonchat/slack" 13 | ) 14 | 15 | const ( 16 | DisplayName = "Slack" 17 | HandlerKey = "slack" 18 | MessageDirection = "in" 19 | MessageBodyType = models.URLEncodedJSONPayloadOrJSON 20 | ) 21 | 22 | func NewHandler() handlers.Handler { 23 | return handlers.Handler{MessageBodyType: MessageBodyType, Normalize: Normalize} 24 | } 25 | 26 | func BuildInboundMessageBytes(ctx *fasthttp.RequestCtx) []byte { 27 | ct := string(ctx.Request.Header.Peek("Content-Type")) 28 | ct = strings.TrimSpace(strings.ToLower(ct)) 29 | if strings.Contains(ct, "application/json") { 30 | return ctx.PostBody() 31 | } 32 | return ctx.FormValue("payload") 33 | } 34 | 35 | func Normalize(config config.Configuration, hReq handlers.HandlerRequest) (cc.Message, error) { 36 | slMsg, err := ccslack.ParseMessageAny(hReq.Body) 37 | if err != nil { 38 | return cc.Message{}, err 39 | } 40 | return ccslack.WebhookInBodySlackToCc(slMsg), nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/handlers/handler_home.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/valyala/fasthttp" 7 | 8 | "github.com/grokify/chathooks/pkg/adapters" 9 | "github.com/grokify/chathooks/pkg/config" 10 | ) 11 | 12 | const ( 13 | QueryParamNamedOutputs = config.ParamNameAdapters 14 | QueryParamInputType = config.ParamNameInputType 15 | QueryParamOutputType = config.ParamNameOutputType 16 | QueryParamOutputURL = config.ParamNameOutputURL 17 | QueryParamToken = config.ParamNameToken 18 | QueryParamDefaultActivity = config.ParamNameActivityDefault 19 | QueryParamDefaultIcon = config.ParamNameIconDefault 20 | //QueryParamURL = config.ParamNameURL 21 | ) 22 | 23 | var ( 24 | ShowDisplayName = false 25 | ) 26 | 27 | // HomeHandler is a fasthttp handler for handling the webhoo proxy homepage. 28 | func HomeHandler(ctx *fasthttp.RequestCtx) { 29 | fmt.Fprintf(ctx, "%s", []byte("Chathooks\nSource: https://github.com/grokify/chathooks")) 30 | } 31 | 32 | type Configuration struct { 33 | ConfigData config.Configuration 34 | AdapterSet adapters.AdapterSet 35 | } 36 | 37 | func IntegrationActivitySuffix(displayName string) string { 38 | if !ShowDisplayName || len(displayName) < 1 { 39 | return "" 40 | } 41 | return "" 42 | } 43 | -------------------------------------------------------------------------------- /docs/handlers/confluence/event-example_comment-created.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment":{ 3 | "spaceKey":"~admin", 4 | "parent":{ 5 | "spaceKey":"~admin", 6 | "modificationDate":1471926079631, 7 | "creatorKey":"ff80808154510724015451074c160001", 8 | "creatorName":"admin", 9 | "lastModifierKey":"ff80808154510724015451074c160001", 10 | "self":"https://cloud-development-environment.atlassian.net/wiki/display/~admin/Some+random+test+page", 11 | "lastModifierName":"admin", 12 | "id":16777227, 13 | "title":"Some random test page", 14 | "creationDate":1471926079631, 15 | "version":1 16 | }, 17 | "modificationDate":1471926091465, 18 | "creatorKey":"ff80808154510724015451074c160001", 19 | "creatorName":"admin", 20 | "lastModifierKey":"ff80808154510724015451074c160001", 21 | "self":"https://cloud-development-environment/wiki/display/~admin/Some+random+test+page?focusedCommentId=16777228#comment-16777228", 22 | "lastModifierName":"admin", 23 | "id":16777228, 24 | "creationDate":1471926091465, 25 | "version":1 26 | }, 27 | "user":"admin", 28 | "userKey":"ff80808154510724015451074c160001", 29 | "timestamp":1471926091468, 30 | "username":"admin" 31 | } -------------------------------------------------------------------------------- /pkg/handlers/templated_handler.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "encoding/json" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | 9 | "github.com/grokify/commonchat" 10 | "github.com/tidwall/gjson" 11 | 12 | "github.com/grokify/chathooks/pkg/config" 13 | ) 14 | 15 | func NewTemplatedHandler(tmpl string) Handler { 16 | return Handler{Normalize: getTemplatedNormalizer(tmpl)} 17 | } 18 | 19 | func getTemplatedNormalizer(tmpl string) func(cfg config.Configuration, hReq HandlerRequest) (commonchat.Message, error) { 20 | return func(cfg config.Configuration, hReq HandlerRequest) (commonchat.Message, error) { 21 | ccMsg := commonchat.NewMessage() 22 | src := string(hReq.Body) 23 | 24 | tokenPattern := regexp.MustCompile(`\${.+?}`) 25 | keyPattern := regexp.MustCompile(`\${(.+?)}`) 26 | formattedJSON := tokenPattern.ReplaceAllStringFunc(tmpl, func(match string) string { 27 | matches := keyPattern.FindStringSubmatch(match) 28 | result := gjson.Get(src, strings.TrimSpace(matches[1])) 29 | switch result.Type { 30 | case gjson.String: 31 | return result.Str 32 | case gjson.Number: 33 | return strconv.FormatFloat(result.Num, 'f', -1, 64) 34 | case gjson.JSON: 35 | return result.Raw 36 | default: 37 | return result.Type.String() 38 | } 39 | }) 40 | 41 | return ccMsg, json.Unmarshal([]byte(formattedJSON), &ccMsg) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Chathooks", 3 | "description": "Webhook proxy for team chat", 4 | "keywords": ["glip"], 5 | "website": "https://github.com/grokify/chathooks", 6 | "repository": "https://github.com/grokify/chathooks", 7 | "addons": [ 8 | "papertrail:choklad" 9 | ], 10 | "formation": { 11 | "web": { 12 | "quantity": 1, 13 | "size": "Free" 14 | } 15 | }, 16 | "env": { 17 | "CHATHOOKS_HOME_URL":{ 18 | "description": "Homepage for project, for homepage rendering only.", 19 | "value": "https://.herokuapp.com", 20 | "required": false 21 | }, 22 | "CHATHOOKS_WEBHOOK_URL":{ 23 | "description": "Webhook URL for project, for homepage rendering only.", 24 | "value": "https://.herokuapp.com/hook", 25 | "required": false 26 | }, 27 | "CHATHOOKS_TOKENS": { 28 | "description": "Comma-delimited list of secret tokens for validation", 29 | "default": "demo account - do not use for production", 30 | "required": false 31 | }, 32 | "CHATHOOKS_ENGINE": { 33 | "description": "HTTP server engine to use, e.g. 'fasthttp' or 'nethttp'.", 34 | "value": "fasthttp", 35 | "required": false 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /docs/handlers/updown/event-example_down.json: -------------------------------------------------------------------------------- 1 | { 2 | "username":"updown.io", 3 | "attachments":[ 4 | { 5 | "text":"Down since *23:25:37 (UTC)*, reason: *Bad Gateway*", 6 | "fallback":"ALERT: DOWN Chathooks Down since 23:25:37 (UTC), reason: Bad Gateway", 7 | "mrkdwn_in":[ 8 | "text", 9 | "pretext", 10 | "fields" 11 | ], 12 | "pretext":"ALERT: DOWN :exclamation:", 13 | "author_name":"Chathooks", 14 | "author_icon":"https://updown.io/checks/wgsw/favicon", 15 | "author_link":"https://chathooks.ngrok.io/about", 16 | "color":"#e43", 17 | "fields":[ 18 | { 19 | "title":"🔇 Mute alerts:", 20 | "value":", , , or " 21 | }, 22 | { 23 | "title":"↻ Reproduce request:", 24 | "value":"```curl -gkvLI -b '' -H 'User-Agent: updown.io daemon 2.6' -H 'Accept: */*' -H 'Connection: Close' -H 'Accept-Language: en' -m 30 --connect-timeout 10 ```" 25 | } 26 | ] 27 | } 28 | ], 29 | "icon_url":"https://updown.io/square-logo.png" 30 | } -------------------------------------------------------------------------------- /docs/icons/icon_victorops.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | 16 | -------------------------------------------------------------------------------- /docs/handlers/kapost/event-example_create-content.json: -------------------------------------------------------------------------------- 1 | { 2 | "operation":"create", 3 | "type":"content", 4 | "payload":{ 5 | "full_post":{ 6 | "id":"523381424aaaaecc80000001", 7 | "idea_title":null, 8 | "content_title":null, 9 | "creator_id":"51e477b9e1f419ecf4000004", 10 | "assignee_id":"51e477b9e1f419ecf4000004", 11 | "campaign_ids":[ 12 | 13 | ], 14 | "is_draft":false, 15 | "submission_deadline":null, 16 | "publish_deadline":null, 17 | "next_task":"Discuss post with creator", 18 | "updated_at":"2013-09-13T21:18:58Z", 19 | "privacy":"members", 20 | "idea":null, 21 | "content":null, 22 | "tags":[ 23 | 24 | ], 25 | "custom_fields":{ 26 | 27 | }, 28 | "excerpt":null, 29 | "categories":[ 30 | 31 | ], 32 | "persona_ids":[ 33 | 34 | ], 35 | "stage_ids":[ 36 | 37 | ], 38 | "attachments":[ 39 | 40 | ], 41 | "content_type":{ 42 | "id":"515b373751c35c02000001c3", 43 | "display_name":"Blog Post" 44 | } 45 | } 46 | }, 47 | "instance":{ 48 | "id":"515b373751c35c02000001c2", 49 | "subdomain":"mongohq" 50 | } 51 | } -------------------------------------------------------------------------------- /pkg/handlers/deskdotcom/handler_deskdotcom_out.go: -------------------------------------------------------------------------------- 1 | package deskdotcom 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | cc "github.com/grokify/commonchat" 7 | 8 | "github.com/grokify/chathooks/pkg/config" 9 | "github.com/grokify/chathooks/pkg/handlers" 10 | "github.com/grokify/chathooks/pkg/models" 11 | ) 12 | 13 | const ( 14 | DisplayName = "Desk.com" 15 | HandlerKey = "deskdotcom" 16 | MessageDirection = "out" 17 | DocumentationURL = "https://support.desk.com/customer/portal/articles/869334-configuring-webhooks-in-desk-com-apps" 18 | MessageBodyType = models.JSON 19 | ) 20 | 21 | func NewHandler() handlers.Handler { 22 | return handlers.Handler{MessageBodyType: MessageBodyType, Normalize: Normalize} 23 | } 24 | 25 | func Normalize(cfg config.Configuration, hReq handlers.HandlerRequest) (cc.Message, error) { 26 | ccMsg, err := CcMessageFromBytes(hReq.Body) 27 | if err != nil { 28 | return ccMsg, err 29 | } 30 | iconURL, err := cfg.GetAppIconURL(HandlerKey) 31 | if err == nil { 32 | ccMsg.IconURL = iconURL.String() 33 | } 34 | return ccMsg, nil 35 | } 36 | 37 | /* 38 | 39 | Example template: 40 | 41 | { 42 | "activity":"Case {{case.id}} updated", 43 | "body":"**Case Type**\n{{case.status}} {{case.type}}\n **Subject**\n[{{case.subject}}]({{case.direct_url}})" 44 | } 45 | 46 | */ 47 | 48 | func CcMessageFromBytes(bytes []byte) (cc.Message, error) { 49 | msg := cc.Message{} 50 | err := json.Unmarshal(bytes, &msg) 51 | return msg, err 52 | } 53 | -------------------------------------------------------------------------------- /examples/examples.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "regexp" 8 | 9 | "github.com/grokify/mogo/os/osutil" 10 | ) 11 | 12 | const ( 13 | HandlersDir = "github.com/grokify/chathooks/docs/handlers" 14 | Examples = "aha,appsignal,apteligent,circleci,codeship,confluence,datadog,deskdotcom,enchant,gosquared,heroku,librato,magnumci,marketo,opsgenie,papertrail,pingdom,raygun,runscope,semaphore,statuspage,travisci,userlike,victorops" 15 | ) 16 | 17 | func AbsDirGopath(dir string) string { 18 | return filepath.Join(os.Getenv("GOPATH"), "src", dir) 19 | } 20 | 21 | func DocsHandlersDirInfo() ([]string, []string, error) { 22 | handlersDir := AbsDirGopath(HandlersDir) 23 | fmt.Println(handlersDir) 24 | 25 | var dirs []string 26 | var exampleFiles []string 27 | sdirs, err := osutil.ReadDirMore(handlersDir, nil, true, false, false) 28 | 29 | if err != nil { 30 | return dirs, exampleFiles, err 31 | } 32 | 33 | for _, sdir := range sdirs { 34 | fmt.Printf("SDIR: %v\n", sdir.Name()) 35 | absSubDir := filepath.Join(handlersDir, sdir.Name()) 36 | exEntries, err := osutil.ReadDirMore(absSubDir, 37 | regexp.MustCompile(`^event-example_.+\.(json|txt)$`), false, true, false) 38 | if err != nil { 39 | return dirs, exampleFiles, err 40 | } 41 | if len(exEntries) > 0 { 42 | dirs = append(dirs, sdir.Name()) 43 | for _, f := range exEntries { 44 | fmt.Printf("FILE: %v\n", f.Name()) 45 | exFilepath := filepath.Join(absSubDir, f.Name()) 46 | exampleFiles = append(exampleFiles, exFilepath) 47 | } 48 | } 49 | } 50 | return dirs, exampleFiles, nil 51 | } 52 | -------------------------------------------------------------------------------- /docs/handlers/slack/event-example_link-emoji.json: -------------------------------------------------------------------------------- 1 | { 2 | "username":"updown.io", 3 | "attachments":[ 4 | { 5 | "text":"Down since *20:17:29 (CEST)*, reason: *Couldn't find the string*", 6 | "fallback":"DOWN ALERT: http://example.com Down since 20:17:29 (CEST), reason: Couldn't find the string", 7 | "mrkdwn_in":[ 8 | "text", 9 | "pretext", 10 | "fields" 11 | ], 12 | "pretext":"DOWN ALERT: :frowning:", 13 | "author_name":"http://example.com", 14 | "author_icon":"https://staging.updown.io/checks/mycheck/favicon", 15 | "author_link":"http://example.com", 16 | "color":"#e43", 17 | "fields":[ 18 | { 19 | "title":"String match:", 20 | "value":"_“12345”_", 21 | "short":true 22 | }, 23 | { 24 | "title":"🔇 Mute alerts:", 25 | "value":"\u003chttps://staging.updown.io/checks/mycheck/mute#1h|For 1 hour\u003e, \u003chttps://staging.updown.io/checks/mycheck/mute#1d|for 1 day\u003e, \u003chttps://staging.updown.io/checks/mycheck/mute#1w|for 1 week\u003e, \u003chttps://staging.updown.io/checks/mycheck/mute#recovery|until recovery\u003e or \u003chttps://staging.updown.io/checks/mycheck/mute#forever|forever\u003e" 26 | }, 27 | { 28 | "title":"↻ Reproduce request:", 29 | "value":"```curl -gkvL -H 'User-Agent: updown.io daemon 2.2' -H 'Accept: */*' -H 'Connection: Close' -H 'Accept-Language: en' -m 30 --connect-timeout 5 \u003chttp://example.com|http://example.com\u003e```" 30 | } 31 | ] 32 | } 33 | ], 34 | "icon_url":"https://updown.io/square-logo.png" 35 | } -------------------------------------------------------------------------------- /docs/slack.md: -------------------------------------------------------------------------------- 1 | # Example Requests 2 | 3 | Most of the time you will likely either: 4 | 5 | * use the proxy URL in an outbound webhook service that supports the Slack format or 6 | * use a client library 7 | 8 | The following examples are provided for reference and testing. 9 | 10 | ## Using `application/json` 11 | 12 | ```bash 13 | $ curl -X POST \ 14 | -H "Content-Type: application/json" \ 15 | -d '{"username":"ghost-bot", "icon_emoji": ":ghost:", "text":"BOO!"}' \ 16 | "http://localhost:8080/hook?inputType=slack&outputType=glip&url=11112222-3333-4444-5555-666677778888" 17 | ``` 18 | 19 | ## Using `application/x-www-form-urlencoded` 20 | 21 | ```bash 22 | $ curl -X POST \ 23 | --data-urlencode 'payload={"username":"ghost-bot", "icon_emoji": ":ghost:", text":"BOO!"}' \ 24 | "http://localhost:8080/hook?inputType=slack&outputType=glip&url=11112222-3333-4444-5555-666677778888" 25 | ``` 26 | 27 | ## Using `multipart/form-data` 28 | 29 | ```bash 30 | $ curl -X POST \ 31 | -F 'payload={"username":"ghost-bot", "icon_emoji": ":ghost:", text":"BOO!"}' \ 32 | "http://localhost:8080/hook?inputType=slack&outputType=glip&url=11112222-3333-4444-5555-666677778888" 33 | ``` 34 | 35 | ## Using Community Ruby SDK 36 | 37 | This has been tested using: 38 | 39 | * [https://github.com/rikas/slack-poster](https://github.com/rikas/slack-poster) 40 | 41 | ```ruby 42 | require 'slack/poster' 43 | 44 | url = 'http://localhost:8080/hook?inputType=slack&outputType=glip&url=11112222-3333-4444-5555-666677778888' 45 | 46 | opts = { 47 | username: 'Ghost Bot [Bot]', 48 | icon_emoji: ':ghost:' 49 | } 50 | 51 | poster = Slack::Poster.new url, opts 52 | poster.send_message 'BOO!' 53 | ``` -------------------------------------------------------------------------------- /docs/icons/icon_opsgenie.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/icons/icon_pingdom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 11 | 14 | 15 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/handlers/helpscout/event-example_customer-created.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":29418, 3 | "firstName":"Vernon", 4 | "lastName":"Bear", 5 | "photoUrl":"http://twitter.com/img/some-avatar.jpg", 6 | "photoType":"twitter", 7 | "gender":"Male", 8 | "age":"30-35", 9 | "organization":"Acme, Inc", 10 | "jobTitle":"CEO and Co-Founder", 11 | "location":"Greater Dallas/FT Worth Area", 12 | "background":"I've worked with Vernon before and he's really great.", 13 | "createdAt":"2012-07-23T12:34:12Z", 14 | "modifiedAt":"2012-07-24T20:18:33Z", 15 | "address":{ 16 | "id":1234, 17 | "lines":[ 18 | "123 West Main St", 19 | "Suite 123" 20 | ], 21 | "city":"Dallas", 22 | "state":"TX", 23 | "postcalCode":"74206", 24 | "country":"US", 25 | "createdAt":"2012-07-23T12:34:12Z", 26 | "modifiedAt":"2012-07-24T20:18:33Z" 27 | }, 28 | "socialProfiles":[ 29 | { 30 | "id":9184, 31 | "value":"https://twitter.com/helpscout", 32 | "type":"twitter" 33 | } 34 | ], 35 | "emails":[ 36 | { 37 | "id":98131, 38 | "value":"vbear@mywork.com", 39 | "location":"work" 40 | } 41 | ], 42 | "phones":[ 43 | { 44 | "id":22381, 45 | "value":"222-333-4444 ", 46 | "location":"home" 47 | } 48 | ], 49 | "chats":[ 50 | { 51 | "id":77183, 52 | "value":"jsprout", 53 | "type":"aim" 54 | } 55 | ], 56 | "websites":[ 57 | { 58 | "id":5584, 59 | "value":"http://www.somewhere.com" 60 | } 61 | ] 62 | } -------------------------------------------------------------------------------- /docs/icons/icon_elasticsearch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pkg/config/interface_constants.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "strings" 4 | 5 | const ( 6 | ParamNameAdapters = "adapters" 7 | ParamNameActivityDefault = "defaultActivity" 8 | ParamNameIconDefault = "defaultIcon" 9 | ParamNameInputType = "inputType" 10 | ParamNameOutputType = "outputType" 11 | ParamNameOutputFormat = "outputFormat" // `card`, `adaptivecard`, `nocard`. Default is `card`. 12 | ParamNameOutputURL = "outputURL" 13 | ParamNameToken = "token" 14 | EnvPath = "ENV_PATH" 15 | EnvEngine = "CHATHOOKS_ENGINE" // awslambda, nethttp, fasthttp 16 | EnvTokens = "CHATHOOKS_TOKENS" 17 | EnvWebhookURL = "CHATHOOKS_URL" 18 | EnvHomeURL = "CHATHOOKS_HOME_URL" 19 | ErrRequiredTokenNotFound = "401.01 Required Token Not Found" 20 | ErrRequiredTokenNotValid = "401.02 Required Token Not Valid" 21 | // ParamNameURL = "url" // legacy. deprecated. 22 | 23 | ParamNameOutputFormatNocard = "nocard" 24 | ParamNameOutputFormatCard = "card" 25 | ParamNameOutputFormatAdaptivecard = "adaptivecard" 26 | ) 27 | 28 | func MustParseOutputFormat(input string) string { 29 | input = strings.ToLower(strings.TrimSpace(input)) 30 | switch input { 31 | case ParamNameOutputFormatNocard: 32 | return ParamNameOutputFormatNocard 33 | case ParamNameOutputFormatNocard + "s": 34 | return ParamNameOutputFormatNocard 35 | case ParamNameOutputFormatCard: 36 | return ParamNameOutputFormatCard 37 | case ParamNameOutputFormatCard + "s": 38 | return ParamNameOutputFormatCard 39 | case ParamNameOutputFormatAdaptivecard: 40 | return ParamNameOutputFormatAdaptivecard 41 | case ParamNameOutputFormatAdaptivecard + "s": 42 | return ParamNameOutputFormatAdaptivecard 43 | default: 44 | return "" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pkg/handlers/confluence/handler_confluence_out_test.go: -------------------------------------------------------------------------------- 1 | package confluence 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/grokify/chathooks/pkg/config" 7 | ) 8 | 9 | var ConfigurationTests = []struct { 10 | v int 11 | want string 12 | }{ 13 | {8080, ":8080"}} 14 | 15 | func TestConfluence(t *testing.T) { 16 | for _, tt := range ConfigurationTests { 17 | cfg := config.Configuration{ 18 | Port: tt.v} 19 | 20 | addr := cfg.Address() 21 | if tt.want != addr { 22 | t.Errorf("Configuration.Address(%v): want %v, got %v", tt.v, tt.want, addr) 23 | } 24 | } 25 | } 26 | 27 | func CommentCreated() []byte { 28 | bytes := []byte(`{ 29 | "comment": { 30 | "spaceKey": "~admin", 31 | "parent": { 32 | "spaceKey": "~admin", 33 | "modificationDate": 1471926079631, 34 | "creatorKey": "ff80808154510724015451074c160001", 35 | "creatorName": "admin", 36 | "lastModifierKey": "ff80808154510724015451074c160001", 37 | "self": "https://cloud-development-environment.atlassian.net/wiki/display/~admin/Some+random+test+page", 38 | "lastModifierName": "admin", 39 | "id": 16777227, 40 | "title": "Some random test page", 41 | "creationDate": 1471926079631, 42 | "version": 1 43 | }, 44 | "modificationDate": 1471926091465, 45 | "creatorKey": "ff80808154510724015451074c160001", 46 | "creatorName": "admin", 47 | "lastModifierKey": "ff80808154510724015451074c160001", 48 | "self": "https://cloud-development-environment/wiki/display/~admin/Some+random+test+page?focusedCommentId=16777228#comment-16777228", 49 | "lastModifierName": "admin", 50 | "id": 16777228, 51 | "creationDate": 1471926091465, 52 | "version": 1 53 | }, 54 | "user": "admin", 55 | "userKey": "ff80808154510724015451074c160001", 56 | "timestamp": 1471926091468, 57 | "username": "admin" 58 | }`) 59 | return bytes 60 | } 61 | -------------------------------------------------------------------------------- /docs/handlers/runscope/event-example_notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables":{ 3 | "foo":"bar", 4 | "baz":"qux" 5 | }, 6 | "test_id":"76598752-cbda-4e1d-820f-6274a62f74ff", 7 | "test_name":"Buckets Test", 8 | "test_run_id":"9c15aa62-21f0-48f2-a819-c99bdf8e4543", 9 | "team_id":"6b9c7f65-9e11-4f77-85ad-e6ee7a28232d", 10 | "team_name":"Acme Inc.", 11 | "environment_uuid":"98290cfc-a008-4ab7-9ea4-8906f12b228f", 12 | "environment_name":"Staging Settings", 13 | "bucket_name":"Rocket Sled", 14 | "bucket_key":"bucket_key", 15 | "test_url":"https://www.runscope.com/radar/bucket_key/76598752-cbda-4e1d-820f-6274a62f74ff", 16 | "test_run_url":"https://www.runscope.com/radar/bucket_key/76598752-cbda-4e1d-820f-6274a62f74ff/results/9c15aa62-21f0-48f2-a819-c99bdf8e4543", 17 | "trigger_url":"https://api.runscope.com/radar/09039249-fdfd-4e1d-820f-6274a62f74ff/trigger", 18 | "result":"fail", 19 | "started_at":1384281308.548077, 20 | "finished_at":1384281310.680218, 21 | "agent":null, 22 | "region":"us1", 23 | "region_name":"US East - Northern Virginia", 24 | "initial_variables":{ 25 | 26 | }, 27 | "requests":[ 28 | { 29 | "url":"https://api.runscope.com/", 30 | "variables":{ 31 | "fail":0, 32 | "total":1, 33 | "pass":1 34 | }, 35 | "assertions":{ 36 | "fail":0, 37 | "total":2, 38 | "pass":2 39 | }, 40 | "scripts":{ 41 | "fail":0, 42 | "total":1, 43 | "pass":1 44 | }, 45 | "result":"pass", 46 | "method":"GET", 47 | "response_time_ms":123, 48 | "response_size_bytes":2048, 49 | "response_status_code":"200", 50 | "note":"Root URL" 51 | } 52 | ] 53 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grokify/chathooks 2 | 3 | // +heroku goVersion go1.22 4 | go 1.24.0 5 | 6 | toolchain go1.24.1 7 | 8 | require ( 9 | github.com/apex/gateway v1.1.2 10 | github.com/aws/aws-lambda-go v1.50.0 11 | github.com/buaazp/fasthttprouter v0.1.1 12 | github.com/caarlos0/env/v9 v9.0.0 13 | github.com/google/go-querystring v1.1.0 14 | github.com/grokify/commonchat v0.3.18 15 | github.com/grokify/mogo v0.72.0 16 | github.com/grokify/sogo v0.12.12 17 | github.com/jessevdk/go-flags v1.6.1 18 | github.com/joho/godotenv v1.5.1 19 | github.com/microcosm-cc/bluemonday v1.0.27 20 | github.com/rs/zerolog v1.34.0 21 | github.com/tidwall/gjson v1.18.0 22 | github.com/valyala/fasthttp v1.68.0 23 | github.com/valyala/quicktemplate v1.8.0 24 | ) 25 | 26 | require ( 27 | github.com/andybalholm/brotli v1.2.0 // indirect 28 | github.com/aymerick/douceur v0.2.0 // indirect 29 | github.com/caarlos0/env/v11 v11.3.1 // indirect 30 | github.com/derekstavis/go-qs v0.0.0-20250518184349-717ef4cb7534 // indirect 31 | github.com/gorilla/css v1.0.1 // indirect 32 | github.com/gorilla/mux v1.8.1 // indirect 33 | github.com/grokify/bitcoinmath v0.1.0 // indirect 34 | github.com/grokify/go-glip v0.5.21 // indirect 35 | github.com/huandu/xstrings v1.5.0 // indirect 36 | github.com/json-iterator/go v1.1.12 // indirect 37 | github.com/klauspost/compress v1.18.1 // indirect 38 | github.com/mattn/go-colorable v0.1.14 // indirect 39 | github.com/mattn/go-isatty v0.0.20 // indirect 40 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 41 | github.com/modern-go/reflect2 v1.0.2 // indirect 42 | github.com/pkg/errors v0.9.1 // indirect 43 | github.com/tidwall/match v1.2.0 // indirect 44 | github.com/tidwall/pretty v1.2.1 // indirect 45 | github.com/valyala/bytebufferpool v1.0.0 // indirect 46 | golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect 47 | golang.org/x/net v0.47.0 // indirect 48 | golang.org/x/sys v0.38.0 // indirect 49 | golang.org/x/text v0.31.0 // indirect 50 | ) 51 | -------------------------------------------------------------------------------- /docs/handlers/statuspage/event-example_incident-updates-create.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta":{ 3 | "unsubscribe":"http://statustest.flyingkleinbrothers.com:5000/?unsubscribe=j0vqr9kl3513", 4 | "documentation":"http://doers.statuspage.io/customer-notifications/webhooks/" 5 | }, 6 | "page":{ 7 | "id":"j2mfxwj97wnj", 8 | "status_indicator":"critical", 9 | "status_description":"Major System Outage" 10 | }, 11 | "incident":{ 12 | "backfilled":false, 13 | "created_at":"2013-05-29T15:08:51-06:00", 14 | "impact":"critical", 15 | "impact_override":null, 16 | "monitoring_at":"2013-05-29T16:07:53-06:00", 17 | "postmortem_body":null, 18 | "postmortem_body_last_updated_at":null, 19 | "postmortem_ignored":false, 20 | "postmortem_notified_subscribers":false, 21 | "postmortem_notified_twitter":false, 22 | "postmortem_published_at":null, 23 | "resolved_at":null, 24 | "scheduled_auto_transition":false, 25 | "scheduled_for":null, 26 | "scheduled_remind_prior":false, 27 | "scheduled_reminded_at":null, 28 | "scheduled_until":null, 29 | "shortlink":"http://j.mp/18zyDQx", 30 | "status":"monitoring", 31 | "updated_at":"2013-05-29T16:30:35-06:00", 32 | "id":"lbkhbwn21v5q", 33 | "organization_id":"j2mfxwj97wnj", 34 | "incident_updates":[ 35 | { 36 | "body":"The cloud, located in Norther Virginia, has once again gone the way of the dodo.", 37 | "created_at":"2013-05-29T15:08:51-06:00", 38 | "display_at":"2013-05-29T15:08:51-06:00", 39 | "status":"investigating", 40 | "twitter_updated_at":null, 41 | "updated_at":"2013-05-29T15:28:51-06:00", 42 | "wants_twitter_update":false, 43 | "id":"qbbsfhy5s9kk", 44 | "incident_id":"lbkhbwn21v5q" 45 | } 46 | ], 47 | "name":"Virginia Is Down" 48 | } 49 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/README.md: -------------------------------------------------------------------------------- 1 | How to add a Userlike Bot 2 | ========================= 3 | 4 | ## Configuring Webhook 5 | 6 | Use the following steps to configure a webhook connection in Userlike. 7 | 8 | 1. Login to *Userlike* and then, on the left navigation menu, click **Config**. 9 | 2. On the *Config* menu, click **Addons Settings**. 10 | 3. In the *SERVICE* column and the *API* row, click the **Edit** icon in the *ACTION* column to display the *Configure Callback API* page. 11 | 4. In the *Configure* section's **Callback URL** field, enter your Userlike proxy URL. 12 | 5. Select one or more events in the next sections that will trigger a webhook alert message, and then click **Update Settings**. 13 | 14 | ## Events 15 | 16 | The following is a list of events from [Userlike's API addon page](https://www.userlike.com/en/public/tutorial/addon/api). 17 | 18 | | TYPE | EVENT | DESCRIPTION | 19 | |------|-------|-------------| 20 | | `offline_message` | `receive` | Receive a callback for each new offline message you receive. | 21 | | `chat_meta` | `start` | Receive a callback for each new chat session. | 22 | | `chat_meta` | `forward` | Receive a callback when are chat session gets forwarded. | 23 | | `chat_meta` | `rating` | Receive a callback when a chat session receives a rating. | 24 | | `chat_meta` | `feedback` | Receive a callback when a chat session receives a feedback. | 25 | | `chat_meta` | `survey` | Receive a callback when a chat session receives a survey. | 26 | | `chat_meta` | `receive` | Receive a callback when a chat session ends and the conversation is finished. | 27 | | `chat_meta` | `goal` | Receive a callback when a goal was reached. | 28 | | `chat_widget` | `config` | Receive a callback when a chat widget configuration changes. | 29 | | `operator` | `online` | Receive a callback when an operator goes online. | 30 | | `operator` | `offline` | Receive a callback when an operator goes offline. | 31 | | `operator` | `away` | Receive a callback when an operator goes away. | 32 | | `operator` | `back` | Receive a callback when an operator comes back. | 33 | -------------------------------------------------------------------------------- /docs/handlers/trello/event-example_notification.json: -------------------------------------------------------------------------------- 1 | { 2 | "action":{ 3 | "id":"51f9424bcd6e040f3c002412", 4 | "idMemberCreator":"4fc78a59a885233f4b349bd9", 5 | "data":{ 6 | "board":{ 7 | "name":"Trello Development", 8 | "id":"4d5ea62fd76aa1136000000c" 9 | }, 10 | "card":{ 11 | "idShort":1458, 12 | "name":"Webhooks", 13 | "id":"51a79e72dbb7e23c7c003778" 14 | }, 15 | "voted":true 16 | }, 17 | "type":"voteOnCard", 18 | "date":"2013-07-31T16:58:51.949Z", 19 | "memberCreator":{ 20 | "id":"4fc78a59a885233f4b349bd9", 21 | "avatarHash":"2da34d23b5f1ac1a20e2a01157bfa9fe", 22 | "fullName":"Doug Patti", 23 | "initials":"DP", 24 | "username":"doug" 25 | } 26 | }, 27 | "model":{ 28 | "id":"4d5ea62fd76aa1136000000c", 29 | "name":"Trello Development", 30 | "desc":"Trello board used by the Trello team to track work on Trello. How meta!\n\nThe development of the Trello API is being tracked at https://trello.com/api\n\nThe development of Trello Mobile applications is being tracked at https://trello.com/mobile", 31 | "closed":false, 32 | "idOrganization":"4e1452614e4b8698470000e0", 33 | "pinned":true, 34 | "url":"https://trello.com/b/nC8QJJoZ/trello-development", 35 | "prefs":{ 36 | "permissionLevel":"public", 37 | "voting":"public", 38 | "comments":"public", 39 | "invitations":"members", 40 | "selfJoin":false, 41 | "cardCovers":true, 42 | "canBePublic":false, 43 | "canBeOrg":false, 44 | "canBePrivate":false, 45 | "canInvite":true 46 | }, 47 | "labelNames":{ 48 | "yellow":"Infrastructure", 49 | "red":"Bug", 50 | "purple":"Repro'd", 51 | "orange":"Feature", 52 | "green":"Mobile", 53 | "blue":"Verified" 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /docs/handlers/paypal/event-example_payment-authorization-created.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":"8PT597110X687430LKGECATA", 3 | "create_time":"2013-06-25T21:41:28Z", 4 | "resource_type":"authorization", 5 | "event_type":"PAYMENT.AUTHORIZATION.CREATED", 6 | "summary":"A payment authorization was created", 7 | "resource":{ 8 | "id":"2DC87612EK520411B", 9 | "create_time":"2013-06-25T21:39:15Z", 10 | "update_time":"2013-06-25T21:39:17Z", 11 | "state":"authorized", 12 | "amount":{ 13 | "total":"7.47", 14 | "currency":"USD", 15 | "details":{ 16 | "subtotal":"7.47" 17 | } 18 | }, 19 | "parent_payment":"PAY-36246664YD343335CKHFA4AY", 20 | "valid_until":"2013-07-24T21:39:15Z", 21 | "links":[ 22 | { 23 | "href":"https://api.sandbox.paypal.com/v1/payments/authorization/2DC87612EK520411B", 24 | "rel":"self", 25 | "method":"GET" 26 | }, 27 | { 28 | "href":"https://api.sandbox.paypal.com/v1/payments/authorization/2DC87612EK520411B/capture", 29 | "rel":"capture", 30 | "method":"POST" 31 | }, 32 | { 33 | "href":"https://api.sandbox.paypal.com/v1/payments/authorization/2DC87612EK520411B/void", 34 | "rel":"void", 35 | "method":"POST" 36 | }, 37 | { 38 | "href":"https://api.sandbox.paypal.com/v1/payments/payment/PAY-36246664YD343335CKHFA4AY", 39 | "rel":"parent_payment", 40 | "method":"GET" 41 | } 42 | ] 43 | }, 44 | "links":[ 45 | { 46 | "href":"https://api.sandbox.paypal.com/v1/notfications/webhooks-events/8PT597110X687430LKGECATA", 47 | "rel":"self", 48 | "method":"GET" 49 | }, 50 | { 51 | "href":"https://api.sandbox.paypal.com/v1/notfications/webhooks-events/8PT597110X687430LKGECATA/resend", 52 | "rel":"resend", 53 | "method":"POST" 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /pkg/config/configuration.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "net/url" 6 | "os" 7 | "path" 8 | "strconv" 9 | 10 | env "github.com/caarlos0/env/v9" 11 | "github.com/rs/zerolog" 12 | ) 13 | 14 | const ( 15 | DocsHandlersSrcDir = "github.com/grokify/chathooks/docs/handlers" 16 | IconBaseURL = "http://grokify.github.io/chathooks/icons/" 17 | EmojiURLFormat = "https://grokify.github.io/emoji/assets/images/%s.png" 18 | 19 | InfoInputMessageParseBegin = "INFO - Input Message Parse Begin" 20 | ErrorInputMessageParseFailed = "FAIL - Input Message Parse Failed" 21 | ) 22 | 23 | func DocsHandlersDir() string { 24 | return path.Join(os.Getenv("GOPATH"), "src", DocsHandlersSrcDir) 25 | } 26 | 27 | // Configuration is the webhook proxy configuration struct. 28 | type Configuration struct { 29 | Port int `env:"PORT" envDefault:"3000"` 30 | Engine string `env:"CHATHOOKS_ENGINE" envDefault:"fasthttp"` 31 | HomeURL string `env:"CHATHOOKS_HOME_URL"` 32 | WebhookURL string `env:"CHATHOOKS_WEBHOOK_URL"` 33 | Tokens []string `env:"CHATHOOKS_TOKENS" envSeparator:","` 34 | LogFormat string `env:"CHATHOOKS_LOG_FORMAT"` 35 | EmojiURLFormat string 36 | IconBaseURL string 37 | LogLevel zerolog.Level 38 | } 39 | 40 | func NewConfigurationEnv() (Configuration, error) { 41 | cfg := Configuration{} 42 | if err := env.Parse(&cfg); err != nil { 43 | return cfg, err 44 | } 45 | cfg.EmojiURLFormat = EmojiURLFormat 46 | cfg.IconBaseURL = IconBaseURL 47 | cfg.LogLevel = 1 48 | return cfg, nil 49 | } 50 | 51 | func ReadConfigurationFile(filepath string) (Configuration, error) { 52 | var configuration Configuration 53 | bytes, err := os.ReadFile(filepath) 54 | if err != nil { 55 | return configuration, err 56 | } 57 | err = json.Unmarshal(bytes, &configuration) 58 | return configuration, err 59 | } 60 | 61 | // Address returns the port address as a string with a `:` prefix 62 | func (c *Configuration) Address() string { 63 | return ":" + strconv.Itoa(c.Port) 64 | } 65 | 66 | func (c *Configuration) GetAppIconURL(appSlug string) (*url.URL, error) { 67 | return buildIconURL(c.IconBaseURL, appSlug) 68 | } 69 | -------------------------------------------------------------------------------- /docs/handlers/travisci/event-example_build.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":1, 3 | "number":"1", 4 | "status":null, 5 | "started_at":null, 6 | "finished_at":null, 7 | "status_message":"Passed", 8 | "commit":"62aae5f70ceee39123ef", 9 | "branch":"master", 10 | "message":"the commit message", 11 | "compare_url":"https://github.com/svenfuchs/minimal/compare/master...develop", 12 | "committed_at":"2011-11-11T11: 11: 11Z", 13 | "committer_name":"Sven Fuchs", 14 | "committer_email":"svenfuchs@artweb-design.de", 15 | "author_name":"Sven Fuchs", 16 | "author_email":"svenfuchs@artweb-design.de", 17 | "type":"push", 18 | "build_url":"https://travis-ci.org/svenfuchs/minimal/builds/1", 19 | "repository":{ 20 | "id":1, 21 | "name":"minimal", 22 | "owner_name":"svenfuchs", 23 | "url":"http://github.com/svenfuchs/minimal" 24 | }, 25 | "config":{ 26 | "notifications":{ 27 | "webhooks":[ 28 | "http://evome.fr/notifications", 29 | "http://example.com/" 30 | ] 31 | } 32 | }, 33 | "matrix":[ 34 | { 35 | "id":2, 36 | "repository_id":1, 37 | "number":"1.1", 38 | "state":"created", 39 | "started_at":null, 40 | "finished_at":null, 41 | "config":{ 42 | "notifications":{ 43 | "webhooks":[ 44 | "http://evome.fr/notifications", 45 | "http://example.com/" 46 | ] 47 | } 48 | }, 49 | "status":null, 50 | "log":"", 51 | "result":null, 52 | "parent_id":1, 53 | "commit":"62aae5f70ceee39123ef", 54 | "branch":"master", 55 | "message":"the commit message", 56 | "committed_at":"2011-11-11T11: 11: 11Z", 57 | "committer_name":"Sven Fuchs", 58 | "committer_email":"svenfuchs@artweb-design.de", 59 | "author_name":"Sven Fuchs", 60 | "author_email":"svenfuchs@artweb-design.de", 61 | "compare_url":"https://github.com/svenfuchs/minimal/compare/master...develop" 62 | } 63 | ] 64 | } -------------------------------------------------------------------------------- /pkg/config/icons.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "errors" 5 | "net/url" 6 | ) 7 | 8 | const ( 9 | DefaultIconFile = "icon_webhookrc_512x512.png" 10 | ) 11 | 12 | var Icons = map[string]string{ 13 | "aha": "icon_aha_256x256.png", 14 | "appsignal": "icon_appsignal_400x400.png", 15 | "apteligent": "icon_apteligent_496x496.png", 16 | "bugsnag": "icon_bugsnag_512x512.png", 17 | "circleci": "icon_circleci_128x128.png", 18 | "codeship": "icon_codeship_512x512.png", 19 | "confluence": "icon_confluence_256x256.png", 20 | "datadog": "icon_datadog_512x512.png", 21 | "deskdotcom": "icon_deskdotcom_400x400.png", 22 | "enchant": "icon_enchant_400x400.png", 23 | "gosquared": "icon_gosquared_128x128.png", 24 | "heroku": "icon_heroku_512x512.png", 25 | "librato": "icon_librato_128x128.png", 26 | "magnumci": "icon_magnumci_400x400.png", 27 | "marketo": "icon_marketo_250x250.png", 28 | "opsgenie": "icon_opsgenie_128x128.png", 29 | "papertrail": "icon_papertrail_128x128.png", 30 | "pingdom": "icon_pingdom_512x512.png", 31 | "raygun": "icon_raygun_512x512.png", 32 | "runscope": "icon_runscope_400x400.png", 33 | "semaphore": "icon_semaphore_512x512.png", 34 | "statuspage": "icon_statuspage_512x512.png", 35 | "travisci": "icon_travisci_225x225.png", 36 | "userlike": "icon_userlike_512x512.png", 37 | "victorops": "icon_victorops_225x225.png", 38 | "wootric": "icon_wootric_200x200.png"} 39 | 40 | func joinURL(baseURL string, pathPart string) (*url.URL, error) { 41 | u, err := url.Parse(pathPart) 42 | if err != nil { 43 | return &url.URL{}, nil 44 | } 45 | base, err := url.Parse(baseURL) 46 | if err != nil { 47 | return &url.URL{}, nil 48 | } 49 | return base.ResolveReference(u), nil 50 | } 51 | 52 | func getAppIconFile(appSlug string) (string, error) { 53 | if file, ok := Icons[appSlug]; ok { 54 | return file, nil 55 | } 56 | return "", errors.New("E_NO_APP_ICON_FILE") 57 | } 58 | 59 | func getAppIconFileWithDefault(appSlug string) string { 60 | file, err := getAppIconFile(appSlug) 61 | if err != nil { 62 | file = DefaultIconFile 63 | } 64 | return file 65 | } 66 | 67 | func buildIconURL(baseURL string, appSlug string) (*url.URL, error) { 68 | iconFile := getAppIconFileWithDefault(appSlug) 69 | return joinURL(baseURL, iconFile) 70 | } 71 | -------------------------------------------------------------------------------- /pkg/adapters/adapter.go: -------------------------------------------------------------------------------- 1 | package adapters 2 | 3 | import ( 4 | "github.com/grokify/commonchat" 5 | "github.com/rs/zerolog/log" 6 | "github.com/valyala/fasthttp" 7 | 8 | "github.com/grokify/chathooks/pkg/models" 9 | ) 10 | 11 | var ( 12 | ShowDisplayName = false 13 | ) 14 | 15 | type AdapterSet struct { 16 | Adapters map[string]commonchat.Adapter 17 | } 18 | 19 | func NewAdapterSet() AdapterSet { 20 | return AdapterSet{Adapters: map[string]commonchat.Adapter{}} 21 | } 22 | 23 | func (set *AdapterSet) SendWebhooks(hookData models.HookData) []models.ErrorInfo { 24 | errs := []models.ErrorInfo{} 25 | hookOpts := map[string]any{} 26 | if hookData.OutputFormat == "nocard" { 27 | hookOpts["useAttachments"] = false 28 | log.Debug(). 29 | Str("hookData.outputFormat", hookData.OutputFormat). 30 | Bool("hookOpts.useAttachments", hookOpts["useAttachments"].(bool)). 31 | Msg("AdapterSet.SendWebhooks.HookOpts") 32 | } 33 | if len(hookData.OutputType) > 0 && len(hookData.OutputURL) > 0 { 34 | if adapter, ok := set.Adapters[hookData.OutputType]; ok { 35 | var msg any 36 | req, res, err := adapter.SendWebhook( 37 | hookData.OutputURL, hookData.CanonicalMessage, &msg, hookOpts) 38 | log.Debug(). 39 | Str("output_type", hookData.OutputType). 40 | Int("status_code", res.StatusCode()). 41 | Str("output_url", hookData.OutputURL). 42 | Str("body", string(res.Body())). 43 | Msg("ADAPTER_API_REQ_RES_INFO") 44 | errs = set.procResponse(errs, req, res, err) 45 | } 46 | } 47 | for _, namedAdapter := range hookData.OutputNames { 48 | if adapter, ok := set.Adapters[namedAdapter]; ok { 49 | var msg any 50 | req, res, err := adapter.SendMessage( 51 | hookData.CanonicalMessage, &msg, hookOpts) 52 | errs = set.procResponse(errs, req, res, err) 53 | } 54 | } 55 | return errs 56 | } 57 | 58 | func (set *AdapterSet) procResponse(errs []models.ErrorInfo, req *fasthttp.Request, res *fasthttp.Response, err error) []models.ErrorInfo { 59 | if err != nil { 60 | errs = append(errs, models.ErrorInfo{StatusCode: 500, Body: []byte(err.Error())}) 61 | } else if res.StatusCode() > 299 { 62 | errs = append(errs, models.ErrorInfo{ 63 | StatusCode: res.StatusCode(), 64 | Body: res.Body(), 65 | }) 66 | } 67 | fasthttp.ReleaseRequest(req) 68 | fasthttp.ReleaseResponse(res) 69 | return errs 70 | } 71 | -------------------------------------------------------------------------------- /docs/icons/icon_heroku.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/handlers/gosquared/event-example_live-chat.json: -------------------------------------------------------------------------------- 1 | { 2 | "version":"0.0.1", 3 | "site_token":"GSN-67890-A", 4 | "timestamp":"2017-05-02T05:19:34.252Z", 5 | "person":{ 6 | "id":"Anon Chat: bba4b6264b073a17c74f1b0da7720114", 7 | "email":"", 8 | "name":"", 9 | "avatar":"", 10 | "chat":{ 11 | "archived":null, 12 | "latest":{ 13 | "message":{ 14 | "type":"message", 15 | "id":"167c06cf-ff7c-4d09-880c-5533795f9673", 16 | "content":"hello world", 17 | "timestamp":1493702374252, 18 | "from":"client", 19 | "private":false, 20 | "session":{ 21 | "title":"", 22 | "href":"http://127.0.0.1:2015/" 23 | }, 24 | "data":{ 25 | 26 | }, 27 | "entities":[ 28 | 29 | ] 30 | }, 31 | "timestamp":1493702374252 32 | }, 33 | "agent":{ 34 | "assigned":"31e043150da1d922ff90f3e54940600d", 35 | "read":1493373060143, 36 | "delivered":1493372637305 37 | }, 38 | "client":{ 39 | "read":1493702374252, 40 | "delivered":1493372587362 41 | } 42 | }, 43 | "lead":{ 44 | "email":"johndoe@example.com" 45 | }, 46 | "status":"", 47 | "presence":"online", 48 | "_anon":{ 49 | "name":"Anon: Steel Blue Shoeprints", 50 | "color":"#4B77BE", 51 | "shape":"human-shoes-footprints" 52 | }, 53 | "_links":[ 54 | { 55 | "rel":"self", 56 | "href":"https://api.gosquared.com/chat/v1/chats/Anon%20Chat%3A%20bba4b6264b073a17c74f1b0da7720114", 57 | "method":"GET" 58 | } 59 | ] 60 | }, 61 | "message":{ 62 | "type":"message", 63 | "id":"167c06cf-ff7c-4d09-880c-5533795f9673", 64 | "content":"hello world", 65 | "timestamp":1493702374252, 66 | "from":"client", 67 | "private":false, 68 | "session":{ 69 | "title":"", 70 | "href":"http://127.0.0.1:2015/" 71 | }, 72 | "data":{ 73 | 74 | }, 75 | "entities":[ 76 | 77 | ], 78 | "person_id":"Anon Chat: bba4b6264b073a17c74f1b0da7720114" 79 | } 80 | } -------------------------------------------------------------------------------- /docs/handlers/statuspage/event-example_incident-updates.json: -------------------------------------------------------------------------------- 1 | { 2 | "meta":{ 3 | "unsubscribe":"http://statustest.flyingkleinbrothers.com:5000/?unsubscribe=j0vqr9kl3513", 4 | "documentation":"http://doers.statuspage.io/customer-notifications/webhooks/" 5 | }, 6 | "page":{ 7 | "id":"j2mfxwj97wnj", 8 | "status_indicator":"critical", 9 | "status_description":"Major System Outage" 10 | }, 11 | "incident":{ 12 | "backfilled":false, 13 | "created_at":"2013-05-29T15:08:51-06:00", 14 | "impact":"critical", 15 | "impact_override":null, 16 | "monitoring_at":"2013-05-29T16:07:53-06:00", 17 | "postmortem_body":null, 18 | "postmortem_body_last_updated_at":null, 19 | "postmortem_ignored":false, 20 | "postmortem_notified_subscribers":false, 21 | "postmortem_notified_twitter":false, 22 | "postmortem_published_at":null, 23 | "resolved_at":null, 24 | "scheduled_auto_transition":false, 25 | "scheduled_for":null, 26 | "scheduled_remind_prior":false, 27 | "scheduled_reminded_at":null, 28 | "scheduled_until":null, 29 | "shortlink":"http://j.mp/18zyDQx", 30 | "status":"monitoring", 31 | "updated_at":"2013-05-29T16:30:35-06:00", 32 | "id":"lbkhbwn21v5q", 33 | "organization_id":"j2mfxwj97wnj", 34 | "incident_updates":[ 35 | { 36 | "body":"A fix has been implemented and we are monitoring the results.", 37 | "created_at":"2013-05-29T16:07:53-06:00", 38 | "display_at":"2013-05-29T16:07:53-06:00", 39 | "status":"monitoring", 40 | "twitter_updated_at":null, 41 | "updated_at":"2013-05-29T16:09:09-06:00", 42 | "wants_twitter_update":false, 43 | "id":"drfcwbnpxnr6", 44 | "incident_id":"lbkhbwn21v5q" 45 | }, 46 | { 47 | "body":"We are waiting for the cloud to come back online and will update when we have further information", 48 | "created_at":"2013-05-29T15:18:51-06:00", 49 | "display_at":"2013-05-29T15:18:51-06:00", 50 | "status":"identified", 51 | "twitter_updated_at":null, 52 | "updated_at":"2013-05-29T15:28:51-06:00", 53 | "wants_twitter_update":false, 54 | "id":"2rryghr4qgrh", 55 | "incident_id":"lbkhbwn21v5q" 56 | }, 57 | { 58 | "body":"The cloud, located in Norther Virginia, has once again gone the way of the dodo.", 59 | "created_at":"2013-05-29T15:08:51-06:00", 60 | "display_at":"2013-05-29T15:08:51-06:00", 61 | "status":"investigating", 62 | "twitter_updated_at":null, 63 | "updated_at":"2013-05-29T15:28:51-06:00", 64 | "wants_twitter_update":false, 65 | "id":"qbbsfhy5s9kk", 66 | "incident_id":"lbkhbwn21v5q" 67 | } 68 | ], 69 | "name":"Virginia Is Down" 70 | } 71 | } -------------------------------------------------------------------------------- /docs/handlers/pagerduty/event-example_incident_trigger.json: -------------------------------------------------------------------------------- 1 | { 2 | "messages":[ 3 | { 4 | "type":"incident.trigger", 5 | "data":{ 6 | "incident":{ 7 | "id":"PRORDTY", 8 | "incident_number":2126, 9 | "created_on":"2016-02-22T21:02:55Z", 10 | "status":"triggered", 11 | "pending_actions":[ 12 | { 13 | "type":"escalate", 14 | "at":"2016-02-22T13:07:55-08:00" 15 | }, 16 | { 17 | "type":"resolve", 18 | "at":"2016-02-22T17:02:55-08:00" 19 | } 20 | ], 21 | "html_url":"https://webdemo.pagerduty.com/incidents/PRORDTY", 22 | "incident_key":"17a02d0d370d4add8e53132199614121", 23 | "service":{ 24 | "id":"PDS1SN6", 25 | "name":"Production XDB Cluster", 26 | "html_url":"https://webdemo.pagerduty.com/services/PDS1SN6", 27 | "deleted_at":null, 28 | "description":"Primary production datastore." 29 | }, 30 | "escalation_policy":{ 31 | "id":"P5ARF12", 32 | "name":"Database Team", 33 | "deleted_at":null 34 | }, 35 | "assigned_to_user":{ 36 | "id":"P553OPV", 37 | "name":"Laura Haley", 38 | "email":"laura.haley@example.com", 39 | "html_url":"https://webdemo.pagerduty.com/users/P553OPV" 40 | }, 41 | "trigger_summary_data":{ 42 | "subject":"CPU Load High on xdb_production_echo" 43 | }, 44 | "trigger_details_html_url":"https://webdemo.pagerduty.com/incidents/PRORDTY/log_entries/Q2AIXW2ZIMCI4P", 45 | "trigger_type":"web_trigger", 46 | "last_status_change_on":"2016-02-22T21:02:55Z", 47 | "last_status_change_by":null, 48 | "number_of_escalations":0, 49 | "assigned_to":[ 50 | { 51 | "at":"2016-02-22T21:02:55Z", 52 | "object":{ 53 | "id":"P553OPV", 54 | "name":"Laura Haley", 55 | "email":"laura.haley@example.com", 56 | "html_url":"https://webdemo.pagerduty.com/users/P553OPV", 57 | "type":"user" 58 | } 59 | } 60 | ], 61 | "urgency":"high" 62 | } 63 | }, 64 | "id":"a52d3f80-d9a7-11e5-8db3-22000ad5aec9", 65 | "created_on":"2016-02-22T21:02:55Z" 66 | } 67 | ] 68 | } -------------------------------------------------------------------------------- /docs/icons/icon_codeship.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/handlers/papertrail/event-example_notifications-array.json: -------------------------------------------------------------------------------- 1 | { 2 | "events":[ 3 | { 4 | "id":7711561783320576, 5 | "received_at":"2011-05-18T20:30:02-07:00", 6 | "display_received_at":"May 18 20:30:02", 7 | "source_ip":"208.75.57.121", 8 | "source_name":"abc", 9 | "source_id":2, 10 | "hostname":"abc", 11 | "program":"CROND", 12 | "severity":"Info", 13 | "facility":"Cron", 14 | "message":"message body" 15 | }, 16 | { 17 | "id":7711562567655424, 18 | "received_at":"2011-05-18T20:30:02-07:00", 19 | "display_received_at":"May 18 20:30:02", 20 | "source_ip":"208.75.57.120", 21 | "source_name":"server1", 22 | "source_id":19, 23 | "hostname":"def", 24 | "program":"CROND", 25 | "severity":"Info", 26 | "facility":"Cron", 27 | "message":"A short event" 28 | }, 29 | { 30 | "id":7711561783320576, 31 | "received_at":"2011-05-18T20:30:02-07:00", 32 | "display_received_at":"May 18 20:30:02", 33 | "source_ip":"208.75.57.121", 34 | "source_name":"abc", 35 | "source_id":2, 36 | "hostname":"abc", 37 | "program":"CROND", 38 | "severity":"Info", 39 | "facility":"Cron", 40 | "message":"message body" 41 | }, 42 | { 43 | "id":7711562567655424, 44 | "received_at":"2011-05-18T20:30:02-07:00", 45 | "display_received_at":"May 18 20:30:02", 46 | "source_ip":"208.75.57.120", 47 | "source_name":"server1", 48 | "source_id":19, 49 | "hostname":"def", 50 | "program":"CROND", 51 | "severity":"Info", 52 | "facility":"Cron", 53 | "message":"A short event" 54 | }, 55 | { 56 | "id":7711561783320576, 57 | "received_at":"2011-05-18T20:30:02-07:00", 58 | "display_received_at":"May 18 20:30:02", 59 | "source_ip":"208.75.57.121", 60 | "source_name":"abc", 61 | "source_id":2, 62 | "hostname":"abc", 63 | "program":"CROND", 64 | "severity":"Info", 65 | "facility":"Cron", 66 | "message":"message body" 67 | }, 68 | { 69 | "id":7711562567655424, 70 | "received_at":"2011-05-18T20:30:02-07:00", 71 | "display_received_at":"May 18 20:30:02", 72 | "source_ip":"208.75.57.120", 73 | "source_name":"server1", 74 | "source_id":19, 75 | "hostname":"def", 76 | "program":"CROND", 77 | "severity":"Info", 78 | "facility":"Cron", 79 | "message":"A short event" 80 | } 81 | ], 82 | "saved_search":{ 83 | "id":42, 84 | "name":"Important stuff", 85 | "query":"cron OR server1", 86 | "html_edit_url":"https://papertrailapp.com/searches/42/edit", 87 | "html_search_url":"https://papertrailapp.com/searches/42" 88 | }, 89 | "max_id":7711582041804800, 90 | "min_id":7711561783320576 91 | } -------------------------------------------------------------------------------- /docs/handlers/stripe/event-example_event.json: -------------------------------------------------------------------------------- 1 | { 2 | "id":"evt_1A1RbA2eZvKYlo2CScZ8ykYw", 3 | "object":"event", 4 | "api_version":"2017-02-14", 5 | "created":1490497160, 6 | "data":{ 7 | "object":{ 8 | "id":"in_1A1Qet2eZvKYlo2CAPY95Tpf", 9 | "object":"invoice", 10 | "amount_due":0, 11 | "application_fee":null, 12 | "attempt_count":0, 13 | "attempted":true, 14 | "charge":null, 15 | "closed":true, 16 | "currency":"usd", 17 | "customer":"cus_4I2DPXVGMnHeJD", 18 | "date":1490493547, 19 | "description":null, 20 | "discount":null, 21 | "ending_balance":0, 22 | "forgiven":false, 23 | "lines":{ 24 | "object":"list", 25 | "data":[ 26 | { 27 | "id":"sub_4I2DOLbYLeFwjZ", 28 | "object":"line_item", 29 | "amount":0, 30 | "currency":"usd", 31 | "description":null, 32 | "discountable":true, 33 | "livemode":false, 34 | "metadata":{ 35 | 36 | }, 37 | "period":{ 38 | "start":1490493480, 39 | "end":1493171880 40 | }, 41 | "plan":{ 42 | "id":"6milkg", 43 | "object":"plan", 44 | "amount":0, 45 | "created":1403747879, 46 | "currency":"usd", 47 | "interval":"month", 48 | "interval_count":1, 49 | "livemode":false, 50 | "metadata":{ 51 | 52 | }, 53 | "name":"Starter", 54 | "statement_descriptor":null, 55 | "trial_period_days":null 56 | }, 57 | "proration":false, 58 | "quantity":1, 59 | "subscription":null, 60 | "subscription_item":"si_18RaBe2eZvKYlo2ChGRGCYYW", 61 | "type":"subscription" 62 | } 63 | ], 64 | "has_more":false, 65 | "total_count":1, 66 | "url":"/v1/invoices/in_1A1Qet2eZvKYlo2CAPY95Tpf/lines" 67 | }, 68 | "livemode":false, 69 | "metadata":{ 70 | 71 | }, 72 | "next_payment_attempt":null, 73 | "paid":true, 74 | "period_end":1490493480, 75 | "period_start":1488074280, 76 | "receipt_number":null, 77 | "starting_balance":0, 78 | "statement_descriptor":null, 79 | "subscription":"sub_4I2DOLbYLeFwjZ", 80 | "subtotal":0, 81 | "tax":null, 82 | "tax_percent":null, 83 | "total":0, 84 | "webhooks_delivered_at":1490493558 85 | } 86 | }, 87 | "livemode":false, 88 | "pending_webhooks":0, 89 | "request":null, 90 | "type":"invoice.payment_succeeded" 91 | } -------------------------------------------------------------------------------- /pkg/handlers/datadog/handler_datadog_out.go: -------------------------------------------------------------------------------- 1 | package datadog 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | cc "github.com/grokify/commonchat" 7 | 8 | "github.com/grokify/chathooks/pkg/config" 9 | "github.com/grokify/chathooks/pkg/handlers" 10 | "github.com/grokify/chathooks/pkg/models" 11 | ) 12 | 13 | const ( 14 | DisplayName = "Datadog" 15 | HandlerKey = "datadog" 16 | MessageDirection = "out" 17 | DocumentationURL = "http://docs.datadoghq.com/integrations/webhooks/" 18 | MessageBodyType = models.JSON 19 | ) 20 | 21 | func NewHandler() handlers.Handler { 22 | return handlers.Handler{MessageBodyType: MessageBodyType, Normalize: Normalize} 23 | } 24 | 25 | func Normalize(cfg config.Configuration, hReq handlers.HandlerRequest) (cc.Message, error) { 26 | ccMsg, err := CcMessageFromBytes(hReq.Body) 27 | if err != nil { 28 | return ccMsg, err 29 | } 30 | iconURL, err := cfg.GetAppIconURL(HandlerKey) 31 | if err == nil { 32 | ccMsg.IconURL = iconURL.String() 33 | } 34 | return ccMsg, nil 35 | } 36 | 37 | /* 38 | 39 | $ID ID of the event (ex: 1234567) 40 | $EVENT_TITLE Title of the event (ex: [Triggered] [Memory Alert]) 41 | $EVENT_MSG Text of the event (ex: @webhook-url Sending to the webhook) 42 | $EVENT_TYPE Type of the event (values: metric_alert_monitor, event_alert, or service_check) 43 | $LAST_UPDATED Date when the event was last updated . 44 | $DATE Date (epoch) where the event happened (ex: 1406662672000) 45 | $AGGREG_KEY ID to aggregate events belonging together (ex: 9bd4ac313a4d1e8fae2482df7b77628) 46 | $ORG_ID ID of your organization (ex: 11023) 47 | $ORG_NAME Name of your organization (ex: Datadog) 48 | $USER User posting the event that triggered the webhook (ex: rudy) 49 | $SNAPSHOT Url of the image if the event contains a snapshot (ex: https://url.to.snpashot.com/) 50 | $LINK Url of the event (ex: https://app.datadoghq.com/event/jump_to?event_id=123456) 51 | $PRIORITY Priority of the event (values: normal or low) 52 | $TAGS Comma-separated list of the event tags (ex: monitor, name:myService, role:computing-node) 53 | $ALERT_ID ID of alert (ex: 1234) 54 | $ALERT_TITLE Title of the alert 55 | $ALERT_METRIC Name of the metric if it’s an alert (ex: system.load.1) 56 | $ALERT_SCOPE Comma-separated list of tags triggering the alert (ex: availability-zone:us-east-1a, role:computing-node) 57 | $ALERT_QUERY Query of the monitor that triggered the webhook 58 | $ALERT_STATUS Summary of the alert status (ex: system.load.1 over host:my-host was > 0 at least once during the last 1m) 59 | $ALERT_TRANSITION Type of alert notification (values: Triggered or Recovered) 60 | If you want to post your webhooks to a service requiring authentication, you can Basic HTTP authentication my modifing your URL from https://my.service.com to https://username:password@my.service.com. 61 | 62 | Example template: 63 | 64 | { 65 | "activity":"Event triggered", 66 | "body":"[Event $ID]($LINK): $EVENT_TITLE\n**Priority**\n$PRIORITY\n**Alert**\n$ALERT_STATUS" 67 | } 68 | 69 | { 70 | "activity":"Event triggered", 71 | "body":"[Event 1234567](https://app.datadoghq.com/event/jump_to?event_id=123456): [Triggered] [Memory Alert]\n**Priority**\n#PRIORITY\n**Alert**\nystem.load.1 over host:my-host was > 0 at least once during the last 1m" 72 | } 73 | 74 | */ 75 | 76 | func CcMessageFromBytes(bytes []byte) (cc.Message, error) { 77 | msg := cc.Message{} 78 | err := json.Unmarshal(bytes, &msg) 79 | return msg, err 80 | } 81 | -------------------------------------------------------------------------------- /docs/icons/icon_twitter_alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_chat-meta_forward.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"forward", 3 | "_type":"chat_meta", 4 | "browser_name":"Safari", 5 | "browser_os":"Mac OS X", 6 | "browser_version":"8", 7 | "chat_widget":{ 8 | "id":9, 9 | "name":"Testing David" 10 | }, 11 | "chat_widget_goal":{ 12 | "id":null, 13 | "name":null 14 | }, 15 | "client_additional01_name":null, 16 | "client_additional01_value":null, 17 | "client_additional02_name":null, 18 | "client_additional02_value":null, 19 | "client_additional03_name":null, 20 | "client_additional03_value":null, 21 | "client_email":"david@optixx.org", 22 | "client_name":"Jo", 23 | "client_uuid":"nEitxHDooFzsPhMoVn0QCw8E.L3mmogIcp+FGwXos5a4NUdZ9/uQbSCBx0wDIRVFWM+o", 24 | "created_at":"2014-12-29 11:26:24", 25 | "custom":{ 26 | "basket":{ 27 | "item01":{ 28 | "desc":"33X Optical Zoom Camcorder Mini DV", 29 | "id":"2acefe58-91e5-11e1-beba-000c2979313a", 30 | "price":139.99, 31 | "url":"http://application/en/electronics/34-camcorder.html" 32 | }, 33 | "item02":{ 34 | "desc":"Home Theater System", 35 | "id":"31aca2f2-91e5-11e1-beba-000c2979313a", 36 | "long":"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", 37 | "price":499.99, 38 | "url":"https://application/en/electronics/39-home-theater.html" 39 | } 40 | }, 41 | "id":"428614f0-91e5-11e1-beba-000c2979313a", 42 | "ref":"3efd5462e" 43 | }, 44 | "data_privacy":false, 45 | "duration":"00:00:13", 46 | "ended_at":null, 47 | "feedback_message":null, 48 | "id":71, 49 | "inital_url":"https://devel.userlike.local/en/", 50 | "loc_city":null, 51 | "loc_country":null, 52 | "loc_lat":null, 53 | "loc_lon":null, 54 | "marked_read":false, 55 | "messages":[ 56 | 57 | ], 58 | "notes":[ 59 | 60 | ], 61 | "operator_created":{ 62 | "email":"david@userlike.com", 63 | "first_name":"David", 64 | "id":5, 65 | "last_name":"Voswinkel", 66 | "name":"David Voswinkel", 67 | "operator_group":{ 68 | "id":14, 69 | "name":"Testing David" 70 | } 71 | }, 72 | "operator_created_id":5, 73 | "operator_current":{ 74 | "email":"beavis@userlike.com", 75 | "first_name":"Beavis", 76 | "id":13, 77 | "last_name":"", 78 | "name":"Beavis", 79 | "operator_group":{ 80 | "id":8, 81 | "name":"Testing" 82 | } 83 | }, 84 | "operator_current_id":13, 85 | "page_impressions":2, 86 | "post_survey_option":null, 87 | "rate":null, 88 | "referrer":null, 89 | "status":"new", 90 | "topic":null, 91 | "url":"https://devel.userlike.local/en/debug/9", 92 | "visits":10, 93 | "was_proactive":false 94 | } -------------------------------------------------------------------------------- /docs/handlers/userlike/event-example_chat-meta_start.json: -------------------------------------------------------------------------------- 1 | { 2 | "_event":"start", 3 | "_type":"chat_meta", 4 | "browser_name":"Safari", 5 | "browser_os":"Mac OS X", 6 | "browser_version":"8", 7 | "chat_widget":{ 8 | "id":9, 9 | "name":"Testing David" 10 | }, 11 | "chat_widget_goal":{ 12 | "id":null, 13 | "name":null 14 | }, 15 | "client_additional01_name":null, 16 | "client_additional01_value":null, 17 | "client_additional02_name":null, 18 | "client_additional02_value":null, 19 | "client_additional03_name":null, 20 | "client_additional03_value":null, 21 | "client_email":"david@optixx.org", 22 | "client_name":"Jo", 23 | "client_uuid":"nEitxHDooFzsPhMoVn0QCw8E.L3mmogIcp+FGwXos5a4NUdZ9/uQbSCBx0wDIRVFWM+o", 24 | "created_at":"2014-12-29 11:26:24", 25 | "custom":{ 26 | "basket":{ 27 | "item01":{ 28 | "desc":"33X Optical Zoom Camcorder Mini DV", 29 | "id":"2acefe58-91e5-11e1-beba-000c2979313a", 30 | "price":139.99, 31 | "url":"http://application/en/electronics/34-camcorder.html" 32 | }, 33 | "item02":{ 34 | "desc":"Home Theater System", 35 | "id":"31aca2f2-91e5-11e1-beba-000c2979313a", 36 | "long":"Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", 37 | "price":499.99, 38 | "url":"https://application/en/electronics/39-home-theater.html" 39 | } 40 | }, 41 | "id":"428614f0-91e5-11e1-beba-000c2979313a", 42 | "ref":"3efd5462e" 43 | }, 44 | "data_privacy":false, 45 | "duration":"00:00:13", 46 | "ended_at":null, 47 | "feedback_message":null, 48 | "id":71, 49 | "inital_url":"https://devel.userlike.local/en/", 50 | "loc_city":null, 51 | "loc_country":null, 52 | "loc_lat":null, 53 | "loc_lon":null, 54 | "marked_read":false, 55 | "messages":[ 56 | 57 | ], 58 | "notes":[ 59 | 60 | ], 61 | "operator_created":{ 62 | "email":"david@userlike.com", 63 | "first_name":"David", 64 | "id":5, 65 | "last_name":"Voswinkel", 66 | "name":"David Voswinkel", 67 | "operator_group":{ 68 | "id":14, 69 | "name":"Testing David" 70 | } 71 | }, 72 | "operator_created_id":5, 73 | "operator_current":{ 74 | "email":"david@userlike.com", 75 | "first_name":"David", 76 | "id":5, 77 | "last_name":"Voswinkel", 78 | "name":"David Voswinkel", 79 | "operator_group":{ 80 | "id":14, 81 | "name":"Testing David" 82 | } 83 | }, 84 | "operator_current_id":5, 85 | "page_impressions":2, 86 | "post_survey_option":null, 87 | "rate":null, 88 | "referrer":null, 89 | "status":"new", 90 | "topic":null, 91 | "url":"https://devel.userlike.local/en/debug/9", 92 | "visits":10, 93 | "was_proactive":false 94 | } --------------------------------------------------------------------------------