<commit_before><?php

namespace App;

use App\Exceptions\CURLRequestException;
use App\Models\Cutiemark;
use App\Models\PreviousUsername;
use App\Models\DeviantartUser;
use App\Models\Post;
use App\Models\Session;
use App\Models\User;
use Exception;
use InvalidArgumentException;
use RuntimeException;

class Users {
  public const RESERVATION_LIMIT = 4;

  // Global cache for storing DA user details
  public static array $da_user_cache = [];
  public static array $preferences_cache = [];

  /**
   * User Information Retriever
   * --------------------------
   * Gets a single row from the 'users' database where $column is equal to $value
   * Returns null if user is not found and false if user data could not be fetched
   *
   * @param string $value
   * @param string $column
   *
   * @return DeviantartUser|null
   * @throws Exception
   */
  public static function getDA(string $value, string $column = 'id'):?DeviantartUser {
    if ($column === 'id')
      return DeviantartUser::find($value);

    if ($column === 'name' && !empty(self::$da_user_cache[$value]))
      return self::$da_user_cache[$value];

    $user = DB::$instance->where($column, $value)->getOne('deviantart_users');

    if (empty($user) && $column === 'name'){
      if (Regexes::$username->match($value)){
        $user = self::fetchDA($value);
      }
    }

    if (isset($user->name))
      self::$da_user_cache[$user->name] = $user;

    return $user;
  }

  /**
   * User Information Fetching
   * -------------------------
   * Fetch user info from DeviantArt's API
   * If multiple usernames are passed as an array it will not return a value
   *
   * @param string $username
   *
   * @return DeviantartUser|null
   * @throws Exception
   */
  public static function fetchDA(string $username):?DeviantartUser {
    $via_previous_name = PreviousUsername::find_by_username($username);
    if (!empty($via_previous_name)) {
      return $via_previous_name->user;
    }

    if (Auth::$session->access === null)
      return null;

    $fetch_params = ["usernames[0]" => $username];

    try {
      $user_data = DeviantArt::request('user/whois', null, $fetch_params);
    }
    catch (CURLRequestException $e){
      return null;
    }

    if (empty($user_data['results'][0]))
      return null;

    $user_data  = $user_data['results'][0];
    $save_success = false;
    $id = strtolower($user_data['userid']);

    $da_user = DeviantartUser::find($id);
    $user_exists = $da_user !== null;
    if (!$user_exists) {
      /** @var User $user */
      $user = User::create([
        'name' => $user_data['username'],
      ]);

      $da_user = new DeviantartUser([
        'id' => $id,
        'created_at' => date('c'),
        'user_id' => $user->id,
      ]);
    }
    else $user = $da_user->user;

    $da_user->name = $user_data['username'];
    $da_user->avatar_url = URL::makeHttps($user_data['usericon']);
    if ($da_user->save())
      $save_success = true;

    $user->assignCorrectRole();

    if (!$save_success)
      throw new RuntimeException('Saving user data failed'.(Permission::sufficient('developer') ? ': '.DB::$instance->getLastError() : ''));

    if ($user_exists) {
      $previous_name = $da_user->user->name;
      if (strcasecmp($previous_name, $da_user->name) !== 0) {
        $da_user->user->update_attributes(['name' => $da_user->name]);
        PreviousUsername::record($da_user->id, $previous_name);
      }
    }

    return $da_user;
  }

  /**
   * Check maximum simultaneous reservation count
   *
   * @param bool $return_as_bool
   *
   * @return bool|null
   */
  public static function checkReservationLimitReached(bool $return_as_bool = false) {
    $resserved_count = DB::$instance
      ->where('reserved_by', Auth::$user->id)
      ->where('deviation_id IS NULL')
      ->count('posts');

    $overTheLimit = !empty($resserved_count) && $resserved_count >= self::RESERVATION_LIMIT;
    if ($return_as_bool)
      return $overTheLimit;<commit_msg>More fixing of creation of previous username records<commit_after><?php

namespace App;

use App\Exceptions\CURLRequestException;
use App\Models\Cutiemark;
use App\Models\PreviousUsername;
use App\Models\DeviantartUser;
use App\Models\Post;
use App\Models\Session;
use App\Models\User;
use Exception;
use InvalidArgumentException;
use RuntimeException;

class Users {
  public const RESERVATION_LIMIT = 4;

  // Global cache for storing DA user details
  public static array $da_user_cache = [];
  public static array $preferences_cache = [];

  /**
   * User Information Retriever
   * --------------------------
   * Gets a single row from the 'users' database where $column is equal to $value
   * Returns null if user is not found and false if user data could not be fetched
   *
   * @param string $value
   * @param string $column
   *
   * @return DeviantartUser|null
   * @throws Exception
   */
  public static function getDA(string $value, string $column = 'id'):?DeviantartUser {
    if ($column === 'id')
      return DeviantartUser::find($value);

    if ($column === 'name' && !empty(self::$da_user_cache[$value]))
      return self::$da_user_cache[$value];

    $user = DB::$instance->where($column, $value)->getOne('deviantart_users');

    if (empty($user) && $column === 'name'){
      if (Regexes::$username->match($value)){
        $user = self::fetchDA($value);
      }
    }

    if (isset($user->name))
      self::$da_user_cache[$user->name] = $user;

    return $user;
  }

  /**
   * User Information Fetching
   * -------------------------
   * Fetch user info from DeviantArt's API
   * If multiple usernames are passed as an array it will not return a value
   *
   * @param string $username
   *
   * @return DeviantartUser|null
   * @throws Exception
   */
  public static function fetchDA(string $username):?DeviantartUser {
    $via_previous_name = PreviousUsername::find_by_username($username);
    if (!empty($via_previous_name)) {
      return $via_previous_name->user;
    }

    if (Auth::$session->access === null)
      return null;

    $fetch_params = ["usernames[0]" => $username];

    try {
      $user_data = DeviantArt::request('user/whois', null, $fetch_params);
    }
    catch (CURLRequestException $e){
      return null;
    }

    if (empty($user_data['results'][0]))
      return null;

    $user_data  = $user_data['results'][0];
    $save_success = false;
    $id = strtolower($user_data['userid']);

    $da_user = DeviantartUser::find($id);
    $user_exists = $da_user !== null;
    if (!$user_exists) {
      /** @var User $user */
      $user = User::create([
        'name' => $user_data['username'],
      ]);

      $da_user = new DeviantartUser([
        'id' => $id,
        'created_at' => date('c'),
        'user_id' => $user->id,
      ]);
    }
    else $user = $da_user->user;

    $da_user->name = $user_data['username'];
    $da_user->avatar_url = URL::makeHttps($user_data['usericon']);
    if ($da_user->save())
      $save_success = true;

    $user->assignCorrectRole();

    if (!$save_success)
      throw new RuntimeException('Saving user data failed'.(Permission::sufficient('developer') ? ': '.DB::$instance->getLastError() : ''));

    if ($user_exists) {
      $previous_name = $da_user->user->name;
      foreach ([$previous_name, $username] as $i => $old_name) {
        if (strcasecmp($old_name, $da_user->name) === 0)
          continue;

        PreviousUsername::record($da_user->id, $old_name);
        if ($i === 0) {
          $da_user->user->update_attributes(['name' => $da_user->name]);
        }
      }
    }

    return $da_user;
  }

  /**
   * Check maximum simultaneous reservation count
   *
   * @param bool $return_as_bool
   *
   * @return bool|null
   */
  public static function checkReservationLimitReached(bool $return_as_bool = false) {
    $resserved_count = DB::$instance
      ->where('reserved_by', Auth::$user->id)
      ->where('deviation_id IS NULL')
      ->count('posts');

    $overTheLimit = !empty($resserved_count) && $resserved_count >= self::RESERVATION_LIMIT;
    if ($return_as_bool)
      return $overTheLimit;
{'fraction_non_alphanumeric': 0.16340593084779131, 'fraction_numerical': 0.0013535129814199582, 'mean_word_length': 3.098840141200202, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6045425', 'n_tokens_mistral': 2615, 'n_tokens_neox': 2561, 'n_words': 580}