gitlab_support_readiness 1.0.43 → 1.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/lib/support_readiness/support_super_form_processor/global_set_collaboration_id.rb +1 -1
  3. data/lib/support_readiness/support_super_form_processor/global_set_org_ase.rb +1 -1
  4. data/lib/support_readiness/support_super_form_processor/global_toggle_escalation.rb +1 -1
  5. data/lib/support_readiness/support_super_form_processor/gratis_support_extension.rb +23 -5
  6. data/lib/support_readiness/support_super_form_processor/gratis_support_former_customer.rb +31 -0
  7. data/lib/support_readiness/support_super_form_processor/gratis_support_migration.rb +31 -0
  8. data/lib/support_readiness/support_super_form_processor/gratis_support_other.rb +31 -0
  9. data/lib/support_readiness/support_super_form_processor/gratis_support_prospect.rb +31 -0
  10. data/lib/support_readiness/support_super_form_processor/gratis_support_upgrade.rb +31 -0
  11. data/lib/support_readiness/support_super_form_processor/namespace_availability.rb +1 -1
  12. data/lib/support_readiness/support_super_form_processor/sa_request_for_support.rb +1 -1
  13. data/lib/support_readiness/support_super_form_processor/usgov_set_collaboration_id.rb +1 -1
  14. data/lib/support_readiness/support_super_form_processor/usgov_set_org_ase.rb +1 -1
  15. data/lib/support_readiness/support_super_form_processor.rb +1 -0
  16. data/lib/support_readiness/ticket_processor/account_blocked.rb +289 -0
  17. data/lib/support_readiness/ticket_processor/email_suppressions.rb +135 -0
  18. data/lib/support_readiness/ticket_processor/link_tagger.rb +102 -0
  19. data/lib/support_readiness/ticket_processor/locked_account.rb +53 -0
  20. data/lib/support_readiness/ticket_processor/namesquatting.rb +223 -0
  21. data/lib/support_readiness/ticket_processor/organization_notes.rb +308 -0
  22. data/lib/support_readiness/ticket_processor/star.rb +32 -0
  23. data/lib/support_readiness/ticket_processor/weighting.rb +121 -0
  24. data/lib/support_readiness/ticket_processor.rb +19 -0
  25. data/lib/support_readiness.rb +1 -0
  26. metadata +11 -2
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module Readiness.
4
+ module Readiness
5
+ # Defines the module TicketProcessor
6
+ module TicketProcessor
7
+ ##
8
+ # Defines the class EmailSuppressions within the module {Readiness::Zendesk}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.44
12
+ class EmailSuppressions < Readiness::Client
13
+ ##
14
+ # Process an Email Suppression request
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.44
18
+ def self.process!(zendesk_client, mailgun_client, ticket_id)
19
+ @zendesk_client = zendesk_client
20
+ @mailgun_client = mailgun_client
21
+ @ticket_id = ticket_id
22
+ @ticket = Readiness::Zendesk::Tickets.find(@zendesk_client, @ticket_id)
23
+ puts 'No ticket found, so no org notes to add' if @ticket.is_a? Hash
24
+ exit 0 if @ticket.is_a? Hash
25
+
26
+ puts 'Ticket is closed, so no org notes to add' if @ticket.status == 'closed'
27
+ exit 0 if @ticket.status == 'closed'
28
+
29
+ @email = @ticket.custom_fields.detect { |t| t['id'] == 4413932829586 }['value']
30
+ return no_email_given if @email.nil?
31
+
32
+ bounce = Readiness::Mailgun::Bounces.find(@mailgun_client, @email)
33
+ if bounce.address.nil?
34
+ no_bounce_exists
35
+ else
36
+ Readiness::Mailgun::Bounces.delete!(@mailgun_client, bounce)
37
+ new_ticket = Readiness::Zendesk::Tickets.new
38
+ new_ticket.id = @ticket.id
39
+ new_ticket.comment = { body: suppression_removed_note(bounce), public: false }
40
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
41
+ new_ticket = Readiness::Zendesk::Tickets.new
42
+ new_ticket.id = @ticket.id
43
+ new_ticket.status = 'solved'
44
+ new_ticket.comment = { body: suppression_removed_comment, public: true }
45
+ new_ticket.custom_fields = [
46
+ { id: 360020735259, value: 'stage-frt' }
47
+ ]
48
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
49
+ end
50
+ end
51
+
52
+ def self.no_email_given
53
+ new_ticket = Readiness::Zendesk::Tickets.new
54
+ new_ticket.id = @ticket.id
55
+ new_ticket.comment = { body: no_email_given_comment, public: false }
56
+ new_ticket.custom_fields = [
57
+ { id: 360020735259, value: 'stage-frt' }
58
+ ]
59
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
60
+ end
61
+
62
+ def self.no_bounce_exists
63
+ new_ticket = Readiness::Zendesk::Tickets.new
64
+ new_ticket.id = @ticket.id
65
+ new_ticket.status = 'pending'
66
+ new_ticket.comment = { body: no_bounce_exists_comment }
67
+ new_ticket.custom_fields = [
68
+ { id: 360020735259, value: 'stage-frt' }
69
+ ]
70
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
71
+ end
72
+
73
+ def self.no_email_given_comment
74
+ <<~STRING
75
+ We were unable to check for email suppressions on this ticket as the value of the `Impacted email address` is blank.
76
+
77
+ Please do the following to correct this and have this ticket re-autoworked:
78
+
79
+ - Please review the ticket and correct the field 'Impacted email address' to have a valid value
80
+ - Remove any of the following tags:
81
+ - `autowork_no_confirmation_email`
82
+ - `autowork_forgot_password`
83
+ - `autowork_notification_emails`
84
+
85
+ Make sure to save the update on the ticket. This should re-trigger the autowork script for you.
86
+ STRING
87
+ end
88
+
89
+ def self.no_bounce_exists_comment
90
+ <<~STRING
91
+ Greetings,
92
+
93
+ We have checked our systems and have not located any suppressions at this time for your email address (#{@email}). We would recommend checking your spam folder or contacting your email provider to help in locating any recent emails from us you may have received or requested.
94
+
95
+ Some common links you might need to get a new email are:
96
+
97
+ - Request a new confirmation email via https://gitlab.com/users/confirmation/new
98
+ - Request a new verification challenge by logging into GitLab.com directly and using the link in the prompt.
99
+ - Request a password reset on gitlab.com via https://gitlab.com/users/password/new
100
+ STRING
101
+ end
102
+
103
+ def self.suppression_removed_note(bounce)
104
+ <<~STRING
105
+ Suppression found and removed in mg.gitlab.com:
106
+
107
+ - Email: #{bounce.address}
108
+ - Code: #{bounce.code}
109
+ - Error: #{bounce.error}
110
+ - Time: #{bounce.created_at}
111
+ STRING
112
+ end
113
+
114
+ def self.suppression_removed_comment
115
+ <<~STRING
116
+ Greetings,
117
+
118
+ It looks like a suppression had been placed in our system on your email address (#{@email}) for gitlab.com emails, so no further emails from that system would have reached you.
119
+
120
+ We have cleared that suppression for you at this time.
121
+
122
+ Some common links you might need to get a new email are:
123
+
124
+ - Request a new confirmation email via https://gitlab.com/users/confirmation/new
125
+ - Request a new verification challenge by logging into GitLab.com directly and using the link in the prompt.
126
+ - Request a password reset on gitlab.com via https://gitlab.com/users/password/new
127
+
128
+ With the removal of the suppression, this ticket has been marked as solved.
129
+
130
+ If the suppression removal did not solve the problem and you are still not receiving emails from gitlab.com, please reply to this email to reopen the ticket and alert GitLab Support.
131
+ STRING
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module Readiness.
4
+ module Readiness
5
+ # Defines the module TicketProcessor
6
+ module TicketProcessor
7
+ ##
8
+ # Defines the class LinkTagger within the module {Readiness::Zendesk}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.44
12
+ class LinkTagger < Readiness::Client
13
+ ##
14
+ # Process a Link Tagging request
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.44
18
+ def self.process!(zendesk_client, gitlab_client, ticket_id)
19
+ @zendesk_client = zendesk_client
20
+ @gitlab_client = gitlab_client
21
+ @ticket_id = ticket_id
22
+ @user = Readiness::Zendesk::Users.find(@zendesk_client, ENV.fetch('COMMENT_AUTHOR'))
23
+ puts 'No such user, so no comment to review' if @user.is_a? Hash
24
+ exit 0 if @user.is_a? Hash
25
+ puts 'User is not an agent, so not proceeding' unless %w[admin agent].include? @user.role
26
+ exit 0 unless %w[admin agent].include? @user.role
27
+ @ticket = Readiness::Zendesk::Tickets.find(@zendesk_client, @ticket_id)
28
+ puts 'No ticket found, so no tags to add' if @ticket.is_a? Hash
29
+ exit 0 if @ticket.is_a? Hash
30
+
31
+ comments = Readiness::Zendesk::Tickets.comments(@zendesk_client, @ticket)
32
+ public_comments = comments.select { |c| c['public'] }
33
+ comment_to_check = public_comments.select { |c| c['author_id'] == @user.id }.last
34
+ tags_to_add = []
35
+ Nokogiri::HTML(comment_to_check['html_body']).css('a').each do |p|
36
+ link = p['href'].split('?').first.split('#').first
37
+ domain = link.split('/')[2]
38
+ if domain == 'gitlab.com'
39
+ if link =~ %r{/-/issues/[0-9]+}
40
+ slug = link.split("#{domain}/").last.split(%r{/-/issues/[0-9]+}).first
41
+ project = Readiness::GitLab::Projects.find(@gitlab_client, CGI.escape(slug))
42
+ unless project.is_a? Hash
43
+ iid = link.split('/').last
44
+ issue = Readiness::GitLab::Issues.find(@gitlab_client, project, iid)
45
+ unless issue.is_a? Hash
46
+ tags_to_add.push('gitlab_issue_link')
47
+ tags_to_add.push("#{slug.gsub('/', '_')}_issues_#{iid}")
48
+ tags_to_add.push("issue~#{slug.gsub('/', '~')}_#{iid}")
49
+ tags_to_add.push("issue_#{project.id}_#{iid}")
50
+ end
51
+ end
52
+ elsif link =~ %r{/-/merge_requests/[0-9]+}
53
+ slug = link.split("#{domain}/").last.split(%r{/-/merge_requests/[0-9]+}).first
54
+ project = Readiness::GitLab::Projects.find(@gitlab_client, CGI.escape(slug))
55
+ unless project.is_a? Hash
56
+ iid = link.split('/').last
57
+ mr = Readiness::GitLab::MergeRequests.find(@gitlab_client, project, iid)
58
+ unless mr['message']
59
+ tags_to_add.push('gitlab_merge_request_link')
60
+ tags_to_add.push("#{slug.gsub('/', '_')}_merge_requests_#{iid}")
61
+ tags_to_add.push("mergerequest~#{slug.gsub('/', '~')}_#{iid}")
62
+ tags_to_add.push("mergerequest_#{project.id}_#{iid}")
63
+ end
64
+ end
65
+ end
66
+ elsif domain == 'docs.gitlab.com'
67
+ tags_to_add.push('docs_link')
68
+ elsif domain == 'handbook.gitlab.com'
69
+ tags_to_add.push('hb_link')
70
+ elsif domain == 'support.gitlab.com'
71
+ if link =~ %r{articles}
72
+ tags_to_add.push('kb_link') unless link =~ %r{4911284066204}
73
+ end
74
+ elsif call_domains.include? domain
75
+ tags_to_add.push('agent_offered_call')
76
+ end
77
+ end
78
+ if tags_to_add.uniq.count.zero?
79
+ puts 'No tags to add on this ticket'
80
+ exit 0
81
+ else
82
+ print "Adding #{tags_to_add.uniq.count} tag(s) to ticket..."
83
+ @ticket = Readiness::Zendesk::Tickets.find(@zendesk_client, @ticket_id)
84
+ new_ticket = Readiness::Zendesk::Tickets.new
85
+ new_ticket.id = @ticket.id
86
+ new_ticket.tags = @ticket.tags + tags_to_add.uniq
87
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
88
+ puts 'done'
89
+ end
90
+ end
91
+
92
+ def self.call_domains
93
+ [
94
+ 'calendly.com',
95
+ 'gitlab.zoom.us',
96
+ 'gitlabmtgs.webex.com',
97
+ 'teams.microsoft.com'
98
+ ]
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module Readiness.
4
+ module Readiness
5
+ # Defines the module TicketProcessor
6
+ module TicketProcessor
7
+ ##
8
+ # Defines the class LockedAccount within the module {Readiness::Zendesk}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.44
12
+ class LockedAccount < Readiness::Client
13
+ ##
14
+ # Process a Locked Account request
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.44
18
+ def self.process!(zendesk_client, ticket_id)
19
+ @zendesk_client = zendesk_client
20
+ @ticket_id = ticket_id
21
+ @ticket = Readiness::Zendesk::Tickets.find(@zendesk_client, @ticket_id)
22
+ puts 'No ticket found, so no org notes to add' if @ticket.is_a? Hash
23
+ exit 0 if @ticket.is_a? Hash
24
+
25
+ puts 'Ticket is closed, so no org notes to add' if @ticket.status == 'closed'
26
+ exit 0 if @ticket.status == 'closed'
27
+
28
+ new_ticket = Readiness::Zendesk::Tickets.new
29
+ new_ticket.id = @ticket.id
30
+ new_ticket.status = 'pending'
31
+ new_ticket.comment = { body: locked_account_comment }
32
+ new_ticket.custom_fields = [
33
+ { id: 360020735259, value: 'stage-frt' }
34
+ ]
35
+ Readiness::Zendesk::Tickets.update!(zendesk_client, new_ticket)
36
+ end
37
+
38
+ def self.locked_account_comment
39
+ <<~STRING
40
+ Hi,
41
+
42
+ Thank you for contacting GitLab support.
43
+
44
+ The account may be locked if the system has registered too many login attempts during a short period of time. It will be locked for 30 minutes, after which it will be unlocked automatically.
45
+
46
+ On GitLab.com, we can also lock an account when there are 3 or more failed login attempts within 24 hours. Upon successful login, you may be redirected to a verification page and an email message with a 6-digit code is sent to your _primary_ email account. Please check your email (including the spam folder) for a message with a 6-digit code to unlock your account.
47
+
48
+ Please let us know if you have any further questions or are unable to receive any emails for your account.
49
+ STRING
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module Readiness.
4
+ module Readiness
5
+ # Defines the module TicketProcessor
6
+ module TicketProcessor
7
+ ##
8
+ # Defines the class Namesquatting within the module {Readiness::Zendesk}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.44
12
+ class Namesquatting < Readiness::Client
13
+ ##
14
+ # Process a Blocked Account request
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.44
18
+ def self.process!(zendesk_client, gitlab_admin_client, ticket_id)
19
+ @zendesk_client = zendesk_client
20
+ @gitlab_admin_client = gitlab_admin_client
21
+ @ticket_id = ticket_id
22
+ @ticket = Readiness::Zendesk::Tickets.find(@zendesk_client, @ticket_id)
23
+ puts 'No ticket found, so no org notes to add' if @ticket.is_a? Hash
24
+ exit 0 if @ticket.is_a? Hash
25
+
26
+ puts 'Ticket is closed, so no org notes to add' if @ticket.status == 'closed'
27
+ exit 0 if @ticket.status == 'closed'
28
+
29
+ return not_for_free_users unless paid_tags.any? { |t| @ticket.tags.include? t }
30
+ return invalid_namespace if Readiness::GitLab::Namespaces.exists?(@gitlab_admin_client, namespace_to_check)
31
+ return rejection_request if Readiness::GitLab::Namespaces.is_paid?(@gitlab_admin_client, namespace)
32
+
33
+ group_checks if namespace.kind == 'group'
34
+ user_checks if namespace.kind == 'user'
35
+ # check if free user ticket, if so reject
36
+ # check if valid namespace, if not reject
37
+ # check if namespace is paid, if so reject
38
+ # group checks
39
+ # immediate if zero projects and not created within 6 months
40
+ # immediate if no data and not created within 6 months
41
+ # reject if recent activity
42
+ # immediate_release if !(projects || data) && not recent owner signin
43
+ # contact_owner(owners)
44
+ # user checks
45
+ # immediate if unconfirmed and created within 90 days
46
+ # immediate if (no recent signing AND not only maintainer) AND projects have no data
47
+ # contact owner if (!recent_signin?(user) && !only_maintainer?(user)) && projects_have_data?(user)
48
+ # reject
49
+ end
50
+
51
+ def self.group_checks
52
+ group = Readiness::GitLab::Groups.new
53
+ group.id = namespace.id
54
+ request = @gitlab_admin_client.connection.get "groups/#{namespace.id}"
55
+ group_data = Oj.load(request.body)
56
+ has_data = false
57
+ recent_activity = false
58
+ projects = Readiness::GitLab::Groups.projects(@gitlab_admin_client, group, ["archived=false", "include_subgroups=true"])
59
+ members = Readiness::GitLab::Groups.members(@gitlab_admin_client, group)
60
+ owners_list = members.select { |m| m['access_level'] == 50 }
61
+ owners = []
62
+
63
+ projects.each do |p|
64
+ has_data = true if p.empty_repo
65
+ recent_activity = true if (Date.today - 2.years) < Date.parse(p.last_activity_at)
66
+ end
67
+ created_recently = Date.parse(group_data['created_at']) <= (Date.today + 6.months)
68
+ return immediate_release if projects.count.zero? && !created_recently
69
+ return immediate_release if !has_data && !created_recently
70
+ return rejection_request if recent_activity
71
+
72
+ owners_list.each do |o|
73
+ search = Readiness::GitLab::Users.search_by_username(@gitlab_admin_client, i['username'])
74
+ owners.push(search.detect { |s| s.username.downcase == i['username'].downcase })
75
+ end
76
+ recent_owner_signin = false
77
+ owners.compact.each do |o|
78
+ recent_owner_signin = true if (Date.today - 2.years) < Date.parse(o.last_sign_in_at)
79
+ end
80
+ return immediate_release if (projects.count.zero? || !has_data) && !recent_owner_signin
81
+
82
+ contact_owner(owners)
83
+ end
84
+
85
+ def self.user_checks
86
+ search = Readiness::GitLab::Users.search_by_username(@gitlab_admin_client, namespace_to_check)
87
+ user_namespace = search.detect { |s| s.username.downcase == namespace_to_check.downcase }
88
+ created_recently = (Date.today - 90.days) < Date.parse(user_namespace.created_at)
89
+ return immediate_release if user_namespace.confirmed_at.nil? && !created_recently
90
+
91
+ has_data = false
92
+ projects = Readiness::GitLab::Users.projects(@gitlab_admin_client, user_namespace, ["archived=false"])
93
+ projects.each do |p|
94
+ has_data = true if p.empty_repo
95
+ break if has_data
96
+ end
97
+ maintainer_check = Readiness::GitLab::Users.only_maintainer?(@gitlab_admin_client, user_namespace)
98
+ recent_signin = (Date.today - 90.days) < Date.parse(user_namespace.created_at)
99
+ return immediate_release if (!created_recently && !maintainer_check) && !has_data
100
+ return contact_owner([user_namespace]) if (!recent_signin && !maintainer_check) && has_data
101
+
102
+ rejection_request
103
+ end
104
+
105
+ def self.paid_tags
106
+ %w[priority-prospect ultimater premium gold silver]
107
+ end
108
+
109
+ def self.namespace
110
+ @namespace ||= Readiness::GitLab::Namespaces.find(@gitlab_admin_client, namespace_to_check)
111
+ end
112
+
113
+ def self.namespace_to_check
114
+ @namespace_to_check ||= ENV.fetch('NAMESPACE')
115
+ end
116
+
117
+ def self.not_for_free_users
118
+ new_ticket = Readiness::Zendesk::Tickets.new
119
+ new_ticket.id = @ticket.id
120
+ new_ticket.status = 'solved'
121
+ new_ticket.comment = { body: not_for_free_users_comment, public: true }
122
+ new_ticket.custom_fields = [
123
+ { id: 360020735259, value: 'stage-frt' }
124
+ ]
125
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
126
+ end
127
+
128
+ def self.invalid_namespace
129
+ new_ticket = Readiness::Zendesk::Tickets.new
130
+ new_ticket.id = @ticket.id
131
+ new_ticket.status = 'solved'
132
+ new_ticket.comment = { body: invalid_namespace_comment, public: true }
133
+ new_ticket.custom_fields = [
134
+ { id: 360020735259, value: 'stage-frt' }
135
+ ]
136
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
137
+ end
138
+
139
+ def self.immediate_release
140
+ new_ticket = Readiness::Zendesk::Tickets.new
141
+ new_ticket.id = @ticket.id
142
+ new_ticket.comment = { body: immediate_release_comment, public: false }
143
+ new_ticket.custom_fields = [
144
+ { id: 360020735259, value: 'stage-frt' }
145
+ ]
146
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
147
+ end
148
+
149
+ def self.rejection_request
150
+ new_ticket = Readiness::Zendesk::Tickets.new
151
+ new_ticket.id = @ticket.id
152
+ new_ticket.status = 'solved'
153
+ new_ticket.comment = { body: rejection_request_comment, public: true }
154
+ new_ticket.custom_fields = [
155
+ { id: 360020735259, value: 'stage-frt' }
156
+ ]
157
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
158
+ end
159
+
160
+ def self.contact_owner(owners)
161
+ new_ticket = Readiness::Zendesk::Tickets.new
162
+ new_ticket.id = @ticket.id
163
+ new_ticket.comment = { body: contact_owner_comment(owners), public: true }
164
+ new_ticket.custom_fields = [
165
+ { id: 360020735259, value: 'stage-frt' }
166
+ ]
167
+ Readiness::Zendesk::Tickets.update!(@zendesk_client, new_ticket)
168
+ end
169
+
170
+ def self.not_for_free_users_comment
171
+ <<~STRING
172
+ Hello,
173
+
174
+ Thank you for reaching out.
175
+
176
+ Please note that According to our [Name Squatting Policy](https://about.gitlab.com/support/gitlab-com-policies/#name-squatting-policy), namespaces may be released when they meet the appropriate criteria, and requested **by a member of paid namespace**.
177
+
178
+ Unfortunately your account doesn't appear to be part of a paid namespace so it isn't eligible for the namesquatting policy. If you believe we made a mistake and you are a part of the paid namespace please let us know and we will revisit this request.
179
+
180
+ I'll mark this ticket as solved, please reach out if you have any further questions.
181
+ STRING
182
+ end
183
+
184
+ def self.invalid_namespace_comment
185
+ <<~STRING
186
+ Hello,
187
+
188
+ We were unable to locate the namespace `#{namespace_to_check}` on gitlab.com at this time. As such, this should mean you are able to utilize it for your setup.
189
+
190
+ I'll mark this ticket as solved, please reach out if you have any further questions.
191
+ STRING
192
+ end
193
+
194
+ def self.immediate_release_comment
195
+ <<~STRING
196
+ The namespace checks for #{namespace_to_check} have determined it is available for immediate release.
197
+ STRING
198
+ end
199
+
200
+ def self.rejection_request_comment
201
+ <<~STRING
202
+ Hello,
203
+
204
+ The namespace requested `#{namespace_to_check}` is **not eligible** for release in accordance with our [Name Squatting Policy](https://about.gitlab.com/support/gitlab-com-policies/#name-squatting-policy) and we are unable to process your request. As per our [Subscription Agreement](https://about.gitlab.com/handbook/legal/subscription-agreement/#5-restrictions-and-responsibilities) point 5.8, `Account names are administered by GitLab on a "first come, first served" basis`.
205
+
206
+ Please note often activity cannot be seen for private namespaces, so activity on a profile is not a true indicator of whether a namespace is active. Profiles can also be made private which also hides activity from public view.
207
+
208
+ I'll mark this ticket as solved, please reach out if you have any further questions.
209
+ STRING
210
+ end
211
+
212
+ def self.contact_owner_comment(owners)
213
+ <<~STRING
214
+ The namespace checks for #{namespace_to_check} have determined it might be eligible for release after contacting owners.
215
+
216
+ The list of owner emails are:
217
+
218
+ #{owners.map { |o| "- #{o.email}" }.join("\n")}
219
+ STRING
220
+ end
221
+ end
222
+ end
223
+ end