├── .editorconfig ├── .env.example ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── app ├── Console │ └── Kernel.php ├── Enums │ └── Group.php ├── Filament │ └── Admin │ │ ├── Pages │ │ └── Dashboard.php │ │ ├── Resources │ │ ├── UserResource.php │ │ └── UserResource │ │ │ └── Pages │ │ │ ├── CreateUser.php │ │ │ ├── EditUser.php │ │ │ └── ListUsers.php │ │ └── Widgets │ │ └── StatsOverview.php ├── Helpers │ ├── GetAppVersion.php │ ├── QueryServer.php │ └── SteamHelper.php ├── Http │ ├── Controllers │ │ ├── Admin │ │ │ ├── AdminSettings │ │ │ │ └── AdminController.php │ │ │ ├── Ban │ │ │ │ └── BanController.php │ │ │ ├── DashboardController.php │ │ │ ├── Group │ │ │ │ └── GroupController.php │ │ │ ├── Mod │ │ │ │ └── ModController.php │ │ │ ├── Mute │ │ │ │ └── MuteController.php │ │ │ ├── Role │ │ │ │ └── RoleController.php │ │ │ ├── Server │ │ │ │ └── ServerController.php │ │ │ └── Settings │ │ │ │ └── SettingsController.php │ │ ├── Appeal │ │ │ └── AppealController.php │ │ ├── Auth │ │ │ ├── AuthController.php │ │ │ └── SteamAuthController.php │ │ ├── Ban │ │ │ └── BanController.php │ │ ├── Controller.php │ │ ├── Dashboard │ │ │ └── HomeController.php │ │ ├── LocaleController.php │ │ ├── Mute │ │ │ └── MuteController.php │ │ ├── Report │ │ │ └── ReportController.php │ │ └── Server │ │ │ └── ServerController.php │ └── Requests │ │ ├── Admin │ │ ├── AdminCreateRequest.php │ │ ├── AdminUpdateRequest.php │ │ ├── Ban │ │ │ ├── BanCreateRequest.php │ │ │ └── BanUpdateRequest.php │ │ ├── Group │ │ │ ├── GroupCreateRequest.php │ │ │ └── GroupUpdateRequest.php │ │ ├── Mod │ │ │ ├── ModCreateRequest.php │ │ │ └── ModUpdateRequest.php │ │ ├── Mute │ │ │ ├── MuteCreateRequest.php │ │ │ └── MuteUpdateRequest.php │ │ ├── Role │ │ │ ├── RoleCreateRequest.php │ │ │ └── RoleUpdateRequest.php │ │ └── Server │ │ │ ├── ServerCreateRequest.php │ │ │ └── ServerUpdateRequest.php │ │ ├── Appeal │ │ └── AppealCreateRequest.php │ │ ├── Auth │ │ └── LoginRequest.php │ │ ├── Report │ │ └── ReportCreateRequest.php │ │ └── User │ │ └── ProfileUpdateRequest.php ├── Jobs │ ├── Appeal.php │ └── ReportPlayer.php ├── Mail │ └── PlayerReported.php ├── Models │ ├── Appeal.php │ ├── Ban.php │ ├── Group.php │ ├── Mod.php │ ├── Mute.php │ ├── Permission.php │ ├── Reason.php │ ├── Region.php │ ├── Report.php │ ├── Role.php │ ├── Server.php │ ├── TimeBan.php │ └── User.php ├── Notifications │ ├── Appeal.php │ ├── ReportPlayer.php │ └── TestEmail.php ├── Observers │ ├── BanObserver.php │ ├── MuteObserver.php │ └── UserObserver.php ├── Providers │ ├── AppServiceProvider.php │ ├── EventServiceProvider.php │ └── Filament │ │ └── AdminPanelProvider.php ├── Services │ └── RconService.php └── Traits │ ├── Group.php │ └── Server.php ├── artisan ├── bootstrap ├── app.php ├── cache │ └── .gitignore └── providers.php ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cors.php ├── database.php ├── debugbar.php ├── filesystems.php ├── hashing.php ├── locales.php ├── location.php ├── logging.php ├── mail.php ├── permissions_web.php ├── queue.php ├── sanctum.php ├── services.php ├── session.php └── view.php ├── database ├── .gitignore ├── factories │ ├── BanFactory.php │ ├── MuteFactory.php │ ├── ServerFactory.php │ └── UserFactory.php ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ ├── 2022_11_23_150916_create_mods_table.php │ ├── 2022_11_28_193231_create_reasons_table.php │ ├── 2022_11_28_193245_create_time_bans_table.php │ ├── 2022_12_14_083707_create_settings_table.php │ ├── 2023_05_23_134640_create_appeals_table.php │ ├── 2023_06_13_125656_create_regions_table.php │ ├── 2023_06_13_140310_create_servers_table.php │ ├── 2023_06_13_140542_create_reports_table.php │ ├── 2023_06_13_140620_create_mutes_table.php │ ├── 2023_06_13_140641_create_bans_table.php │ ├── 2023_07_18_104629_create_groups_table.php │ └── 2023_07_19_102438_create_table_user_has_groups.php └── seeders │ ├── DatabaseSeeder.php │ ├── ModsSeeder.php │ ├── ReasonSeeder.php │ ├── RegionsSeeder.php │ ├── TimeBansSeeder.php │ └── UserWeb.php ├── package-lock.json ├── package.json ├── phpunit.xml ├── postcss.config.js ├── public ├── .htaccess ├── css │ └── filament │ │ ├── filament │ │ └── app.css │ │ ├── forms │ │ └── forms.css │ │ └── support │ │ └── support.css ├── favicon.png ├── images │ ├── games │ │ ├── alienswarm.png │ │ ├── csgo.png │ │ ├── csource.png │ │ ├── cspromod.png │ │ ├── dods.png │ │ ├── dys.png │ │ ├── eye.png │ │ ├── gmod.png │ │ ├── hidden.png │ │ ├── hl2-fortressforever.png │ │ ├── hl2ctf.png │ │ ├── hl2dm.png │ │ ├── ins.png │ │ ├── l4d.png │ │ ├── l4d2.png │ │ ├── nucleardawn.png │ │ ├── pdark.png │ │ ├── pvkii.png │ │ ├── ship.png │ │ ├── source-forts.png │ │ ├── synergy.png │ │ ├── tf2.png │ │ ├── web.png │ │ └── zps.png │ ├── http_errors │ │ ├── 400.png │ │ ├── 403.png │ │ ├── 404.png │ │ ├── 410.png │ │ ├── 418.png │ │ ├── 429.png │ │ ├── 500.png │ │ ├── 503.png │ │ ├── 504.png │ │ └── README.md │ ├── l.png │ ├── shield.png │ ├── smac.png │ ├── unknown.svg │ └── w.png ├── index.php ├── js │ └── filament │ │ ├── filament │ │ ├── app.js │ │ └── echo.js │ │ ├── forms │ │ └── components │ │ │ ├── color-picker.js │ │ │ ├── date-time-picker.js │ │ │ ├── file-upload.js │ │ │ ├── key-value.js │ │ │ ├── markdown-editor.js │ │ │ ├── rich-editor.js │ │ │ ├── select.js │ │ │ ├── tags-input.js │ │ │ └── textarea.js │ │ ├── notifications │ │ └── notifications.js │ │ ├── support │ │ └── support.js │ │ ├── tables │ │ └── components │ │ │ └── table.js │ │ └── widgets │ │ └── components │ │ ├── chart.js │ │ └── stats-overview │ │ └── stat │ │ └── chart.js ├── locales │ ├── laravel │ │ ├── en.json │ │ ├── en │ │ │ ├── auth.php │ │ │ ├── pagination.php │ │ │ ├── passwords.php │ │ │ └── validation.php │ │ ├── es.json │ │ ├── es │ │ │ ├── auth.php │ │ │ ├── pagination.php │ │ │ ├── passwords.php │ │ │ └── validation.php │ │ ├── pt.json │ │ └── pt │ │ │ ├── auth.php │ │ │ ├── pagination.php │ │ │ ├── passwords.php │ │ │ └── validation.php │ └── react │ │ ├── en │ │ ├── buttons.json │ │ ├── errors.json │ │ ├── sidebar.json │ │ ├── table.json │ │ └── translations.json │ │ ├── es │ │ ├── buttons.json │ │ ├── errors.json │ │ ├── sidebar.json │ │ ├── table.json │ │ └── translations.json │ │ └── pt │ │ ├── buttons.json │ │ ├── errors.json │ │ ├── sidebar.json │ │ ├── table.json │ │ └── translations.json └── robots.txt ├── resources ├── ts │ ├── App.tsx │ ├── TableColumns.ts │ ├── api │ │ ├── getServers.ts │ │ ├── getSettings.ts │ │ ├── http.ts │ │ ├── locale.ts │ │ └── steam.ts │ ├── assets │ │ └── app.css │ ├── components │ │ ├── Avatar.tsx │ │ ├── FlashMessageRender.tsx │ │ ├── Translate.tsx │ │ ├── elements │ │ │ ├── AnimationFade.tsx │ │ │ ├── Box.tsx │ │ │ ├── Collapse.tsx │ │ │ ├── Counter.tsx │ │ │ ├── Form.tsx │ │ │ ├── Image.tsx │ │ │ ├── Label.tsx │ │ │ ├── NavLink.tsx │ │ │ ├── PageContentBlock.tsx │ │ │ ├── Progress.tsx │ │ │ ├── Select.tsx │ │ │ ├── SourceAdminReg.tsx │ │ │ ├── Spinner.tsx │ │ │ ├── SubNavigation.tsx │ │ │ ├── TextArea.tsx │ │ │ ├── button │ │ │ │ ├── Button.tsx │ │ │ │ ├── index.js │ │ │ │ ├── style.module.css │ │ │ │ └── types.ts │ │ │ ├── field │ │ │ │ ├── Field.tsx │ │ │ │ ├── index.js │ │ │ │ ├── style.ts │ │ │ │ └── types.ts │ │ │ ├── inputs │ │ │ │ ├── Input.tsx │ │ │ │ ├── index.js │ │ │ │ ├── style.module.css │ │ │ │ └── types.ts │ │ │ ├── modal │ │ │ │ ├── Modal.tsx │ │ │ │ ├── index.js │ │ │ │ ├── style.module.css │ │ │ │ └── types.ts │ │ │ └── table │ │ │ │ ├── Table.tsx │ │ │ │ ├── index.js │ │ │ │ ├── style.module.css │ │ │ │ └── types.ts │ │ ├── layout │ │ │ ├── Header.tsx │ │ │ ├── Layout.tsx │ │ │ └── SideBar.tsx │ │ └── pages │ │ │ ├── ErrorPage.tsx │ │ │ ├── admin │ │ │ ├── AdminOverview │ │ │ │ ├── AdminOverview.tsx │ │ │ │ └── AdminOverviewData.tsx │ │ │ ├── AdminSettings │ │ │ │ ├── AdminCreate.tsx │ │ │ │ ├── AdminIndex.tsx │ │ │ │ └── AdminShow.tsx │ │ │ ├── BanSettings │ │ │ │ ├── BanCreate.tsx │ │ │ │ ├── BanIndex.tsx │ │ │ │ └── BanShow.tsx │ │ │ ├── GroupSettings │ │ │ │ ├── GroupCreate.tsx │ │ │ │ ├── GroupIndex.tsx │ │ │ │ └── GroupShow.tsx │ │ │ ├── ModSettings │ │ │ │ ├── ModCreate.tsx │ │ │ │ ├── ModIndex.tsx │ │ │ │ └── ModShow.tsx │ │ │ ├── MuteSettings │ │ │ │ ├── MuteCreate.tsx │ │ │ │ ├── MuteIndex.tsx │ │ │ │ └── MuteShow.tsx │ │ │ ├── PanelSettings │ │ │ │ ├── GeneralSettings.tsx │ │ │ │ ├── MailSettings.tsx │ │ │ │ └── SettingsContainer.tsx │ │ │ ├── RoleSettings │ │ │ │ ├── RoleCreate.tsx │ │ │ │ ├── RoleIndex.tsx │ │ │ │ └── RoleShow.tsx │ │ │ └── ServerSettings │ │ │ │ ├── ServerCreate.tsx │ │ │ │ ├── ServerIndex.tsx │ │ │ │ └── ServerShow.tsx │ │ │ ├── appeal │ │ │ └── AppealContainer.tsx │ │ │ ├── auth │ │ │ ├── LoginContainer.tsx │ │ │ └── steam │ │ │ │ └── SteamContainer.tsx │ │ │ ├── bans │ │ │ └── BansContainer.tsx │ │ │ ├── dashboard │ │ │ └── DashboardContainer.tsx │ │ │ ├── mutes │ │ │ └── MutesContainer.tsx │ │ │ ├── report │ │ │ └── ReportContainer.tsx │ │ │ └── servers │ │ │ └── ServersContainer.tsx │ ├── helpers │ │ ├── index.ts │ │ └── types.ts │ ├── hooks │ │ ├── useDeviceType.ts │ │ └── useFlashMessages.ts │ ├── i18n │ │ ├── index.ts │ │ └── locales.ts │ ├── routers │ │ └── routes.ts │ ├── stores │ │ ├── components │ │ │ └── sidebar.ts │ │ ├── flashes.ts │ │ ├── settings.ts │ │ ├── theme │ │ │ └── device.ts │ │ └── user.ts │ ├── types │ │ └── index.ts │ └── yup │ │ ├── YupFields.ts │ │ └── YupSchemas.ts └── views │ ├── layouts │ ├── admin.blade.php │ ├── app.blade.php │ └── base.blade.php │ ├── mail │ ├── appeal.blade.php │ └── playerReported.blade.php │ └── vendor │ └── mail │ ├── html │ ├── button.blade.php │ ├── footer.blade.php │ ├── header.blade.php │ ├── layout.blade.php │ ├── message.blade.php │ ├── panel.blade.php │ ├── subcopy.blade.php │ ├── table.blade.php │ └── themes │ │ └── default.css │ └── text │ ├── button.blade.php │ ├── footer.blade.php │ ├── header.blade.php │ ├── layout.blade.php │ ├── message.blade.php │ ├── panel.blade.php │ ├── subcopy.blade.php │ └── table.blade.php ├── routes ├── admin.php ├── api.php ├── channels.php ├── console.php └── web.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── debugbar │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tailwind.config.js ├── tests ├── CreatesApplication.php ├── ExampleTest.php ├── Pest.php └── TestCase.php └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 2 19 | 20 | [*.php] 21 | indent_size = 4 22 | 23 | [*.blade.php] 24 | indent_size = 2 25 | 26 | [*.js] 27 | indent_size = 4 28 | 29 | [*.jsx] 30 | indent_size = 2 31 | 32 | [*.tsx] 33 | indent_size = 2 34 | 35 | [*.json] 36 | indent_size = 4 37 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=false 5 | APP_URL=http://localhost 6 | APP_TIMEZONE="UTC" # https://www.php.net/manual/en/timezones.php 7 | 8 | LOG_CHANNEL=stack 9 | LOG_DEPRECATIONS_CHANNEL=null 10 | LOG_LEVEL=debug 11 | 12 | DB_CONNECTION=mysql 13 | DB_HOST=127.0.0.1 14 | DB_PORT=3306 15 | DB_DATABASE=laravel 16 | DB_USERNAME=root 17 | DB_PASSWORD= 18 | 19 | BROADCAST_DRIVER=log 20 | CACHE_DRIVER=redis 21 | FILESYSTEM_DISK=local 22 | QUEUE_CONNECTION=redis 23 | SESSION_DRIVER=redis 24 | SESSION_LIFETIME=120 25 | 26 | MEMCACHED_HOST=127.0.0.1 27 | 28 | REDIS_HOST=127.0.0.1 29 | REDIS_PASSWORD=null 30 | REDIS_PORT=6379 31 | 32 | MAIL_MAILER=smtp 33 | MAIL_HOST=mailpit 34 | MAIL_PORT=1025 35 | MAIL_USERNAME=null 36 | MAIL_PASSWORD=null 37 | MAIL_ENCRYPTION=null 38 | MAIL_FROM_ADDRESS="hello@example.com" 39 | MAIL_FROM_NAME="${APP_NAME}" 40 | 41 | AWS_ACCESS_KEY_ID= 42 | AWS_SECRET_ACCESS_KEY= 43 | AWS_DEFAULT_REGION=us-east-1 44 | AWS_BUCKET= 45 | AWS_USE_PATH_STYLE_ENDPOINT=false 46 | 47 | PUSHER_APP_ID= 48 | PUSHER_APP_KEY= 49 | PUSHER_APP_SECRET= 50 | PUSHER_HOST= 51 | PUSHER_PORT=443 52 | PUSHER_SCHEME=https 53 | PUSHER_APP_CLUSTER=mt1 54 | 55 | STEAM_AUTH_API_KEYS="" 56 | SETTINGS_CACHE_ENABLED=true 57 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.blade.php diff=html 4 | *.css diff=css 5 | *.html diff=html 6 | *.md diff=markdown 7 | *.php diff=php 8 | 9 | /.github export-ignore 10 | CHANGELOG.md export-ignore 11 | .styleci.yml export-ignore 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/build 3 | /public/hot 4 | /public/storage 5 | /storage/*.key 6 | /vendor 7 | .env 8 | .env.backup 9 | .env.production 10 | .phpunit.result.cache 11 | Homestead.json 12 | Homestead.yaml 13 | auth.json 14 | npm-debug.log 15 | yarn-error.log 16 | /.fleet 17 | /.idea 18 | /.vscode 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SourceAdmin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | SourceAdmin 3 |

4 |
5 | 6 | SourceAdmin is a control panel for managing Source Games, it uses the [Rcon](https://developer.valvesoftware.com/wiki/Source_RCON_Protocol) protocol for many of the useful actions for your servers, such as kick, ban and statistics in general. 7 | 8 |

Project Status

9 | 10 | Currently this project is in development by [Ferks](https://github.com/Ferks-FK), and there is still a lot of building ahead. 11 | If you find any problems with the current code, please open an issue [here](https://github.com/Ferks-FK/SourceAdmin/issues). 12 | Contributions are also welcome. 13 | 14 |

Support

15 | 16 | The project is not really stable yet, but we have a [Discord Group](https://discord.gg/BmGkqSwVHs) to support this project. 17 | 18 |

To-Do List

19 | 20 | - [x] Build a basic front-end. 21 | - [ ] Build all the main logics of the project (kick, ban, statistics). 22 | - [ ] Build a SourcePawn plugin for the game servers (SourceBans plugins are not compatible with this project). 23 | 24 |

Demo

25 | 26 | https://demo.sourceadmin.net/ 27 | 28 |

Preview

29 | 30 | ![](https://i.imgur.com/KiWQEFh.gif) 31 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 19 | } 20 | 21 | /** 22 | * Register the commands for the application. 23 | * 24 | * @return void 25 | */ 26 | protected function commands() 27 | { 28 | $this->load(__DIR__.'/Commands'); 29 | 30 | require base_path('routes/console.php'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Enums/Group.php: -------------------------------------------------------------------------------- 1 | get($this::GITHUB_URL); 20 | 21 | if ($response->successful()) { 22 | $version = $response->object()->tag_name; 23 | 24 | Cache::put('version', $version, now()->addDay()); 25 | 26 | return $version; 27 | } 28 | 29 | Cache::put('version', $version, now()->addHour()); 30 | 31 | return 'unknown'; 32 | } catch (ConnectionException $e) { 33 | Cache::put('version', $version, now()->addHour()); 34 | 35 | return 'unknown'; 36 | } 37 | } 38 | 39 | return Cache::get('version', 'unknown'); 40 | } 41 | 42 | public function isLastestVersion(): bool 43 | { 44 | return $this->getCurrentVersion() === $this->getLatestVersion(); 45 | } 46 | 47 | public function getCurrentVersion() 48 | { 49 | return config('app.version'); 50 | } 51 | 52 | protected function getLatestVersion() 53 | { 54 | return $this->getVersionFromGithub(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/Helpers/SteamHelper.php: -------------------------------------------------------------------------------- 1 | 15) { 18 | return $steamID; 19 | } 20 | 21 | $parts = explode(':', $steamID); 22 | $universe = $parts[0] == 'STEAM' ? 1 : 0; 23 | $accountId = ($parts[2] * 2) + $parts[1] + 0x0110000100000000 + $universe; 24 | 25 | return (string) $accountId; 26 | } 27 | 28 | /** 29 | * Convert a steam64 to SteamID format. 30 | * 31 | * @param int $steam64 The steam64 to be converted. 32 | * 33 | * @return int|string 34 | */ 35 | public static function convertSteam64ToID(int $steam64): int|string 36 | { 37 | // Check if the format is already STEAM_0:... 38 | if (!is_numeric($steam64) || strlen($steam64) !== 17) { 39 | return $steam64; 40 | } 41 | 42 | $steamId64 = (int) $steam64; 43 | $accountId = ($steamId64 & 1) === 0 ? ($steamId64 - 76561197960265728) / 2 : ($steamId64 - 76561197960265729) / 2; 44 | 45 | $steamID = "STEAM_0:" . (($steamId64 & 1) === 0 ? 0 : 1) . ":" . $accountId; 46 | 47 | return $steamID; 48 | } 49 | 50 | /** 51 | * Generates the link to a user's steam profile. 52 | * 53 | * @param string $steamID The user's steamID. 54 | * 55 | * @return string 56 | */ 57 | public static function generateSteamProfileLink(string $steamID) 58 | { 59 | $steamID = self::convertSteamIDTo64($steamID); 60 | 61 | return 'https://steamcommunity.com/profiles/' . $steamID; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/Http/Controllers/Appeal/AppealController.php: -------------------------------------------------------------------------------- 1 | all()); 32 | 33 | AppealJob::dispatch($appeal); 34 | 35 | return redirect()->route('appeal.create')->with('success', __('Your :attribute has been sent to the administrators.', ['attribute' => __('appeal')])); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/AuthController.php: -------------------------------------------------------------------------------- 1 | getCredentials(); 33 | 34 | if (!Auth::validate($credentials)) { 35 | return redirect()->route('auth')->with('error', __('Could not find a user with these credentials.')); 36 | } 37 | 38 | $user = Auth::getProvider()->retrieveByCredentials($credentials); 39 | 40 | Auth::login($user, true); 41 | 42 | return redirect()->route('home.index'); 43 | } 44 | 45 | /** 46 | * Make the user logout of the system. 47 | * 48 | * @param \Illuminate\Http\Request $request 49 | * 50 | * @return \Illuminate\Http\RedirectResponse 51 | */ 52 | public function logout(Request $request) 53 | { 54 | auth()->logout(); 55 | 56 | $request->session()->invalidate(); 57 | 58 | $request->session()->regenerateToken(); 59 | 60 | return redirect()->route('home.index'); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | can($permission)) { 29 | abort(403); 30 | } 31 | } 32 | 33 | /** 34 | * Check if user has permissions 35 | * 36 | * @param string $permission 37 | * @return bool 38 | */ 39 | public function can(string $permission): bool 40 | { 41 | /** @var User $user */ 42 | $user = Auth::user(); 43 | 44 | $isRootAdmin = $user->can(Permission::ALL_PERMISSIONS) ? true : null; 45 | 46 | return $isRootAdmin ?? $user->can($permission); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Http/Controllers/LocaleController.php: -------------------------------------------------------------------------------- 1 | input('locale'); 19 | 20 | if (in_array($locale, array_column(config('locales.locales'), 'code'))) { 21 | Session::put('locale', $locale); 22 | } else { 23 | Session::put('locale', config('app.locale')); 24 | } 25 | 26 | return response()->json([ 27 | 'message' => __('The language was set successfully.') 28 | ]); 29 | } 30 | 31 | /** 32 | * Get the available locales. 33 | * 34 | * @param \Illuminate\Http\Request $request 35 | * 36 | * @return mixed 37 | */ 38 | public function availableLocales(Request $request) 39 | { 40 | $locales = config('locales.locales'); 41 | 42 | if ($request->ajax()) { 43 | return response()->json($locales); 44 | } 45 | 46 | return $locales; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Http/Controllers/Server/ServerController.php: -------------------------------------------------------------------------------- 1 | $this->getServersIds(), 27 | 'data' => $this->getServerData($request) 28 | ]); 29 | } 30 | 31 | /** 32 | * Get a connection to a server. 33 | * 34 | * @param \Illuminate\Http\Request $request 35 | * @param int $id 36 | * 37 | * @return \Illuminate\Http\JsonResponse 38 | */ 39 | public function getServer(Request $request, int $id) 40 | { 41 | return $this->connectToServer($request, $id); 42 | } 43 | 44 | /** 45 | * Get the servers. 46 | * 47 | * @param \Illuminate\Http\Request $request 48 | */ 49 | protected function getServerData(Request $request) 50 | { 51 | $query = QueryBuilder::for(ServerModel::class) 52 | ->where('enabled', true); 53 | 54 | return $request->boolean('all') ? $query->get() : $query->paginate(10)->appends(request()->query()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/AdminCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | 'name' => ['required', 'string'], 30 | 'email' => ['required', 'string', 'email', 'unique:users,email'], 31 | 'steam_id' => [ 32 | 'required', 33 | 'string', 34 | 'unique:users,steam_id', 35 | 'regex:/^(STEAM_[0-5]:[0-1]:\d+|\d{17})$/' 36 | ], 37 | 'role' => ['nullable', 'numeric', 'exists:roles,id'], 38 | 'groups' => ['nullable', 'array'], 39 | 'groups.*' => ['exists:groups,id'], 40 | 'password' => [ 41 | 'required', 42 | 'confirmed', 43 | 'min:8', 44 | 'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/' 45 | ] 46 | ]; 47 | } 48 | 49 | protected function failedValidation(Validator $validator) 50 | { 51 | if ($validator->fails()) { 52 | throw new HttpResponseException ( 53 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 54 | ); 55 | } 56 | 57 | parent::failedValidation($validator); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Ban/BanCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | "ip" => ['string', 'nullable', 'ipv4'], 30 | "steam_id" => ['nullable', 'string', 'regex:/^(STEAM_[0-5]:[0-1]:\d+|\d{17})$/'], 31 | "player_name" => ['required', 'string', 'min:4', 'max:32'], 32 | "time_ban_id" => ['required', 'numeric', 'exists:time_bans,id'], 33 | "admin_id" => ['required', 'numeric', 'exists:users,id'], 34 | "reason_id" => ['required', 'numeric', 'exists:reasons,id'] 35 | ]; 36 | } 37 | 38 | protected function failedValidation(Validator $validator) 39 | { 40 | if ($validator->fails()) { 41 | throw new HttpResponseException ( 42 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 43 | ); 44 | } 45 | 46 | parent::failedValidation($validator); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Ban/BanUpdateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | "reason_id" => ['required', 'numeric', 'exists:reasons,id'], 30 | "time_ban_id" => ['required', 'numeric', 'exists:time_bans,id'] 31 | ]; 32 | } 33 | 34 | protected function failedValidation(Validator $validator) 35 | { 36 | if ($validator->fails()) { 37 | throw new HttpResponseException ( 38 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 39 | ); 40 | } 41 | 42 | parent::failedValidation($validator); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Mod/ModCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | 'name' => ['required', 'string', 'unique:mods,name'], 30 | 'mod' => ['required', 'string'], 31 | 'upload_mod_icon' => ['required', 'file', 'mimes:png,jpg', 'max:5120'], 32 | 'enabled' => ['boolean'] 33 | ]; 34 | } 35 | 36 | protected function failedValidation(Validator $validator) 37 | { 38 | if ($validator->fails()) { 39 | throw new HttpResponseException ( 40 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 41 | ); 42 | } 43 | 44 | parent::failedValidation($validator); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Mod/ModUpdateRequest.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | public function rules() 28 | { 29 | return [ 30 | 'name' => ['required', 'string'], 31 | 'mod' => [ 32 | 'required', 33 | 'string', 34 | Rule::unique('mods', 'mod')->ignore($this->mod, 'mod') 35 | ], 36 | 'icon_id' => ['required', 'numeric'], 37 | 'enabled' => ['boolean'] 38 | ]; 39 | } 40 | 41 | protected function failedValidation(Validator $validator) 42 | { 43 | if ($validator->fails()) { 44 | throw new HttpResponseException ( 45 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 46 | ); 47 | } 48 | 49 | parent::failedValidation($validator); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Mute/MuteCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | "ip" => ['string', 'nullable', 'ipv4'], 30 | "steam_id" => ['nullable', 'string', 'regex:/^(STEAM_[0-5]:[0-1]:\d+|\d{17})$/'], 31 | "player_name" => ['required', 'string', 'min:4', 'max:32'], 32 | "time_ban_id" => ['required', 'numeric', 'exists:time_bans,id'], 33 | "admin_id" => ['required', 'numeric', 'exists:users,id'], 34 | "reason_id" => ['required', 'numeric', 'exists:reasons,id'] 35 | ]; 36 | } 37 | 38 | protected function failedValidation(Validator $validator) 39 | { 40 | if ($validator->fails()) { 41 | throw new HttpResponseException ( 42 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 43 | ); 44 | } 45 | 46 | parent::failedValidation($validator); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Mute/MuteUpdateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | "reason_id" => ['required', 'numeric', 'exists:reasons,id'], 30 | "time_ban_id" => ['required', 'numeric', 'exists:time_bans,id'] 31 | ]; 32 | } 33 | 34 | protected function failedValidation(Validator $validator) 35 | { 36 | if ($validator->fails()) { 37 | throw new HttpResponseException ( 38 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 39 | ); 40 | } 41 | 42 | parent::failedValidation($validator); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Role/RoleCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | 'name' => ['required', 'string', 'unique:roles,name'], 30 | 'description' => ['nullable', 'string'], 31 | 'permissions' => ['required', 'array'], 32 | 'permissions.*' => ['exists:permissions,name'] 33 | ]; 34 | } 35 | 36 | protected function prepareForValidation() 37 | { 38 | $permissions = $this->input('permissions'); 39 | 40 | // Remove all other permissions if the 'All Permissions' option is sent. 41 | if (in_array('*', $permissions)) { 42 | $permissions = ['*']; 43 | } 44 | 45 | $this->merge([ 46 | 'permissions' => $permissions, 47 | ]); 48 | } 49 | 50 | protected function failedValidation(Validator $validator) 51 | { 52 | if ($validator->fails()) { 53 | throw new HttpResponseException ( 54 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 55 | ); 56 | } 57 | 58 | parent::failedValidation($validator); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Role/RoleUpdateRequest.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | public function rules() 28 | { 29 | return [ 30 | 'name' => [ 31 | 'required', 32 | 'string', 33 | Rule::unique('roles', 'name')->ignore($this->id, 'id') 34 | ], 35 | 'description' => ['nullable', 'string'], 36 | 'permissions' => ['required', 'array'], 37 | 'permissions.*' => ['exists:permissions,name'] 38 | ]; 39 | } 40 | 41 | protected function prepareForValidation() 42 | { 43 | $permissions = $this->input('permissions'); 44 | 45 | // Remove all other permissions if the 'All Permissions' option is sent. 46 | if (in_array('*', $permissions)) { 47 | $permissions = ['*']; 48 | } 49 | 50 | $this->merge([ 51 | 'permissions' => $permissions, 52 | ]); 53 | } 54 | 55 | protected function failedValidation(Validator $validator) 56 | { 57 | if ($validator->fails()) { 58 | throw new HttpResponseException ( 59 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 60 | ); 61 | } 62 | 63 | parent::failedValidation($validator); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/Http/Requests/Admin/Server/ServerCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | 'ip' => ['required', 'regex:/^(?:(?:https?|http):\/\/)?(?:[a-zA-Z0-9]+\.[a-zA-Z]{2,}|(?:\d{1,3}\.){3}\d{1,3})(?:\/\S*)?$/'], 30 | 'port' => ['required', 'regex:/^(?:[1-9]\d{0,3}|[1-5]\d{4}|6(?:[0-4]\d{3}|5(?:[0-4]\d{2}|5(?:[0-2]\d|3[0-5]))))$/'], 31 | 'rcon' => ['required', 'min:8', 'confirmed'], 32 | 'mod_id' => ['required', 'numeric', 'exists:mods,id'], 33 | 'region_id' => ['required', 'numeric', 'exists:regions,id'], 34 | 'enabled' => ['required', 'boolean'] 35 | ]; 36 | } 37 | 38 | protected function failedValidation(Validator $validator) 39 | { 40 | if ($validator->fails()) { 41 | throw new HttpResponseException ( 42 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 43 | ); 44 | } 45 | 46 | parent::failedValidation($validator); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/Http/Requests/Appeal/AppealCreateRequest.php: -------------------------------------------------------------------------------- 1 | 25 | */ 26 | public function rules() 27 | { 28 | return [ 29 | 'player_steam_id' => ['nullable', 'string', 'regex:/^(STEAM_[0-5]:[0-1]:\d+|\d{17})$/'], 30 | 'player_ip' => ['string', 'nullable', 'ipv4'], 31 | 'player_name' => ['required', 'string', 'min:4', 'max:32'], 32 | 'player_email' => ['required', 'string', 'email'], 33 | 'reason' => ['required', 'string', 'max:1024'] 34 | ]; 35 | } 36 | 37 | protected function failedValidation(Validator $validator) 38 | { 39 | if ($validator->fails()) { 40 | throw new HttpResponseException ( 41 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 42 | ); 43 | } 44 | 45 | parent::failedValidation($validator); 46 | } 47 | 48 | public function attributes() 49 | { 50 | return [ 51 | trans('validation.attributes') 52 | ]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/Http/Requests/Auth/LoginRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 29 | 'password' => 'required' 30 | ]; 31 | } 32 | 33 | /** 34 | * Get the needed authorization credentials from the request. 35 | * 36 | * @return array 37 | * @throws \Illuminate\Contracts\Container\BindingResolutionException 38 | */ 39 | public function getCredentials() 40 | { 41 | // The form field for providing username or password 42 | // have name of "username", however, in order to support 43 | // logging users in with both (username and email) 44 | // we have to check if user has entered one or another 45 | $username = $this->get('name'); 46 | 47 | if ($this->isEmail($username)) { 48 | return [ 49 | 'email' => $username, 50 | 'password' => $this->get('password') 51 | ]; 52 | } 53 | 54 | return $this->only('name', 'password'); 55 | } 56 | 57 | /** 58 | * Validate if provided parameter is valid email. 59 | * 60 | * @param $param 61 | * @return bool 62 | * @throws \Illuminate\Contracts\Container\BindingResolutionException 63 | */ 64 | private function isEmail($param) 65 | { 66 | $factory = $this->container->make(ValidationFactory::class); 67 | 68 | return !$factory->make( 69 | ['name' => $param], 70 | ['name' => 'email'] 71 | )->fails(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/Http/Requests/Report/ReportCreateRequest.php: -------------------------------------------------------------------------------- 1 | 29 | */ 30 | public function rules() 31 | { 32 | $servers_ids = $this->getServersIds(getAll: true); // Allow only the server ID's registered in the DB. 33 | 34 | return [ 35 | 'player_steam_id' => ['nullable', 'string', 'regex:/^(STEAM_[0-5]:[0-1]:\d+|\d{17})$/'], 36 | 'player_ip' => ['string', 'nullable', 'ipv4'], 37 | 'player_name' => ['required', 'string', 'min:4', 'max:32'], 38 | 'comments' => ['required', 'string', 'max:1024'], 39 | 'reporter_name' => ['required', 'string', 'min:4', 'max:32'], 40 | 'reporter_email' => ['required', 'string', 'email'], 41 | 'server_id' => ['required', Rule::in($servers_ids)], 42 | 'upload_demo' => ['nullable', 'file', 'mimes:zip,rar,dem', 'max:25000'] 43 | ]; 44 | 45 | } 46 | 47 | protected function failedValidation(Validator $validator) 48 | { 49 | if ($validator->fails()) { 50 | throw new HttpResponseException ( 51 | redirect()->back()->withInput()->withErrors($validator->errors(), 'errors') 52 | ); 53 | } 54 | 55 | parent::failedValidation($validator); 56 | } 57 | 58 | public function attributes() 59 | { 60 | return [ 61 | trans('validation.attributes') 62 | ]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/Http/Requests/User/ProfileUpdateRequest.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | public function rules() 17 | { 18 | return [ 19 | 'name' => ['string', 'max:255'], 20 | 'email' => ['email', 'max:255', Rule::unique(User::class)->ignore($this->user()->id)], 21 | ]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Jobs/Appeal.php: -------------------------------------------------------------------------------- 1 | appeal = $appeal; 29 | } 30 | 31 | /** 32 | * Execute the job. 33 | * 34 | * @return void 35 | */ 36 | public function handle() 37 | { 38 | $users = User::all(); 39 | foreach ($users as $user) { 40 | Notification::send($user, new AppealNotification($user, $this->appeal)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/Jobs/ReportPlayer.php: -------------------------------------------------------------------------------- 1 | report = $report; 31 | } 32 | 33 | /** 34 | * Execute the job. 35 | * 36 | * @return void 37 | */ 38 | public function handle() 39 | { 40 | $users = User::all(); 41 | foreach ($users as $user) { 42 | Notification::send($user, new ReportPlayerNotification($user, $this->report)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Mail/PlayerReported.php: -------------------------------------------------------------------------------- 1 | user = $user; 32 | } 33 | 34 | /** 35 | * Build the message. 36 | * 37 | * @return $this 38 | */ 39 | public function build() 40 | { 41 | $this->subject('Player Reported'); 42 | 43 | return $this->markdown('mail.reportPlayer', [ 44 | 'user' => $this->user 45 | ]); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/Models/Appeal.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | protected $fillable = [ 18 | 'player_ip', 19 | 'player_steam_id', 20 | 'player_name', 21 | 'player_email', 22 | 'reason' 23 | ]; 24 | } 25 | -------------------------------------------------------------------------------- /app/Models/Ban.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | protected $fillable = [ 22 | 'ip', 23 | 'steam_id', 24 | 'player_name', 25 | 'admin_id', 26 | 'reason_id', 27 | 'time_ban_id', 28 | 'removed_by', 29 | 'removed_on', 30 | 'unban_reason', 31 | 'flag_url' 32 | ]; 33 | 34 | /** 35 | * Get the ISO code of the ban country. 36 | * 37 | * @param mixed $ip 38 | * @return string|null 39 | */ 40 | public static function getLocation(mixed $ip): string|null 41 | { 42 | $countryCode = Location::get($ip); 43 | 44 | return $countryCode != false ? strtolower($countryCode->countryCode) : null; 45 | } 46 | 47 | /** 48 | * Get the server associated with the ban. 49 | */ 50 | public function server(): HasOne 51 | { 52 | return $this->hasOne(Server::class); 53 | } 54 | 55 | /** 56 | * Get the time_ban associated with the ban. 57 | */ 58 | public function time_ban(): HasOne 59 | { 60 | return $this->hasOne(TimeBans::class); 61 | } 62 | 63 | /** 64 | * Get the admin associated with the ban. 65 | */ 66 | public function admin(): HasOne 67 | { 68 | return $this->hasOne(User::class); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/Models/Group.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | protected $fillable = [ 19 | 'name', 20 | 'description', 21 | 'type' 22 | ]; 23 | 24 | /** 25 | * Get the users associated with the group. 26 | */ 27 | public function users(): BelongsToMany 28 | { 29 | return $this->belongsToMany(User::class, 'user_has_groups'); 30 | } 31 | 32 | /** 33 | * Get the permissions associated with the group. 34 | */ 35 | public function permissions() 36 | { 37 | return $this->belongsToMany(Permission::class, 'group_has_permissions'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Models/Mod.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected $fillable = [ 21 | 'mod', 22 | 'name', 23 | 'enabled' 24 | ]; 25 | 26 | /** 27 | * Get the servers associated with the mod. 28 | */ 29 | public function servers(): HasMany 30 | { 31 | return $this->hasMany(Server::class); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Models/Mute.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | protected $fillable = [ 20 | 'ip', 21 | 'steam_id', 22 | 'player_name', 23 | 'admin_id', 24 | 'reason_id', 25 | 'time_ban_id', 26 | 'removed_by', 27 | 'removed_on', 28 | 'unban_reason' 29 | ]; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/Models/Permission.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | protected $fillable = [ 18 | 'name', 19 | 'guard_name', 20 | 'readable_name' 21 | ]; 22 | 23 | /** 24 | * Get the groups associated with the permission. 25 | */ 26 | public function groups() 27 | { 28 | return $this->belongsToMany(Group::class, 'group_has_permissions'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Models/Reason.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | protected $fillable = [ 18 | 'reason' 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /app/Models/Region.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected $fillable = [ 21 | 'region', 22 | 'enabled' 23 | ]; 24 | 25 | /** 26 | * Get the servers associated with the region. 27 | */ 28 | public function servers(): HasMany 29 | { 30 | return $this->hasMany(Server::class); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Models/Report.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | protected $fillable = [ 18 | 'player_ip', 19 | 'player_steam_id', 20 | 'player_name', 21 | 'comments', 22 | 'reporter_name', 23 | 'reporter_email', 24 | 'server_id', 25 | 'upload_demo' 26 | ]; 27 | } 28 | -------------------------------------------------------------------------------- /app/Models/Role.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | protected $fillable = [ 18 | 'name', 19 | 'guard_name', 20 | 'description' 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /app/Models/Server.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | protected $fillable = [ 20 | 'ip', 21 | 'port', 22 | 'rcon', 23 | 'mod_id', 24 | 'region_id', 25 | 'enabled' 26 | ]; 27 | 28 | /** 29 | * The attributes that should be hidden for serialization. 30 | * 31 | * @var array 32 | */ 33 | protected $hidden = [ 34 | 'rcon' 35 | ]; 36 | 37 | /** 38 | * The attributes that should be cast. 39 | * 40 | * @var array 41 | */ 42 | protected $casts = [ 43 | 'id' => 'integer', 44 | 'enabled' => 'boolean' 45 | ]; 46 | 47 | public function setRconAttribute($value) 48 | { 49 | $this->attributes['rcon'] = Hash::make($value); 50 | } 51 | 52 | /** 53 | * Get the mod associated with the server. 54 | */ 55 | public function mod(): HasOne 56 | { 57 | return $this->hasOne(Mod::class); 58 | } 59 | 60 | /** 61 | * Get the bans associated with the server. 62 | */ 63 | public function bans() 64 | { 65 | return $this->hasMany(Ban::class); 66 | } 67 | 68 | /** 69 | * Get the region associated with the server. 70 | */ 71 | public function region(): HasOne 72 | { 73 | return $this->hasOne(Region::class); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/Models/TimeBan.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | protected $fillable = [ 21 | 'name', 22 | 'value' 23 | ]; 24 | 25 | /** 26 | * The attributes that should be cast. 27 | * 28 | * @var array 29 | */ 30 | protected $casts = [ 31 | 'id' => 'int' 32 | ]; 33 | 34 | /** 35 | * Get the bans associated with the time_ban. 36 | */ 37 | public function bans(): HasMany 38 | { 39 | return $this->hasMany(Ban::class); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Notifications/Appeal.php: -------------------------------------------------------------------------------- 1 | user = $user; 29 | $this->appeal = $appeal; 30 | $this->steamHelper = new SteamHelper; 31 | } 32 | 33 | /** 34 | * Get the notification's delivery channels. 35 | * 36 | * @param mixed $notifiable 37 | * @return array 38 | */ 39 | public function via() 40 | { 41 | return ['mail']; 42 | } 43 | 44 | /** 45 | * Get the mail representation of the notification. 46 | * 47 | * @param mixed $notifiable 48 | * @return \Illuminate\Notifications\Messages\MailMessage 49 | */ 50 | public function toMail() 51 | { 52 | $steamProfile = is_null($this->appeal->player_steam_id) ? null : $this->steamHelper->generateSteamProfileLink($this->appeal->player_steam_id); 53 | 54 | return (new MailMessage) 55 | ->subject('Appeal Received') 56 | ->markdown('mail.appeal', [ 57 | 'userName' => $this->user->name, 58 | 'content' => $this->appeal, 59 | 'steamIDUrl' => $steamProfile 60 | ]); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/Notifications/ReportPlayer.php: -------------------------------------------------------------------------------- 1 | user = $user; 29 | $this->report = $report; 30 | $this->steamHelper = new SteamHelper; 31 | } 32 | 33 | /** 34 | * Get the notification's delivery channels. 35 | * 36 | * @param mixed $notifiable 37 | * @return array 38 | */ 39 | public function via() 40 | { 41 | return ['mail']; 42 | } 43 | 44 | /** 45 | * Get the mail representation of the notification. 46 | * 47 | * @param mixed $notifiable 48 | * @return \Illuminate\Notifications\Messages\MailMessage 49 | */ 50 | public function toMail() 51 | { 52 | $steamProfile = is_null($this->report->player_steam_id) ? null : $this->steamHelper->generateSteamProfileLink($this->report->player_steam_id); 53 | 54 | return (new MailMessage) 55 | ->subject('Player Report') 56 | ->markdown('mail.playerReported', [ 57 | 'userName' => $this->user->name, 58 | 'content' => $this->report, 59 | 'steamIDUrl' => $steamProfile 60 | ]); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/Notifications/TestEmail.php: -------------------------------------------------------------------------------- 1 | user = $user; 25 | } 26 | 27 | /** 28 | * Get the notification's delivery channels. 29 | * 30 | * @param mixed $notifiable 31 | * @return array 32 | */ 33 | public function via() 34 | { 35 | return ['mail']; 36 | } 37 | 38 | /** 39 | * Get the mail representation of the notification. 40 | * 41 | * @param mixed $notifiable 42 | * @return \Illuminate\Notifications\Messages\MailMessage 43 | */ 44 | public function toMail() 45 | { 46 | return (new MailMessage) 47 | ->subject('SourceAdmin Mail Test') 48 | ->greeting('Hello ' . $this->user->name . '!') 49 | ->line('This is a test message from SourceAdmin Panel, everything is working!') 50 | ->action('Return to panel', route('home.index')); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/Observers/BanObserver.php: -------------------------------------------------------------------------------- 1 | updatedBanLength($ban); 31 | } 32 | 33 | /** 34 | * Handle the Ban "updated" event. 35 | * 36 | * @param \App\Models\Ban $ban 37 | * @return void 38 | */ 39 | public function updated(Ban $ban) 40 | { 41 | // Search the servers for the banned player, and if found, kick him. 42 | } 43 | 44 | /** 45 | * Handle the Ban "updating" event. 46 | * 47 | * @param \App\Models\Ban $ban 48 | * @return void 49 | */ 50 | public function updating(Ban $ban) 51 | { 52 | $this->updatedBanLength($ban); 53 | } 54 | 55 | protected function updatedBanLength(Ban $ban): void 56 | { 57 | $time_ban = TimeBan::where('id', $ban->time_ban_id)->get('value')->first(); 58 | 59 | // Set to null if the ban is permanent. 60 | if ($time_ban->value == 0) { 61 | $ban->end_at = null; 62 | 63 | return; 64 | } 65 | 66 | // Set a new end date for the ban if it is not permanent. 67 | if ($time_ban->value != 0) { 68 | $end_at = Carbon::now(config('app.timezone'))->addMinutes($time_ban->value)->toDateTimeString(); 69 | 70 | $ban->end_at = $end_at; 71 | 72 | return; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/Observers/UserObserver.php: -------------------------------------------------------------------------------- 1 | > 19 | */ 20 | protected $listen = [ 21 | Registered::class => [ 22 | SendEmailVerificationNotification::class, 23 | ], 24 | ]; 25 | 26 | /** 27 | * Register any events for your application. 28 | * 29 | * @return void 30 | */ 31 | public function boot() 32 | { 33 | Ban::observe(BanObserver::class); 34 | Mute::observe(MuteObserver::class); 35 | } 36 | 37 | /** 38 | * Determine if events and listeners should be automatically discovered. 39 | * 40 | * @return bool 41 | */ 42 | public function shouldDiscoverEvents() 43 | { 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Traits/Group.php: -------------------------------------------------------------------------------- 1 | groups()->where('type', $groupType)->get(); 22 | 23 | $permissionsToSync = $groups->flatMap(function ($group) use ($groupType) { 24 | return $group->permissions()->where('type', $groupType)->pluck('id')->all(); 25 | }); 26 | 27 | $user->syncPermissions($permissionsToSync); 28 | } 29 | 30 | /** 31 | * Remove all individual user permissions. 32 | * 33 | * @param \App\Models\Group $group 34 | * 35 | * @return void 36 | */ 37 | public function removeAllPermissions(GroupModel $group) 38 | { 39 | $usersIds = $group->users()->pluck('id')->all(); 40 | $users = User::whereIn('id', $usersIds)->get(); 41 | 42 | foreach ($users as $user) { 43 | $user->syncPermissions([]); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Traits/Server.php: -------------------------------------------------------------------------------- 1 | ip, $server->port, $server->rcon); 17 | 18 | if ($request->boolean('getPlayers')) { 19 | return response()->json([ 20 | "server" => $query->getServerData(), 21 | "players" => $query->getPlayerData() 22 | ]); 23 | } 24 | 25 | return response()->json([ 26 | "server" => $query->getServerData() 27 | ]); 28 | } 29 | 30 | public function getServerAttributes($id, array $attrs) 31 | { 32 | return ServerModel::where('id', $id)->get($attrs); 33 | } 34 | 35 | public function getServersIds(int $limit = 10, bool $getAll = false): array 36 | { 37 | $servers = ServerModel::where('enabled', true)->pluck('id')->toArray(); 38 | 39 | if ($getAll) { 40 | return ServerModel::pluck('id')->toArray(); 41 | } 42 | 43 | return array_slice($servers, 0, $limit); 44 | } 45 | 46 | public function removeServerFromCache($id) 47 | { 48 | if (Cache::has('server.' . $id)) { 49 | Cache::forget('server.' . $id); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 34 | 35 | $status = $kernel->handle( 36 | $input = new Symfony\Component\Console\Input\ArgvInput, 37 | new Symfony\Component\Console\Output\ConsoleOutput 38 | ); 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Shutdown The Application 43 | |-------------------------------------------------------------------------- 44 | | 45 | | Once Artisan has finished running, we will fire off the shutdown events 46 | | so that any final work may be done by the application before we shut 47 | | down the process. This is the last thing to happen to the request. 48 | | 49 | */ 50 | 51 | $kernel->terminate($input, $status); 52 | 53 | exit($status); 54 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | withRouting( 9 | web: __DIR__.'/../routes/web.php', 10 | commands: __DIR__.'/../routes/console.php', 11 | health: '/up', 12 | ) 13 | ->withMiddleware(function (Middleware $middleware) { 14 | // 15 | }) 16 | ->withExceptions(function (Exceptions $exceptions) { 17 | // 18 | })->create(); 19 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /bootstrap/providers.php: -------------------------------------------------------------------------------- 1 | ['api/*', 'sanctum/csrf-cookie'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 65536, 48 | 'threads' => 1, 49 | 'time' => 4, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /config/locales.php: -------------------------------------------------------------------------------- 1 | [ 15 | [ 16 | "name" => "English (United States)", 17 | "code" => "en", 18 | "flag" => "us" 19 | ], 20 | [ 21 | "name" => "Portuguese (Brazil)", 22 | "code" => "pt", 23 | "flag" => "br" 24 | ], 25 | [ 26 | "name" => "Spanish (Spain)", 27 | "code" => "es", 28 | "flag" => "es" 29 | ] 30 | ] 31 | ]; 32 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), 21 | 'scheme' => 'https', 22 | ], 23 | 24 | 'postmark' => [ 25 | 'token' => env('POSTMARK_TOKEN'), 26 | ], 27 | 28 | 'ses' => [ 29 | 'key' => env('AWS_ACCESS_KEY_ID'), 30 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 31 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 32 | ], 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /database/factories/BanFactory.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class BanFactory extends Factory 11 | { 12 | /** 13 | * Define the model's default state. 14 | * 15 | * @return array 16 | */ 17 | public function definition() 18 | { 19 | return [ 20 | "ip" => $this->faker->ipv4(), 21 | "player_name" => $this->faker->name(), 22 | "created_at" => now(), 23 | "end_at" => now()->addDays(15), 24 | "admin_id" => mt_rand(1, 10), 25 | "reason_id" => mt_rand(1, 10), 26 | "time_ban_id" => mt_rand(1, 10), 27 | "server_id" => 1, 28 | "flag_url" => "https://flagcdn.com/br.svg" 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /database/factories/MuteFactory.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class MuteFactory extends Factory 12 | { 13 | /** 14 | * Define the model's default state. 15 | * 16 | * @return array 17 | */ 18 | public function definition() 19 | { 20 | $column_types = ['chat', 'voice', 'all']; 21 | 22 | return [ 23 | "ip" => $this->faker->ipv4(), 24 | "player_name" => $this->faker->name(), 25 | "created_at" => now(), 26 | "end_at" => now()->addDays(15), 27 | "admin_id" => mt_rand(1, 10), 28 | "reason_id" => mt_rand(1, 10), 29 | "time_ban_id" => mt_rand(1, 10), 30 | "server_id" => 1, 31 | "type" => $column_types[array_rand($column_types)] 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/factories/ServerFactory.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class ServerFactory extends Factory 11 | { 12 | /** 13 | * Define the model's default state. 14 | * 15 | * @return array 16 | */ 17 | public function definition() 18 | { 19 | return [ 20 | "ip" => "103.88.233.84", 21 | "port" => "27315", 22 | "rcon" => "password", 23 | "mod_id" => 2, 24 | "region_id" => 3 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class UserFactory extends Factory 12 | { 13 | /** 14 | * Define the model's default state. 15 | * 16 | * @return array 17 | */ 18 | public function definition() 19 | { 20 | return [ 21 | 'name' => fake()->name(), 22 | 'email' => fake()->unique()->safeEmail(), 23 | 'steam_id' => 'STEAM_0:1:' . random_int(1234567895, 9876543211), 24 | 'email_verified_at' => now(), 25 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 26 | 'remember_token' => Str::random(10), 27 | ]; 28 | } 29 | 30 | /** 31 | * Indicate that the model's email address should be unverified. 32 | * 33 | * @return static 34 | */ 35 | public function unverified() 36 | { 37 | return $this->state(fn (array $attributes) => [ 38 | 'email_verified_at' => null, 39 | ]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->bigInteger('steam_id')->unique(); 21 | $table->timestamp('email_verified_at')->nullable(); 22 | $table->string('password'); 23 | $table->boolean('should_re_login')->default(true); 24 | $table->rememberToken(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('users'); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('uuid')->unique(); 19 | $table->text('connection'); 20 | $table->text('queue'); 21 | $table->longText('payload'); 22 | $table->longText('exception'); 23 | $table->timestamp('failed_at')->useCurrent(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('failed_jobs'); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->morphs('tokenable'); 19 | $table->string('name'); 20 | $table->string('token', 64)->unique(); 21 | $table->text('abilities')->nullable(); 22 | $table->timestamp('last_used_at')->nullable(); 23 | $table->timestamp('expires_at')->nullable(); 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('personal_access_tokens'); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /database/migrations/2022_11_23_150916_create_mods_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('mod'); 19 | $table->string('name'); 20 | $table->boolean('enabled'); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('mods'); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /database/migrations/2022_11_28_193231_create_reasons_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('reason'); 19 | $table->timestamps(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('reasons'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/migrations/2022_11_28_193245_create_time_bans_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('name'); 19 | $table->integer('value'); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('time_bans'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/migrations/2022_12_14_083707_create_settings_table.php: -------------------------------------------------------------------------------- 1 | id(); 13 | 14 | $table->string('group'); 15 | $table->string('name'); 16 | $table->boolean('locked')->default(false); 17 | $table->json('payload'); 18 | 19 | $table->timestamps(); 20 | 21 | $table->unique(['group', 'name']); 22 | }); 23 | } 24 | 25 | public function down() 26 | { 27 | Schema::dropIfExists('settings'); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /database/migrations/2023_05_23_134640_create_appeals_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->ipAddress('player_ip')->nullable(); 19 | $table->string('player_steam_id')->nullable(); 20 | $table->string('player_name'); 21 | $table->string('player_email'); 22 | $table->longText('reason'); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('appeals'); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /database/migrations/2023_06_13_125656_create_regions_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('region'); 19 | $table->boolean('enabled'); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('regions'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/migrations/2023_06_13_140310_create_servers_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->ipAddress('ip'); 19 | $table->integer('port'); 20 | $table->string('rcon'); 21 | $table->foreignId('mod_id')->nullable()->constrained('mods')->nullOnDelete(); 22 | $table->foreignId('region_id')->constrained('regions'); 23 | $table->boolean('enabled')->default(true); 24 | $table->timestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::dropIfExists('servers'); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /database/migrations/2023_06_13_140542_create_reports_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->ipAddress('player_ip')->nullable(); 19 | $table->string('player_steam_id')->nullable(); 20 | $table->string('player_name'); 21 | $table->longText('comments'); 22 | $table->string('reporter_name')->nullable(); 23 | $table->string('reporter_email'); 24 | $table->foreignId('server_id')->nullable()->constrained('servers')->nullOnDelete(); 25 | $table->string('upload_demo')->nullable(); 26 | $table->timestamps(); 27 | }); 28 | } 29 | 30 | /** 31 | * Reverse the migrations. 32 | * 33 | * @return void 34 | */ 35 | public function down() 36 | { 37 | Schema::dropIfExists('reports'); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /database/migrations/2023_06_13_140620_create_mutes_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->ipAddress('ip')->nullable(); 19 | $table->string('steam_id')->nullable(); 20 | $table->string('player_name'); 21 | $table->enum('type', ['chat', 'voice', 'all']); 22 | $table->timestamp('created_at')->useCurrent(); 23 | $table->timestamp('end_at')->nullable(); 24 | $table->foreignId('admin_id')->nullable()->constrained('users')->nullOnDelete(); 25 | $table->foreignId('reason_id')->constrained('reasons'); 26 | $table->foreignId('time_ban_id')->constrained('time_bans'); 27 | $table->foreignId('server_id')->nullable()->constrained('servers')->nullOnDelete(); 28 | $table->foreignId('removed_by')->nullable()->constrained('users'); 29 | $table->timestamp('removed_on')->nullable(); 30 | $table->string('unban_reason')->nullable(); 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | * 37 | * @return void 38 | */ 39 | public function down() 40 | { 41 | Schema::dropIfExists('mutes'); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /database/migrations/2023_06_13_140641_create_bans_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->ipAddress('ip')->nullable(); 19 | $table->string('steam_id')->nullable(); 20 | $table->string('player_name'); 21 | $table->timestamp('created_at')->useCurrent(); 22 | $table->timestamp('end_at')->nullable(); 23 | $table->foreignId('admin_id')->nullable()->constrained('users')->nullOnDelete(); 24 | $table->foreignId('reason_id')->constrained('reasons'); 25 | $table->foreignId('time_ban_id')->constrained('time_bans'); 26 | $table->foreignId('server_id')->nullable()->constrained('servers')->nullOnDelete(); 27 | $table->foreignId('removed_by')->nullable()->constrained('users'); 28 | $table->timestamp('removed_on')->nullable(); 29 | $table->string('unban_reason')->nullable(); 30 | $table->string('flag_url')->nullable(); 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | * 37 | * @return void 38 | */ 39 | public function down() 40 | { 41 | Schema::dropIfExists('bans'); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /database/migrations/2023_07_18_104629_create_groups_table.php: -------------------------------------------------------------------------------- 1 | id(); 19 | $table->string('name')->unique(); 20 | $table->string('description')->nullable(); 21 | $table->enum('type', [Group::WEB->value, Group::SERVER->value, Group::SERVER_ADMIN->value]); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('groups'); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /database/migrations/2023_07_19_102438_create_table_user_has_groups.php: -------------------------------------------------------------------------------- 1 | foreignId('user_id')->constrained('users')->cascadeOnDelete(); 18 | $table->foreignId('group_id')->constrained('groups')->cascadeOnDelete(); 19 | $table->primary(['user_id', 'group_id']); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('user_has_groups'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call([ 27 | UserWeb::class, // The 'Console' user, used for when something non-human does an action on the servers. 28 | ModsSeeder::class, 29 | ReasonSeeder::class, 30 | TimeBansSeeder::class, 31 | RegionsSeeder::class, 32 | ]); 33 | 34 | if (config("app.env") === "development" || config("app.env") === "local") { 35 | User::factory(150)->create(); 36 | Server::factory(1)->create(); 37 | Ban::factory(150)->create(); 38 | Mute::factory(150)->create(); 39 | 40 | $this->editMyUser(); 41 | } 42 | } 43 | 44 | protected function editMyUser() 45 | { 46 | $me = User::find(1); 47 | 48 | $me->name = 'Ferks'; 49 | $me->should_re_login = false; 50 | $me->steam_id = 'STEAM_0:1:222936006'; 51 | 52 | $me->save(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /database/seeders/ModsSeeder.php: -------------------------------------------------------------------------------- 1 | mods() as $mod_key => $mod_value) { 18 | DB::table('mods')->insert([ 19 | 'mod' => $mod_key, 20 | 'name' => $mod_value, 21 | 'enabled' => $mod_key === 'web' ? false : true 22 | ]); 23 | } 24 | } 25 | 26 | private function mods() 27 | { 28 | return [ 29 | // IDK all the names of the games, if you do, tell me later xD 30 | 31 | 'web' => config('app.name'), 32 | 'alienswarm' => 'Alien Swarm', 33 | 'csgo' => 'Counter Strike - Global Offensive', 34 | 'csource' => 'Counter Strike - Source', 35 | 'cspromod' => 'Counter Strike - Source Promod', 36 | 'dods' => 'Day of Defeat', 37 | 'dys' => 'Dystopia', 38 | 'eye' => 'E.Y.E - Divine Cybermancy', 39 | 'gmod' => "Garry's Mod", 40 | 'hidden' => 'Hidden', 41 | 'hl2-fortressforever' => 'Fortress Forever', 42 | 'hl2ctf' => 'Half-Life 2 - Capture the Flag', 43 | 'hl2dm' => 'Half-Life 2 - Deathmatch', 44 | 'ins' => 'Insurgency', 45 | 'l4d' => 'Left 4 Dead', 46 | 'l4d2' => 'Left 4 Dead 2', 47 | 'nucleardawn' => 'Nuclear Dawn', 48 | 'pdark' => 'Perfect Dark: Source', 49 | 'pvkii' => 'Pirates, Vikings, and Knights II', 50 | 'ship' => 'The Ship', 51 | 'source-forts' => 'SourceForts Gamemode', 52 | 'synergy' => 'Synergy', 53 | 'tf2' => 'Team Fortress 2', 54 | 'zps' => 'Zombie Panic - Source' 55 | ]; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /database/seeders/ReasonSeeder.php: -------------------------------------------------------------------------------- 1 | reasons() as $reason) { 18 | DB::table('reasons')->insert([ 19 | 'reason' => $reason 20 | ]); 21 | } 22 | } 23 | 24 | public function reasons() 25 | { 26 | return [ 27 | 'Aimbot', 28 | 'WallHack', 29 | 'Antirecoil', 30 | 'Spinhack', 31 | 'Multi-Hack', 32 | 'Team Killing', 33 | 'Team Flashing', 34 | 'Spamming Mic/Chat', 35 | 'Inappropriate Spray', 36 | 'Inappropriate Language', 37 | 'Inappropriate Name', 38 | 'Ignoring Admins', 39 | 'Team Stacking' 40 | ]; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /database/seeders/RegionsSeeder.php: -------------------------------------------------------------------------------- 1 | regions() as $region) { 18 | DB::table('regions')->insert([ 19 | 'region' => $region, 20 | 'enabled' => true 21 | ]); 22 | } 23 | } 24 | 25 | private function regions() 26 | { 27 | return [ 28 | 'Africa', 29 | 'North America', 30 | 'South America', 31 | 'Asia', 32 | 'Europe', 33 | 'Oceania', 34 | 'Antarctica' 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /database/seeders/TimeBansSeeder.php: -------------------------------------------------------------------------------- 1 | time_bans() as $name => $value) { 18 | DB::table('time_bans')->insert([ 19 | "name" => $name, 20 | "value" => $value 21 | ]); 22 | } 23 | } 24 | 25 | public function time_bans() 26 | { 27 | return [ 28 | 'Permanent' => 0, 29 | '5 Minutes' => 5, 30 | '10 Minutes' => 10, 31 | '30 Minutes' => 30, 32 | '1 Hour' => 60, 33 | '2 Hours' => 120, 34 | '3 Hours' => 180, 35 | '6 Hours' => 360, 36 | '1 Day' => 1440, 37 | '2 Days' => 2880, 38 | '3 Days' => 4320, 39 | '6 Days' => 8640, 40 | '1 Week' => 10080, 41 | '2 Week' => 20160, 42 | '3 Week' => 30240, 43 | '1 Month' => 43830, 44 | '2 Months' => 87660, 45 | '3 Months' => 131490, 46 | '1 Year' => 525960 47 | ]; 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /database/seeders/UserWeb.php: -------------------------------------------------------------------------------- 1 | where('name', "CONSOLE")) { 18 | DB::table('users')->insert([ 19 | "name" => "CONSOLE", 20 | "email" => "console@console.com", 21 | "password" => "" 22 | ]); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@sourceadmin/panel", 3 | "license": "MIT", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "update-deps": "npx npm-check-updates -u" 9 | }, 10 | "devDependencies": { 11 | "@tailwindcss/forms": "^0.5.10", 12 | "autoprefixer": "^10.4.21", 13 | "axios": "^1.9.0", 14 | "postcss": "^8.5.3", 15 | "tailwindcss": "^3.4.17", 16 | "laravel-vite-plugin": "^0.7.8", 17 | "vite": "^4.4.2" 18 | }, 19 | "dependencies": {} 20 | } 21 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests/Unit 10 | 11 | 12 | ./tests/Feature 13 | 14 | 15 | 16 | 17 | ./app 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'tailwindcss/nesting': {}, 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/favicon.png -------------------------------------------------------------------------------- /public/images/games/alienswarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/alienswarm.png -------------------------------------------------------------------------------- /public/images/games/csgo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/csgo.png -------------------------------------------------------------------------------- /public/images/games/csource.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/csource.png -------------------------------------------------------------------------------- /public/images/games/cspromod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/cspromod.png -------------------------------------------------------------------------------- /public/images/games/dods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/dods.png -------------------------------------------------------------------------------- /public/images/games/dys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/dys.png -------------------------------------------------------------------------------- /public/images/games/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/eye.png -------------------------------------------------------------------------------- /public/images/games/gmod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/gmod.png -------------------------------------------------------------------------------- /public/images/games/hidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/hidden.png -------------------------------------------------------------------------------- /public/images/games/hl2-fortressforever.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/hl2-fortressforever.png -------------------------------------------------------------------------------- /public/images/games/hl2ctf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/hl2ctf.png -------------------------------------------------------------------------------- /public/images/games/hl2dm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/hl2dm.png -------------------------------------------------------------------------------- /public/images/games/ins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/ins.png -------------------------------------------------------------------------------- /public/images/games/l4d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/l4d.png -------------------------------------------------------------------------------- /public/images/games/l4d2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/l4d2.png -------------------------------------------------------------------------------- /public/images/games/nucleardawn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/nucleardawn.png -------------------------------------------------------------------------------- /public/images/games/pdark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/pdark.png -------------------------------------------------------------------------------- /public/images/games/pvkii.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/pvkii.png -------------------------------------------------------------------------------- /public/images/games/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/ship.png -------------------------------------------------------------------------------- /public/images/games/source-forts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/source-forts.png -------------------------------------------------------------------------------- /public/images/games/synergy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/synergy.png -------------------------------------------------------------------------------- /public/images/games/tf2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/tf2.png -------------------------------------------------------------------------------- /public/images/games/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/web.png -------------------------------------------------------------------------------- /public/images/games/zps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/games/zps.png -------------------------------------------------------------------------------- /public/images/http_errors/400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/400.png -------------------------------------------------------------------------------- /public/images/http_errors/403.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/403.png -------------------------------------------------------------------------------- /public/images/http_errors/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/404.png -------------------------------------------------------------------------------- /public/images/http_errors/410.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/410.png -------------------------------------------------------------------------------- /public/images/http_errors/418.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/418.png -------------------------------------------------------------------------------- /public/images/http_errors/429.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/429.png -------------------------------------------------------------------------------- /public/images/http_errors/500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/500.png -------------------------------------------------------------------------------- /public/images/http_errors/503.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/503.png -------------------------------------------------------------------------------- /public/images/http_errors/504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/http_errors/504.png -------------------------------------------------------------------------------- /public/images/http_errors/README.md: -------------------------------------------------------------------------------- 1 | https://freedesignresources.net/free-http-status-code-images 2 | -------------------------------------------------------------------------------- /public/images/l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/l.png -------------------------------------------------------------------------------- /public/images/shield.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/shield.png -------------------------------------------------------------------------------- /public/images/smac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/smac.png -------------------------------------------------------------------------------- /public/images/w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ferks-FK/SourceAdmin/01bf117dc1c7c0db70bf49ae90f5ea3b1b6fc5c2/public/images/w.png -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class); 50 | 51 | $response = $kernel->handle( 52 | $request = Request::capture() 53 | )->send(); 54 | 55 | $kernel->terminate($request, $response); 56 | -------------------------------------------------------------------------------- /public/js/filament/forms/components/key-value.js: -------------------------------------------------------------------------------- 1 | function r({state:o}){return{state:o,rows:[],shouldUpdateRows:!0,init:function(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(t,e)=>{let s=i=>i===null?0:Array.isArray(i)?i.length:typeof i!="object"?0:Object.keys(i).length;s(t)===0&&s(e)===0||this.updateRows()})},addRow:function(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow:function(t){this.rows.splice(t,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows:function(t){let e=Alpine.raw(this.rows);this.rows=[];let s=e.splice(t.oldIndex,1)[0];e.splice(t.newIndex,0,s),this.$nextTick(()=>{this.rows=e,this.updateState()})},updateRows:function(){if(!this.shouldUpdateRows){this.shouldUpdateRows=!0;return}let t=[];for(let[e,s]of Object.entries(this.state??{}))t.push({key:e,value:s});this.rows=t},updateState:function(){let t={};this.rows.forEach(e=>{e.key===""||e.key===null||(t[e.key]=e.value)}),this.shouldUpdateRows=!1,this.state=t}}}export{r as default}; 2 | -------------------------------------------------------------------------------- /public/js/filament/forms/components/tags-input.js: -------------------------------------------------------------------------------- 1 | function i({state:a,splitKeys:n}){return{newTag:"",state:a,createTag:function(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag:function(t){this.state=this.state.filter(e=>e!==t)},reorderTags:function(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{"x-on:blur":"createTag()","x-model":"newTag","x-on:keydown"(t){["Enter",...n].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},"x-on:paste"(){this.$nextTick(()=>{if(n.length===0){this.createTag();return}let t=n.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{i as default}; 2 | -------------------------------------------------------------------------------- /public/js/filament/forms/components/textarea.js: -------------------------------------------------------------------------------- 1 | function r({initialHeight:t,shouldAutosize:i,state:s}){return{state:s,wrapperEl:null,init:function(){this.wrapperEl=this.$el.parentNode,this.setInitialHeight(),i?this.$watch("state",()=>{this.resize()}):this.setUpResizeObserver()},setInitialHeight:function(){this.$el.scrollHeight<=0||(this.wrapperEl.style.height=t+"rem")},resize:function(){if(this.setInitialHeight(),this.$el.scrollHeight<=0)return;let e=this.$el.scrollHeight+"px";this.wrapperEl.style.height!==e&&(this.wrapperEl.style.height=e)},setUpResizeObserver:function(){new ResizeObserver(()=>{this.wrapperEl.style.height=this.$el.style.height}).observe(this.$el)}}}export{r as default}; 2 | -------------------------------------------------------------------------------- /public/locales/laravel/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Could not find a user with these credentials.": "Could not find a user with these credentials.", 3 | "Steam API key has not been configured.": "Steam API key has not been configured.", 4 | "Failed to validate your steam account.": "Failed to validate your steam account.", 5 | "We could not find a user related to your steam account.": "We could not find a user related to your steam account.", 6 | "Your :attribute has been sent to the administrators.": "Your :attribute has been sent to the administrators.", 7 | "The :attribute has been successfully :action.": "The :attribute has been successfully :action.", 8 | "The settings has been successfully updated": "The settings has been successfully updated.", 9 | "The page expired, please try again.": "The page expired, please try again.", 10 | "appeal": "appeal", 11 | "report": "report", 12 | "created": "created", 13 | "updated": "updated", 14 | "deleted": "deleted", 15 | "administrator": "administrator", 16 | "ban": "ban", 17 | "mute": "mute", 18 | "group": "group", 19 | "mod": "mod", 20 | "role": "role", 21 | "server": "server", 22 | "settings": "settings", 23 | "re-applied": "re-applied", 24 | "undone": "undone" 25 | } 26 | -------------------------------------------------------------------------------- /public/locales/laravel/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'password' => 'The provided password is incorrect.', 18 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 19 | ]; 20 | -------------------------------------------------------------------------------- /public/locales/laravel/en/pagination.php: -------------------------------------------------------------------------------- 1 | 'Previous', 17 | 'next' => 'Next', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /public/locales/laravel/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset!', 17 | 'sent' => 'We have emailed your password reset link!', 18 | 'throttled' => 'Please wait before retrying.', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that email address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /public/locales/laravel/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "Could not find a user with these credentials.": "No se ha podido encontrar un usuario con estas credenciales.", 3 | "Steam API key has not been configured.": "No se ha configurado la clave API de Steam.", 4 | "Failed to validate your steam account.": "No se ha podido validar tu cuenta de steam.", 5 | "We could not find a user related to your steam account.": "No hemos podido encontrar un usuario relacionado con su cuenta de steam.", 6 | "Your :attribute has been sent to the administrators.": "Su :attribute ha sido enviada a los administradores.", 7 | "The :attribute has been successfully :action.": "El :attribute ha sido :action con éxito.", 8 | "The settings has been successfully updated": "Los ajustes se han actualizado con éxito.", 9 | "The page expired, please try again.": "La página ha caducado, inténtelo de nuevo.", 10 | "appeal": "recurso", 11 | "report": "denuncia", 12 | "created": "creado", 13 | "updated": "actualizado", 14 | "deleted": "eliminado", 15 | "administrator": "administrador", 16 | "ban": "prohibición", 17 | "mute": "mute", 18 | "group": "grupo", 19 | "mod": "mod", 20 | "role": "papel", 21 | "server": "servidor", 22 | "settings": "ajustes", 23 | "re-applied": "reaplicado", 24 | "undone": "deshecho" 25 | } 26 | -------------------------------------------------------------------------------- /public/locales/laravel/es/auth.php: -------------------------------------------------------------------------------- 1 | 'Estas credenciales no coinciden con nuestros registros.', 16 | 'password' => 'La contraseña ingresada no es correcta.', 17 | 'throttle' => 'Demasiados intentos de acceso. Por favor intente nuevamente en :seconds segundos.', 18 | ]; 19 | -------------------------------------------------------------------------------- /public/locales/laravel/es/pagination.php: -------------------------------------------------------------------------------- 1 | 'Siguiente', 16 | 'previous' => 'Anterior', 17 | ]; 18 | -------------------------------------------------------------------------------- /public/locales/laravel/es/passwords.php: -------------------------------------------------------------------------------- 1 | '¡Su contraseña ha sido restablecida!', 16 | 'sent' => '¡Le hemos enviado por correo electrónico el enlace para restablecer su contraseña!', 17 | 'throttled' => 'Por favor espere antes de intentar de nuevo.', 18 | 'token' => 'El token de restablecimiento de contraseña es inválido.', 19 | 'user' => 'No encontramos ningún usuario con ese correo electrónico.', 20 | ]; 21 | -------------------------------------------------------------------------------- /public/locales/laravel/pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "Could not find a user with these credentials.": "Não foi possível encontrar um usuário com essas credenciais.", 3 | "Steam API key has not been configured.": "A chave da API do Steam não foi configurada.", 4 | "Failed to validate your steam account.": "Falha ao validar sua conta Steam.", 5 | "We could not find a user related to your steam account.": "Não foi possível encontrar um usuário relacionado à sua conta Steam.", 6 | "Your :attribute has been sent to the administrators.": "Sua :attribute foi enviada aos administradores.", 7 | "The :attribute has been successfully :action.": "O :attribute foi :action com sucesso.", 8 | "The settings has been successfully updated": "As configurações foram atualizadas com sucesso.", 9 | "The page expired, please try again.": "A página expirou, tente novamente.", 10 | "appeal": "apelação", 11 | "report": "denúncia", 12 | "created": "criado", 13 | "updated": "atualizado", 14 | "deleted": "excluido", 15 | "administrator": "administrador", 16 | "ban": "banimento", 17 | "mute": "mute", 18 | "group": "grupo", 19 | "mod": "mod", 20 | "role": "função", 21 | "server": "servidor", 22 | "settings": "configurações", 23 | "re-applied": "reaplicado", 24 | "undone": "desfeito" 25 | } 26 | -------------------------------------------------------------------------------- /public/locales/laravel/pt/auth.php: -------------------------------------------------------------------------------- 1 | 'Essas credenciais não correspondem aos nossos registros.', 17 | 'password' => 'A senha fornecida está incorreta.', 18 | 'throttle' => 'Muitas tentativas de login. Tente novamente em :seconds segundos.', 19 | ]; 20 | -------------------------------------------------------------------------------- /public/locales/laravel/pt/pagination.php: -------------------------------------------------------------------------------- 1 | 'Anterior', 17 | 'next' => 'Próximo', 18 | ]; 19 | -------------------------------------------------------------------------------- /public/locales/laravel/pt/passwords.php: -------------------------------------------------------------------------------- 1 | 'Sua senha foi redefinida!', 17 | 'sent' => 'Enviamos seu link de redefinição de senha por e-mail!', 18 | 'throttled' => 'Aguarde antes de tentar novamente.', 19 | 'token' => 'Este token de redefinição de senha é inválido.', 20 | 'user' => "Não conseguimos encontrar um usuário com esse endereço de e-mail.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /public/locales/react/en/buttons.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "Login", 3 | "logout": "Logout", 4 | "login_steam": "Login with steam", 5 | "back": "Back", 6 | "submit": "Submit", 7 | "cancel": "Cancel", 8 | "delete": "Delete", 9 | "update": "Update", 10 | "unban": "Unban", 11 | "reban": "Reban", 12 | "unmute": "Unmute", 13 | "remute": "Remute", 14 | "delete_account": "Delete Account", 15 | "delete_ban": "Delete Ban", 16 | "delete_mute": "Delete Mute", 17 | "delete_server": "Delete Server", 18 | "delete_role": "Delete Role", 19 | "delete_group": "Delete Group", 20 | "delete_mod": "Delete Mod" 21 | } 22 | -------------------------------------------------------------------------------- /public/locales/react/en/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "503": "{{status}}: Service Unavailable.", 3 | "500": "{{status}}: Server Error.", 4 | "404": "{{status}}: Page Not Found.", 5 | "403": "{{status}}: Forbidden.", 6 | "validating_data": "There was an error validating the data provided." 7 | } 8 | -------------------------------------------------------------------------------- /public/locales/react/en/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": "Dashboard", 3 | "servers": "Servers", 4 | "bans": "Bans", 5 | "mutes": "Mutes", 6 | "report_player": "Report Player", 7 | "appeal_ban": "Appeal Ban", 8 | "admin": "Admin", 9 | "admin_overview": "Admin Overview", 10 | "admins": "Administrators", 11 | "groups": "Groups", 12 | "mods": "Mods", 13 | "roles": "Roles", 14 | "settings": "Settings", 15 | "return": "Return" 16 | } 17 | -------------------------------------------------------------------------------- /public/locales/react/en/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "mod": "MOD", 3 | "os": "OS", 4 | "vac": "VAC", 5 | "host_name": "HostName", 6 | "players": "Players", 7 | "map": "Map", 8 | "ping": "Latency", 9 | "name" : "Name", 10 | "score": "Score", 11 | "time": "Time", 12 | "mod_country": "MOD/Country", 13 | "mod_type": "MOD/Type", 14 | "datetime": "Date/Time", 15 | "player": "Player", 16 | "admin": "Admin", 17 | "length": "Length", 18 | "progress": "Progress", 19 | "expired": "Expired", 20 | "unbanned": "Unbanned", 21 | "permanent": "Permanent", 22 | "no_data_found": "No data was found.", 23 | "no_players_found": "No players in the server.", 24 | "connect": "Connect", 25 | "id": "Id", 26 | "email": "Email", 27 | "steam_id": "Steam ID", 28 | "is_verified": "Is Verified", 29 | "role": "Role", 30 | "immunity": "Immunity", 31 | "showing_pagination": "Showing: {{from}} to {{to}} of {{total}}", 32 | "previous": "Previous", 33 | "next": "Next", 34 | "users_count": "Users Count", 35 | "permissions_count": "Permissions Count", 36 | "type": "Type", 37 | "icon": "Icon", 38 | "enabled": "Enabled" 39 | } 40 | -------------------------------------------------------------------------------- /public/locales/react/es/buttons.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "Entrar", 3 | "logout": "Salir", 4 | "login_steam": "Inicie sesión con steam", 5 | "back": "Volver", 6 | "submit": "Enviar", 7 | "cancel": "Cancelar", 8 | "delete": "Eliminar", 9 | "update": "Actualización", 10 | "unban": "Desbanear", 11 | "reban": "Reban", 12 | "unmute": "Unmute", 13 | "remute": "Remute", 14 | "delete_account": "Eliminar cuenta", 15 | "delete_ban": "Eliminar prohibición", 16 | "delete_mute": "Eliminar mute", 17 | "delete_server": "Eliminar servidor", 18 | "delete_role": "Eliminar función", 19 | "delete_group": "Eliminar grupo", 20 | "delete_mod": "Eliminar mod" 21 | } 22 | -------------------------------------------------------------------------------- /public/locales/react/es/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "503": "{{status}}: Servicio no disponible.", 3 | "500": "{{status}}: Error en el servidor.", 4 | "404": "{{status}}: Página no encontrada.", 5 | "403": "{{status}}: Prohibido.", 6 | "validating_data": "Se ha producido un error al validar los datos proporcionados." 7 | } 8 | -------------------------------------------------------------------------------- /public/locales/react/es/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": "Panel de control", 3 | "servers": "Servidores", 4 | "bans": "Prohibiciones", 5 | "mutes": "Comunicaciones", 6 | "report_player": "Denunciar jugador", 7 | "appeal_ban": "Prohibición de protestas", 8 | "admin": "Administración", 9 | "admin_overview": "Administración General", 10 | "admins": "Administradores", 11 | "groups": "Grupos", 12 | "mods": "Mods", 13 | "roles": "Funciones", 14 | "settings": "Ajustes", 15 | "return": "Volver" 16 | } 17 | -------------------------------------------------------------------------------- /public/locales/react/es/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "mod": "MOD", 3 | "os": "OS", 4 | "vac": "VAC", 5 | "host_name": "Servidor", 6 | "players": "Jugadores", 7 | "map": "Mapa", 8 | "ping": "Latencia", 9 | "name" : "Nombre", 10 | "score": "Puntuación", 11 | "time": "Tiempo", 12 | "mod_country": "MOD/País", 13 | "mod_type": "MOD/Tipo", 14 | "datetime": "Fecha/Tiempo", 15 | "player": "Jugador", 16 | "admin": "Admin", 17 | "length": "Longitud", 18 | "progress": "Progreso", 19 | "expired": "Caducado", 20 | "unbanned": "No bloqueado", 21 | "permanent": "Permanente", 22 | "no_data_found": "No se encontraron datos.", 23 | "no_players_found": "Sin jugadores en el servidor.", 24 | "connect": "Conectar", 25 | "id": "Id", 26 | "email": "Correo electrónico", 27 | "steam_id": "Steam ID", 28 | "is_verified": "Verificado", 29 | "role": "Papel", 30 | "immunity": "Inmunidad", 31 | "showing_pagination": "Mostrando: {{from}} a {{to}} del total {{total}}", 32 | "previous": "Anterior", 33 | "next": "Siguiente", 34 | "users_count": "Número de usuarios", 35 | "permissions_count": "Número de permisos", 36 | "type": "Tipo", 37 | "icon": "Icono", 38 | "enabled": "Activado" 39 | } 40 | -------------------------------------------------------------------------------- /public/locales/react/pt/buttons.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "Logar", 3 | "logout": "Sair", 4 | "login_steam": "Logar com steam", 5 | "back": "Voltar", 6 | "submit": "Enviar", 7 | "cancel": "Cancelar", 8 | "delete": "Excluir", 9 | "update": "Atualizar", 10 | "unban": "Desbanir", 11 | "reban": "Rebanir", 12 | "unmute": "Desmutar", 13 | "remute": "Remutar", 14 | "delete_account": "Excluir conta", 15 | "delete_ban": "Exluir banimento", 16 | "delete_mute": "Excluir Mute", 17 | "delete_server": "Excluir Servidor", 18 | "delete_role": "Excluir Função", 19 | "delete_group": "Excluir Grupo", 20 | "delete_mod": "Excluir Mod" 21 | } 22 | -------------------------------------------------------------------------------- /public/locales/react/pt/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "503": "{{status}}: Serviço indisponível.", 3 | "500": "{{status}}: Erro do servidor.", 4 | "404": "{{status}}: Página não encontrada.", 5 | "403": "{{status}}: Proibido.", 6 | "validating_data": "Ocorreu um erro ao validar os dados fornecidos." 7 | } 8 | -------------------------------------------------------------------------------- /public/locales/react/pt/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "dashboard": "Painel de controle", 3 | "servers": "Servidores", 4 | "bans": "Banimentos", 5 | "mutes": "Comunicações", 6 | "report_player": "Reportar Jogador", 7 | "appeal_ban": "Protestar Banimento", 8 | "admin": "Administração", 9 | "admin_overview": "Administração Geral", 10 | "admins": "Administradores", 11 | "groups": "Grupos", 12 | "mods": "Mods", 13 | "roles": "Funções", 14 | "settings": "Configurações", 15 | "return": "Voltar" 16 | } 17 | -------------------------------------------------------------------------------- /public/locales/react/pt/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "mod": "MOD", 3 | "os": "OS", 4 | "vac": "VAC", 5 | "host_name": "Servidor", 6 | "players": "Jogadores", 7 | "map": "Mapa", 8 | "ping": "Latência", 9 | "name" : "Nome", 10 | "score": "Pontos", 11 | "time": "Tempo", 12 | "mod_country": "MOD/País", 13 | "mod_type": "MOD/Tipo", 14 | "datetime": "Data/Tempo", 15 | "player": "Jogador", 16 | "admin": "Administrador", 17 | "length": "Comprimento", 18 | "progress": "Progresso", 19 | "expired": "Expirado", 20 | "unbanned": "Desbanido", 21 | "permanent": "Permanente", 22 | "no_data_found": "Nenhum dado foi encontrado.", 23 | "no_players_found": "Nenhum jogador no servidor.", 24 | "connect": "Conectar", 25 | "id": "Id", 26 | "email": "Email", 27 | "steam_id": "Steam ID", 28 | "is_verified": "É verificado", 29 | "role": "Função", 30 | "immunity": "Imunidade", 31 | "showing_pagination": "Mostrando: {{from}} a {{to}} do total {{total}}", 32 | "previous": "Anterior", 33 | "next": "Próximo", 34 | "users_count": "Número de usuários", 35 | "permissions_count": "Número de permissões", 36 | "type": "Tipo", 37 | "icon": "Ícone", 38 | "enabled": "Ativado" 39 | } 40 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /resources/ts/App.tsx: -------------------------------------------------------------------------------- 1 | import './i18n'; 2 | import './assets/app.css'; 3 | import React from 'react'; 4 | import { createRoot } from 'react-dom/client'; 5 | import { createInertiaApp } from '@inertiajs/react'; 6 | import { Layout } from "@/components/layout/Layout"; 7 | import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'; 8 | import { UserData } from "@/stores/user"; 9 | import { GeneralSettingsProps } from "@/api/getSettings"; 10 | 11 | interface UserAuth { 12 | el: HTMLElement 13 | App: React.ComponentType 14 | props: { 15 | initialPage: { 16 | props: { 17 | layout: LayoutType 18 | locale: string 19 | generalSettings: GeneralSettingsProps 20 | auth: { 21 | user: UserData 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | export type LayoutType = 'admin' | 'app' 29 | 30 | createInertiaApp({ 31 | resolve: (name) => resolvePageComponent(`./components/pages/${name}.tsx`, import.meta.glob('./components/pages/**/*.tsx')), 32 | setup({ el, App, props }: UserAuth) { 33 | const userAuth = props.initialPage.props.auth.user 34 | const layout = props.initialPage.props.layout 35 | const locale = props.initialPage.props.locale 36 | const generalSettings = props.initialPage.props.generalSettings 37 | 38 | createRoot(el).render( 39 | 40 | 41 | 42 | ) 43 | }, 44 | progress: { 45 | delay: 25 46 | } 47 | }) 48 | -------------------------------------------------------------------------------- /resources/ts/api/getServers.ts: -------------------------------------------------------------------------------- 1 | import http from "@/api/http"; 2 | import { ServerDataResponse, PlayerDataResponse } from "@/types" 3 | 4 | export type ResponseData = { 5 | server: ServerDataResponse, 6 | players?: PlayerDataResponse[] 7 | } 8 | 9 | export async function getServerData(server_id: number, getPlayers: boolean = true): Promise { 10 | const response = await http.get(`/servers/${server_id}`, { params: { getPlayers: getPlayers } }) 11 | 12 | return response.data 13 | } 14 | -------------------------------------------------------------------------------- /resources/ts/api/getSettings.ts: -------------------------------------------------------------------------------- 1 | import http from "@/api/http"; 2 | 3 | export type SettingResponse = Record 4 | 5 | export type GeneralSettingsProps = { 6 | site_name: string 7 | time_zone: string 8 | steam_web_api_key: string 9 | } 10 | 11 | export type MailSettingsProps = { 12 | smtp_host: string 13 | smtp_port: number 14 | smtp_encryption: string 15 | smtp_username: string 16 | smtp_password: string 17 | smtp_mail_from: string 18 | smtp_mail_from_name: string 19 | } 20 | 21 | type GeneralSettingsAtributes = 'site_name' | 'time_zone' | 'steam_web_api_key' 22 | type MailSettingsAtributes = 'smtp_host' | 'smtp_port' | 'smtp_encryption' | 'smtp_username' | 'smtp_password' | 'smtp_mail_from' | 'smtp_mail_from_name' 23 | 24 | export async function getSettings(group: string): Promise { 25 | const response = await http.get('/admin/panel_settings/settings', { params: { group: group } }) 26 | 27 | return response.data 28 | } 29 | 30 | export async function getTimeZones(): Promise { 31 | const response = await http.get('/admin/panel_settings/timezones') 32 | 33 | return response.data 34 | } 35 | -------------------------------------------------------------------------------- /resources/ts/api/http.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance } from 'axios'; 2 | 3 | const http: AxiosInstance = axios.create({ 4 | withCredentials: true, 5 | timeout: 20000, 6 | headers: { 7 | 'X-Requested-With': 'XMLHttpRequest', 8 | 'Accept': 'application/json', 9 | 'Content-Type': 'application/json' 10 | }, 11 | validateStatus: (number) => { 12 | return number >= 200 && number < 300 13 | } 14 | }) 15 | 16 | export default http; 17 | -------------------------------------------------------------------------------- /resources/ts/api/locale.ts: -------------------------------------------------------------------------------- 1 | import http from "@/api/http"; 2 | 3 | type LocaleDataResponse = { 4 | message: string 5 | } 6 | 7 | export type Locale = { 8 | name: string, 9 | code: string, 10 | flag: string 11 | } 12 | 13 | export async function getAvailableLocales(): Promise { 14 | const response = await http.get('/locale') 15 | 16 | return response.data 17 | } 18 | 19 | export async function setLocale(locale: string = 'en'): Promise { 20 | const response = await http.post('/locale/setLocale', { locale: locale }) 21 | 22 | return response.data 23 | } 24 | -------------------------------------------------------------------------------- /resources/ts/api/steam.ts: -------------------------------------------------------------------------------- 1 | import http from '@/api/http'; 2 | 3 | type SteamDataResponse = { 4 | url: string | null 5 | isActive: boolean 6 | } 7 | 8 | export async function steamAuth(): Promise { 9 | const response = await http.get('/steam/auth') 10 | 11 | return response.data 12 | } 13 | -------------------------------------------------------------------------------- /resources/ts/components/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import { md5 } from "@/helpers"; 2 | import { Image } from "@/components/elements/Image"; 3 | import classNames from "classnames"; 4 | import { HTMLAttributes } from "react"; 5 | 6 | interface Props extends HTMLAttributes { 7 | email: string, 8 | size: number 9 | } 10 | 11 | function Avatar({ email, size, className }: Props) { 12 | return ( 13 |
14 | Avatar 19 |
20 | ); 21 | }; 22 | 23 | export { Avatar } 24 | -------------------------------------------------------------------------------- /resources/ts/components/Translate.tsx: -------------------------------------------------------------------------------- 1 | import { HTMLAttributes } from "react"; 2 | import { Trans, useTranslation } from "react-i18next"; 3 | 4 | interface Props extends HTMLAttributes { 5 | ns: string 6 | } 7 | 8 | function Translate({ ns, children, ...props }: Props) { 9 | const { t } = useTranslation(ns); 10 | 11 | return ( 12 | 13 | { children } 14 | 15 | ) 16 | } 17 | 18 | export { Translate } 19 | -------------------------------------------------------------------------------- /resources/ts/components/elements/AnimationFade.tsx: -------------------------------------------------------------------------------- 1 | import { motion, MotionProps } from "framer-motion"; 2 | import { FlashMessageRender } from "@/components/FlashMessageRender"; 3 | import { HTMLAttributes } from "react"; 4 | 5 | type Props = HTMLAttributes & MotionProps 6 | 7 | function AnimationFade({ children }: Props) { 8 | return ( 9 | 16 | 17 | {children} 18 | 19 | ) 20 | } 21 | 22 | export { AnimationFade } 23 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Box.tsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import { HTMLAttributes } from "react"; 3 | 4 | interface Props extends HTMLAttributes { 5 | title: string, 6 | description: string | JSX.Element, 7 | paragraph?: string | JSX.Element, 8 | borderColor?: string 9 | } 10 | 11 | function Box({ title, description, paragraph, borderColor, className }: Props) { 12 | 13 | return ( 14 |
15 |
16 |

{title}

17 |
{description}
18 | {paragraph && ( 19 |
{paragraph}
20 | )} 21 |
22 |
23 | ) 24 | } 25 | 26 | export { Box } 27 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Collapse.tsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import { HTMLAttributes } from "react"; 3 | import { useRef, useState, useEffect } from "react"; 4 | 5 | interface Props extends HTMLAttributes { 6 | visible: boolean 7 | } 8 | 9 | const Collapse = ({ children, visible }: Props) => { 10 | const [containerHeight, setContainerHeight] = useState(0); 11 | const containerRef = useRef(null) 12 | 13 | useEffect(() => { 14 | if (containerRef.current) { 15 | setContainerHeight(containerRef.current.scrollHeight) 16 | } 17 | }, []) 18 | 19 | return ( 20 |
25 | {children} 26 |
27 | ) 28 | } 29 | 30 | export { Collapse } 31 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Counter.tsx: -------------------------------------------------------------------------------- 1 | import { animate } from "framer-motion"; 2 | import { useEffect, useRef } from "react"; 3 | import { formatSizeUnits } from "@/helpers";; 4 | 5 | interface Props { 6 | from?: number, 7 | to: number, 8 | convertToHumanSizeUnit?: boolean 9 | } 10 | 11 | type CounterProps = Props & { 12 | title: string 13 | } 14 | 15 | function Counter({ from, to, convertToHumanSizeUnit }: Props) { 16 | const ref = useRef(null); 17 | 18 | useEffect(() => { 19 | if (!ref.current || ref.current === null) return 20 | 21 | const controls = animate(from, to, { 22 | duration: 1.5, 23 | onUpdate(value) { 24 | if (ref.current) { 25 | ref.current.textContent = convertToHumanSizeUnit ? formatSizeUnits(value!) : value!.toFixed(0); 26 | } 27 | } 28 | }); 29 | 30 | return () => controls.stop(); 31 | }, [from, to]); 32 | 33 | return ( 34 |

35 | ) 36 | } 37 | 38 | 39 | const CounterContainer = ({ title, from = 0, to, convertToHumanSizeUnit = false }: CounterProps) => ( 40 |

41 |   42 |

{title}

43 |
44 | ) 45 | 46 | export { Counter, CounterContainer } 47 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Form.tsx: -------------------------------------------------------------------------------- 1 | import { Form as FormikForm, FormikFormProps } from "formik"; 2 | import classNames from "classnames"; 3 | import { HTMLAttributes } from "react"; 4 | 5 | type Props = HTMLAttributes & FormikFormProps & { 6 | title?: string 7 | formSize?: FormSize 8 | formikClassNames?: string 9 | } 10 | 11 | type FormSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full' 12 | 13 | function Form({ title, formSize, children, className, formikClassNames, ...props }: Props) { 14 | const handleFormSize = () => { 15 | switch (formSize) { 16 | case 'xs': 17 | return 'max-w-xs' 18 | case 'sm': 19 | return 'max-w-sm' 20 | case 'md': 21 | return 'max-w-md' 22 | case 'lg': 23 | return 'max-w-lg' 24 | case 'xl': 25 | return 'max-w-xl' 26 | case 'full': 27 | return 'max-w-full' 28 | default: 29 | return 'max-w-sm' 30 | } 31 | } 32 | 33 | return ( 34 |
35 |
36 | { title &&

{title}

} 37 | 38 |
39 | {children} 40 |
41 |
42 |
43 |
44 | ) 45 | } 46 | 47 | export { Form } 48 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Image.tsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import { ComponentPropsWithoutRef } from "react"; 3 | 4 | type Props = ComponentPropsWithoutRef<'img'> 5 | 6 | function Image({ src, alt, children, className, ...props }: Props) { 7 | return ( 8 | 9 | {children} 10 | 11 | ) 12 | } 13 | 14 | export { Image } 15 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Label.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentPropsWithoutRef } from "react"; 2 | 3 | type Props = ComponentPropsWithoutRef<'label'> 4 | 5 | function Label({ htmlFor, children }: Props) { 6 | return ( 7 | 10 | ) 11 | } 12 | 13 | export { Label }; 14 | -------------------------------------------------------------------------------- /resources/ts/components/elements/NavLink.tsx: -------------------------------------------------------------------------------- 1 | import { Link, InertiaLinkProps } from '@inertiajs/react'; 2 | import classNames from 'classnames'; 3 | 4 | function NavLink({ href, children, className, ...props }: InertiaLinkProps) { 5 | return ( 6 | 11 | {children} 12 | 13 | ) 14 | } 15 | 16 | export { NavLink } 17 | -------------------------------------------------------------------------------- /resources/ts/components/elements/PageContentBlock.tsx: -------------------------------------------------------------------------------- 1 | import { SourceAdminReg } from "@/components/elements/SourceAdminReg"; 2 | import { AnimationFade } from '@/components/elements/AnimationFade'; 3 | import { Head } from '@inertiajs/react'; 4 | import classNames from "classnames"; 5 | import { HTMLAttributes } from "react"; 6 | 7 | interface Props extends HTMLAttributes { 8 | title?: string 9 | } 10 | 11 | function PageContentBlock({ title, children, className }: Props) { 12 | return ( 13 | <> 14 | 15 |
16 | 17 | {children} 18 | 19 |
20 | 21 |
22 |
23 | 24 | ); 25 | } 26 | 27 | export { PageContentBlock } 28 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Progress.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react" 2 | 3 | interface Props { 4 | bgColor: string, 5 | completed: number 6 | } 7 | 8 | function Progress({ bgColor, completed }: Props) { 9 | 10 | const ContainerStyles: CSSProperties = { 11 | height: 10, 12 | width: '100%', 13 | backgroundColor: "#e0e0de", 14 | borderRadius: 50 15 | } 16 | 17 | const barStyles: CSSProperties = { 18 | height: '100%', 19 | width: `${completed}%`, 20 | borderRadius: 'inherit', 21 | textAlign: 'right', 22 | transition: 'width 0.5s ease-in-out', 23 | } 24 | 25 | return ( 26 |
27 |
28 |
29 | ) 30 | } 31 | 32 | export { Progress } 33 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Select.tsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | import { CSSProperties } from "react"; 3 | 4 | type Props = JSX.IntrinsicElements['select'] 5 | 6 | function Select({ children, className, onChange, value, name, ...props }: Props) { 7 | const SelectCustomStyles: CSSProperties = { 8 | WebkitAppearance: "none", 9 | MozAppearance: "none", 10 | backgroundPositionX: "calc(100% - 0.75rem)", 11 | backgroundPositionY: "center" 12 | } 13 | 14 | return ( 15 | 25 | ) 26 | } 27 | 28 | export { Select } 29 | -------------------------------------------------------------------------------- /resources/ts/components/elements/SourceAdminReg.tsx: -------------------------------------------------------------------------------- 1 | const SourceAdminReg = () => ( 2 |

3 | 9 | SourceAdmin® 10 | 11 |  © 2022 - {new Date().getFullYear()} 12 |

13 | ); 14 | 15 | export { SourceAdminReg } 16 | -------------------------------------------------------------------------------- /resources/ts/components/elements/Spinner.tsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames" 2 | import React from "react"; 3 | 4 | export type SpinnerSize = 'small' | 'base' | 'large' 5 | 6 | interface Props { 7 | size?: SpinnerSize 8 | centered?: boolean 9 | } 10 | 11 | interface SpinnerProps extends React.FC { 12 | Size?: Record<'SMALL' | 'BASE' | 'LARGE', SpinnerSize>; 13 | } 14 | 15 | const SpinnerComponent = (props: Props) => ( 16 |
21 | ) 22 | 23 | const Spinner: SpinnerProps = ({ centered, size }) => ( 24 | centered ? ( 25 |
29 | 30 |
31 | ) : ( 32 | 33 | ) 34 | ) 35 | 36 | export { Spinner } 37 | -------------------------------------------------------------------------------- /resources/ts/components/elements/SubNavigation.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | 3 | interface SubNavigationProps { 4 | children: ReactNode 5 | } 6 | 7 | export const SubNavigation = (props: SubNavigationProps) => ( 8 |
9 | {props.children} 10 |
11 | ) 12 | -------------------------------------------------------------------------------- /resources/ts/components/elements/TextArea.tsx: -------------------------------------------------------------------------------- 1 | import classNames from "classnames"; 2 | 3 | type Props = JSX.IntrinsicElements['textarea'] 4 | 5 | function TextArea({ name, rows = 5, className, ...props }: Props) { 6 | return ( 7 |