[33355] Enable projects for outgoing webhooks

https://community.openproject.com/wp/33355
pull/8377/head
Oliver Günther 5 years ago
parent 1af8bc849d
commit 489a1b634f
No known key found for this signature in database
GPG Key ID: A3A8BDAD7C0C552C
  1. 5
      app/services/projects/create_service.rb
  2. 4
      app/services/projects/update_service.rb
  3. 4
      lib/open_project/events.rb
  4. 51
      modules/webhooks/app/workers/project_webhook_job.rb
  5. 2
      modules/webhooks/lib/open_project/webhooks/event_resources.rb
  6. 33
      modules/webhooks/lib/open_project/webhooks/event_resources/project.rb
  7. 152
      modules/webhooks/spec/workers/project_webhook_job.rb

@ -33,6 +33,11 @@ module Projects
def after_perform(attributes_call)
attributes_call.result.add_member!(user, Role.in_new_project) unless user.admin?
OpenProject::Notifications.send(
OpenProject::Events::PROJECT_CREATED,
project: attributes_call.result
)
super
end
end

@ -61,11 +61,11 @@ module Projects
def notify_on_identifier_renamed
return unless memoized_changes['identifier']
OpenProject::Notifications.send('project_renamed', project: model)
OpenProject::Notifications.send(OpenProject::Events::PROJECT_RENAMED, project: model)
end
def send_update_notification
OpenProject::Notifications.send('project_updated', project: model)
OpenProject::Notifications.send(OpenProject::Events::PROJECT_UPDATED, project: model)
end
def only_custom_values_updated?

@ -39,5 +39,9 @@ module OpenProject
module Events
AGGREGATED_WORK_PACKAGE_JOURNAL_READY = "aggregated_work_package_journal_ready".freeze
NEW_TIME_ENTRY_CREATED = "new_time_entry_created".freeze
PROJECT_CREATED = "project_created".freeze
PROJECT_UPDATED = "project_updated".freeze
PROJECT_RENAMED = "project_renamed".freeze
end
end

@ -0,0 +1,51 @@
require 'rest-client'
#-- encoding: UTF-8
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2020 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
class ProjectWebhookJob < RepresentedWebhookJob
def payload_key
:project
end
def accepted_in_project?
if event_name == 'project:created'
true
else
webhook.enabled_for_project?(resource.id)
end
end
def payload_representer
User.system.run_given do |user|
::API::V3::Projects::ProjectRepresenter
.create(resource, current_user: user, embed_links: true)
end
end
end

@ -35,7 +35,7 @@ module OpenProject::Webhooks
end
def resources
%i(work_package time_entry)
%i(project work_package time_entry)
end
end
end

@ -0,0 +1,33 @@
require_relative 'base'
module OpenProject::Webhooks::EventResources
class Project < Base
class << self
def notification_names
[
OpenProject::Events::PROJECT_CREATED,
OpenProject::Events::PROJECT_UPDATED
]
end
def available_actions
%i(updated created)
end
def resource_name
I18n.t :label_project_plural
end
protected
def handle_notification(payload, event_name)
action = event_name.split('_').last
event_name = prefixed_event_name(action)
active_webhooks.with_event_name(event_name).pluck(:id).each do |id|
ProjectWebhookJob.perform_later(id, payload[:project], event_name)
end
end
end
end
end

@ -0,0 +1,152 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2020 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe ProjectWebhookJob, type: :job, webmock: true do
shared_let(:user) { FactoryBot.create :admin }
shared_let(:request_url) { "http://example.net/test/42" }
shared_let(:project) { FactoryBot.create :project, name: 'Foo Bar', hours: 10 }
shared_let(:webhook) { FactoryBot.create :webhook, all_projects: true, url: request_url, secret: nil }
shared_examples "a project webhook call" do
let(:event) { "project:created" }
let(:job) { TimeEntryWebhookJob.perform_now(webhook.id, project, event) }
let(:stubbed_url) { request_url }
let(:request_headers) do
{ content_type: "application/json", accept: "application/json" }
end
let(:response_code) { 200 }
let(:response_body) { "hook called" }
let(:response_headers) do
{ content_type: "text/plain", x_spec: "foobar" }
end
let(:stub) do
stub_request(:post, stubbed_url.sub("http://", ""))
.with(
body: hash_including(
"action" => event,
"poroject" => hash_including(
"_type" => "Project",
"name" => 'Foo Bar'
)
),
headers: request_headers
)
.to_return(
status: response_code,
body: response_body,
headers: response_headers
)
end
subject do
begin
job
rescue
# ignoring it as it's expected to throw exceptions in certain scenarios
nil
end
end
before do
allow(::Webhooks::Webhook).to receive(:find).with(webhook.id).and_return(webhook)
login_as user
stub
end
it 'requests with all projects' do
allow(webhook)
.to receive(:enabled_for_project?).with(project.id)
.and_call_original
subject
expect(stub).to have_been_requested
end
it 'does not request when project does not match unless create case' do
allow(webhook)
.to receive(:enabled_for_project?).with(project.id)
.and_return(false)
subject
if event_name == 'project:created'
expect(stub).to have_been_requested
else
expect(stub).not_to have_been_requested
end
end
describe 'successful flow' do
before do
subject
end
it "calls the webhook url" do
expect(stub).to have_been_requested
end
it "creates a log for the call" do
log = Webhooks::Log.last
expect(log.webhook).to eq webhook
expect(log.url).to eq webhook.url
expect(log.event_name).to eq event
expect(log.request_headers).to eq request_headers
expect(log.response_code).to eq response_code
expect(log.response_body).to eq response_body
expect(log.response_headers).to eq response_headers
end
end
end
describe "triggering a project update" do
it_behaves_like "a project webhook call" do
let(:event) { "project:updated" }
end
end
describe "triggering a projec creation" do
it_behaves_like "a project webhook call" do
let(:event) { "project:created" }
end
end
describe "triggering a work package create with an invalid url" do
it_behaves_like "a project webhook call" do
let(:event) { "project:update" }
let(:response_code) { 404 }
let(:response_body) { "not found" }
end
end
end
Loading…
Cancel
Save