mirror of
https://github.com/sp-tarkov/forge.git
synced 2025-02-12 12:10:41 -05:00
Resolves Some Larastan Issues
This commit is contained in:
parent
bd2d38b4e4
commit
bbb8fab1a1
@ -4,16 +4,24 @@ namespace App\Http\Controllers\Api\V0;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Str;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
class ApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Determine if the given relationship should be included in the request. If more than one relationship is provided,
|
||||
* only one needs to be present in the request for this method to return true.
|
||||
*
|
||||
* @param string|string[] $relationships
|
||||
*/
|
||||
public static function shouldInclude(string|array $relationships): bool
|
||||
{
|
||||
$param = request()->get('include');
|
||||
try {
|
||||
$param = request()->get('include');
|
||||
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $param) {
|
||||
return false;
|
||||
|
@ -7,13 +7,15 @@ use App\Http\Requests\Api\V0\StoreModRequest;
|
||||
use App\Http\Requests\Api\V0\UpdateModRequest;
|
||||
use App\Http\Resources\Api\V0\ModResource;
|
||||
use App\Models\Mod;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ModController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(ModFilter $filters)
|
||||
public function index(ModFilter $filters): AnonymousResourceCollection
|
||||
{
|
||||
return ModResource::collection(Mod::filter($filters)->paginate());
|
||||
}
|
||||
@ -21,15 +23,12 @@ class ModController extends ApiController
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(StoreModRequest $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function store(StoreModRequest $request): void {}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Mod $mod)
|
||||
public function show(Mod $mod): JsonResource
|
||||
{
|
||||
return new ModResource($mod);
|
||||
}
|
||||
@ -37,16 +36,10 @@ class ModController extends ApiController
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(UpdateModRequest $request, Mod $mod)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function update(UpdateModRequest $request, Mod $mod): void {}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Mod $mod)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function destroy(Mod $mod): void {}
|
||||
}
|
||||
|
@ -7,13 +7,15 @@ use App\Http\Requests\Api\V0\StoreUserRequest;
|
||||
use App\Http\Requests\Api\V0\UpdateUserRequest;
|
||||
use App\Http\Resources\Api\V0\UserResource;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UsersController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(UserFilter $filters)
|
||||
public function index(UserFilter $filters): AnonymousResourceCollection
|
||||
{
|
||||
return UserResource::collection(User::filter($filters)->paginate());
|
||||
}
|
||||
@ -21,15 +23,12 @@ class UsersController extends ApiController
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(StoreUserRequest $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function store(StoreUserRequest $request): void {}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(User $user)
|
||||
public function show(User $user): JsonResource
|
||||
{
|
||||
return new UserResource($user);
|
||||
}
|
||||
@ -37,16 +36,10 @@ class UsersController extends ApiController
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(UpdateUserRequest $request, User $user)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function update(UpdateUserRequest $request, User $user): void {}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
//
|
||||
}
|
||||
public function destroy(User $user): void {}
|
||||
}
|
||||
|
@ -6,26 +6,27 @@ use App\Http\Requests\ModRequest;
|
||||
use App\Http\Resources\ModResource;
|
||||
use App\Models\Mod;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ModController extends Controller
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
public function index()
|
||||
public function index(): View
|
||||
{
|
||||
$this->authorize('viewAny', Mod::class);
|
||||
|
||||
return view('mod.index');
|
||||
}
|
||||
|
||||
public function store(ModRequest $request)
|
||||
public function store(ModRequest $request): ModResource
|
||||
{
|
||||
$this->authorize('create', Mod::class);
|
||||
|
||||
return new ModResource(Mod::create($request->validated()));
|
||||
}
|
||||
|
||||
public function show(int $modId, string $slug)
|
||||
public function show(int $modId, string $slug): View
|
||||
{
|
||||
$mod = Mod::with([
|
||||
'versions',
|
||||
@ -47,7 +48,7 @@ class ModController extends Controller
|
||||
return view('mod.show', compact(['mod']));
|
||||
}
|
||||
|
||||
public function update(ModRequest $request, Mod $mod)
|
||||
public function update(ModRequest $request, Mod $mod): ModResource
|
||||
{
|
||||
$this->authorize('update', $mod);
|
||||
|
||||
@ -56,12 +57,5 @@ class ModController extends Controller
|
||||
return new ModResource($mod);
|
||||
}
|
||||
|
||||
public function destroy(Mod $mod)
|
||||
{
|
||||
$this->authorize('delete', $mod);
|
||||
|
||||
$mod->delete();
|
||||
|
||||
return response()->json();
|
||||
}
|
||||
public function destroy(Mod $mod): void {}
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ namespace App\Http\Controllers;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
public function show(Request $request, User $user, string $username)
|
||||
public function show(Request $request, User $user, string $username): View
|
||||
{
|
||||
if ($user->slug() !== $username) {
|
||||
abort(404);
|
||||
|
@ -11,14 +11,21 @@ class ModFilter
|
||||
{
|
||||
/**
|
||||
* The query builder instance for the mod model.
|
||||
*
|
||||
* @var Builder<Mod>
|
||||
*/
|
||||
protected Builder $builder;
|
||||
|
||||
/**
|
||||
* The filter that should be applied to the query.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
protected array $filters;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $filters
|
||||
*/
|
||||
public function __construct(array $filters)
|
||||
{
|
||||
$this->builder = $this->baseQuery();
|
||||
@ -27,6 +34,8 @@ class ModFilter
|
||||
|
||||
/**
|
||||
* The base query for the mod listing.
|
||||
*
|
||||
* @return Builder<Mod>
|
||||
*/
|
||||
private function baseQuery(): Builder
|
||||
{
|
||||
@ -49,6 +58,8 @@ class ModFilter
|
||||
|
||||
/**
|
||||
* Apply the filters to the query.
|
||||
*
|
||||
* @return Builder<Mod>
|
||||
*/
|
||||
public function apply(): Builder
|
||||
{
|
||||
@ -58,13 +69,13 @@ class ModFilter
|
||||
}
|
||||
}
|
||||
|
||||
//dd($this->builder->toRawSql());
|
||||
|
||||
return $this->builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order the query by the given type.
|
||||
*
|
||||
* @return Builder<Mod>
|
||||
*/
|
||||
private function order(string $type): Builder
|
||||
{
|
||||
@ -92,6 +103,8 @@ class ModFilter
|
||||
|
||||
/**
|
||||
* Filter the results by the given search term.
|
||||
*
|
||||
* @return Builder<Mod>
|
||||
*/
|
||||
private function query(string $term): Builder
|
||||
{
|
||||
@ -100,6 +113,8 @@ class ModFilter
|
||||
|
||||
/**
|
||||
* Filter the results by the featured status.
|
||||
*
|
||||
* @return Builder<Mod>
|
||||
*/
|
||||
private function featured(string $option): Builder
|
||||
{
|
||||
@ -112,6 +127,9 @@ class ModFilter
|
||||
|
||||
/**
|
||||
* Filter the results to specific SPT versions.
|
||||
*
|
||||
* @param array<int, string> $versions
|
||||
* @return Builder<Mod>
|
||||
*/
|
||||
private function sptVersions(array $versions): Builder
|
||||
{
|
||||
|
@ -2,16 +2,20 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class UserRole extends Model
|
||||
{
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The relationship between a user role and users.
|
||||
*
|
||||
* @return HasMany<User>
|
||||
*/
|
||||
public function users(): HasMany
|
||||
{
|
||||
|
@ -18,6 +18,11 @@ class ResetPassword extends OriginalResetPassword implements ShouldQueue
|
||||
parent::__construct($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [];
|
||||
|
@ -13,6 +13,11 @@ class VerifyEmail extends OriginalVerifyEmail implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [];
|
||||
|
@ -18,6 +18,8 @@ class DependencyVersionService
|
||||
|
||||
/**
|
||||
* Satisfies all dependency constraints of a ModVersion.
|
||||
*
|
||||
* @return array<int, array<string, int>>
|
||||
*/
|
||||
private function satisfyConstraint(ModVersion $modVersion): array
|
||||
{
|
||||
|
@ -19,6 +19,8 @@ class SptVersionService
|
||||
|
||||
/**
|
||||
* Satisfies the version constraint of a given ModVersion. Returns the ID of the satisfying SptVersion.
|
||||
*
|
||||
* @return array<int>
|
||||
*/
|
||||
private function satisfyConstraint(ModVersion $modVersion): array
|
||||
{
|
||||
|
@ -6,11 +6,21 @@ use Illuminate\Http\JsonResponse;
|
||||
|
||||
trait ApiResponses
|
||||
{
|
||||
/**
|
||||
* Return a success JSON response.
|
||||
*
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
protected function success(string $message, ?array $data = []): JsonResponse
|
||||
{
|
||||
return $this->baseResponse(message: $message, data: $data, code: 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* The base response.
|
||||
*
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
private function baseResponse(?string $message = '', ?array $data = [], ?int $code = 200): JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
@ -19,6 +29,9 @@ trait ApiResponses
|
||||
], $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error JSON response.
|
||||
*/
|
||||
protected function error(string $message, int $code): JsonResponse
|
||||
{
|
||||
return $this->baseResponse(message: $message, code: $code);
|
||||
|
@ -11,7 +11,7 @@ trait HasCoverPhoto
|
||||
/**
|
||||
* Update the user's cover photo.
|
||||
*/
|
||||
public function updateCoverPhoto(UploadedFile $cover, $storagePath = 'cover-photos'): void
|
||||
public function updateCoverPhoto(UploadedFile $cover, string $storagePath = 'cover-photos'): void
|
||||
{
|
||||
tap($this->cover_photo_path, function ($previous) use ($cover, $storagePath) {
|
||||
$this->forceFill([
|
||||
@ -51,15 +51,17 @@ trait HasCoverPhoto
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to the user's cover photo.
|
||||
* Get the cover photo URL for the user.
|
||||
*
|
||||
* @return Attribute<string, never>
|
||||
*/
|
||||
public function coverPhotoUrl(): Attribute
|
||||
{
|
||||
return Attribute::get(function (): string {
|
||||
return $this->cover_photo_path
|
||||
return new Attribute(
|
||||
get: fn (): string => $this->cover_photo_path
|
||||
? Storage::disk($this->coverPhotoDisk())->url($this->cover_photo_path)
|
||||
: $this->defaultCoverPhotoUrl();
|
||||
});
|
||||
: $this->defaultCoverPhotoUrl()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,17 +2,28 @@
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use App\Models\Mod;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class ModList extends Component
|
||||
{
|
||||
/**
|
||||
* The mods to display.
|
||||
*
|
||||
* @var Collection<int, Mod>
|
||||
*/
|
||||
public Collection $mods;
|
||||
|
||||
public string $versionScope;
|
||||
|
||||
public function __construct($mods, $versionScope)
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*
|
||||
* @param Collection<int, Mod> $mods
|
||||
*/
|
||||
public function __construct(Collection $mods, string $versionScope)
|
||||
{
|
||||
$this->mods = $mods;
|
||||
$this->versionScope = $versionScope;
|
||||
|
@ -11,10 +11,25 @@ use Illuminate\View\Component;
|
||||
|
||||
class ModListSection extends Component
|
||||
{
|
||||
/**
|
||||
* The featured mods listed on the homepage.
|
||||
*
|
||||
* @var Collection<int, Mod>
|
||||
*/
|
||||
public Collection $modsFeatured;
|
||||
|
||||
/**
|
||||
* The latest mods listed on the homepage.
|
||||
*
|
||||
* @var Collection<int, Mod>
|
||||
*/
|
||||
public Collection $modsLatest;
|
||||
|
||||
/**
|
||||
* The last updated mods listed on the homepage.
|
||||
*
|
||||
* @var Collection<int, Mod>
|
||||
*/
|
||||
public Collection $modsUpdated;
|
||||
|
||||
public function __construct()
|
||||
@ -24,6 +39,11 @@ class ModListSection extends Component
|
||||
$this->modsUpdated = $this->fetchUpdatedMods();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the featured mods homepage listing.
|
||||
*
|
||||
* @return Collection<int, Mod>
|
||||
*/
|
||||
private function fetchFeaturedMods(): Collection
|
||||
{
|
||||
return Mod::select(['id', 'name', 'slug', 'teaser', 'thumbnail', 'featured', 'downloads'])
|
||||
@ -39,6 +59,11 @@ class ModListSection extends Component
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the latest mods homepage listing.
|
||||
*
|
||||
* @return Collection<int, Mod>
|
||||
*/
|
||||
private function fetchLatestMods(): Collection
|
||||
{
|
||||
return Mod::select(['id', 'name', 'slug', 'teaser', 'thumbnail', 'featured', 'created_at', 'downloads'])
|
||||
@ -53,6 +78,11 @@ class ModListSection extends Component
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the recently updated mods homepage listing.
|
||||
*
|
||||
* @return Collection<int, Mod>
|
||||
*/
|
||||
private function fetchUpdatedMods(): Collection
|
||||
{
|
||||
return Mod::select(['id', 'name', 'slug', 'teaser', 'thumbnail', 'featured', 'downloads'])
|
||||
@ -81,6 +111,11 @@ class ModListSection extends Component
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the sections for the homepage mod lists.
|
||||
*
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function getSections(): array
|
||||
{
|
||||
return [
|
||||
|
@ -2,14 +2,16 @@
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use App\Models\Mod;
|
||||
use App\Models\ModVersion;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class ModListStats extends Component
|
||||
{
|
||||
public function __construct(
|
||||
public $mod,
|
||||
public $modVersion
|
||||
public Mod $mod,
|
||||
public ModVersion $modVersion
|
||||
) {}
|
||||
|
||||
public function render(): View
|
||||
|
@ -6,6 +6,9 @@ use App\Models\License;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* @extends Factory<License>
|
||||
*/
|
||||
class LicenseFactory extends Factory
|
||||
{
|
||||
protected $model = License::class;
|
||||
|
@ -8,6 +8,9 @@ use App\Models\ModVersion;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* @extends Factory<ModDependency>
|
||||
*/
|
||||
class ModDependencyFactory extends Factory
|
||||
{
|
||||
protected $model = ModDependency::class;
|
||||
|
@ -7,25 +7,23 @@ use App\Models\Mod;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Random\RandomException;
|
||||
|
||||
/**
|
||||
* @extends Factory<Mod>
|
||||
*/
|
||||
class ModFactory extends Factory
|
||||
{
|
||||
protected $model = Mod::class;
|
||||
|
||||
/**
|
||||
* @throws RandomException
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
|
||||
$name = fake()->catchPhrase();
|
||||
$name = fake()->sentence(rand(3, 5));
|
||||
|
||||
return [
|
||||
'name' => $name,
|
||||
'slug' => Str::slug($name),
|
||||
'teaser' => fake()->sentence(),
|
||||
'description' => fake()->paragraphs(random_int(4, 20), true),
|
||||
'description' => fake()->paragraphs(rand(4, 20), true),
|
||||
'license_id' => License::factory(),
|
||||
'source_code_link' => fake()->url(),
|
||||
'featured' => fake()->boolean(),
|
||||
|
@ -8,6 +8,9 @@ use App\Models\SptVersion;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* @extends Factory<ModVersion>
|
||||
*/
|
||||
class ModVersionFactory extends Factory
|
||||
{
|
||||
protected $model = ModVersion::class;
|
||||
|
@ -6,6 +6,9 @@ use App\Models\SptVersion;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* @extends Factory<SptVersion>
|
||||
*/
|
||||
class SptVersionFactory extends Factory
|
||||
{
|
||||
protected $model = SptVersion::class;
|
||||
|
@ -2,10 +2,14 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
@ -13,6 +17,8 @@ class UserFactory extends Factory
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
protected $model = User::class;
|
||||
|
||||
/**
|
||||
* Define the user's default state.
|
||||
*/
|
||||
|
@ -6,6 +6,9 @@ use App\Models\UserRole;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* @extends Factory<UserRole>
|
||||
*/
|
||||
class UserRoleFactory extends Factory
|
||||
{
|
||||
protected $model = UserRole::class;
|
||||
|
@ -23,7 +23,7 @@ return new class extends PulseMigration
|
||||
match ($this->driver()) {
|
||||
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||
'sqlite' => $table->string('key_hash'),
|
||||
default => $table->string('key_hash'),
|
||||
};
|
||||
$table->mediumText('value');
|
||||
|
||||
@ -40,7 +40,7 @@ return new class extends PulseMigration
|
||||
match ($this->driver()) {
|
||||
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||
'sqlite' => $table->string('key_hash'),
|
||||
default => $table->string('key_hash'),
|
||||
};
|
||||
$table->bigInteger('value')->nullable();
|
||||
|
||||
@ -59,7 +59,7 @@ return new class extends PulseMigration
|
||||
match ($this->driver()) {
|
||||
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||
'sqlite' => $table->string('key_hash'),
|
||||
default => $table->string('key_hash'),
|
||||
};
|
||||
$table->string('aggregate');
|
||||
$table->decimal('value', 20, 2);
|
||||
|
Loading…
x
Reference in New Issue
Block a user