Welcome to mirror list, hosted at ThFree Co, Russian Federation.

in_product_marketing_emails_service.rb « namespaces « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f009f5d8538008215da623121b738cf6d6707b55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# frozen_string_literal: true

module Namespaces
  class InProductMarketingEmailsService
    include Gitlab::Experimentation::GroupTypes

    INTERVAL_DAYS = [1, 5, 10].freeze
    TRACKS = {
      create: :git_write,
      verify: :pipeline_created,
      trial: :trial_started,
      team: :user_added
    }.freeze

    def self.send_for_all_tracks_and_intervals
      TRACKS.each_key do |track|
        INTERVAL_DAYS.each do |interval|
          new(track, interval).execute
        end
      end
    end

    def initialize(track, interval)
      @track = track
      @interval = interval
      @sent_email_user_ids = []
    end

    def execute
      groups_for_track.each_batch do |groups|
        groups.each do |group|
          send_email_for_group(group)
        end
      end
    end

    private

    attr_reader :track, :interval, :sent_email_user_ids

    def send_email_for_group(group)
      experiment_enabled_for_group = experiment_enabled_for_group?(group)
      experiment_add_group(group, experiment_enabled_for_group)
      return unless experiment_enabled_for_group

      users_for_group(group).each do |user|
        send_email(user, group) if can_perform_action?(user, group)
      end
    end

    def experiment_enabled_for_group?(group)
      Gitlab::Experimentation.in_experiment_group?(:in_product_marketing_emails, subject: group)
    end

    def experiment_add_group(group, experiment_enabled_for_group)
      variant = experiment_enabled_for_group ? GROUP_EXPERIMENTAL : GROUP_CONTROL
      Experiment.add_group(:in_product_marketing_emails, variant: variant, group: group)
    end

    # rubocop: disable CodeReuse/ActiveRecord
    def groups_for_track
      onboarding_progress_scope = OnboardingProgress
        .completed_actions_with_latest_in_range(completed_actions, range)
        .incomplete_actions(incomplete_action)

      # Filtering out sub-groups is a temporary fix to prevent calling
      # `.root_ancestor` on groups that are not root groups.
      # See https://gitlab.com/groups/gitlab-org/-/epics/5594 for more information.
      Group.where(parent_id: nil).joins(:onboarding_progress).merge(onboarding_progress_scope)
    end

    def users_for_group(group)
      group.users.where(email_opted_in: true)
        .where.not(id: sent_email_user_ids)
    end
    # rubocop: enable CodeReuse/ActiveRecord

    def can_perform_action?(user, group)
      case track
      when :create
        user.can?(:create_projects, group)
      when :verify
        user.can?(:create_projects, group)
      when :trial
        user.can?(:start_trial, group)
      when :team
        user.can?(:admin_group_member, group)
      else
        raise NotImplementedError, "No ability defined for track #{track}"
      end
    end

    def send_email(user, group)
      NotificationService.new.in_product_marketing(user.id, group.id, track, series)
      sent_email_user_ids << user.id
    end

    def completed_actions
      index = TRACKS.keys.index(track)
      index == 0 ? [:created] : TRACKS.values[0..index - 1]
    end

    def range
      (interval + 1).days.ago.beginning_of_day..(interval + 1).days.ago.end_of_day
    end

    def incomplete_action
      TRACKS[track]
    end

    def series
      INTERVAL_DAYS.index(interval)
    end
  end
end