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 <event>.plan_my_stuff namespace via ActiveSupport::Notifications (Rails convention: event first, library last - matches sql.active_record, deliver.action_mailer). Subscribers run synchronously.
Constant Summary collapse
- EVENT_SUFFIX =
'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 <event>.plan_my_stuff 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.
57 58 59 60 61 62 63 64 65 |
# File 'lib/plan_my_stuff/notifications.rb', line 57 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. An Array recurses on its first element and pluralizes that key, so batch events carry the full set under one key (a batch of project items keys as :project_items, a batch of issues as :issues, an empty/unknown batch as :resources).
75 76 77 78 79 80 81 82 83 |
# File 'lib/plan_my_stuff/notifications.rb', line 75 def infer_resource_key(resource) case resource when PlanMyStuff::Issue then :issue when PlanMyStuff::Comment then :comment when PlanMyStuff::BaseProjectItem then :project_item when Array then :"#{infer_resource_key(resource.first)}s" else :resource end end |
.instrument(event, resource, user: nil, **extra) ⇒ void
This method returns an undefined value.
Fires <event>.plan_my_stuff with a normalized payload.
31 32 33 34 35 36 |
# File 'lib/plan_my_stuff/notifications.rb', line 31 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}.#{EVENT_SUFFIX}", 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).
118 119 120 121 122 123 |
# File 'lib/plan_my_stuff/notifications.rb', line 118 def log(event, payload) logger = rails_logger return if logger.nil? logger.debug { "[PlanMyStuff] #{event}.#{EVENT_SUFFIX} #{log_fields(payload)}" } end |
.log_fields(payload) ⇒ String
137 138 139 140 141 142 143 144 145 146 |
# File 'lib/plan_my_stuff/notifications.rb', line 137 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?
126 127 128 129 130 131 |
# File 'lib/plan_my_stuff/notifications.rb', line 126 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.
42 43 44 45 46 47 |
# File 'lib/plan_my_stuff/notifications.rb', line 42 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.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/plan_my_stuff/notifications.rb', line 92 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 |