class Lita::Gsuite

Constants

COMMANDS
OOB_OAUTH_URI
TIMER_INTERVAL
WINDOW_COMMANDS

Public Instance Methods

account_summary(response) click to toggle source
# File lib/lita/gsuite.rb, line 63
def account_summary(response)
  return unless confirm_user_authenticated(response)

  Commands::AccountSummary.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user)
  )
end
deletion_candidates(response) click to toggle source
# File lib/lita/gsuite.rb, line 73
def deletion_candidates(response)
  return unless confirm_user_authenticated(response)

  Commands::DeletionCandidates.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end
empty_groups(response) click to toggle source
# File lib/lita/gsuite.rb, line 84
def empty_groups(response)
  return unless confirm_user_authenticated(response)

  Commands::EmptyGroups.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end
list_admins(response) click to toggle source
# File lib/lita/gsuite.rb, line 95
def list_admins(response)
  return unless confirm_user_authenticated(response)

  Commands::ListAdmins.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end
no_org_unit(response) click to toggle source
# File lib/lita/gsuite.rb, line 106
def no_org_unit(response)
  return unless confirm_user_authenticated(response)

  Commands::NoOrgUnit.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end
schedule_add_weekly(response) click to toggle source
# File lib/lita/gsuite.rb, line 201
def schedule_add_weekly(response)
  return unless confirm_user_authenticated(response)

  _, day, time, cmd_name = *response.match_data

  schedule = WeeklySchedule.new(
    id: SecureRandom.hex(3),
    day: day,
    time: time,
    cmd: COMMANDS.fetch(cmd_name.downcase, nil),
    user_id: response.user.id,
    room_id: response.room.id,
  )
  if schedule.valid?
    redis.hmset("weekly-schedule", schedule.id, schedule.to_json)
    response.reply("scheduled command")
  else
    response.reply("invalid command")
  end
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
schedule_add_window(response) click to toggle source
# File lib/lita/gsuite.rb, line 224
def schedule_add_window(response)
  return unless confirm_user_authenticated(response)

  cmd_name = response.match_data[1].to_s
  schedule = WindowSchedule.new(
    id: SecureRandom.hex(3),
    cmd: WINDOW_COMMANDS.fetch(cmd_name.downcase, nil),
    user_id: response.user.id,
    room_id: response.room.id,
  )
  if schedule.valid?
    redis.hmset("window-schedule", schedule.id, schedule.to_json)
    response.reply("scheduled command")
  else
    response.reply("invalid command")
  end
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
schedule_commands(response) click to toggle source
# File lib/lita/gsuite.rb, line 187
def schedule_commands(response)
  msg = "The following commands are available for scheduling weekly:\n\n"
  COMMANDS.each do |cmd_name, cmd_klass|
    msg += "- #{cmd_name}\n"
  end
  msg += "The following commands are available for scheduling for sliding windows:\n\n"
  WINDOW_COMMANDS.each do |cmd_name, cmd_klass|
    msg += "- #{cmd_name}\n"
  end
  response.reply(msg)
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
schedule_delete(response) click to toggle source
# File lib/lita/gsuite.rb, line 244
def schedule_delete(response)
  cmd_id = response.match_data[1].to_s

  count = redis.hdel("weekly-schedule", cmd_id)
  count += redis.hdel("window-schedule", cmd_id)
  if count > 0
    response.reply("scheduled command #{cmd_id} deleted")
  else
    response.reply("no scheduled command with ID #{cmd_id} found")
  end
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
schedule_list(response) click to toggle source
# File lib/lita/gsuite.rb, line 172
def schedule_list(response)
  room_commands = (weekly_commands_for_room(response.room.name) + window_commands_for_room(response.room.name)).select { |cmd|
    cmd.room_id == response.room.id
  }
  if room_commands.any?
    room_commands.each do |cmd|
      response.reply("#{cmd.human}")
    end
  else
    response.reply("no scheduled commands for this room")
  end
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
set_token(response) click to toggle source
# File lib/lita/gsuite.rb, line 163
def set_token(response)
  auth_code = response.match_data[1].to_s

  google_authorizer.get_and_store_credentials_from_code(user_id: response.user.id, code: auth_code, base_url: OOB_OAUTH_URI)
  response.reply("#{response.user.name} now authorized")
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
start_auth(response) click to toggle source
# File lib/lita/gsuite.rb, line 151
def start_auth(response)
  credentials = google_credentials_for_user(response.user)
  url = google_authorizer.get_authorization_url(base_url: OOB_OAUTH_URI)
  if credentials.nil?
    response.reply "Open the following URL in your browser and enter the resulting code via the 'gsuite set-token <foo>' command:\n\n#{url}"
  else
    response.reply "#{response.user.name} is already authorized with Google. To re-authorize, open the following URL in your browser and enter the resulting code via the 'gsuite set-token <foo>' command:\n\n#{url}"
  end
rescue StandardError => e
  response.reply("Error: #{e.class} #{e.message}")
end
start_timers(payload) click to toggle source
# File lib/lita/gsuite.rb, line 58
def start_timers(payload)
  weekly_commands_timer
  window_commands_timer
end
suspension_candidates(response) click to toggle source
# File lib/lita/gsuite.rb, line 117
def suspension_candidates(response)
  return unless confirm_user_authenticated(response)

  Commands::SuspensionCandidates.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end
two_factor_off(response) click to toggle source
# File lib/lita/gsuite.rb, line 128
def two_factor_off(response)
  return unless confirm_user_authenticated(response)

  ou_path = response.match_data[1].to_s
  Commands::TwoFactorOff.new(ou_path).run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end
two_factor_stats(response) click to toggle source
# File lib/lita/gsuite.rb, line 140
def two_factor_stats(response)
  return unless confirm_user_authenticated(response)

  Commands::TwoFactorStats.new.run(
    robot,
    Source.new(room: response.room),
    gateway(response.user),
    negative_ack: true
  )
end

Private Instance Methods

confirm_user_authenticated(response) click to toggle source
# File lib/lita/gsuite.rb, line 260
def confirm_user_authenticated(response)
  credentials = google_credentials_for_user(response.user)
  if credentials.nil?
    response.reply("#{response.user.name} not authorized with Google yet. Use the 'gsuite auth' command to initiate authorization")
    false
  else
    true
  end
end
every_with_logged_errors(interval) { || ... } click to toggle source
# File lib/lita/gsuite.rb, line 358
def every_with_logged_errors(interval, &block)
  every(interval) do
    logged_errors do
      yield
    end
  end
end
gateway(user) click to toggle source
# File lib/lita/gsuite.rb, line 376
def gateway(user)
  Lita::GsuiteGateway.new(
    user_authorization: google_authorizer.get_credentials(user.id)
  )
end
google_authorizer() click to toggle source
# File lib/lita/gsuite.rb, line 274
def google_authorizer
  @google_authorizer ||= begin
    client_id = Google::Auth::ClientId.new(
      config.oauth_client_id,
      config.oauth_client_secret
    )
    token_store = RedisTokenStore.new(redis)
    Google::Auth::UserAuthorizer.new(client_id, GsuiteGateway::OAUTH_SCOPES, token_store)
  end
end
google_credentials_for_user(user) click to toggle source
# File lib/lita/gsuite.rb, line 270
def google_credentials_for_user(user)
  google_authorizer.get_credentials(user.id)
end
logged_errors() { || ... } click to toggle source
# File lib/lita/gsuite.rb, line 366
def logged_errors(&block)
  yield
rescue StandardError => e
  $stderr.puts "Error in timer loop: #{e.class} #{e.message} #{e.backtrace.first}"
end
weekly_at(time, day, name, &block) click to toggle source
# File lib/lita/gsuite.rb, line 372
def weekly_at(time, day, name, &block)
  Lita::Timing::Scheduled.new(name, redis).weekly_at(time, day, &block)
end
weekly_commands() click to toggle source
# File lib/lita/gsuite.rb, line 326
def weekly_commands
  redis.hgetall("weekly-schedule").map { |_id, data|
    JSON.parse(data)
  }.map { |data|
    WeeklySchedule.new(
      id: data.fetch("id", "foo"),
      day: data.fetch("day", nil),
      time: data.fetch("time", "12:00"),
      room_id: data.fetch("room_id", nil),
      user_id: data.fetch("user_id", nil),
      cmd: COMMANDS.fetch(data.fetch("cmd", nil), nil),
    )
  }.select { |schedule|
    schedule.valid?
  }
end
weekly_commands_for_room(room_id) click to toggle source
# File lib/lita/gsuite.rb, line 314
def weekly_commands_for_room(room_id)
  weekly_commands.select { |cmd|
    cmd.room_id == room_id
  }
end
weekly_commands_timer() click to toggle source
# File lib/lita/gsuite.rb, line 285
def weekly_commands_timer
  every_with_logged_errors(TIMER_INTERVAL) do |timer|
    weekly_commands.each do |cmd|
      weekly_at(cmd.time, cmd.day, "#{cmd.id}-#{cmd.name}") do
        target = Source.new(
          room: Lita::Room.create_or_update(cmd.room_id)
        )
        user = Lita::User.find_by_id(cmd.user_id)
        cmd.run(robot, target, gateway(user))
      end
    end
  end
end
window_commands() click to toggle source
# File lib/lita/gsuite.rb, line 343
def window_commands
  redis.hgetall("window-schedule").map { |_id, data|
    JSON.parse(data)
  }.map { |data|
    WindowSchedule.new(
      id: data.fetch("id", nil),
      room_id: data.fetch("room_id", nil),
      user_id: data.fetch("user_id", nil),
      cmd: WINDOW_COMMANDS.fetch(data.fetch("cmd", nil), nil),
    )
  }.select { |schedule|
    schedule.valid?
  }
end
window_commands_for_room(room_id) click to toggle source
# File lib/lita/gsuite.rb, line 320
def window_commands_for_room(room_id)
  window_commands.select { |cmd|
    cmd.room_id == room_id
  }
end
window_commands_timer() click to toggle source
# File lib/lita/gsuite.rb, line 299
def window_commands_timer
  every_with_logged_errors(TIMER_INTERVAL) do |timer|
    window_commands.each do |cmd|
      target = Source.new(
          room: Lita::Room.create_or_update(cmd.room_id)
      )
      user = Lita::User.find_by_id(cmd.user_id)
      sliding_window ||= Lita::Timing::SlidingWindow.new("#{cmd.id}-#{cmd.name}", redis)
      sliding_window.advance(duration_minutes: cmd.duration_minutes, buffer_minutes: cmd.buffer_minutes) do |window_start, window_end|
        cmd.run(robot, target, gateway(user), window_start, window_end)
      end
    end
  end
end