Fix deprecations

This commit is contained in:
DariusIII
2026-03-26 11:43:32 +01:00
parent 6aee2ef718
commit 0ea9125286
8 changed files with 314 additions and 83 deletions
+25 -4
View File
@@ -978,7 +978,7 @@ final class User extends Authenticatable implements MustVerifyEmailContract
return true;
}
$additionalDays = ($addYears ?? 0) * self::DAYS_PER_YEAR;
$additionalDays = self::resolveRoleDurationDays($roleModel, $addYears);
$promotionDays = $applyPromotions
? RolePromotion::calculateAdditionalDays($roleModel->id)
: 0;
@@ -1027,7 +1027,7 @@ final class User extends Authenticatable implements MustVerifyEmailContract
if ($pendingRole && $pendingStartDate) {
// Calculate when the pending role would expire
$pendingRoleBaseDays = $pendingRole->addyears * self::DAYS_PER_YEAR;
$pendingRoleBaseDays = self::resolveRoleDurationDays($pendingRole, null);
$pendingRolePromotionDays = ! in_array($pendingRole->name, self::PROMOTION_EXCLUDED_ROLES, true)
? RolePromotion::calculateAdditionalDays($pendingRole->id)
: 0;
@@ -1066,7 +1066,7 @@ final class User extends Authenticatable implements MustVerifyEmailContract
'hadPendingRole' => $user->hasPendingRole(),
]);
$baseDays = ($addYears ?? $roleModel->addyears) * self::DAYS_PER_YEAR;
$baseDays = self::resolveRoleDurationDays($roleModel, $addYears);
$promotionDays = ! in_array($roleModel->name, self::PROMOTION_EXCLUDED_ROLES, true) && $applyPromotions
? RolePromotion::calculateAdditionalDays($roleModel->id)
: 0;
@@ -1111,7 +1111,7 @@ final class User extends Authenticatable implements MustVerifyEmailContract
?int $changedBy,
bool $preserveCurrentExpiry,
): bool {
$baseDays = ($addYears ?? $roleModel->addyears) * self::DAYS_PER_YEAR;
$baseDays = self::resolveRoleDurationDays($roleModel, $addYears);
$promotionDays = ! in_array($roleModel->name, self::PROMOTION_EXCLUDED_ROLES, true) && $applyPromotions
? RolePromotion::calculateAdditionalDays($roleModel->id)
: 0;
@@ -1155,6 +1155,27 @@ final class User extends Authenticatable implements MustVerifyEmailContract
return $updated;
}
/**
* Resolve the number of role-duration days to apply.
*/
private static function resolveRoleDurationDays(Role $roleModel, ?int $addYears, bool $useRoleDefaultWhenMissing = true): int
{
if ($addYears !== null) {
return max(0, $addYears) * self::DAYS_PER_YEAR;
}
if (! $useRoleDefaultWhenMissing) {
return 0;
}
$rawAddYears = Role::query()->whereKey($roleModel->id)->value('addyears');
$roleAddYears = is_numeric($rawAddYears)
? (int) $rawAddYears
: (is_numeric($roleModel->addyears ?? null) ? (int) $roleModel->addyears : 0);
return max(0, $roleAddYears) * self::DAYS_PER_YEAR;
}
/**
* Track promotion application statistics.
*/
+26 -1
View File
@@ -1209,6 +1209,31 @@ class ReleaseSearchService
);
}
/**
* Build the lightweight paged ID query used by compatibility tests and targeted callers.
*
* @param array{0: string, 1: string} $orderBy
*/
protected function buildSearchPageIdsSql(string $whereSql, array $orderBy, int $limit, int $offset): string
{
return sprintf(
'SELECT r.id FROM releases r %s ORDER BY r.%s %s LIMIT %d OFFSET %d',
$whereSql,
$orderBy[0],
$orderBy[1],
$limit,
$offset,
);
}
/**
* Get a lightweight releases count directly from the releases table for compatibility callers.
*/
protected function getReleasesCountForWhere(string $whereSql): int
{
return $this->getPagerCount(sprintf('SELECT COUNT(*) as count FROM releases r %s', $whereSql));
}
/**
* Get the passworded releases clause.
*/
@@ -1255,7 +1280,7 @@ class ReleaseSearchService
*
* @param string $query The query to get the count from.
*/
private function getPagerCount(string $query): int
protected function getPagerCount(string $query): int
{
$maxResults = (int) config('nntmux.max_pager_results');
$cacheExpiry = config('nntmux.cache_expiry_short');
@@ -4,16 +4,82 @@ namespace Tests\Feature;
use App\Models\Country;
use Database\Seeders\CountriesTableSeeder;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use PDO;
use Tests\TestCase;
final class CountriesTableSeederTest extends TestCase
{
private string $databasePath = '';
/**
* @var array<string, string|false>
*/
private array $originalEnvironment = [];
public function createApplication()
{
$this->databasePath = sys_get_temp_dir().'/nntmux-countries-test.sqlite';
$this->originalEnvironment = [
'APP_ENV' => getenv('APP_ENV'),
'DB_CONNECTION' => getenv('DB_CONNECTION'),
'DB_DATABASE' => getenv('DB_DATABASE'),
];
if (file_exists($this->databasePath)) {
unlink($this->databasePath);
}
$pdo = new PDO('sqlite:'.$this->databasePath);
$pdo->exec('CREATE TABLE settings (name VARCHAR PRIMARY KEY, value TEXT NULL)');
$settings = [
'categorizeforeign' => '0',
'catwebdl' => '0',
'delaytime' => '2',
'crossposttime' => '2',
'maxnzbsprocessed' => '1000',
'completionpercent' => '100',
'collection_timeout' => '30',
'maxsizetoformrelease' => '10737418240',
'minsizetoformrelease' => '0',
'minfilestoformrelease' => '1',
'releaseretentiondays' => '0',
'deletepasswordedrelease' => '0',
'miscotherretentionhours' => '0',
'mischashedretentionhours' => '0',
'partretentionhours' => '0',
'last_run_time' => '',
];
$statement = $pdo->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
foreach ($settings as $name => $value) {
$statement->execute(['name' => $name, 'value' => $value]);
}
$this->setEnvironmentValue('APP_ENV', 'testing');
$this->setEnvironmentValue('DB_CONNECTION', 'sqlite');
$this->setEnvironmentValue('DB_DATABASE', $this->databasePath);
$app = require __DIR__.'/../../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
protected function setUp(): void
{
parent::setUp();
config([
'database.default' => 'sqlite',
'database.connections.sqlite.database' => $this->databasePath,
]);
Schema::dropIfExists('countries');
Schema::create('countries', function (Blueprint $table): void {
@@ -25,6 +91,19 @@ final class CountriesTableSeederTest extends TestCase
});
}
protected function tearDown(): void
{
if ($this->databasePath !== '' && file_exists($this->databasePath)) {
unlink($this->databasePath);
}
parent::tearDown();
foreach ($this->originalEnvironment as $key => $value) {
$this->setEnvironmentValue($key, $value === false ? null : $value);
}
}
public function test_it_seeds_countries_using_iso_codes_as_the_primary_key(): void
{
$this->seed(CountriesTableSeeder::class);
@@ -43,4 +122,18 @@ final class CountriesTableSeederTest extends TestCase
$this->assertSame('US', countryCode('United States of America'));
$this->assertSame('', countryCode('Atlantis'));
}
private function setEnvironmentValue(string $key, ?string $value): void
{
if ($value === null) {
putenv($key);
unset($_ENV[$key], $_SERVER[$key]);
return;
}
putenv($key.'='.$value);
$_ENV[$key] = $value;
$_SERVER[$key] = $value;
}
}
+139 -34
View File
@@ -4,35 +4,99 @@ namespace Tests\Feature;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use PDO;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;
use Tests\TestCase;
final class RoleUpgradeTest extends TestCase
{
private string $databasePath = '';
/**
* @var array<string, string|false>
*/
private array $originalEnvironment = [];
private User $user;
private Role $userRole;
private Role $supporterRole;
public function createApplication()
{
$this->databasePath = sys_get_temp_dir().'/nntmux-role-upgrade-test.sqlite';
$this->originalEnvironment = [
'APP_ENV' => getenv('APP_ENV'),
'DB_CONNECTION' => getenv('DB_CONNECTION'),
'DB_DATABASE' => getenv('DB_DATABASE'),
];
if (file_exists($this->databasePath)) {
unlink($this->databasePath);
}
$pdo = new PDO('sqlite:'.$this->databasePath);
$pdo->exec('CREATE TABLE settings (name VARCHAR PRIMARY KEY, value TEXT NULL)');
$settings = [
'categorizeforeign' => '0',
'catwebdl' => '0',
'delaytime' => '2',
'crossposttime' => '2',
'maxnzbsprocessed' => '1000',
'completionpercent' => '100',
'collection_timeout' => '30',
'maxsizetoformrelease' => '10737418240',
'minsizetoformrelease' => '0',
'minfilestoformrelease' => '1',
'releaseretentiondays' => '0',
'deletepasswordedrelease' => '0',
'miscotherretentionhours' => '0',
'mischashedretentionhours' => '0',
'partretentionhours' => '0',
'last_run_time' => '',
];
$statement = $pdo->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
foreach ($settings as $name => $value) {
$statement->execute(['name' => $name, 'value' => $value]);
}
$this->setEnvironmentValue('APP_ENV', 'testing');
$this->setEnvironmentValue('DB_CONNECTION', 'sqlite');
$this->setEnvironmentValue('DB_DATABASE', $this->databasePath);
$app = require __DIR__.'/../../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
protected function setUp(): void
{
parent::setUp();
// Use in-memory SQLite database for test isolation
config(['database.default' => 'sqlite', 'database.connections.sqlite.database' => ':memory:']);
config(['database.default' => 'sqlite', 'database.connections.sqlite.database' => $this->databasePath]);
DB::purge();
DB::reconnect();
// Create minimal tables needed for testing
$this->createTestTables();
// Create the basic User role
$this->userRole = Role::firstOrCreate(
['name' => 'User'],
app(PermissionRegistrar::class)->forgetCachedPermissions();
// Create the basic User and Supporter roles using raw inserts so custom columns
// are always populated consistently across mixed-suite runs.
DB::table('roles')->insert([
[
'name' => 'User',
'guard_name' => 'web',
'addyears' => 0,
'apirequests' => 10,
@@ -41,12 +105,11 @@ final class RoleUpgradeTest extends TestCase
'isdefault' => 1,
'donation' => 0,
'canpreview' => 0,
]
);
// Create the Supporter role with addyears = 1 as default
$this->supporterRole = Role::firstOrCreate(
['name' => 'Supporter'],
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'Supporter',
'guard_name' => 'web',
'addyears' => 1,
'apirequests' => 100,
@@ -55,8 +118,13 @@ final class RoleUpgradeTest extends TestCase
'isdefault' => 0,
'donation' => 10,
'canpreview' => 1,
]
);
'created_at' => now(),
'updated_at' => now(),
],
]);
$this->userRole = Role::query()->where('name', 'User')->where('guard_name', 'web')->firstOrFail();
$this->supporterRole = Role::query()->where('name', 'Supporter')->where('guard_name', 'web')->firstOrFail();
// Create a test user with the User role
$this->user = $this->createTestUser($this->userRole->id);
$this->user->assignRole($this->userRole);
@@ -66,6 +134,14 @@ final class RoleUpgradeTest extends TestCase
{
DB::disconnect();
parent::tearDown();
if ($this->databasePath !== '' && file_exists($this->databasePath)) {
unlink($this->databasePath);
}
foreach ($this->originalEnvironment as $key => $value) {
$this->setEnvironmentValue($key, $value === false ? null : $value);
}
}
/**
@@ -73,8 +149,19 @@ final class RoleUpgradeTest extends TestCase
*/
private function createTestTables(): void
{
DB::statement('DROP TABLE IF EXISTS role_promotion_stats');
DB::statement('DROP TABLE IF EXISTS role_promotions');
DB::statement('DROP TABLE IF EXISTS user_activities');
DB::statement('DROP TABLE IF EXISTS user_role_history');
DB::statement('DROP TABLE IF EXISTS role_has_permissions');
DB::statement('DROP TABLE IF EXISTS model_has_permissions');
DB::statement('DROP TABLE IF EXISTS permissions');
DB::statement('DROP TABLE IF EXISTS model_has_roles');
DB::statement('DROP TABLE IF EXISTS roles');
DB::statement('DROP TABLE IF EXISTS users');
// Users table
DB::statement('CREATE TABLE IF NOT EXISTS users (
DB::statement('CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
@@ -103,7 +190,7 @@ final class RoleUpgradeTest extends TestCase
)');
// Roles table (spatie/laravel-permission)
DB::statement('CREATE TABLE IF NOT EXISTS roles (
DB::statement('CREATE TABLE roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255) NOT NULL,
guard_name VARCHAR(255) NOT NULL,
@@ -119,7 +206,7 @@ final class RoleUpgradeTest extends TestCase
)');
// Model has roles table (spatie/laravel-permission)
DB::statement('CREATE TABLE IF NOT EXISTS model_has_roles (
DB::statement('CREATE TABLE model_has_roles (
role_id INTEGER NOT NULL,
model_type VARCHAR(255) NOT NULL,
model_id INTEGER NOT NULL,
@@ -127,7 +214,7 @@ final class RoleUpgradeTest extends TestCase
)');
// Permissions table (spatie/laravel-permission)
DB::statement('CREATE TABLE IF NOT EXISTS permissions (
DB::statement('CREATE TABLE permissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255) NOT NULL,
guard_name VARCHAR(255) NOT NULL,
@@ -136,7 +223,7 @@ final class RoleUpgradeTest extends TestCase
)');
// Model has permissions table (spatie/laravel-permission)
DB::statement('CREATE TABLE IF NOT EXISTS model_has_permissions (
DB::statement('CREATE TABLE model_has_permissions (
permission_id INTEGER NOT NULL,
model_type VARCHAR(255) NOT NULL,
model_id INTEGER NOT NULL,
@@ -144,27 +231,30 @@ final class RoleUpgradeTest extends TestCase
)');
// Role has permissions table (spatie/laravel-permission)
DB::statement('CREATE TABLE IF NOT EXISTS role_has_permissions (
DB::statement('CREATE TABLE role_has_permissions (
permission_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
PRIMARY KEY (permission_id, role_id)
)');
// User role history table (if needed)
DB::statement('CREATE TABLE IF NOT EXISTS user_role_history (
// User role history table
DB::statement('CREATE TABLE user_role_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
users_id INTEGER NOT NULL,
old_roles_id INTEGER NULL,
new_roles_id INTEGER NOT NULL,
old_rolechangedate DATETIME NULL,
new_rolechangedate DATETIME NULL,
changed_by_user_id INTEGER NULL,
reason TEXT NULL,
created_at DATETIME NULL
user_id INTEGER NOT NULL,
old_role_id INTEGER NULL,
new_role_id INTEGER NOT NULL,
old_expiry_date DATETIME NULL,
new_expiry_date DATETIME NULL,
effective_date DATETIME NOT NULL,
is_stacked INTEGER DEFAULT 0,
change_reason TEXT NULL,
changed_by INTEGER NULL,
created_at DATETIME NULL,
updated_at DATETIME NULL
)');
// User activities table
DB::statement('CREATE TABLE IF NOT EXISTS user_activities (
DB::statement('CREATE TABLE user_activities (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NULL,
username VARCHAR(255) NOT NULL,
@@ -175,7 +265,7 @@ final class RoleUpgradeTest extends TestCase
)');
// Role promotions table
DB::statement('CREATE TABLE IF NOT EXISTS role_promotions (
DB::statement('CREATE TABLE role_promotions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255) NOT NULL,
description TEXT NULL,
@@ -189,7 +279,7 @@ final class RoleUpgradeTest extends TestCase
)');
// Role promotion stats table
DB::statement('CREATE TABLE IF NOT EXISTS role_promotion_stats (
DB::statement('CREATE TABLE role_promotion_stats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
role_promotion_id INTEGER NOT NULL,
@@ -203,6 +293,20 @@ final class RoleUpgradeTest extends TestCase
)');
}
private function setEnvironmentValue(string $key, ?string $value): void
{
if ($value === null) {
putenv($key);
unset($_ENV[$key], $_SERVER[$key]);
return;
}
putenv($key.'='.$value);
$_ENV[$key] = $value;
$_SERVER[$key] = $value;
}
/**
* Helper to create a test user without factory.
*/
@@ -280,11 +384,12 @@ final class RoleUpgradeTest extends TestCase
addYears: null
);
$this->assertTrue($result, 'updateUserRole should return true');
$this->user->refresh();
$updatedUser = DB::table('users')->where('id', $this->user->id)->first();
// The rolechangedate should be 1 year from now (365 days) - the role's default
$expectedExpiryDate = Carbon::parse('2025-01-01 12:00:00')->addDays($this->supporterRole->addyears * 365);
$this->assertNotNull($this->user->rolechangedate, 'Role change date should not be null');
$actualExpiryDate = Carbon::parse($this->user->rolechangedate);
$this->assertNotNull($updatedUser?->rolechangedate, 'Role change date should not be null');
$actualExpiryDate = Carbon::parse($updatedUser->rolechangedate);
$this->assertEquals(
$expectedExpiryDate->toDateString(),
$actualExpiryDate->toDateString(),
-2
View File
@@ -22,7 +22,6 @@ class AniDBParseTest extends TestCase
private function invokeExtract(object $instance, string $name): array
{
$rm = new ReflectionMethod($instance, 'extractTitleEpisode');
$rm->setAccessible(true);
/** @var array $result */
$result = $rm->invoke($instance, $name);
@@ -32,7 +31,6 @@ class AniDBParseTest extends TestCase
private function getStatus(object $instance): ?int
{
$rp = new ReflectionProperty($instance, 'status');
$rp->setAccessible(true);
/** @var int|null $status */
$status = $rp->getValue($instance);
-2
View File
@@ -20,12 +20,10 @@ final class AniDBProcessingTest extends TestCase
// Ensure status property exists and set to null before call.
if ($ref->hasProperty('status')) {
$propStatus = $ref->getProperty('status');
$propStatus->setAccessible(true);
$propStatus->setValue($instance, null);
}
$method = $ref->getMethod('extractTitleEpisode');
$method->setAccessible(true);
$result = $method->invoke($instance, $name);
if (isset($propStatus)) {
@@ -1,73 +1,65 @@
<?php
declare(strict_types=1);
namespace Tests\Unit\Services;
use App\Services\AnimeMatchingService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Services\AnimeProcessor;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
class AnimeMatchingServiceTest extends TestCase
final class AnimeMatchingServiceTest extends TestCase
{
use RefreshDatabase;
private AnimeMatchingService $service;
protected function setUp(): void
private function invokeExtract(string $searchName): array
{
parent::setUp();
$this->service = new AnimeMatchingService;
$reflection = new ReflectionClass(AnimeProcessor::class);
/** @var AnimeProcessor $processor */
$processor = $reflection->newInstanceWithoutConstructor();
$method = $reflection->getMethod('extractTitleEpisode');
/** @var array $result */
$result = $method->invoke($processor, $searchName);
return $result;
}
/** @test */
public function it_extracts_title_and_episode_from_dash_format(): void
public function test_extracts_title_from_dash_format(): void
{
$searchName = '[SubsPlease] Steins Gate - 01 [1080p].mkv';
$result = $this->service->extractTitleEpisode($searchName);
$result = $this->invokeExtract($searchName);
$this->assertNotNull($result);
$this->assertEquals('Steins Gate', $result['title']);
$this->assertEquals(1, $result['epno']);
$this->assertSame(['title' => 'Steins Gate'], $result);
}
/** @test */
public function it_extracts_title_and_episode_from_e_format(): void
public function test_extracts_title_from_e_format(): void
{
$searchName = 'Cowboy Bebop E05 [1080p].mkv';
$result = $this->service->extractTitleEpisode($searchName);
$result = $this->invokeExtract($searchName);
$this->assertNotNull($result);
$this->assertEquals('Cowboy Bebop', $result['title']);
$this->assertEquals(5, $result['epno']);
$this->assertSame(['title' => 'Cowboy Bebop'], $result);
}
/** @test */
public function it_extracts_movie_format(): void
public function test_extracts_movie_format_title(): void
{
$searchName = 'One Punch Man Movie [BD 1080p].mkv';
$result = $this->service->extractTitleEpisode($searchName);
$result = $this->invokeExtract($searchName);
$this->assertNotNull($result);
$this->assertEquals('One Punch Man', $result['title']);
$this->assertEquals(1, $result['epno']);
$this->assertSame('One Punch Man', $result['title']);
}
/** @test */
public function it_strips_group_tags(): void
public function test_strips_group_tags_from_title(): void
{
$searchName = '[HorribleSubs] Attack on Titan - 12 [720p].mkv';
$result = $this->service->extractTitleEpisode($searchName);
$result = $this->invokeExtract($searchName);
$this->assertNotNull($result);
$this->assertEquals('Attack on Titan', $result['title']);
$this->assertEquals(12, $result['epno']);
$this->assertSame('Attack on Titan', $result['title']);
}
/** @test */
public function it_returns_null_for_unparseable_names(): void
public function test_falls_back_to_cleaned_title_when_no_episode_pattern_exists(): void
{
$searchName = 'Random.File.Name.Without.Episode.mkv';
$result = $this->service->extractTitleEpisode($searchName);
$result = $this->invokeExtract($searchName);
$this->assertNull($result);
$this->assertSame(['title' => 'Random File Name Without Episode mkv'], $result);
}
}
-1
View File
@@ -25,7 +25,6 @@ class SteamServiceTest extends TestCase
{
$ref = new ReflectionClass($obj);
$m = $ref->getMethod($method);
$m->setAccessible(true);
return $m->invokeArgs($obj, $args);
}