├── .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 | 
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 |
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 |
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 |
8 | { children }
9 |
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 |
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 |
23 | { children }
24 |
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 |
13 | )
14 | }
15 |
16 | export { TextArea }
17 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/button/index.js:
--------------------------------------------------------------------------------
1 | export { default as Button } from "./Button";
2 | export { default as styles } from "./style.module.css";
3 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/button/types.ts:
--------------------------------------------------------------------------------
1 | import { IconDefinition, SizeProp } from '@fortawesome/fontawesome-svg-core';
2 |
3 | export enum Shape {
4 | Default,
5 | IconSquare,
6 | }
7 |
8 | export enum Size {
9 | Default,
10 | Small,
11 | Large,
12 | }
13 |
14 | export enum Variant {
15 | Primary,
16 | Secondary,
17 | Warning,
18 | Info,
19 | }
20 |
21 | export enum iconPosition {
22 | Right = 'right',
23 | Left = 'left'
24 | }
25 |
26 | export const Options = { Shape, Size, Variant, iconPosition };
27 |
28 | export type ButtonProps = JSX.IntrinsicElements['button'] & {
29 | shape?: Shape;
30 | size?: Size;
31 | variant?: Variant;
32 | };
33 |
34 | export interface IconButtonProps extends ButtonProps {
35 | icon: IconDefinition
36 | iconSize?: SizeProp,
37 | iconPosition?: iconPosition
38 | }
39 |
40 | export interface LinkButtonProps extends ButtonProps {
41 | to: string,
42 | linkClassName?: string
43 | }
44 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/field/index.js:
--------------------------------------------------------------------------------
1 | export { default as Field } from './Field';
2 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/field/types.ts:
--------------------------------------------------------------------------------
1 | import { FormikErrors, FormikTouched, FieldInputProps } from 'formik';
2 | import { InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react';
3 |
4 | export interface FieldProps extends InputHTMLAttributes {
5 | name: string
6 | label: string
7 | description?: string
8 | touched: FormikTouched
9 | field: FieldInputProps
10 | errors: FormikErrors
11 | }
12 |
13 | export type BaseInputProps = Omit & Omit, 'name'>
14 | export type TextAreaProps = Omit & Omit, 'name'>
15 | export type SelectProps = Omit & Omit, 'name'>
16 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/inputs/index.js:
--------------------------------------------------------------------------------
1 | export { default as Input } from "./Input";
2 | export { default as styles } from "./style.module.css";
3 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/inputs/style.module.css:
--------------------------------------------------------------------------------
1 | .input {
2 | @apply w-full py-3 px-4 outline-none bg-[#1e2327] text-white border;
3 | @apply rounded-md text-base font-normal transition-all duration-150 ease-in-out;
4 |
5 | &.small {
6 | @apply py-2 px-3 font-normal text-sm focus:ring-2;
7 | }
8 |
9 | &.large {
10 | @apply py-3 px-4;
11 | }
12 |
13 | &.secondary {
14 | @apply text-slate-50 bg-transparent hover:!bg-dark-secondary;
15 |
16 | &:disabled {
17 | background: transparent !important;
18 | }
19 | }
20 |
21 | &:disabled {
22 | @apply cursor-not-allowed;
23 | }
24 | }
25 |
26 | .primary {
27 | @apply bg-dark-primary text-slate-50;
28 | @apply border-slate-200 hover:border-slate-400;
29 |
30 | &.secondary {
31 | @apply hover:bg-dark-primary active:bg-dark-primary;
32 | }
33 |
34 | &:disabled {
35 | @apply bg-dark-primary/75 text-slate-200/75;
36 | }
37 | }
38 |
39 | .checkbox {
40 | @apply w-4 p-0 cursor-pointer rounded-sm border-neutral-500 bg-neutral-600 text-neutral-500;
41 |
42 | &:focus, &:active {
43 | @apply ring-2 ring-neutral-500 ring-offset-2 ring-offset-neutral-700;
44 | }
45 |
46 | &.indeterminate:checked {
47 | @apply text-neutral-500/50 border border-neutral-500;
48 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='white'%3E%3Cpath fill-rule='evenodd' d='M5 10a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1z' clip-rule='evenodd' /%3E%3C/svg%3E");
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/inputs/types.ts:
--------------------------------------------------------------------------------
1 | export enum Size {
2 | Default,
3 | Small,
4 | Large,
5 | }
6 |
7 | export enum Variant {
8 | Primary,
9 | Secondary,
10 | }
11 |
12 | export const Options = { Size, Variant };
13 |
14 | export type InputProps = JSX.IntrinsicElements['input'] & {
15 | size?: Size
16 | variant?: Variant
17 | };
18 |
19 | export interface InputSearchProps extends InputProps {
20 | searchQuery: string
21 | minChars?: number
22 | }
23 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/modal/index.js:
--------------------------------------------------------------------------------
1 | export { default as Modal } from "./Modal";
2 | export { default as styles } from "./style.module.css";
3 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/modal/style.module.css:
--------------------------------------------------------------------------------
1 | .modalBackdrop {
2 | @apply bg-black/50 z-10 fixed inset-0;
3 | }
4 |
5 | .modal {
6 | @apply max-w-xl max-h-[350px] h-fit flex flex-col bg-dark-primary rounded;
7 | @apply py-3 z-20 fixed inset-4;
8 | }
9 |
10 | .modalHeader {
11 | @apply flex items-center justify-center h-16 px-8 shrink-0;
12 | }
13 |
14 | .modalHeading {
15 | @apply text-base text-center text-white;
16 | }
17 |
18 | .modalContent {
19 | @apply px-4 flex flex-col overflow-y-auto text-white w-full;
20 | }
21 |
22 | .closeModalBtn {
23 | @apply w-8 h-8 flex items-center justify-center rounded bg-dark-secondary text-gray-500 cursor-pointer;
24 | @apply transition-colors duration-100 ease-in-out absolute top-1 right-1 p-1 border-none;
25 |
26 | &:hover {
27 | @apply text-gray-400 bg-dark-secondary/50;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/modal/types.ts:
--------------------------------------------------------------------------------
1 | import Record from "react";
2 |
3 | export enum Position {
4 | Top,
5 | Center
6 | }
7 |
8 | export const Options = { Position }
9 |
10 | export type ModalProps = JSX.IntrinsicElements['div'] & {
11 | isVisible: boolean,
12 | heading?: string,
13 | onClickCloseBtn: () => void | null,
14 | onClickBackdrop: () => void | null,
15 | onPressEscKey: () => void,
16 | animation?: Record,
17 | backdropAnimation?: Record,
18 | position?: Position
19 | }
20 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/table/index.js:
--------------------------------------------------------------------------------
1 | export { default as Table } from "./Table";
2 | export { default as styles } from "./style.module.css";
3 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/table/style.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | @apply flex flex-col gap-4 overflow-x-auto whitespace-nowrap md:whitespace-normal;
3 | }
4 |
5 | .table {
6 | @apply w-full text-sm text-left text-gray-500;
7 | }
8 |
9 | .thread {
10 | @apply text-xs text-gray-300 uppercase bg-dark-primary;
11 | }
12 |
13 | .header {
14 | @apply flex text-center items-center justify-between p-4 bg-dark-primary border-b border-dark-secondary;
15 | }
16 |
17 | .row {
18 | @apply cursor-pointer bg-dark-neutral border-b border-gray-700 hover:bg-dark-secondary;
19 | }
20 |
21 | .pagination_container {
22 | @apply flex flex-wrap items-center overflow-x-auto sm:justify-end gap-2;
23 | }
24 |
25 | .pagination_item {
26 | @apply flex items-center justify-center h-8 text-center py-0 px-2 border-none text-white !rounded-2xl disabled:cursor-not-allowed;
27 | }
28 |
--------------------------------------------------------------------------------
/resources/ts/components/elements/table/types.ts:
--------------------------------------------------------------------------------
1 | import { PaginationProps as PaginationBaseProps } from '@/types';
2 | import { IconDefinition, SizeProp } from '@fortawesome/fontawesome-svg-core';
3 | import { HTMLAttributes } from 'react';
4 |
5 | export enum iconPosition {
6 | Right = 'right',
7 | Left = 'left'
8 | }
9 |
10 | export enum SizeRowProps {
11 | Sm = 'sm',
12 | Base = 'base'
13 | }
14 |
15 | type ColumnObject = {
16 | name: string
17 | i18nKey: string
18 | ns?: string
19 | }
20 |
21 | export type TableProps = JSX.IntrinsicElements['table'] & {
22 | columns: ColumnObject[]
23 | dataLength: number
24 | colSpan?: number
25 | };
26 |
27 | export interface HeaderProps extends HTMLAttributes {
28 | title?: string
29 | icon?: IconDefinition
30 | iconSize?: SizeProp
31 | iconPosition?: iconPosition
32 | }
33 |
34 | export interface RowProps extends HTMLAttributes {
35 | size?: SizeRowProps
36 | }
37 |
38 | export type TDProps = JSX.IntrinsicElements['td']
39 |
40 | export interface PaginationProps {
41 | paginationData: PaginationBaseProps
42 | visible: boolean
43 | }
44 |
--------------------------------------------------------------------------------
/resources/ts/components/layout/Layout.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode, useEffect } from "react";
2 | import { Header } from "@/components/layout/Header";
3 | import { SideBar } from "@/components/layout/SideBar";
4 | import { UserData, useUserStore } from "@/stores/user";
5 | import { useDeviceType } from "@/hooks/useDeviceType";
6 | import { LayoutType } from "@/App";
7 | import { useSettingsStore } from "@/stores/settings";
8 | import { GeneralSettingsProps } from "@/api/getSettings";
9 |
10 | interface Props {
11 | children: ReactNode
12 | userAuth: UserData
13 | layout: LayoutType
14 | locale: string
15 | generalSettings: GeneralSettingsProps
16 | }
17 |
18 | export const Layout = ({ children, userAuth, layout, locale, generalSettings }: Props) => {
19 | const [ isLogged, setUserData ] = useUserStore((state) => [state.isLogged, state.setUserData]);
20 | const [ settings, setSettings ] = useSettingsStore((state) => [state.data, state.setSettings]);
21 |
22 | useDeviceType()
23 |
24 | useEffect(() => {
25 | if (!isLogged && userAuth) {
26 | setUserData(userAuth)
27 | }
28 |
29 | if (!settings) {
30 | setSettings({
31 | GeneralSettings: generalSettings
32 | })
33 | }
34 | }, [isLogged, settings])
35 |
36 | return (
37 | <>
38 |