Module: PlanMyStuff::Notifications
- Defined in:
- lib/plan_my_stuff/notifications.rb
Overview
Central instrumentation helper. Domain classes call PlanMyStuff::Notifications.instrument at mutation points so consuming apps can subscribe for email, webhooks, Slack, etc.
Events are fired under the plan_my_stuff.<event> namespace via ActiveSupport::Notifications. Subscribers run synchronously.
Constant Summary collapse
- EVENT_PREFIX =
'plan_my_stuff'- SKIPPED_LOG_KEYS =
%i[user timestamp visibility visibility_allowlist].freeze
Class Method Summary collapse
-
.build_payload(resource, actor, extra) ⇒ Hash
Builds the payload hash for an event.
-
.infer_resource_key(resource) ⇒ Symbol
Maps a resource object to its payload key.
-
.instrument(event, resource, user: nil, **extra) ⇒ void
Fires plan_my_stuff.<event> with a normalized payload.
-
.log(event, payload) ⇒ void
Emits a debug log line for the event.
- .log_fields(payload) ⇒ String
- .rails_logger ⇒ Logger?
-
.resolve_current_user ⇒ Object?
Invokes
config.current_userif it responds tocall. -
.visibility_fields(resource) ⇒ Hash
Extracts visibility + allowlist from
Issue/Commentresources.
Class Method Details
.build_payload(resource, actor, extra) ⇒ Hash
Builds the payload hash for an event.
54 55 56 57 58 59 60 61 62 |
# File 'lib/plan_my_stuff/notifications.rb', line 54 def build_payload(resource, actor, extra) payload = { infer_resource_key(resource) => resource, :user => actor, :timestamp => Time.current, } payload.merge!(visibility_fields(resource)) payload.merge(extra) end |
.infer_resource_key(resource) ⇒ Symbol
Maps a resource object to its payload key.
70 71 72 73 74 75 76 77 |
# File 'lib/plan_my_stuff/notifications.rb', line 70 def infer_resource_key(resource) case resource when PlanMyStuff::Issue then :issue when PlanMyStuff::Comment then :comment when PlanMyStuff::BaseProjectItem then :project_item else :resource end end |
.instrument(event, resource, user: nil, **extra) ⇒ void
This method returns an undefined value.
Fires plan_my_stuff.<event> with a normalized payload.
28 29 30 31 32 33 |
# File 'lib/plan_my_stuff/notifications.rb', line 28 def instrument(event, resource, user: nil, **extra) actor = user || resolve_current_user payload = build_payload(resource, actor, extra) log(event, payload) ActiveSupport::Notifications.instrument("#{EVENT_PREFIX}.#{event}", payload) end |
.log(event, payload) ⇒ void
This method returns an undefined value.
Emits a debug log line for the event. No-op when no logger is available (e.g. outside Rails).
112 113 114 115 116 117 |
# File 'lib/plan_my_stuff/notifications.rb', line 112 def log(event, payload) logger = rails_logger return if logger.nil? logger.debug { "[PMS] #{EVENT_PREFIX}.#{event} #{log_fields(payload)}" } end |
.log_fields(payload) ⇒ String
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/plan_my_stuff/notifications.rb', line 131 def log_fields(payload) fields = [] fields << "user=#{payload[:user].inspect}" if payload.key?(:user) payload.each do |key, value| next if SKIPPED_LOG_KEYS.include?(key) fields << "#{key}=#{value.inspect}" end fields.join(' ') end |
.rails_logger ⇒ Logger?
120 121 122 123 124 125 |
# File 'lib/plan_my_stuff/notifications.rb', line 120 def rails_logger return unless defined?(Rails) return unless Rails.respond_to?(:logger) Rails.logger end |
.resolve_current_user ⇒ Object?
Invokes config.current_user if it responds to call.
39 40 41 42 43 44 |
# File 'lib/plan_my_stuff/notifications.rb', line 39 def resolve_current_user resolver = PlanMyStuff.configuration.current_user return if resolver.nil? resolver.respond_to?(:call) ? resolver.call : resolver end |
.visibility_fields(resource) ⇒ Hash
Extracts visibility + allowlist from Issue/Comment resources. Returns an empty hash for resources without visibility.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/plan_my_stuff/notifications.rb', line 86 def visibility_fields(resource) case resource when PlanMyStuff::Issue { visibility: resource..visibility, visibility_allowlist: Array.wrap(resource..visibility_allowlist), } when PlanMyStuff::Comment parent_allowlist = resource.issue ? resource.issue..visibility_allowlist : [] { visibility: resource.visibility&.to_s, visibility_allowlist: Array.wrap(parent_allowlist), } else {} end end |