about summary refs log tree commit diff
path: root/app/models
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2022-06-09 21:57:36 +0200
committerGitHub <noreply@github.com>2022-06-09 21:57:36 +0200
commita2871cd74719a7a5a104daaa3dcc0e2670b7c2df (patch)
treecfd30fe202cd5be1c2984f4031d825d950784da2 /app/models
parent17ba5e1e616c853a389b9c24a347d873747f2126 (diff)
Add administrative webhooks (#18510)
* Add administrative webhooks

* Fix error when webhook is deleted before delivery worker runs
Diffstat (limited to 'app/models')
-rw-r--r--app/models/admin/action_log.rb1
-rw-r--r--app/models/report.rb6
-rw-r--r--app/models/user.rb10
-rw-r--r--app/models/webhook.rb58
4 files changed, 73 insertions, 2 deletions
diff --git a/app/models/admin/action_log.rb b/app/models/admin/action_log.rb
index 852bff713..401bfd9ac 100644
--- a/app/models/admin/action_log.rb
+++ b/app/models/admin/action_log.rb
@@ -1,4 +1,5 @@
 # frozen_string_literal: true
+
 # == Schema Information
 #
 # Table name: admin_action_logs
diff --git a/app/models/report.rb b/app/models/report.rb
index 6d4166540..2efb6d4a7 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -55,6 +55,8 @@ class Report < ApplicationRecord
 
   before_validation :set_uri, only: :create
 
+  after_create_commit :trigger_webhooks
+
   def object_type
     :flag
   end
@@ -143,4 +145,8 @@ class Report < ApplicationRecord
 
     errors.add(:rule_ids, I18n.t('reports.errors.invalid_rules')) unless rules.size == rule_ids&.size
   end
+
+  def trigger_webhooks
+    TriggerWebhookWorker.perform_async('report.created', 'Report', id)
+  end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index 23febb6fe..81f6a58f6 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -37,7 +37,6 @@
 #  sign_in_token_sent_at     :datetime
 #  webauthn_id               :string
 #  sign_up_ip                :inet
-#  skip_sign_in_token        :boolean
 #
 
 class User < ApplicationRecord
@@ -120,6 +119,7 @@ class User < ApplicationRecord
   before_validation :sanitize_languages
   before_create :set_approved
   after_commit :send_pending_devise_notifications
+  after_create_commit :trigger_webhooks
 
   # This avoids a deprecation warning from Rails 5.1
   # It seems possible that a future release of devise-two-factor will
@@ -182,7 +182,9 @@ class User < ApplicationRecord
   end
 
   def update_sign_in!(new_sign_in: false)
-    old_current, new_current = current_sign_in_at, Time.now.utc
+    old_current = current_sign_in_at
+    new_current = Time.now.utc
+
     self.last_sign_in_at     = old_current || new_current
     self.current_sign_in_at  = new_current
 
@@ -472,4 +474,8 @@ class User < ApplicationRecord
   def invite_text_required?
     Setting.require_invite_text && !invited? && !external? && !bypass_invite_request_check?
   end
+
+  def trigger_webhooks
+    TriggerWebhookWorker.perform_async('account.created', 'Account', account_id)
+  end
 end
diff --git a/app/models/webhook.rb b/app/models/webhook.rb
new file mode 100644
index 000000000..431edd75d
--- /dev/null
+++ b/app/models/webhook.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+# == Schema Information
+#
+# Table name: webhooks
+#
+#  id         :bigint(8)        not null, primary key
+#  url        :string           not null
+#  events     :string           default([]), not null, is an Array
+#  secret     :string           default(""), not null
+#  enabled    :boolean          default(TRUE), not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#
+
+class Webhook < ApplicationRecord
+  EVENTS = %w(
+    account.created
+    report.created
+  ).freeze
+
+  scope :enabled, -> { where(enabled: true) }
+
+  validates :url, presence: true, url: true
+  validates :secret, presence: true, length: { minimum: 12 }
+  validates :events, presence: true
+
+  validate :validate_events
+
+  before_validation :strip_events
+  before_validation :generate_secret
+
+  def rotate_secret!
+    update!(secret: SecureRandom.hex(20))
+  end
+
+  def enable!
+    update!(enabled: true)
+  end
+
+  def disable!
+    update!(enabled: false)
+  end
+
+  private
+
+  def validate_events
+    errors.add(:events, :invalid) if events.any? { |e| !EVENTS.include?(e) }
+  end
+
+  def strip_events
+    self.events = events.map { |str| str.strip.presence }.compact if events.present?
+  end
+
+  def generate_secret
+    self.secret = SecureRandom.hex(20) if secret.blank?
+  end
+end