diff --git a/README.md b/README.md index e3497490..8f59cfed 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Klaxon is a free, quick to set up and easy to use *robot* that checks websites r You list websites you want monitored and Klaxon will visit them and, if they change, email you what's different. It saves you having to reload dozens of links yourself every day. -It's perfect for monitoring website changes you might miss, like freedom of information disclosure logs, court records, and anything related to Donald Trump. And it can even send notifications to your Slack and Discord channels. +It's perfect for monitoring website changes you might miss, like freedom of information disclosure logs, court records, and anything related to Donald Trump. And it can even send notifications to Slack, Discord, Microsoft Teams, and Amazon SQS. Read more below, or say hello to the humans behind the project at the [Google Group email list](https://groups.google.com/forum/#!forum/news-klaxon-users). @@ -18,7 +18,7 @@ The public release of this free and open source software was supported by Knight ## How Does Klaxon Work? -Klaxon enables users to "bookmark" portions of a webpage and be notified (via email, [Slack, or Discord](#notify-a-slack-or-discord-channel)) of any changes that may occur to those sections. [Learn more about bookmarklets on the help.md page](data/help.md). +Klaxon enables users to "bookmark" portions of a webpage and be notified (via email, [Slack, Discord](#notify-a-slack-or-discord-channel), Microsoft Teams, or Amazon SQS) of any changes that may occur to those sections. [Learn more about bookmarklets on the help.md page](data/help.md). [![Circle CI](https://circleci.com/gh/themarshallproject/klaxon.svg?style=svg)](https://circleci.com/gh/themarshallproject/klaxon) @@ -54,7 +54,7 @@ If you have a Heroku account and you’re ready to go, it’s time to click on t You must be logged into your Heroku account, and it will take you to a page to configure your new app in Heroku’s dashboard. First, give your app a name in the first box. While this is technically optional, this will also double as the URL for your Klaxon instance, so think carefully about it for a moment. Try maybe an abbreviation for your newsroom with a hyphen and the word klaxon, like “wp-klaxon” or “sl-klaxon”. This will become a URL as https://sl-klaxon.herokuapp.com/ -Scroll down to the “* Admin_emails” field, add a comma-separated list of email addresses for your newsroom’s Klaxon administrators. These administrators will be able to create accounts for any user in your organization, as well as configure various Klaxons and integrations with services like Slack and Discord. +Scroll down to the “* Admin_emails” field, add a comma-separated list of email addresses for your newsroom’s Klaxon administrators. These administrators will be able to create accounts for any user in your organization, as well as configure various Klaxons and integrations with services like Slack and Microsoft Teams. Click the big purple “Deploy for Free” button. If you haven’t given Heroku your credit card yet, it will ask you for your information now. As long as you’re on the free settings, it won’t charge you, but Heroku wants to be prepared in case you change tiers. After that, give Heroku a few minutes for the app to build. diff --git a/app/assets/javascripts/teams_integrations.js b/app/assets/javascripts/teams_integrations.js new file mode 100644 index 00000000..dee720fa --- /dev/null +++ b/app/assets/javascripts/teams_integrations.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/teams_integrations.scss b/app/assets/stylesheets/teams_integrations.scss new file mode 100644 index 00000000..4c6a27c5 --- /dev/null +++ b/app/assets/stylesheets/teams_integrations.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the teams_integrations controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/integrations_controller.rb b/app/controllers/integrations_controller.rb index 204a6d7f..1c2e8e3c 100644 --- a/app/controllers/integrations_controller.rb +++ b/app/controllers/integrations_controller.rb @@ -4,5 +4,6 @@ class IntegrationsController < ApplicationController def index @slack_integrations = SlackIntegration.all @sqs_integrations = SqsIntegration.all + @teams_integrations = TeamsIntegration.all end end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index a63955a2..131d7e04 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -36,12 +36,14 @@ def new @page = Page.new @users = User.all @slack_integrations = SlackIntegration.all + @teams_integrations = TeamsIntegration.all end # GET /pages/1/edit def edit @users = User.all @slack_integrations = SlackIntegration.all + @teams_integrations = TeamsIntegration.all end # POST /pages diff --git a/app/controllers/teams_integrations_controller.rb b/app/controllers/teams_integrations_controller.rb new file mode 100644 index 00000000..ed2ca763 --- /dev/null +++ b/app/controllers/teams_integrations_controller.rb @@ -0,0 +1,59 @@ +class TeamsIntegrationsController < ApplicationController + before_action :set_teams_integration, only: [:show, :edit, :update, :destroy] + before_action :authorize + + # GET /teams_integrations + def index + @teams_integrations = TeamsIntegration.all + end + + # GET /teams_integrations/1 + def show + end + + # GET /teams_integrations/new + def new + @teams_integration = TeamsIntegration.new + end + + # GET /teams_integrations/1/edit + def edit + end + + # POST /teams_integrations + def create + @teams_integration = TeamsIntegration.new(teams_integration_params) + + if @teams_integration.save + redirect_to integrations_path, notice: 'Teams integration was successfully created.' + else + render :new + end + end + + # PATCH/PUT /teams_integrations/1 + def update + if @teams_integration.update(teams_integration_params) + redirect_to integrations_path, notice: 'Teams integration was successfully updated.' + else + render :edit + end + end + + # DELETE /teams_integrations/1 + def destroy + @teams_integration.destroy + redirect_to integrations_path, notice: 'Teams integration was successfully destroyed.' + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_teams_integration + @teams_integration = TeamsIntegration.find(params[:id]) + end + + # Only allow a trusted parameter "white list" through. + def teams_integration_params + params.require(:teams_integration).permit(:channel, :webhook_url) + end +end diff --git a/app/helpers/teams_integrations_helper.rb b/app/helpers/teams_integrations_helper.rb new file mode 100644 index 00000000..7285cbf7 --- /dev/null +++ b/app/helpers/teams_integrations_helper.rb @@ -0,0 +1,2 @@ +module TeamsIntegrationsHelper +end diff --git a/app/lib/teams_notification.rb b/app/lib/teams_notification.rb new file mode 100644 index 00000000..89edd5e0 --- /dev/null +++ b/app/lib/teams_notification.rb @@ -0,0 +1,12 @@ +class TeamsNotification + def self.perform(url, payload) + json = payload.to_json + request = HTTParty.post(url, body: json, headers: {'Content-Type' => 'application/json'}) + if request.code == 200 + request.body + else + puts "Error sending webhook to url=#{url} for payload=#{payload.to_json}" + return false + end + end +end diff --git a/app/models/page.rb b/app/models/page.rb index e2ba5081..365fbbbe 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -74,6 +74,8 @@ def update_subscriptions User.find(id).subscribe(self) elsif model == 'slack' SlackIntegration.find(id).subscribe(self) + elsif model == 'teams' + TeamsIntegration.find(id).subscribe(self) else raise "unknown subscription type" end diff --git a/app/models/teams_integration.rb b/app/models/teams_integration.rb new file mode 100644 index 00000000..18654460 --- /dev/null +++ b/app/models/teams_integration.rb @@ -0,0 +1,95 @@ +class TeamsIntegration < ApplicationRecord + + validates :channel, length: { minimum: 2 } + validates :webhook_url, length: { minimum: 10 } + after_destroy :remove_subscriptions + + include Rails.application.routes.url_helpers + + def subscriptions + Subscription.where(watcher: self) + end + + def watching + subscriptions.map(&:watching) + end + + def subscribe(watchable) + # TODO: extract this. also in User + Subscription.where(watcher: self, watching: watchable).first_or_create do |subscription| + puts "#{self} subscribed to #{watchable}" + end + end + + def is_subscribed_to?(watchable) + Subscription.where(watcher: self, watching: watchable).exists? + end + + def send_notification(change) + puts "teams_integration#send_notification #{self.channel}" + + change_date = change&.created_at&.strftime("%A, %B %d, %Y at %H:%M") + page_name = change&.after&.page&.name + source_url = change&.after&.page&.url + summary = "#{page_name} changed" + text = "#{page_name} changed #{page_change_url(change)}" + + icon_url = URI.join(root_url, '/images/klaxon-logo-100px.png').to_s + + payload = { + "@type": "MessageCard", + "@context": "https://schema.org/extensions", + "themeColor": "FF0B3A", + "summary": summary, + "sections": [ + { + "activityTitle": "Klaxon", + "activitySubtitle": change_date, + "activityImage": icon_url, + "text": text + } + ], + "potentialAction": [ + { + "@type": "OpenUri", + "name": "Go to Source", + "targets": [ + { + "os": "default", + "uri": source_url + } + ] + }, + { + "@type": "OpenUri", + "name": "Compare Snapshots", + "targets": [ + { + "os": "default", + "uri": "#{page_change_url(change)}" + } + ] + }, + { + "@type": "OpenUri", + "name": "Snapshot HTML", + "targets": [ + { + "os": "default", + "uri": "#{show_page_snapshot_html_url(change)}" + } + ] + } + ] + } + + TeamsNotification.perform(self.webhook_url, payload) + return payload + end + + def remove_subscriptions + subscriptions.each do |s| + s.destroy + end + end +end diff --git a/app/views/integrations/index.html.erb b/app/views/integrations/index.html.erb index 2a089018..04ffcab2 100644 --- a/app/views/integrations/index.html.erb +++ b/app/views/integrations/index.html.erb @@ -8,7 +8,7 @@
-

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack. We hope to add more in the future. If you’re interested in helping, visit our repo.

+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack, Microsoft Teams, and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

@@ -75,6 +75,33 @@ <% end %> +
+
+

Teams

+
+
+ <%= link_to "Create Teams Integration", new_teams_integration_path, class: 'btn btn-default btn-lg btn-block' %> +
+
+ <% if @teams_integrations.present? %> + + + + + + + + + <% @teams_integrations.each do |integration| %> + + + + + <% end %> + +
Channel
<%= integration.channel %><%= link_to "Edit", edit_teams_integration_path(integration), class: 'btn btn-default btn-block pull-right', style: "max-width: 136px !important;" %> +
+ <% end %>
diff --git a/app/views/pages/_form.html.erb b/app/views/pages/_form.html.erb index 02afd462..0ac421e5 100644 --- a/app/views/pages/_form.html.erb +++ b/app/views/pages/_form.html.erb @@ -65,6 +65,7 @@
Slack

It looks like you haven't configured any Slack notifications yet, would you like to? <%= link_to "Go to settings.", integrations_path %> +

<% else %>
Slack
@@ -80,6 +81,29 @@ <% end %>
<% end %> + + <% if @teams_integrations.empty? %> + +
+
Teams
+

It looks like you haven't configured any Teams notifications yet, would you like to? <%= link_to "Go to settings.", integrations_path %> +

+ <% else %> +
+
Teams
+

Which of the Teams channels that you’ve added should get notification when this item changes?

+ + <% @teams_integrations.each do |teams| %> +
+ +
+ <% end %> +
+ <% end %> +
diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 29f69d9d..95a5d85f 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -12,7 +12,7 @@
-

Klaxon enables reporters and editors to monitor scores of sites and files on the web for newsworthy changes. Get email and Slack notifications when something changes.

+

Klaxon enables reporters and editors to monitor scores of sites and files on the web for newsworthy changes. Get email, Slack, Microsoft Teams, and/or Amazon SQS notifications when something changes.

diff --git a/app/views/slack_integrations/edit.html.erb b/app/views/slack_integrations/edit.html.erb index 990fdd07..607c615e 100644 --- a/app/views/slack_integrations/edit.html.erb +++ b/app/views/slack_integrations/edit.html.erb @@ -7,7 +7,7 @@
-

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack. We hope to add more in the future. If you’re interested in helping, visit our repo.

+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack, Microsoft Teams, and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

@@ -19,4 +19,4 @@
-<%= render 'form' %> \ No newline at end of file +<%= render 'form' %> diff --git a/app/views/slack_integrations/new.html.erb b/app/views/slack_integrations/new.html.erb index c1065814..d16fb4cd 100644 --- a/app/views/slack_integrations/new.html.erb +++ b/app/views/slack_integrations/new.html.erb @@ -7,7 +7,7 @@
-

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack. We hope to add more in the future. If you’re interested in helping, visit our repo.

+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack, Microsoft Teams, and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

@@ -15,4 +15,4 @@
-<%= render 'form' %> \ No newline at end of file +<%= render 'form' %> diff --git a/app/views/sqs_integrations/edit.html.erb b/app/views/sqs_integrations/edit.html.erb index f0a0125e..29b93afd 100644 --- a/app/views/sqs_integrations/edit.html.erb +++ b/app/views/sqs_integrations/edit.html.erb @@ -7,7 +7,7 @@
-

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack, Microsoft Teams, and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

diff --git a/app/views/sqs_integrations/new.html.erb b/app/views/sqs_integrations/new.html.erb index 65fd5c4e..97de8cba 100644 --- a/app/views/sqs_integrations/new.html.erb +++ b/app/views/sqs_integrations/new.html.erb @@ -7,7 +7,7 @@
-

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Slack, Microsoft Teams, and Amazon SQS. We hope to add more in the future. If you’re interested in helping, visit our repo.

diff --git a/app/views/static/help.html.erb b/app/views/static/help.html.erb index 917ca7c9..ed5768b8 100644 --- a/app/views/static/help.html.erb +++ b/app/views/static/help.html.erb @@ -37,7 +37,7 @@ img {
-

Klaxon enables reporters and editors to monitor scores of sites and files on the web for newsworthy changes. Get email and Slack notifications when something changes. It’s an open source project being built by The Marshall Project.

+

Klaxon enables reporters and editors to monitor scores of sites and files on the web for newsworthy changes. Get email, Slack, Microsoft Teams, and/or Amazon SQS notifications when something changes. It’s an open source project being built by The Marshall Project.

diff --git a/app/views/teams_integrations/_form.html.erb b/app/views/teams_integrations/_form.html.erb new file mode 100644 index 00000000..8bc463c9 --- /dev/null +++ b/app/views/teams_integrations/_form.html.erb @@ -0,0 +1,39 @@ +<%= simple_form_for(@teams_integration) do |f| %> + <%= f.error_notification %> + +
+
+
+
+

Details

+
+
+
+
+
+ +
+ <%= f.input :channel, label: false, class: 'form-control' %> +
+
+
+ +
+ <%= f.input :webhook_url, label: false, class: 'form-control' %> +
+
+ +
+
+ +
+
+ <%= f.button :submit, class: "btn btn-default btn-lg btn-block" %> +
+
+
+
+
+
+ +<% end %> diff --git a/app/views/teams_integrations/edit.html.erb b/app/views/teams_integrations/edit.html.erb new file mode 100644 index 00000000..7df8359b --- /dev/null +++ b/app/views/teams_integrations/edit.html.erb @@ -0,0 +1,22 @@ +
+
+
+
+

Editing Teams Integration

+
+
+
+
+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Teams. We hope to add more in the future. If you’re interested in helping, visit our repo.

+
+
+ +
+
+ <%= link_to 'Delete? It’s Permanent.', @teams_integration, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-default btn-lg btn-block" %> +
+
+
+
+ +<%= render 'form' %> diff --git a/app/views/teams_integrations/index.html.erb b/app/views/teams_integrations/index.html.erb new file mode 100644 index 00000000..f382de3e --- /dev/null +++ b/app/views/teams_integrations/index.html.erb @@ -0,0 +1,29 @@ +

<%= notice %>

+ +

Listing Teams Integrations

+ + + + + + + + + + + + <% @teams_integrations.each do |teams_integration| %> + + + + + + + + <% end %> + +
ChannelWebhook url
<%= teams_integration.channel %><%= teams_integration.webhook_url %><%= link_to 'Show', teams_integration %><%= link_to 'Edit', edit_teams_integration_path(teams_integration) %><%= link_to 'Destroy', teams_integration, method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Teams integration', new_teams_integration_path %> diff --git a/app/views/teams_integrations/new.html.erb b/app/views/teams_integrations/new.html.erb new file mode 100644 index 00000000..dd865696 --- /dev/null +++ b/app/views/teams_integrations/new.html.erb @@ -0,0 +1,18 @@ +
+
+
+
+

New Teams Integration

+
+
+
+
+

Integrations allow you to push alerts to various platforms. For now, Klaxon supports Teams. We hope to add more in the future. If you’re interested in helping, visit our repo.

+
+
+ +
+
+
+
+<%= render 'form' %> diff --git a/app/views/teams_integrations/show.html.erb b/app/views/teams_integrations/show.html.erb new file mode 100644 index 00000000..5b07939b --- /dev/null +++ b/app/views/teams_integrations/show.html.erb @@ -0,0 +1,14 @@ +

<%= notice %>

+ +

+ Channel: + <%= @teams_integration.channel %> +

+ +

+ Webhook url: + <%= @teams_integration.webhook_url %> +

+ +<%= link_to 'Edit', edit_teams_integration_path(@teams_integration) %> | +<%= link_to 'Back', teams_integrations_path %> diff --git a/config/routes.rb b/config/routes.rb index 78fe2cba..d13c8a93 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -44,6 +44,7 @@ get '/' => 'integrations#index', as: :integrations resources :slack, as: 'slack_integrations', controller: 'slack_integrations' resources :sqs, as: 'sqs_integrations', controller: 'sqs_integrations' + resources :teams, as: 'teams_integrations', controller: 'teams_integrations' end get '/help' => 'static#help', as: :help diff --git a/data/help.md b/data/help.md index 0a59f3b9..e6b05ad8 100644 --- a/data/help.md +++ b/data/help.md @@ -1,6 +1,6 @@ ## How Klaxon works -Klaxon is a tool that enables journalists and researchers to monitor scores of websites for noteworthy changes. When it finds something new on one of the pages it's watching, it saves a version of it, or a "snapshot,” and emails an alert and pings a Slack channel. +Klaxon is a tool that enables journalists and researchers to monitor scores of websites for noteworthy changes. When it finds something new on one of the pages it's watching, it saves a version of it, or a "snapshot,” and alerts via email, Slack, Microsoft Teams, and/or Amazon SQS. #Bookmark Set-Up diff --git a/db/migrate/20211230105330_create_teams_integrations.rb b/db/migrate/20211230105330_create_teams_integrations.rb new file mode 100644 index 00000000..38439cb6 --- /dev/null +++ b/db/migrate/20211230105330_create_teams_integrations.rb @@ -0,0 +1,10 @@ +class CreateTeamsIntegrations < ActiveRecord::Migration[4.2] + def change + create_table :teams_integrations do |t| + t.string :channel + t.text :webhook_url + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c8b20819..e3bf505f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_02_23_221320) do +ActiveRecord::Schema.define(version: 2021_12_30_105330) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -72,6 +72,13 @@ t.datetime "updated_at", null: false end + create_table "teams_integrations", id: :serial, force: :cascade do |t| + t.string "channel" + t.text "webhook_url" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "subscriptions", id: :serial, force: :cascade do |t| t.integer "watcher_id" t.string "watcher_type" diff --git a/spec/controllers/teams_integrations_controller_spec.rb b/spec/controllers/teams_integrations_controller_spec.rb new file mode 100644 index 00000000..c4ecb8ab --- /dev/null +++ b/spec/controllers/teams_integrations_controller_spec.rb @@ -0,0 +1,156 @@ +require 'rails_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to specify the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. +# +# Compared to earlier versions of this generator, there is very limited use of +# stubs and message expectations in this spec. Stubs are only used when there +# is no simpler way to get a handle on the object needed for the example. +# Message expectations are only used when there is no simpler way to specify +# that an instance is receiving a specific message. + +RSpec.describe TeamsIntegrationsController, type: :controller do + + # This should return the minimal set of attributes required to create a valid + # TeamsIntegration. As you add validations to TeamsIntegration, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + before(:each) { login } + + describe "GET #index" do + it "assigns all teams_integrations as @teams_integrations" do + teams_integration = TeamsIntegration.create! valid_attributes + get :index, params: {} + expect(assigns(:teams_integrations)).to eq([teams_integration]) + end + end + + describe "GET #show" do + it "assigns the requested teams_integration as @teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + get :show, params: {:id => teams_integration.to_param} + expect(assigns(:teams_integration)).to eq(teams_integration) + end + end + + describe "GET #new" do + it "assigns a new teams_integration as @teams_integration" do + get :new, params: {} + expect(assigns(:teams_integration)).to be_a_new(TeamsIntegration) + end + end + + describe "GET #edit" do + it "assigns the requested teams_integration as @teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + get :edit, params: {:id => teams_integration.to_param} + expect(assigns(:teams_integration)).to eq(teams_integration) + end + end + + describe "POST #create" do + context "with valid params" do + it "creates a new TeamsIntegration" do + expect { + post :create, params: {:teams_integration => valid_attributes} + }.to change(TeamsIntegration, :count).by(1) + end + + it "assigns a newly created teams_integration as @teams_integration" do + post :create, params: {:teams_integration => valid_attributes} + expect(assigns(:teams_integration)).to be_a(TeamsIntegration) + expect(assigns(:teams_integration)).to be_persisted + end + + it "redirects to the created teams_integration" do + post :create, params: {:teams_integration => valid_attributes} + expect(response).to redirect_to(TeamsIntegration.last) + end + end + + context "with invalid params" do + it "assigns a newly created but unsaved teams_integration as @teams_integration" do + post :create, params: {:teams_integration => invalid_attributes} + expect(assigns(:teams_integration)).to be_a_new(TeamsIntegration) + end + + it "re-renders the 'new' template" do + post :create, params: {:teams_integration => invalid_attributes} + expect(response).to render_template("new") + end + end + end + + describe "PUT #update" do + context "with valid params" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + put :update, params: {:id => teams_integration.to_param, :teams_integration => new_attributes} + teams_integration.reload + skip("Add assertions for updated state") + end + + it "assigns the requested teams_integration as @teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + put :update, params: {:id => teams_integration.to_param, :teams_integration => valid_attributes} + expect(assigns(:teams_integration)).to eq(teams_integration) + end + + it "redirects to the teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + put :update, params: {:id => teams_integration.to_param, :teams_integration => valid_attributes} + expect(response).to redirect_to(teams_integration) + end + end + + context "with invalid params" do + it "assigns the teams_integration as @teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + put :update, params: {:id => teams_integration.to_param, :teams_integration => invalid_attributes} + expect(assigns(:teams_integration)).to eq(teams_integration) + end + + it "re-renders the 'edit' template" do + teams_integration = TeamsIntegration.create! valid_attributes + put :update, params: {:id => teams_integration.to_param, :teams_integration => invalid_attributes} + expect(response).to render_template("edit") + end + end + end + + describe "DELETE #destroy" do + it "destroys the requested teams_integration" do + teams_integration = TeamsIntegration.create! valid_attributes + expect { + delete :destroy, params: {:id => teams_integration.to_param} + }.to change(TeamsIntegration, :count).by(-1) + end + + it "redirects to the teams_integrations list" do + teams_integration = TeamsIntegration.create! valid_attributes + delete :destroy, params: {:id => teams_integration.to_param} + expect(response).to redirect_to(teams_integrations_url) + end + end + +end diff --git a/spec/factories.rb b/spec/factories.rb index dcaf2115..f027d4d4 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -17,6 +17,11 @@ queue_url { "https://sqs.us-east-1.amazonaws.com/1234567890/klaxon-sqs-q-test" } end + factory :teams_integration do + channel { "Klaxon" } + webhook_url { "https://test.webhook.office.com/webhookb2/wxyz-789@1234-abc/IncomingWebhook/abcdefg/abc-def-g1234" } + end + factory :change do end diff --git a/spec/helpers/teams_integrations_helper.rb b/spec/helpers/teams_integrations_helper.rb new file mode 100644 index 00000000..6a7ab013 --- /dev/null +++ b/spec/helpers/teams_integrations_helper.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the TeamsIntegrationsHelper. For example: +# +# describe TeamsIntegrationsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe TeamsIntegrationsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb index 4e2200f1..4d3e5a32 100644 --- a/spec/models/subscription_spec.rb +++ b/spec/models/subscription_spec.rb @@ -27,4 +27,13 @@ expect(slack_integration.watching).to include(page) end + + it "allows a teams channel to subscribe to a page" do + teams_integration = create(:teams_integration) + page = create(:page) + + teams_integration.subscribe(page) + + expect(teams_integration.watching).to include(page) + end end diff --git a/spec/models/teams_integrations_spec.rb b/spec/models/teams_integrations_spec.rb new file mode 100644 index 00000000..a74f75da --- /dev/null +++ b/spec/models/teams_integrations_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +RSpec.describe TeamsIntegration, type: :model do + it "generates the correct payload" do + stub_request(:post, /test-webhook.com/) + + page = create(:page, :with_snapshots, snapshot_count: 2) + teams = create(:teams_integration) + + teams.subscribe(page) + + change = page.latest_change + expect(change.after.page).to eq page + + payload = teams.send_notification(change) + end +end diff --git a/spec/requests/teams_integrations_spec.rb b/spec/requests/teams_integrations_spec.rb new file mode 100644 index 00000000..4b69e48d --- /dev/null +++ b/spec/requests/teams_integrations_spec.rb @@ -0,0 +1,6 @@ +require 'rails_helper' + +RSpec.describe "TeamsIntegrations", type: :request do + describe "GET /teams_integrations" do + end +end diff --git a/spec/routing/teams_integrations_routing_spec.rb b/spec/routing/teams_integrations_routing_spec.rb new file mode 100644 index 00000000..956fe80d --- /dev/null +++ b/spec/routing/teams_integrations_routing_spec.rb @@ -0,0 +1,39 @@ +require "rails_helper" + +RSpec.describe TeamsIntegrationsController, type: :routing do + describe "routing" do + + # it "routes to #index" do + # expect(:get => "/teams_integrations").to route_to("teams_integrations#index") + # end + + # it "routes to #new" do + # expect(:get => "/teams_integrations/new").to route_to("teams_integrations#new") + # end + + # it "routes to #show" do + # expect(:get => "/teams_integrations/1").to route_to("teams_integrations#show", :id => "1") + # end + + # it "routes to #edit" do + # expect(:get => "/teams_integrations/1/edit").to route_to("teams_integrations#edit", :id => "1") + # end + + # it "routes to #create" do + # expect(:post => "/teams_integrations").to route_to("teams_integrations#create") + # end + + # it "routes to #update via PUT" do + # expect(:put => "/teams_integrations/1").to route_to("teams_integrations#update", :id => "1") + # end + + # it "routes to #update via PATCH" do + # expect(:patch => "/teams_integrations/1").to route_to("teams_integrations#update", :id => "1") + # end + + # it "routes to #destroy" do + # expect(:delete => "/teams_integrations/1").to route_to("teams_integrations#destroy", :id => "1") + # end + + end +end diff --git a/spec/views/teams_integrations/edit.html.erb_spec.rb b/spec/views/teams_integrations/edit.html.erb_spec.rb new file mode 100644 index 00000000..4bb7cc4d --- /dev/null +++ b/spec/views/teams_integrations/edit.html.erb_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe "teams_integrations/edit", type: :view do + # before(:each) do + # @teams_integration = assign(:teams_integration, TeamsIntegration.create!( + # :channel => "MyString", + # :webhook_url => "MyText" + # )) + # end + + # it "renders the edit teams_integration form" do + # render + + # assert_select "form[action=?][method=?]", teams_integration_path(@teams_integration), "post" do + + # assert_select "input#teams_integration_channel[name=?]", "teams_integration[channel]" + + # assert_select "textarea#teams_integration_webhook_url[name=?]", "teams_integration[webhook_url]" + # end + # end +end diff --git a/spec/views/teams_integrations/index.html.erb_spec.rb b/spec/views/teams_integrations/index.html.erb_spec.rb new file mode 100644 index 00000000..edf8f5b7 --- /dev/null +++ b/spec/views/teams_integrations/index.html.erb_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe "teams_integrations/index", type: :view do + # before(:each) do + # assign(:teams_integrations, [ + # TeamsIntegration.create!( + # :channel => "Channel", + # :webhook_url => "MyText" + # ), + # TeamsIntegration.create!( + # :channel => "Channel", + # :webhook_url => "MyText" + # ) + # ]) + # end + + # it "renders a list of teams_integrations" do + # render + # assert_select "tr>td", :text => "Channel".to_s, :count => 2 + # assert_select "tr>td", :text => "MyText".to_s, :count => 2 + # end +end diff --git a/spec/views/teams_integrations/new.html.erb_spec.rb b/spec/views/teams_integrations/new.html.erb_spec.rb new file mode 100644 index 00000000..0fb44f69 --- /dev/null +++ b/spec/views/teams_integrations/new.html.erb_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe "teams_integrations/new", type: :view do + # before(:each) do + # assign(:teams_integration, TeamsIntegration.new( + # :channel => "MyString", + # :webhook_url => "MyText" + # )) + # end + + # it "renders new teams_integration form" do + # render + + # assert_select "form[action=?][method=?]", teams_integrations_path, "post" do + + # assert_select "input#teams_integration_channel[name=?]", "teams_integration[channel]" + + # assert_select "textarea#teams_integration_webhook_url[name=?]", "teams_integration[webhook_url]" + # end + # end +end diff --git a/spec/views/teams_integrations/show.html.erb_spec.rb b/spec/views/teams_integrations/show.html.erb_spec.rb new file mode 100644 index 00000000..85714611 --- /dev/null +++ b/spec/views/teams_integrations/show.html.erb_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +RSpec.describe "teams_integrations/show", type: :view do + # before(:each) do + # @teams_integration = assign(:teams_integration, TeamsIntegration.create!( + # :channel => "Channel", + # :webhook_url => "MyText" + # )) + # end + + # it "renders attributes in

" do + # render + # expect(rendered).to match(/Channel/) + # expect(rendered).to match(/MyText/) + # end +end