Feature #29664 » 0001-wip.patch
| app/models/issue.rb | ||
|---|---|---|
| 59 | 59 |
:author_key => :author_id |
| 60 | 60 | |
| 61 | 61 |
acts_as_mentionable :attributes => ['description'] |
| 62 |
acts_as_webhookable |
|
| 62 | 63 | |
| 63 | 64 |
DONE_RATIO_OPTIONS = %w(issue_field issue_status) |
| 64 | 65 | |
| ... | ... | |
| 130 | 131 |
after_create_commit :add_auto_watcher |
| 131 | 132 |
after_commit :create_parent_issue_journal |
| 132 | 133 | |
| 133 |
after_create_commit ->{ Webhook.trigger('issue.created', self) }
|
|
| 134 |
after_update_commit ->{ Webhook.trigger('issue.updated', self) }
|
|
| 135 |
after_destroy_commit ->{ Webhook.trigger('issue.deleted', self) }
|
|
| 134 |
def webhook_payload(user, action) |
|
| 135 |
h = super |
|
| 136 |
if action == 'updated' && current_journal.present? |
|
| 137 |
journal = journals.visible(user).find_by_id(current_journal.id) |
|
| 138 |
if journal.present? |
|
| 139 |
h[:data][:journal] = journal_payload(journal, user) |
|
| 140 |
h[:timestamp] = journal.created_on.iso8601 |
|
| 141 |
end |
|
| 142 |
end |
|
| 143 |
h |
|
| 144 |
end |
|
| 136 | 145 | |
| 137 | 146 |
# Returns a SQL conditions string used to find all issues visible by the specified user |
| 138 | 147 |
def self.visible_condition(user, options={})
|
| ... | ... | |
| 1709 | 1718 | |
| 1710 | 1719 |
private |
| 1711 | 1720 | |
| 1721 |
def journal_payload(journal, user) |
|
| 1722 |
{
|
|
| 1723 |
id: journal.id, |
|
| 1724 |
created_on: journal.created_on.iso8601, |
|
| 1725 |
notes: journal.notes, |
|
| 1726 |
user: {
|
|
| 1727 |
id: journal.user.id, |
|
| 1728 |
name: journal.user.name, |
|
| 1729 |
}, |
|
| 1730 |
details: journal.visible_details(user).map do |d| |
|
| 1731 |
{
|
|
| 1732 |
property: d.property, |
|
| 1733 |
prop_key: d.prop_key, |
|
| 1734 |
old_value: d.old_value, |
|
| 1735 |
value: d.value, |
|
| 1736 |
} |
|
| 1737 |
end |
|
| 1738 |
} |
|
| 1739 |
end |
|
| 1740 | ||
| 1712 | 1741 |
def user_tracker_permission?(user, permission) |
| 1713 | 1742 |
if project && !project.active? |
| 1714 | 1743 |
perm = Redmine::AccessControl.permission(permission) |
| app/models/news.rb | ||
|---|---|---|
| 37 | 37 |
acts_as_activity_provider :scope => proc {preload(:project, :author)},
|
| 38 | 38 |
:author_key => :author_id |
| 39 | 39 |
acts_as_watchable |
| 40 |
acts_as_webhookable |
|
| 40 | 41 | |
| 41 | 42 |
after_create :add_author_as_watcher |
| 42 | 43 |
after_create_commit :send_notification |
| 43 | 44 | |
| 44 |
after_create_commit ->{ Webhook.trigger('news.created', self) }
|
|
| 45 |
after_update_commit ->{ Webhook.trigger('news.updated', self) }
|
|
| 46 |
after_destroy_commit ->{ Webhook.trigger('news.deleted', self) }
|
|
| 47 | ||
| 48 | 45 |
scope :visible, (lambda do |*args| |
| 49 | 46 |
joins(:project). |
| 50 | 47 |
where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args)) |
| app/models/time_entry.rb | ||
|---|---|---|
| 46 | 46 |
acts_as_activity_provider :timestamp => "#{table_name}.created_on",
|
| 47 | 47 |
:author_key => :user_id, |
| 48 | 48 |
:scope => proc {joins(:project).preload(:project)}
|
| 49 |
acts_as_webhookable |
|
| 49 | 50 | |
| 50 | 51 |
validates_presence_of :author_id, :user_id, :activity_id, :project_id, :hours, :spent_on |
| 51 | 52 |
validates_presence_of :issue_id, :if => lambda {Setting.timelog_required_fields.include?('issue_id')}
|
| ... | ... | |
| 58 | 59 |
before_validation :set_author_if_nil |
| 59 | 60 |
validate :validate_time_entry |
| 60 | 61 | |
| 61 |
after_create_commit ->{ Webhook.trigger('time_entry.created', self) }
|
|
| 62 |
after_update_commit ->{ Webhook.trigger('time_entry.updated', self) }
|
|
| 63 |
after_destroy_commit ->{ Webhook.trigger('time_entry.deleted', self) }
|
|
| 64 | ||
| 65 | 62 |
scope :visible, (lambda do |*args| |
| 66 | 63 |
joins(:project). |
| 67 | 64 |
where(TimeEntry.visible_condition(args.shift || User.current, *args)) |
| ... | ... | |
| 82 | 79 |
'issue_id', 'activity_id', 'spent_on', |
| 83 | 80 |
'custom_field_values', 'custom_fields' |
| 84 | 81 | |
| 82 |
def webhook_payload_api_template |
|
| 83 |
"app/views/timelog/show.api.rsb" |
|
| 84 |
end |
|
| 85 | ||
| 85 | 86 |
# Returns a SQL conditions string used to find all time entries visible by the specified user |
| 86 | 87 |
def self.visible_condition(user, options={})
|
| 87 | 88 |
Project.allowed_to_condition(user, :view_time_entries, options) do |role, user| |
| app/models/version.rb | ||
|---|---|---|
| 123 | 123 |
before_destroy :nullify_projects_default_version |
| 124 | 124 |
after_save :update_default_project_version |
| 125 | 125 | |
| 126 |
after_create_commit ->{ Webhook.trigger('version.created', self) }
|
|
| 127 |
after_update_commit ->{ Webhook.trigger('version.updated', self) }
|
|
| 128 |
after_destroy_commit ->{ Webhook.trigger('version.deleted', self) }
|
|
| 129 | ||
| 130 | 126 |
belongs_to :project |
| 131 | 127 |
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify, :extend => FixedIssuesExtension |
| 132 | 128 | |
| ... | ... | |
| 134 | 130 |
acts_as_attachable :view_permission => :view_files, |
| 135 | 131 |
:edit_permission => :manage_files, |
| 136 | 132 |
:delete_permission => :manage_files |
| 133 |
acts_as_webhookable |
|
| 137 | 134 | |
| 138 | 135 |
VERSION_STATUSES = %w(open locked closed) |
| 139 | 136 |
VERSION_SHARINGS = %w(none descendants hierarchy tree system) |
| ... | ... | |
| 416 | 413 |
@default_project_version = (arg == '1' || arg == true) |
| 417 | 414 |
end |
| 418 | 415 | |
| 419 |
def created_on |
|
| 420 |
created_at |
|
| 421 |
end |
|
| 422 | ||
| 423 |
def updated_on |
|
| 424 |
updated_at |
|
| 425 |
end |
|
| 426 | ||
| 427 | 416 |
private |
| 428 | 417 | |
| 429 | 418 |
# Update the issue's fixed versions. Used if a version's sharing changes. |
| app/models/webhook.rb | ||
|---|---|---|
| 94 | 94 |
end |
| 95 | 95 | |
| 96 | 96 |
def setable_events |
| 97 |
WebhookPayload::EVENTS
|
|
| 97 |
WebhookPayload.events
|
|
| 98 | 98 |
end |
| 99 | 99 | |
| 100 | 100 |
def setable_event_names |
| app/models/webhook_payload.rb | ||
|---|---|---|
| 27 | 27 |
self.user = user |
| 28 | 28 |
end |
| 29 | 29 | |
| 30 |
EVENTS = {
|
|
| 31 |
issue: %w[created updated deleted],
|
|
| 32 |
wiki_page: %w[created updated deleted],
|
|
| 33 |
time_entry: %w[created updated deleted],
|
|
| 34 |
news: %w[created updated deleted],
|
|
| 35 |
version: %w[created updated deleted],
|
|
| 36 |
}
|
|
| 30 |
def self.events
|
|
| 31 |
@events ||= ApplicationRecord.descendants.each_with_object({}) do |model, hash|
|
|
| 32 |
if model.respond_to?(:webhook_options) && model.webhook_options
|
|
| 33 |
hash[model.model_name.singular.to_sym] = %w[created updated deleted]
|
|
| 34 |
end
|
|
| 35 |
end
|
|
| 36 |
end
|
|
| 37 | 37 | |
| 38 | 38 |
def to_h |
| 39 | 39 |
type, action = event.split('.')
|
| 40 |
if EVENTS[type.to_sym].include?(action)
|
|
| 41 |
send("#{type}_payload", action)
|
|
| 40 |
if self.class.events[type.to_sym]&.include?(action)
|
|
| 41 |
object.webhook_payload(user, action)
|
|
| 42 | 42 |
else |
| 43 | 43 |
raise ArgumentError, "invalid event: #{event}"
|
| 44 | 44 |
end |
| 45 | 45 |
end |
| 46 | 46 | |
| 47 |
private |
|
| 48 | ||
| 49 |
def issue_payload(action) |
|
| 50 |
issue = object |
|
| 51 |
if issue.current_journal.present? |
|
| 52 |
journal = issue.journals.visible(user).find_by_id(issue.current_journal.id) |
|
| 53 |
end |
|
| 54 |
ts = case action |
|
| 55 |
when 'created' |
|
| 56 |
issue.created_on |
|
| 57 |
when 'deleted' |
|
| 58 |
Time.now |
|
| 59 |
else |
|
| 60 |
journal&.created_on || issue.updated_on |
|
| 61 |
end |
|
| 62 |
h = {
|
|
| 63 |
type: event, |
|
| 64 |
timestamp: ts.iso8601, |
|
| 65 |
data: {
|
|
| 66 |
issue: ApiRenderer.new("app/views/issues/show.api.rsb", user).to_h(issue: issue)
|
|
| 67 |
} |
|
| 68 |
} |
|
| 69 |
if action == 'updated' && journal.present? |
|
| 70 |
h[:data][:journal] = journal_payload(journal) |
|
| 71 |
end |
|
| 72 |
h |
|
| 73 |
end |
|
| 74 | ||
| 75 |
def journal_payload(journal) |
|
| 76 |
{
|
|
| 77 |
id: journal.id, |
|
| 78 |
created_on: journal.created_on.iso8601, |
|
| 79 |
notes: journal.notes, |
|
| 80 |
user: {
|
|
| 81 |
id: journal.user.id, |
|
| 82 |
name: journal.user.name, |
|
| 83 |
}, |
|
| 84 |
details: journal.visible_details(user).map do |d| |
|
| 85 |
{
|
|
| 86 |
property: d.property, |
|
| 87 |
prop_key: d.prop_key, |
|
| 88 |
old_value: d.old_value, |
|
| 89 |
value: d.value, |
|
| 90 |
} |
|
| 91 |
end |
|
| 92 |
} |
|
| 93 |
end |
|
| 94 | ||
| 95 |
def wiki_page_payload(action) |
|
| 96 |
wiki_page = object |
|
| 97 | ||
| 98 |
ts = case action |
|
| 99 |
when 'created' |
|
| 100 |
wiki_page.created_on |
|
| 101 |
when 'deleted' |
|
| 102 |
Time.now |
|
| 103 |
else |
|
| 104 |
wiki_page.updated_on |
|
| 105 |
end |
|
| 106 | ||
| 107 |
{
|
|
| 108 |
type: event, |
|
| 109 |
timestamp: ts.iso8601, |
|
| 110 |
data: {
|
|
| 111 |
wiki_page: ApiRenderer.new("app/views/wiki/show.api.rsb", user).to_h(page: wiki_page, content: wiki_page.content)
|
|
| 112 |
} |
|
| 113 |
} |
|
| 114 |
end |
|
| 115 | ||
| 116 |
def time_entry_payload(action) |
|
| 117 |
time_entry = object |
|
| 118 |
ts = case action |
|
| 119 |
when 'created' |
|
| 120 |
time_entry.created_on |
|
| 121 |
when 'deleted' |
|
| 122 |
Time.now |
|
| 123 |
else |
|
| 124 |
time_entry.updated_on |
|
| 125 |
end |
|
| 126 |
{
|
|
| 127 |
type: event, |
|
| 128 |
timestamp: ts.iso8601, |
|
| 129 |
data: {
|
|
| 130 |
time_entry: ApiRenderer.new("app/views/timelog/show.api.rsb", user).to_h(time_entry: time_entry)
|
|
| 131 |
} |
|
| 132 |
} |
|
| 133 |
end |
|
| 134 | ||
| 135 |
def news_payload(action) |
|
| 136 |
news = object |
|
| 137 |
ts = case action |
|
| 138 |
when 'created' |
|
| 139 |
news.created_on |
|
| 140 |
when 'deleted' |
|
| 141 |
Time.now |
|
| 142 |
else |
|
| 143 |
news.updated_on |
|
| 144 |
end |
|
| 145 |
{
|
|
| 146 |
type: event, |
|
| 147 |
timestamp: ts.iso8601, |
|
| 148 |
data: {
|
|
| 149 |
news: ApiRenderer.new("app/views/news/show.api.rsb", user).to_h(news: news)
|
|
| 150 |
} |
|
| 151 |
} |
|
| 152 |
end |
|
| 153 | ||
| 154 |
def version_payload(action) |
|
| 155 |
version = object |
|
| 156 |
ts = case action |
|
| 157 |
when 'created' |
|
| 158 |
version.created_on |
|
| 159 |
when 'deleted' |
|
| 160 |
Time.now |
|
| 161 |
else |
|
| 162 |
version.updated_on |
|
| 163 |
end |
|
| 164 |
{
|
|
| 165 |
type: event, |
|
| 166 |
timestamp: ts.iso8601, |
|
| 167 |
data: {
|
|
| 168 |
version: ApiRenderer.new("app/views/versions/show.api.rsb", user).to_h(version: version)
|
|
| 169 |
} |
|
| 170 |
} |
|
| 171 |
end |
|
| 172 | ||
| 173 | 47 |
# given a path to an API template (relative to RAILS_ROOT), renders it and returns the resulting hash |
| 174 | 48 |
class ApiRenderer |
| 175 | 49 |
include ApplicationHelper |
| app/models/wiki_page.rb | ||
|---|---|---|
| 47 | 47 |
:preload => [:content, {:wiki => :project}],
|
| 48 | 48 |
:permission => :view_wiki_pages, |
| 49 | 49 |
:project_key => "#{Wiki.table_name}.project_id"
|
| 50 |
acts_as_webhookable |
|
| 50 | 51 | |
| 51 | 52 |
attr_accessor :redirect_existing_links |
| 52 | 53 |
attr_writer :deleted_attachment_ids |
| ... | ... | |
| 62 | 63 |
before_destroy :delete_redirects |
| 63 | 64 |
after_save :handle_children_move, :delete_selected_attachments |
| 64 | 65 | |
| 65 |
after_create_commit ->{ Webhook.trigger('wiki_page.created', self) }
|
|
| 66 |
after_update_commit ->{ Webhook.trigger('wiki_page.updated', self) }
|
|
| 67 |
after_destroy_commit ->{ Webhook.trigger('wiki_page.deleted', self) }
|
|
| 68 | ||
| 69 | 66 |
# eager load information about last updates, without loading text |
| 70 | 67 |
scope :with_updated_on, lambda {preload(:content_without_text)}
|
| 71 | 68 | |
| ... | ... | |
| 81 | 78 |
safe_attributes 'deleted_attachment_ids', |
| 82 | 79 |
:if => lambda {|page, user| page.attachments_deletable?(user)}
|
| 83 | 80 | |
| 81 |
def webhook_payload_ivars |
|
| 82 |
{ page: self, content: content }
|
|
| 83 |
end |
|
| 84 | ||
| 85 |
def webhook_payload_api_template |
|
| 86 |
"app/views/wiki/show.api.rsb" |
|
| 87 |
end |
|
| 88 | ||
| 84 | 89 |
def initialize(attributes=nil, *args) |
| 85 | 90 |
super |
| 86 | 91 |
if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase) |
| config/locales/en.yml | ||
|---|---|---|
| 1185 | 1185 |
label_alert_caution: Caution |
| 1186 | 1186 |
label_alert_important: Important |
| 1187 | 1187 | |
| 1188 |
webhook_events_issue: Issues |
|
| 1189 |
webhook_events_issue_created: Issue created |
|
| 1190 |
webhook_events_issue_updated: Issue updated |
|
| 1191 |
webhook_events_issue_deleted: Issue deleted |
|
| 1192 |
webhook_events_wiki_page: Wiki pages |
|
| 1193 |
webhook_events_wiki_page_created: Wiki page created |
|
| 1194 |
webhook_events_wiki_page_updated: Wiki page updated |
|
| 1195 |
webhook_events_wiki_page_deleted: Wiki page deleted |
|
| 1196 |
webhook_events_time_entry: Time entries |
|
| 1197 |
webhook_events_time_entry_created: Time entry created |
|
| 1198 |
webhook_events_time_entry_updated: Time entry updated |
|
| 1199 |
webhook_events_time_entry_deleted: Time entry deleted |
|
| 1200 |
webhook_events_news: News |
|
| 1201 |
webhook_events_news_created: News created |
|
| 1202 |
webhook_events_news_updated: News updated |
|
| 1203 |
webhook_events_news_deleted: News deleted |
|
| 1188 |
webhook_event_created: "%{type} created"
|
|
| 1189 |
webhook_event_updated: "%{type} updated"
|
|
| 1190 |
webhook_event_deleted: "%{type} deleted"
|
|
| 1204 | 1191 |
webhook_url_info: Redmine will send a POST request to this URL whenever one of the selected events occurs in one of the selected projects. |
| 1205 | 1192 |
webhook_secret_info_html: If provided, Redmine will use this to create a hash signature that is sent with each delivery as the value of the X-Redmine-Signature-256 header. |
| 1206 | 1193 | |
| lib/redmine/acts/webhookable.rb | ||
|---|---|---|
| 1 |
# frozen_string_literal: true |
|
| 2 | ||
| 3 |
# Redmine - project management software |
|
| 4 |
# Copyright (C) 2006- Jean-Philippe Lang |
|
| 5 |
# |
|
| 6 |
# This program is free software; you can redistribute it and/or |
|
| 7 |
# modify it under the terms of the GNU General Public License |
|
| 8 |
# as published by the Free Software Foundation; either version 2 |
|
| 9 |
# of the License, or (at your option) any later version. |
|
| 10 |
# |
|
| 11 |
# This program is distributed in the hope that it will be useful, |
|
| 12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 14 |
# GNU General Public License for more details. |
|
| 15 |
# |
|
| 16 |
# You should have received a copy of the GNU General Public License |
|
| 17 |
# along with this program; if not, write to the Free Software |
|
| 18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 19 | ||
| 20 |
module Redmine |
|
| 21 |
module Acts |
|
| 22 |
module Webhookable |
|
| 23 |
def self.included(base) |
|
| 24 |
base.extend ClassMethods |
|
| 25 |
end |
|
| 26 | ||
| 27 |
module ClassMethods |
|
| 28 |
def acts_as_webhookable(options = {})
|
|
| 29 |
cattr_accessor :webhook_options |
|
| 30 |
self.webhook_options = options |
|
| 31 | ||
| 32 |
after_create_commit ->{ Webhook.trigger(event_name('created'), self) }
|
|
| 33 |
after_update_commit ->{ Webhook.trigger(event_name('updated'), self) }
|
|
| 34 |
after_destroy_commit ->{ Webhook.trigger(event_name('deleted'), self) }
|
|
| 35 | ||
| 36 |
include Redmine::Acts::Webhookable::InstanceMethods |
|
| 37 |
end |
|
| 38 |
end |
|
| 39 | ||
| 40 |
module InstanceMethods |
|
| 41 |
def event_name(action) |
|
| 42 |
"#{self.class.model_name.singular}.#{action}"
|
|
| 43 |
end |
|
| 44 | ||
| 45 |
def webhook_payload(user, action) |
|
| 46 |
{
|
|
| 47 |
type: event_name(action), |
|
| 48 |
timestamp: webhook_payload_timestamp(action), |
|
| 49 |
data: {
|
|
| 50 |
self.class.model_name.singular.to_sym => |
|
| 51 |
WebhookPayload::ApiRenderer.new(webhook_payload_api_template, user).to_h(**webhook_payload_ivars) |
|
| 52 |
} |
|
| 53 |
} |
|
| 54 |
end |
|
| 55 | ||
| 56 |
def webhook_payload_ivars |
|
| 57 |
{ self.class.model_name.singular.to_sym => self }
|
|
| 58 |
end |
|
| 59 | ||
| 60 |
def webhook_payload_api_template |
|
| 61 |
"app/views/#{self.class.model_name.plural}/show.api.rsb"
|
|
| 62 |
end |
|
| 63 | ||
| 64 |
def webhook_payload_timestamp(action) |
|
| 65 |
ts = case action |
|
| 66 |
when 'created' |
|
| 67 |
created_on |
|
| 68 |
when 'deleted' |
|
| 69 |
Time.now |
|
| 70 |
else |
|
| 71 |
updated_on |
|
| 72 |
end |
|
| 73 |
ts.iso8601 |
|
| 74 |
end |
|
| 75 |
end |
|
| 76 |
end |
|
| 77 |
end |
|
| 78 |
end |
|
| lib/redmine/preparation.rb | ||
|---|---|---|
| 22 | 22 |
def self.prepare |
| 23 | 23 |
ApplicationRecord.include Redmine::Acts::Positioned |
| 24 | 24 |
ApplicationRecord.include Redmine::Acts::Mentionable |
| 25 |
ApplicationRecord.include Redmine::Acts::Webhookable |
|
| 25 | 26 |
ApplicationRecord.include Redmine::I18n |
| 26 | 27 | |
| 27 | 28 |
Scm::Base.add "Subversion" |
| test/unit/webhook_payload_test.rb | ||
|---|---|---|
| 28 | 28 |
@issue = @project.issues.first |
| 29 | 29 |
end |
| 30 | 30 | |
| 31 |
WebhookPayload.events.each do |type, actions| |
|
| 32 |
actions.each do |action| |
|
| 33 |
test "#{type} #{action} payload should be correct" do
|
|
| 34 |
model_class = type.to_s.classify.constantize |
|
| 35 |
obj = model_class.first || model_class.generate! |
|
| 36 |
p = WebhookPayload.new("#{type}.#{action}", obj, @dlopper)
|
|
| 37 |
assert h = p.to_h |
|
| 38 |
assert_equal "#{type}.#{action}", h[:type]
|
|
| 39 |
assert h.dig(:data, type) |
|
| 40 |
end |
|
| 41 |
end |
|
| 42 |
end |
|
| 43 | ||
| 31 | 44 |
test "issue update payload should contain journal" do |
| 32 | 45 |
@issue.init_journal(@dlopper) |
| 33 | 46 |
@issue.subject = "new subject" |
| ... | ... | |
| 40 | 53 |
assert i = h.dig(:data, :issue) |
| 41 | 54 |
assert_equal 'new subject', i[:subject], i.inspect |
| 42 | 55 |
end |
| 43 | ||
| 44 |
test "should compute payload of deleted issue" do |
|
| 45 |
@issue.destroy |
|
| 46 |
p = WebhookPayload.new('issue.deleted', @issue, @dlopper)
|
|
| 47 |
assert h = p.to_h |
|
| 48 |
assert_equal 'issue.deleted', h[:type] |
|
| 49 |
assert_nil h.dig(:data, :journal) |
|
| 50 |
assert i = h.dig(:data, :issue) |
|
| 51 |
assert_equal @issue.subject, i[:subject], i.inspect |
|
| 52 |
end |
|
| 53 | ||
| 54 |
test "wiki page created payload should contain page details" do |
|
| 55 |
wiki = @project.wiki |
|
| 56 |
page = WikiPage.new(:title => 'Test Page', :wiki => wiki) |
|
| 57 |
page.content = WikiContent.new(text: 'Test content', author: @dlopper) |
|
| 58 |
page.save! |
|
| 59 | ||
| 60 |
p = WebhookPayload.new('wiki_page.created', page, @dlopper)
|
|
| 61 |
assert h = p.to_h |
|
| 62 |
assert_equal 'wiki_page.created', h[:type] |
|
| 63 |
assert_equal 'Test_Page', h.dig(:data, :wiki_page, :title) |
|
| 64 |
assert_equal 'Test content', h.dig(:data, :wiki_page, :text) |
|
| 65 |
assert_equal @dlopper.name, h.dig(:data, :wiki_page, :author, :name) |
|
| 66 |
end |
|
| 67 | ||
| 68 |
test "wiki page updated payload should contain updated timestamp" do |
|
| 69 |
wiki = @project.wiki |
|
| 70 |
page = WikiPage.new(wiki: wiki, title: 'Test Page') |
|
| 71 |
page.content = WikiContent.new(text: 'Initial content', author: @dlopper) |
|
| 72 |
page.save! |
|
| 73 | ||
| 74 |
page.content.text = 'Updated content' |
|
| 75 |
page.content.save! |
|
| 76 |
page.reload |
|
| 77 | ||
| 78 |
p = WebhookPayload.new('wiki_page.updated', page, @dlopper)
|
|
| 79 |
h = p.to_h |
|
| 80 |
assert_equal 'wiki_page.updated', h[:type] |
|
| 81 |
assert_equal 'Updated content', h.dig(:data, :wiki_page, :text) |
|
| 82 |
end |
|
| 83 | ||
| 84 |
test "wiki page deleted payload should contain basic info" do |
|
| 85 |
wiki = @project.wiki |
|
| 86 |
page = WikiPage.new(wiki: wiki, title: 'Test Page') |
|
| 87 |
page.content = WikiContent.new(text: 'Test content', author: @dlopper) |
|
| 88 |
page.save! |
|
| 89 | ||
| 90 |
page.destroy |
|
| 91 | ||
| 92 |
p = WebhookPayload.new('wiki_page.deleted', page, @dlopper)
|
|
| 93 |
h = p.to_h |
|
| 94 |
assert_equal 'wiki_page.deleted', h[:type] |
|
| 95 |
assert_equal 'Test_Page', h.dig(:data, :wiki_page, :title) |
|
| 96 |
end |
|
| 97 | ||
| 98 |
test "time entry created payload should contain time entry details" do |
|
| 99 |
time_entry = TimeEntry.generate! |
|
| 100 | ||
| 101 |
p = WebhookPayload.new('time_entry.created', time_entry, @dlopper)
|
|
| 102 |
assert h = p.to_h |
|
| 103 |
assert_equal 'time_entry.created', h[:type] |
|
| 104 |
assert_equal time_entry.hours, h.dig(:data, :time_entry, :hours) |
|
| 105 |
end |
|
| 106 | ||
| 107 |
test "time entry updated payload should contain updated timestamp" do |
|
| 108 |
time_entry = TimeEntry.first |
|
| 109 | ||
| 110 |
time_entry.hours = 2.5 |
|
| 111 |
time_entry.save! |
|
| 112 | ||
| 113 |
p = WebhookPayload.new('time_entry.updated', time_entry, @dlopper)
|
|
| 114 |
h = p.to_h |
|
| 115 |
assert_equal 'time_entry.updated', h[:type] |
|
| 116 |
assert_equal 2.5, h.dig(:data, :time_entry, :hours) |
|
| 117 |
end |
|
| 118 | ||
| 119 |
test "time entry deleted payload should contain basic info" do |
|
| 120 |
time_entry = TimeEntry.first |
|
| 121 |
time_entry.destroy |
|
| 122 | ||
| 123 |
p = WebhookPayload.new('time_entry.deleted', time_entry, @dlopper)
|
|
| 124 |
h = p.to_h |
|
| 125 |
assert_equal 'time_entry.deleted', h[:type] |
|
| 126 |
assert_equal 4.25, h.dig(:data, :time_entry, :hours) |
|
| 127 |
end |
|
| 128 | ||
| 129 |
test "news created payload should contain news details" do |
|
| 130 |
news = News.generate! |
|
| 131 | ||
| 132 |
p = WebhookPayload.new('news.created', news, @dlopper)
|
|
| 133 |
assert h = p.to_h |
|
| 134 |
assert_equal 'news.created', h[:type] |
|
| 135 |
assert_equal news.title, h.dig(:data, :news, :title) |
|
| 136 |
end |
|
| 137 | ||
| 138 |
test "news updated payload should contain updated timestamp" do |
|
| 139 |
news = News.first |
|
| 140 | ||
| 141 |
news.title = 'Updated title' |
|
| 142 |
news.save! |
|
| 143 | ||
| 144 |
p = WebhookPayload.new('news.updated', news, @dlopper)
|
|
| 145 |
h = p.to_h |
|
| 146 |
assert_equal 'news.updated', h[:type] |
|
| 147 |
assert_equal 'Updated title', h.dig(:data, :news, :title) |
|
| 148 |
end |
|
| 149 | ||
| 150 |
test "news deleted payload should contain basic info" do |
|
| 151 |
news = News.first |
|
| 152 |
news.destroy |
|
| 153 | ||
| 154 |
p = WebhookPayload.new('news.deleted', news, @dlopper)
|
|
| 155 |
h = p.to_h |
|
| 156 |
assert_equal 'news.deleted', h[:type] |
|
| 157 |
assert_equal 'Updated title', h.dig(:data, :news, :title) |
|
| 158 |
end |
|
| 159 | ||
| 160 |
test "version created payload should contain version details" do |
|
| 161 |
version = Version.generate! |
|
| 162 | ||
| 163 |
p = WebhookPayload.new('version.created', version, @dlopper)
|
|
| 164 |
assert h = p.to_h |
|
| 165 |
assert_equal 'version.created', h[:type] |
|
| 166 |
assert_equal version.name, h.dig(:data, :version, :name) |
|
| 167 |
end |
|
| 168 | ||
| 169 |
test "version updated payload should contain updated timestamp" do |
|
| 170 |
version = Version.first |
|
| 171 | ||
| 172 |
version.name = 'Updated name' |
|
| 173 |
version.save! |
|
| 174 | ||
| 175 |
p = WebhookPayload.new('version.updated', version, @dlopper)
|
|
| 176 |
h = p.to_h |
|
| 177 |
assert_equal 'version.updated', h[:type] |
|
| 178 |
assert_equal 'Updated name', h.dig(:data, :version, :name) |
|
| 179 |
end |
|
| 180 | ||
| 181 |
test "version deleted payload should contain basic info" do |
|
| 182 |
version = Version.first |
|
| 183 |
version.destroy |
|
| 184 | ||
| 185 |
p = WebhookPayload.new('version.deleted', version, @dlopper)
|
|
| 186 |
h = p.to_h |
|
| 187 |
assert_equal 'version.deleted', h[:type] |
|
| 188 |
assert_equal 'Updated name', h.dig(:data, :version, :name) |
|
| 189 |
end |
|
| 190 | 56 |
end |
- « Previous
- 1
- …
- 14
- 15
- 16
- Next »