Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bin/action-account
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby

ENV['LOGIN_TASK_LOG_LEVEL'] ||= 'warn'
require_relative '../config/environment.rb'
require 'action_account'
ActionAccount.new(argv: ARGV.dup, stdout: STDOUT, stderr: STDERR).run
144 changes: 144 additions & 0 deletions lib/action_account.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
require_relative './script_base'

class ActionAccount
attr_reader :argv, :stdout, :stderr

def initialize(argv:, stdout:, stderr:)
@argv = argv
@stdout = stdout
@stderr = stderr
end

def script_base
@script_base ||= ScriptBase.new(
argv:,
stdout:,
stderr:,
subtask_class: subtask(argv.shift),
banner: banner,
)
end

def run
script_base.run
end

def banner
basename = File.basename($PROGRAM_NAME)
<<~EOS
#{basename} [subcommand] [arguments] [options]
Example usage:

* #{basename} review-reject uuid1 uuid2

* #{basename} review-pass uuid1 uuid2

Options:
EOS
end

# @api private
# A subtask is a class that has a run method, the type signature should look like:
# +#run(args: Array<String>, config: Config) -> Result+
# @return [Class,nil]
def subtask(name)
{
'review-reject' => ReviewReject,
'review-pass' => ReviewPass,
}[name]
end

class ReviewReject
def run(args:, config:)
uuids = args

users = User.where(uuid: uuids).order(:uuid)

table = []
table << %w[uuid status]

users.each do |user|
if !user.fraud_review_pending?
table << [user.uuid, 'Error: User does not have a pending fraud review']
next
end

if FraudReviewChecker.new(user).fraud_review_eligible?
profile = user.fraud_review_pending_profile
profile.reject_for_fraud(notify_user: true)

table << [user.uuid, "User's profile has been deactivated due to fraud rejection."]
else
table << [user.uuid, 'User is past the 30 day review eligibility']
end
end

if config.include_missing?
(uuids - users.map(&:uuid)).each do |missing_uuid|
table << [missing_uuid, 'Error: Could not find user with that UUID']
end
end

ScriptBase::Result.new(
subtask: 'review-reject',
uuids: users.map(&:uuid),
table:,
)
end
end

class ReviewPass
def run(args:, config:)
uuids = args

users = User.where(uuid: uuids).order(:uuid)

table = []
table << %w[uuid status]

users.each do |user|
if !user.fraud_review_pending?
table << [user.uuid, 'Error: User does not have a pending fraud review']
next
end

if FraudReviewChecker.new(user).fraud_review_eligible?
profile = user.fraud_review_pending_profile
profile.activate_after_passing_review

if profile.active?
event, _disavowal_token = UserEventCreator.new(current_user: user).
create_out_of_band_user_event(:account_verified)

UserAlerts::AlertUserAboutAccountVerified.call(
user: user,
date_time: event.created_at,
sp_name: nil,
)

table << [user.uuid, "User's profile has been activated and the user has been emailed."]
else
table << [
user.uuid,
"There was an error activating the user's profile. Please try again",
]
end
else
table << [user.uuid, 'User is past the 30 day review eligibility']
end
end

if config.include_missing?
(uuids - users.map(&:uuid)).each do |missing_uuid|
table << [missing_uuid, 'Error: Could not find user with that UUID']
end
end

ScriptBase::Result.new(
subtask: 'review-pass',
uuids: users.map(&:uuid),
table:,
)
end
end
end
160 changes: 27 additions & 133 deletions lib/data_pull.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'optparse'
require_relative './script_base'

class DataPull
attr_reader :argv, :stdout, :stderr
Expand All @@ -9,91 +9,39 @@ def initialize(argv:, stdout:, stderr:)
@stderr = stderr
end

Result = Struct.new(
:table, # tabular output, rendered as an ASCII table or as CSV
:json, # output that should only be formatted as JSON
:subtask, # name of subtask, used for audit logging
:uuids, # Array of UUIDs entered or returned, used for audit logging
keyword_init: true,
)

Config = Struct.new(
:include_missing,
:format,
:show_help,
:requesting_issuers,
keyword_init: true,
) do
alias_method :include_missing?, :include_missing
alias_method :show_help?, :show_help
end

def config
@config ||= Config.new(
include_missing: true,
format: :table,
show_help: false,
requesting_issuers: [],
def script_base
@script_base ||= ScriptBase.new(
argv:,
stdout:,
stderr:,
subtask_class: subtask(argv.shift),
banner: banner,
)
end

def run
option_parser.parse!(argv)
subtask_class = subtask(argv.shift)
script_base.run
end

if config.show_help? || !subtask_class
stderr.puts '*Task*: `help`'
stderr.puts '*UUIDs*: N/A'
def banner
basename = File.basename($PROGRAM_NAME)
<<~EOS
#{basename} [subcommand] [arguments] [options]

stdout.puts option_parser
return
end
Example usage:

result = subtask_class.new.run(args: argv, config:)
* #{basename} uuid-lookup email1@example.com email2@example.com

stderr.puts "*Task*: `#{result.subtask}`"
stderr.puts "*UUIDs*: #{result.uuids.map { |uuid| "`#{uuid}`" }.join(', ')}"
* #{basename} uuid-convert partner-uuid1 partner-uuid2

if result.json
stdout.puts result.json.to_json
else
render_output(result.table)
end
end
* #{basename} email-lookup uuid1 uuid2

# @param [Array<Array<String>>] rows
def render_output(rows)
return if rows.blank?

case config.format
when :table
require 'terminal-table'
table = Terminal::Table.new
header, *body = rows
table << header
table << :separator
body.each do |row|
table << row
end
stdout.puts table
when :csv
require 'csv'
CSV.instance(stdout) do |csv|
rows.each do |row|
csv << row
end
end
when :json
headers, *body = rows
* #{basename} ig-request uuid1 uuid2 --requesting-issuer ABC:DEF:GHI

objects = body.map do |values|
headers.zip(values).to_h
end
* #{basename} profile-summary uuid1 uuid2

stdout.puts JSON.pretty_generate(objects)
else
raise "Unknown format=#{config.format}"
end
Options:
EOS
end

# @api private
Expand All @@ -110,60 +58,6 @@ def subtask(name)
}[name]
end

# rubocop:disable Metrics/BlockLength
def option_parser
basename = File.basename($PROGRAM_NAME)

@option_parser ||= OptionParser.new do |opts|
opts.banner = <<~EOS
#{basename} [subcommand] [arguments] [options]

Example usage:

* #{basename} uuid-lookup email1@example.com email2@example.com

* #{basename} uuid-convert partner-uuid1 partner-uuid2

* #{basename} email-lookup uuid1 uuid2

* #{basename} ig-request uuid1 uuid2 --requesting-issuer ABC:DEF:GHI

* #{basename} profile-summary uuid1 uuid2

Options:
EOS

opts.on('-i=ISSUER', '--requesting-issuer=ISSUER', <<-MSG) do |issuer|
requesting issuer (used for ig-request task)
MSG
config.requesting_issuers << issuer
end

opts.on('--help') do
config.show_help = true
end

opts.on('--csv') do
config.format = :csv
end

opts.on('--table', 'Output format as an ASCII table (default)') do
config.format = :table
end

opts.on('--json') do
config.format = :json
end

opts.on('--[no-]include-missing', <<~STR) do |include_missing|
Whether or not to add rows in the output for missing inputs, defaults to on
STR
config.include_missing = include_missing
end
end
end
# rubocop:enable Metrics/BlockLength

class UuidLookup
def run(args:, config:)
emails = args
Expand All @@ -183,7 +77,7 @@ def run(args:, config:)
end
end

Result.new(
ScriptBase::Result.new(
subtask: 'uuid-lookup',
table:,
uuids:,
Expand All @@ -209,7 +103,7 @@ def run(args:, config:)
end
end

Result.new(
ScriptBase::Result.new(
subtask: 'uuid-convert',
uuids: identities.map { |u| u.user.uuid },
table:,
Expand Down Expand Up @@ -238,7 +132,7 @@ def run(args:, config:)
end
end

Result.new(
ScriptBase::Result.new(
subtask: 'email-lookup',
uuids: users.map(&:uuid),
table:,
Expand All @@ -259,7 +153,7 @@ def run(args:, config:)
DataRequests::Deployed::CreateUserReport.new(user, config.requesting_issuers).call
end

Result.new(
ScriptBase::Result.new(
subtask: 'ig-request',
uuids: users.map(&:uuid),
json: output,
Expand Down Expand Up @@ -310,7 +204,7 @@ def run(args:, config:)
end
end

Result.new(
ScriptBase::Result.new(
subtask: 'profile-summary',
uuids: users.map(&:uuid),
table:,
Expand Down
Loading