lib/lazylead/cc.rb
# frozen_string_literal: true
# The MIT License
#
# Copyright (c) 2019-2022 Yurii Dubinka
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
# OR OTHER DEALINGS IN THE SOFTWARE.
require "forwardable"
module Lazylead
# Entry point for email CC detection.
# The email may need CC email addresses, thus, there are various strategies
# how it can be done.
class CC
# Build an CC in order to detect email addresses by different conditions.
#
# Supported conditions(types):
# - PlainCC
# - PredefinedCC
# - ComponentCC
# - Empty
#
def detect(emails, sys)
return emails if recognized?(emails)
return PlainCC.new(emails) if plain?(emails)
return EmptyCC.new if undefined?(emails)
type = emails["type"].constantize
return ComponentCC.new(emails["project"], sys) if type.is_a? ComponentCC
type.new(emails["opts"])
end
# Detect that raw CC is a string which may has plain email addresses
def plain?(text)
(text.is_a? String) && text.to_s.include?("@")
end
def recognized?(emails)
[EmptyCC, PlainCC, ComponentCC, PredefinedCC].member? emails.class
end
def undefined?(emails)
return true unless emails.key? "type"
emails["type"].nil? || emails["type"].blank?
end
end
# Array of CC addresses from text for email notification.
#
# PlainCC.new("a@f.com, , -,b@f.com").cc # ==> ["a@f.com", "b@f.com"]
#
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
# License:: MIT
class PlainCC
include Enumerable
extend Forwardable
def_delegators :@cc, :each
# The regexp expression for email notification is very simple, here is the
# reason why https://bit.ly/38iLKeo
def initialize(text, regxp = /[^\s]@[^\s]/)
@text = text
@regxp = regxp
end
def cc
@cc ||= if @text.include? ","
@text.split(",").map(&:strip).select { |e| e[@regxp] }
elsif @text[@regxp]
[@text.strip]
end
end
def each(&block)
cc.each(&block)
end
end
# Empty CC email addresses.
class EmptyCC
def cc
[]
end
end
# Predefined CC addresses for email notification.
# You may define a hash where
# - key is Jira ticket component
# - value is CC email address(es)
#
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
# License:: MIT
class PredefinedCC
def initialize(orig)
@orig = orig
end
def [](key)
to_h[key]
end
def cc(*names)
return to_h.values.flatten.uniq.compact if names.count.zero?
return self[names.first] if names.count == 1
to_h.values_at(names.first, *names.drop(1)).flatten.uniq.compact
end
def to_h
@to_h ||= if @orig.is_a? Hash
@orig.each_with_object({}) do |i, o|
o[i.first] = Lazylead::PlainCC.new(i.last).cc
end
else
{}
end
end
end
# CC addresses based on Jira component owners for email notification.
# Allows to detect the CC for particular ticket based on its component.
#
# Author:: Yurii Dubinka (yurii.dubinka@gmail.com)
# Copyright:: Copyright (c) 2019-2020 Yurii Dubinka
# License:: MIT
class ComponentCC < Lazylead::PredefinedCC
def initialize(prj, jira)
super({})
@prj = prj
@jira = jira
end
def to_h
@to_h ||= components.each_with_object({}) do |c, h|
email = lead(c.attrs["id"])
next if email.nil? || email.blank?
h[c.attrs["name"]] = email
end
end
private
def lead(component_id)
@jira.raw do |j|
lead = j.Component
.find(component_id, expand: "", fields: "")
.attrs["lead"]
next if lead.nil? || lead.empty?
j.User.find(lead["key"]).attrs["emailAddress"]
end
end
def components
@jira.raw do |j|
j.Project.find(@prj, expand: "components", fields: "").components
end
end
end
end