🆙 Final fix delete storage link to fix news_images and logs 🆙

This commit is contained in:
Remco
2026-01-07 20:29:24 +01:00
parent 65ea6c167f
commit acf2d7e661
447 changed files with 208 additions and 66965 deletions
@@ -1,24 +0,0 @@
<?php
namespace App\Services\Articles;
use App\Models\Articles\WebsiteArticle;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;
class ArticleService
{
public function getArticles(bool $paginate = false, int $perPage = 8): array|Collection|LengthAwarePaginator
{
$query = WebsiteArticle::with(['user' => function ($query): void {
$query->select('id', 'username', 'look');
}])->orderByDesc('id');
return $paginate ? $query->paginate($perPage) : $query->get();
}
public function fetchArticle(string $slug): WebsiteArticle
{
return WebsiteArticle::where('slug', '=', $slug)->firstOrFail();
}
}
@@ -1,48 +0,0 @@
<?php
namespace App\Services\Articles;
use App\Models\Articles\WebsiteArticle;
use App\Models\Articles\WebsiteArticleComment;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
class CommentService
{
public function store(string $comment, WebsiteArticle $article): mixed
{
if ($article->userHasReachedArticleCommentLimit()) {
return back()->withErrors([
'message' => __('You can only comment :amount times per article', ['amount' => setting('max_comment_per_article')]),
]);
}
if (! $article->can_comment) {
return back()->withErrors([
'message' => __('This article has been locked from receiving comments'),
]);
}
return $article->comments()->create([
'user_id' => Auth::id(),
'comment' => $comment,
]);
}
public function destroy(WebsiteArticleComment $comment): bool|RedirectResponse|null
{
if (! $comment->canBeDeleted()) {
return back()->withErrors([
'message' => __('You can only delete your own comments'),
]);
}
if (! $comment->delete()) {
return back()->withErrors([
'message' => __('An error occurred while deleting the comment'),
]);
}
return $comment->delete();
}
}
@@ -1,36 +0,0 @@
<?php
namespace App\Services\Articles;
use App\Models\Articles\WebsiteArticle;
use App\Models\Articles\WebsiteArticleReaction;
use App\Models\User;
use Illuminate\Http\Request;
class ReactionService
{
public function toggleReaction(WebsiteArticle $article, User $user, Request $request): array
{
$reaction = $request->get('reaction');
if (! is_string($reaction) || ! in_array($reaction, config('habbo.reactions'))) {
return ['success' => false];
}
$existingReaction = WebsiteArticleReaction::getReaction($article->id, $user->id, $reaction);
if ($existingReaction instanceof \App\Models\Articles\WebsiteArticleReaction) {
$existingReaction->update(['active' => ! $existingReaction->active]);
} else {
$article->reactions()->create([
'reaction' => $reaction,
]);
}
return [
'success' => true,
'added' => $existingReaction?->active ?? true,
'username' => $user->username,
];
}
}
@@ -1,17 +0,0 @@
<?php
namespace App\Services\Community;
use App\Models\Miscellaneous\CameraWeb;
class CameraService
{
public function fetchPhotos(bool $paginate = false, int $perPage = 8): mixed
{
$photos = CameraWeb::where('visible', true)
->latest('id')
->with('user:id,username,look');
return $paginate ? $photos->paginate($perPage) : $photos->get();
}
}
@@ -1,36 +0,0 @@
<?php
namespace App\Services\Community\RareValues;
use App\Models\Community\RareValue\WebsiteRareValueCategory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
class RareValueCategoriesService
{
public function fetchAllCategories(): Collection
{
return WebsiteRareValueCategory::all();
}
public function fetchCategoriesByPriority(): Builder|Collection
{
return WebsiteRareValueCategory::orderBy('priority')->with('furniture')->get();
}
public function fetchCategoryById(int $id): ?WebsiteRareValueCategory
{
return WebsiteRareValueCategory::orderBy('priority')->whereId($id)->with('furniture')->first();
}
public function searchCategories(string $searchTerm): Collection
{
return WebsiteRareValueCategory::orderBy('priority')->whereHas('furniture', function ($query) use ($searchTerm): void {
$query->where('name', 'like', '%' . $searchTerm . '%');
})
->with(['furniture' => function ($query) use ($searchTerm): void {
$query->where('name', 'like', '%' . $searchTerm . '%');
}])
->get();
}
}
@@ -1,5 +0,0 @@
<?php
namespace App\Services\Community\RareValues;
class RareValuesService {}
@@ -1,35 +0,0 @@
<?php
namespace App\Services\Community;
use App\Models\Community\Staff\WebsiteOpenPosition;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
class StaffApplicationService
{
public function storeApplication(User $user, int $positionId, string $content): void
{
$user->applications()->create([
'rank_id' => $positionId,
'content' => $content,
]);
}
public function fetchOpenPositions(): Collection
{
return WebsiteOpenPosition::canApply()->with('permission')->get();
}
public function hasUserAppliedForPosition($user, $positionId): bool
{
return $user->applications()->where('rank_id', $positionId)->exists();
}
public function isPositionOpenForApplication($position): bool
{
$currentTime = now();
return $position->apply_from <= $currentTime && $position->apply_to >= $currentTime;
}
}
@@ -1,60 +0,0 @@
<?php
namespace App\Services\Community;
use App\Models\Game\Permission;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
class StaffService
{
public function fetchStaffPositions(): Collection
{
$cacheEnabled = setting('enable_caching') === '1';
if ($cacheEnabled && Cache::has('staff_positions')) {
return Cache::get('staff_positions');
}
$employees = Permission::query()
->select('id', 'rank_name', 'badge', 'staff_color', 'job_description')
->when(Auth::user()->rank < (int) setting('min_rank_to_see_hidden_staff'), fn ($query) => $query->where('hidden_rank', false))
->where('id', '>=', setting('min_staff_rank'))
->orderByDesc('id')
->with(['users' => function ($query): void {
$query->select('id', 'username', 'rank', 'motto', 'look', 'hidden_staff', 'online')
->when(Auth::user()->rank < (int) setting('min_rank_to_see_hidden_staff'), fn ($query) => $query->where('hidden_staff', false));
}])
->get();
if ($cacheEnabled) {
$cacheTimer = (int) setting('cache_timer');
Cache::put('staff_positions', $employees, now()->addMinutes($cacheTimer));
}
return $employees;
}
public function fetchEmployeeIds(): array
{
$cacheEnabled = setting('enable_caching') === '1';
if ($cacheEnabled && Cache::has('staff_ids')) {
return Cache::get('staff_ids');
}
$staffIds = User::select('id')
->where('rank', '>=', setting('min_staff_rank'))
->get()
->pluck('id')->toArray();
if ($cacheEnabled) {
$cacheTimer = (int) setting('cache_timer');
Cache::put('staff_ids', $staffIds, now()->addMinutes($cacheTimer));
}
return $staffIds;
}
}
@@ -1,34 +0,0 @@
<?php
namespace App\Services\Community;
use App\Models\Community\Staff\WebsiteTeam;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;
class TeamService
{
public function fetchTeams(): Collection
{
$cacheEnabled = setting('enable_caching') === '1';
if (Cache::has('hotel_teams') && $cacheEnabled) {
return Cache::get('hotel_teams');
}
$employees = WebsiteTeam::select(['id', 'rank_name', 'badge', 'staff_color', 'staff_background', 'job_description'])
->where('hidden_rank', false)
->orderByDesc('id')
->with(['users' => function ($query): void {
$query->select('id', 'username', 'look', 'motto', 'rank', 'team_id', 'online');
}])
->get();
if ($cacheEnabled) {
$cacheTimer = (int) setting('cache_timer');
Cache::put('hotel_teams', $employees, now()->addMinutes($cacheTimer));
}
return $employees;
}
}
@@ -1,79 +0,0 @@
<?php
namespace App\Services;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
/* Credits to Kani for this */
class FindRetrosService
{
/**
* The findretros verification uri.
*/
public const FIND_RETROS_VERIFY_URI = '%s/validate.php?user=%s&ip=%s';
/**
* The findretros redirect uri.
*/
public const FIND_RETROS_REDIRECT_URI = '%s/servers/%s/vote?minimal=1&return=1';
public const FIND_RETROS_CACHE_KEY = 'voted.%s';
/**
* The guzzle client instance
*/
protected Client $client;
/**
* Initialise Find Retros Service
*/
public function __construct()
{
$this->client = new Client(['verify' => false]);
}
/**
* Check the user has voted.
*/
public function checkHasVoted(): bool
{
if (! config('habbo.findretros.enabled')) {
return true;
}
$cacheKey = sprintf(self::FIND_RETROS_CACHE_KEY, request()->ip());
if (request()->ip() === '127.0.0.1') {
return true;
}
if (request()->has('novote')) {
return true;
}
if (Cache::has($cacheKey)) {
return true;
}
$uri = sprintf(self::FIND_RETROS_VERIFY_URI, config('habbo.findretros.api'), config('habbo.findretros.name'), request()->ip());
$request = $this->client->get($uri);
$response = $request->getBody()->getContents();
if (in_array($response, ['1', '2'])) {
Cache::put($cacheKey, true, now()->addMinutes(30));
return true;
}
return false;
}
/**
* Retrieve the find retros redirect url.
*/
public function getRedirectUri(): string
{
return sprintf(self::FIND_RETROS_REDIRECT_URI, config('habbo.findretros.api'), config('habbo.findretros.name'));
}
}
@@ -1,25 +0,0 @@
<?php
namespace App\Services;
use App\Models\WebsiteHousekeepingPermission;
use Illuminate\Support\Collection;
class HousekeepingPermissionsService
{
public ?Collection $permissions;
public function __construct()
{
$this->permissions = WebsiteHousekeepingPermission::all()->pluck('min_rank', 'permission');
}
public function getOrDefault(string $permissionName, bool $default = false): bool
{
if (! array_key_exists($permissionName, $this->permissions->toArray())) {
return $default;
}
return auth()->check() && auth()->user()->rank >= (int) $this->permissions->get($permissionName);
}
}
@@ -1,28 +0,0 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class IpLookupService
{
private string $baseUrl = 'https://api.ipdata.co';
public function __construct(private readonly string $apiKey) {}
public function ipLookup(string $ip)
{
$response = Http::acceptJson()->get(sprintf('%s/%s?api-key=%s', $this->baseUrl, $ip, $this->apiKey));
if (! $response->ok()) {
$message = array_key_exists('message', $response->json()) ? $response->json()['message'] : 'Unknown error';
return [
'message' => $message,
'status' => $response->status(),
];
}
return $response->json();
}
}
@@ -1,28 +0,0 @@
<?php
namespace App\Services;
use App\Models\Miscellaneous\WebsitePermission;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
class PermissionsService
{
public ?Collection $permissions;
public function __construct()
{
Cache::remember('website_permissions', now()->addMinutes(30), fn () => WebsitePermission::all()->pluck('min_rank', 'permission'));
$this->permissions = Cache::get('website_permissions');
}
public function getOrDefault(string $permissionName, bool $default = false): bool
{
if (! array_key_exists($permissionName, $this->permissions->toArray())) {
return $default;
}
return auth()->check() && auth()->user()->rank >= (int) $this->permissions->get($permissionName);
}
}
-257
View File
@@ -1,257 +0,0 @@
<?php
namespace App\Services;
use App\Enums\CurrencyTypes;
use App\Exceptions\RconConnectionException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Socket;
class RconService
{
protected ?Socket $socket = null;
public bool $isConnected = false;
protected array $config = [];
public function __construct()
{
$this->config = [
'ip' => setting('rcon_ip'),
'port' => (int) setting('rcon_port'),
];
$this->initialize();
}
private function initialize(): void
{
$this->socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (! $this->socket) {
$error = socket_strerror(socket_last_error());
Log::error("RCON initialization failed: $error");
$this->closeConnection();
return;
}
if (! @socket_connect($this->socket, $this->config['ip'], $this->config['port'])) {
$error = socket_strerror(socket_last_error());
Log::error("RCON connection failed: $error");
$this->closeConnection();
return;
}
$this->isConnected = true;
}
private function closeConnection(): void
{
if ($this->socket instanceof \Socket) {
socket_close($this->socket);
}
$this->socket = null;
$this->isConnected = false;
}
public function isConnected(): bool
{
return $this->isConnected;
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function sendCommand(string $command, ?array $data = null)
{
if (! $this->isConnected) {
$error = 'RCON command failed: Not connected';
Log::error($error);
$this->closeConnection();
return $this->isConnected;
}
$payload = json_encode(['key' => $command, 'data' => $data], JSON_THROW_ON_ERROR);
if (! @socket_write($this->socket, $payload, strlen($payload))) {
$error = socket_strerror(socket_last_error($this->socket));
Log::error("RCON command ($command) failed: $error");
$this->closeConnection();
return $this->isConnected;
}
return $this->isConnected;
}
/**
* @throws RconConnectionException|JsonException
*/
public function sendGift($user, int $item_id, string $message = 'Here is a gift.'): void
{
$this->sendCommand('sendgift', [
'user_id' => $user->id,
'itemid' => $item_id,
'message' => $message,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function giveCredits($user, int $credits): void
{
$this->sendCommand('givecredits', [
'user_id' => $user->id,
'credits' => $credits,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function giveBadge($user, string $badge): void
{
$this->sendCommand('givebadge', [
'user_id' => $user->id,
'badge' => $badge,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function setMotto($user, string $motto): void
{
$this->sendCommand('setmotto', [
'user_id' => $user->id,
'motto' => $motto,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function updateWordFilter(): void
{
$this->sendCommand('updatewordfilter');
}
/**
* @throws RconConnectionException|JsonException
*/
public function disconnectUser($user): void
{
$this->sendCommand('disconnect', [
'user_id' => $user->id,
'username' => $user->username,
]);
}
/**
* @throws RconConnectionException|JsonException
*/
public function givePoints($user, CurrencyTypes $type, int $amount): void
{
$this->sendCommand('givepoints', [
'user_id' => $user->id,
'points' => $amount,
'type' => $type,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function giveGotw($user, int $amount): void
{
$this->givePoints($user, CurrencyTypes::Points, $amount);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function giveDiamonds($user, int $amount): void
{
$this->givePoints($user, CurrencyTypes::Diamonds, $amount);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function giveDuckets($user, int $amount): void
{
$this->givePoints($user, CurrencyTypes::DUCKETS, $amount);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function setRank($user, int $rank): void
{
$this->sendCommand('setrank', [
'user_id' => $user->id,
'rank' => $rank,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function updateCatalog(): void
{
$this->sendCommand('updatecatalog');
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function alertUser($user, string $message): void
{
$this->sendCommand('alertuser', [
'user_id' => $user->id,
'message' => $message,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function forwardUser($user, int $roomId): void
{
$this->sendCommand('forwarduser', [
'user_id' => $user->id,
'room_id' => $roomId,
]);
}
/**
* @throws RconConnectionException
* @throws JsonException
*/
public function updateConfig($user, string $command): void
{
$this->sendCommand('executecommand', [
'user_id' => $user->id,
'command' => $command,
]);
}
}
@@ -1,34 +0,0 @@
<?php
namespace App\Services;
use App\Models\Miscellaneous\WebsiteSetting;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema;
use Throwable;
class SettingsService
{
public ?Collection $settings;
public function __construct()
{
try {
Cache::remember('website_settings', now()->addMinutes(5), fn () => Schema::hasTable('website_settings') ? WebsiteSetting::all()->pluck('value', 'key') : collect());
$this->settings = Cache::get('website_settings');
} catch (Throwable) {
$this->settings = collect();
}
}
public function getOrDefault(string $settingName, ?string $default = null): string
{
if (! $this->settings instanceof \Illuminate\Support\Collection) {
return (string) $default;
}
return (string) $this->settings->get($settingName, $default);
}
}
@@ -1,39 +0,0 @@
<?php
namespace App\Services\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Jenssegers\Agent\Agent;
class SessionService
{
public function fetchSessionLogs(Request $request): Collection
{
return collect(
Auth::user()->sessions,
)->map(function ($session) use ($request) {
$agent = $this->createAgent($session);
return (object) [
'agent' => [
'is_desktop' => $agent->isDesktop(),
'platform' => $agent->platform(),
'browser' => $agent->browser(),
],
'ip_address' => $session->ip_address,
'is_current_device' => $session->id === $request->session()->getId(),
'last_active' => \Illuminate\Support\Facades\Date::createFromTimestamp($session->last_activity)->diffForHumans(),
];
});
}
protected function createAgent($session): Agent
{
return tap(new Agent, function ($agent) use ($session): void {
$agent->setUserAgent($session->user_agent);
});
}
}
@@ -1,30 +0,0 @@
<?php
namespace App\Services\User;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
class UserApiService
{
public function fetchUser(string $username, array $columns): User
{
return User::select($columns)->where('username', '=', $username)->first();
}
public function onlineUsers($columns = ['username', 'motto', 'look'], bool $randomOrder = true): Builder
{
$query = User::select($columns)->where('online', '=', '1');
if ($randomOrder) {
$query = $query->inRandomOrder();
}
return $query;
}
public function onlineUserCount(): int
{
return User::where('online', '=', '1')->count();
}
}
@@ -1,14 +0,0 @@
<?php
namespace App\Services\User;
use App\Actions\UserActions;
use App\Models\User;
class UserService extends UserActions
{
public function getUser(string $username): ?User
{
return User::where('username', $username)->first();
}
}
-17
View File
@@ -1,17 +0,0 @@
<?php
namespace App\Services;
use Illuminate\Foundation\Vite;
class ViteService extends Vite
{
/**
* Generate a script tag for the given URL.
*/
#[\Override]
protected function makeScriptTag($url): string
{
return sprintf('<script type="module" src="%s" data-turbolinks-eval="false"></script>', $url);
}
}