chromium/ash/edusumer/graduation_utils.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/edusumer/graduation_utils.h"

#include <optional>

#include "ash/constants/ash_pref_names.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/prefs/pref_service.h"

namespace ash::graduation {

namespace {
// Dictionary keys used for accessing kGraduationEnablementStatus pref values.
constexpr char kIsEnabledKey[] = "is_enabled";
constexpr char kStartDateKey[] = "start_date";
constexpr char kEndDateKey[] = "end_date";
constexpr char kDayKey[] = "day";
constexpr char kMonthKey[] = "month";
constexpr char kYearKey[] = "year";

// Returns a Time object representing a date at local midnight if the date is
// valid. Returns std::nullopt if the date is invalid.
std::optional<base::Time> GetLocalMidnightTimeForDate(
    const base::Value::Dict* date) {
  CHECK(date);
  std::optional<int> day = date->FindInt(kDayKey);
  std::optional<int> month = date->FindInt(kMonthKey);
  std::optional<int> year = date->FindInt(kYearKey);
  if (!day || !month || !year) {
    return std::nullopt;
  }

  base::Time::Exploded exploded;
  exploded.day_of_month = *day;
  exploded.month = *month;
  exploded.year = *year;
  exploded.hour = 0;
  exploded.minute = 0;
  exploded.second = 0;
  exploded.millisecond = 0;

  base::Time time;
  bool date_exists = base::Time::FromLocalExploded(exploded, &time);
  if (!date_exists) {
    return std::nullopt;
  }
  return time.LocalMidnight();
}
}  // namespace

bool IsEligibleForGraduation(PrefService* pref_service) {
  CHECK(pref_service);
  const base::Value::Dict& graduation_policy_pref =
      pref_service->GetDict(prefs::kGraduationEnablementStatus);
  if (graduation_policy_pref.empty()) {
    return false;
  }

  bool is_enabled =
      graduation_policy_pref.FindBool(kIsEnabledKey).value_or(false);
  if (!is_enabled) {
    return false;
  }

  // Compare the current date at local midnight time to the start and end dates
  // at local midnight time.
  base::Time current_time = base::Time::Now().LocalMidnight();

  const base::Value::Dict* start_date_dict =
      graduation_policy_pref.FindDict(kStartDateKey);
  if (start_date_dict) {
    std::optional<base::Time> start_time =
        GetLocalMidnightTimeForDate(start_date_dict);
    if (!start_time) {
      return false;
    }
    if (current_time < *start_time) {
      return false;
    }
  }

  const base::Value::Dict* end_date_dict =
      graduation_policy_pref.FindDict(kEndDateKey);
  if (end_date_dict) {
    std::optional<base::Time> end_time =
        GetLocalMidnightTimeForDate(end_date_dict);
    if (!end_time) {
      return false;
    }
    if (current_time > *end_time) {
      return false;
    }
  }

  return true;
}
}  // namespace ash::graduation