feat(addonsmanager): Phase 1 — Server Content Manager conversion
- Rename UI labels from "Addons Manager" to "Server Content Manager" - Add server_content_categories.php: central category map with 8 types - Bump module db_version 1→2 with safe VARCHAR(32) migration for addon_type - addons_manager.php: use category map for type list + comments - addons_installer.php: use category map + full TODO blocks for Phase 2+ - user_addons.php: dynamic category iteration via category map - monitor_buttons.php: updated header comment - English lang: updated all user-visible strings, added new type labels - global.php + gamemanager.php: updated LANG_addons_manager, LANG_user_addons, LANG_addons - Created SERVER_CONTENT_ROADMAP.md with full review and migration plan Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/1e8f1b08-96d6-4c47-8f27-efe972d7cf17 Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
parent
4176bf3bfa
commit
d562d849b7
10 changed files with 672 additions and 198 deletions
|
|
@ -80,7 +80,7 @@ define('LANG_gamemanager', "Game Manager");
|
|||
define('LANG_game_monitor', "Game Monitor");
|
||||
define('LANG_steam_workshop', "Steam Workshop");
|
||||
define('LANG_dashboard', "Dashboard");
|
||||
define('LANG_user_addons', "Addons");
|
||||
define('LANG_user_addons', "Server Content");
|
||||
define('LANG_ftp', "FTP");
|
||||
define('LANG_shop', "Shop");
|
||||
define('LANG_shop_guest', "Shop");
|
||||
|
|
@ -95,7 +95,7 @@ define('LANG_user_admin', "Users");
|
|||
define('LANG_sub_users', "Sub Users");
|
||||
define('LANG_show_groups', "Groups");
|
||||
define('LANG_user_games', "Game Servers");
|
||||
define('LANG_addons_manager', "Addons Manager");
|
||||
define('LANG_addons_manager', "Server Content Manager");
|
||||
define('LANG_ftp_admin', "FTP users");
|
||||
define('LANG_orders', "Orders");
|
||||
define('LANG_services', "Services");
|
||||
|
|
|
|||
|
|
@ -22,49 +22,61 @@
|
|||
*
|
||||
*/
|
||||
|
||||
define('LANG_install_plugin', "Install Plugins");
|
||||
define('LANG_install_mappack', "Install Maps");
|
||||
define('LANG_install_config', "Install Configs");
|
||||
// --- Server Content Manager (formerly Addons Manager) ---
|
||||
// UI labels are updated to use "Server Content" terminology.
|
||||
// Internal keys remain unchanged for backward compatibility with other languages.
|
||||
|
||||
define('LANG_install_plugin', "Install Plugin / Mod");
|
||||
define('LANG_install_mappack', "Install Map Pack");
|
||||
define('LANG_install_config', "Install Config Pack");
|
||||
define('LANG_game_name', "Game Name");
|
||||
define('LANG_directory', "Directory Path");
|
||||
define('LANG_remote_server', "Remote server");
|
||||
define('LANG_select_addon', "Select Addon");
|
||||
define('LANG_select_addon', "Select Server Content Item");
|
||||
define('LANG_install', "Install");
|
||||
define('LANG_failed_to_start_file_download', "Failed to start file download.");
|
||||
define('LANG_no_games_servers_available', "There are no game servers available in your account.");
|
||||
define('LANG_addon_installed_successfully', "Addon installed successfully");
|
||||
define('LANG_addon_installed_successfully', "Server content item installed successfully");
|
||||
define('LANG_path', "Path");
|
||||
define('LANG_wait_while_decompressing', "Wait while the file %s is decompressed.");
|
||||
define('LANG_addon_name', "Addon Name");
|
||||
define('LANG_addon_name', "Content Item Name");
|
||||
define('LANG_url', "URL");
|
||||
define('LANG_select_game_type', "Select Game Type");
|
||||
define('LANG_plugin', "Plugin");
|
||||
define('LANG_mappack', "MapPack");
|
||||
define('LANG_config', "Config");
|
||||
define('LANG_type', "Addon Type");
|
||||
define('LANG_plugin', "Plugins / Mods");
|
||||
define('LANG_mappack', "Map Packs");
|
||||
define('LANG_config', "Config Packs");
|
||||
// Additional category labels (for future content types already defined in server_content_categories.php)
|
||||
define('LANG_version', "Server Versions");
|
||||
define('LANG_modpack', "Modpacks");
|
||||
define('LANG_workshop', "Workshop Content");
|
||||
define('LANG_script', "Scripted Installer");
|
||||
define('LANG_profile', "Server Profiles");
|
||||
define('LANG_type', "Content Type");
|
||||
define('LANG_game', "Game");
|
||||
define('LANG_show_all_addons', "Show All Addons");
|
||||
define('LANG_show_addons_for_selected_type', "Show Addons For Selected Type");
|
||||
define('LANG_show_addons_for_selected_game', "Show Addons For Selected Game");
|
||||
define('LANG_show_all_addons', "Show All Server Content");
|
||||
define('LANG_show_addons_for_selected_type', "Show Content For Selected Type");
|
||||
define('LANG_show_addons_for_selected_game', "Show Content For Selected Game");
|
||||
define('LANG_linux_games', "Linux Games:");
|
||||
define('LANG_windows_games', "Windows Games:");
|
||||
define('LANG_create_addon', "Create Addon");
|
||||
define('LANG_addons_db', "Addons Database");
|
||||
define('LANG_addon_has_been_created', "The addon %s has been created.");
|
||||
define('LANG_remove_addon', "Remove Addon");
|
||||
define('LANG_fill_the_url_address_to_a_compressed_file', "Please, fill an URL address for a compressed file.");
|
||||
define('LANG_fill_the_addon_name', "Please, fill a name for the addon package.");
|
||||
define('LANG_select_an_addon_type', "Please, select an addon type.");
|
||||
define('LANG_select_a_game_type', "Please, select a game type.");
|
||||
define('LANG_edit_addon', "Edit Addon");
|
||||
define('LANG_post-script', "Post-install script(bash)");
|
||||
define('LANG_create_addon', "Create Server Content Item");
|
||||
define('LANG_addons_db', "Server Content Database");
|
||||
define('LANG_addon_has_been_created', "The server content item \"%s\" has been created.");
|
||||
define('LANG_remove_addon', "Remove");
|
||||
define('LANG_fill_the_url_address_to_a_compressed_file', "Please enter a URL for the compressed file to download.");
|
||||
define('LANG_fill_the_addon_name', "Please enter a name for the server content item.");
|
||||
define('LANG_select_an_addon_type', "Please select a content type.");
|
||||
define('LANG_select_a_game_type', "Please select a game type.");
|
||||
define('LANG_edit_addon', "Edit");
|
||||
define('LANG_invalid_addon', "Invalid server content item or access denied.");
|
||||
define('LANG_invalid_addon_type', "Invalid content type selected.");
|
||||
define('LANG_post-script', "Post-install script (bash)");
|
||||
define('LANG_replacements', "Replacements:");
|
||||
define('LANG_addon_name_info', "Enter a name for this addon, this is the name that the user sees.");
|
||||
define('LANG_url_info', "Enter a web address that contains a file to download, if compressed in zip or tar.gz will be unpacked in the root directory of the server or on the path given below.");
|
||||
define('LANG_path_info', "The path must be relative to the server folder and contain no slashes at the beginning or end, eg: cstrike/cfg. If left blank will use the server root path.");
|
||||
define('LANG_post-script_info', "Enter Bash language code, this will be executed as a script, you can use text replacements to customize the installation, they will be replaced by data from the server on which you install the addon. The script will start from the root folder of the server or the specified path.");
|
||||
define('LANG_addon_name_info', "Enter a display name for this server content item.");
|
||||
define('LANG_url_info', "Enter a download URL for a compressed file (.zip or .tar.gz). It will be extracted into the server root or the path specified below.");
|
||||
define('LANG_path_info', "Path relative to the server folder, with no leading or trailing slashes (e.g. cstrike/cfg). Leave blank to use the server root.");
|
||||
define('LANG_post-script_info', "Enter a Bash script to run after installation. Use the replacement variables listed on the left to inject server-specific values. The script runs from the server root or the specified path.");
|
||||
define('LANG_show_to_group', "Show to group");
|
||||
define('LANG_all_groups', "All groups");
|
||||
define('LANG_show_addons_for_selected_group', "Show addons for selected group");
|
||||
define('LANG_show_addons_for_selected_group', "Show content for selected group");
|
||||
define('LANG_group', "Group");
|
||||
?>
|
||||
|
|
@ -128,7 +128,7 @@ define('LANG_server_cant_start', "server can not start");
|
|||
define('LANG_server_cant_stop', "server can not stop");
|
||||
define('LANG_error_occured_remote_host', "Error occurred on the remote host");
|
||||
define('LANG_follow_server_status', "You can follow the server status from");
|
||||
define('LANG_addons', "Addons");
|
||||
define('LANG_addons', "Server Content");
|
||||
define('LANG_hostname', "Hostname");
|
||||
define('LANG_ping', "Ping");
|
||||
define('LANG_team', "Team");
|
||||
|
|
|
|||
297
Panel/modules/addonsmanager/SERVER_CONTENT_ROADMAP.md
Normal file
297
Panel/modules/addonsmanager/SERVER_CONTENT_ROADMAP.md
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
# Server Content Manager — Roadmap & Safety Review
|
||||
|
||||
> **Module:** `Panel/modules/addonsmanager`
|
||||
> **Status:** Phase 1 complete — UI/language cleanup, category map, VARCHAR(32) migration, installer documentation
|
||||
> **Branch:** Panel-unstable
|
||||
> **Maintained by:** WDS (GSP is a heavily customized fork of OGP)
|
||||
|
||||
---
|
||||
|
||||
## 1. Current Behaviour Summary
|
||||
|
||||
The **Addons Manager** (now labelled "Server Content Manager" in the UI) lets
|
||||
admins define downloadable content items that can be pushed to game server
|
||||
homes by users.
|
||||
|
||||
### Flow
|
||||
|
||||
```
|
||||
Admin creates Server Content item (addons_manager.php)
|
||||
└─> stored in OGP_DB_PREFIXaddons
|
||||
|
||||
User visits game monitor
|
||||
└─> monitor_buttons.php checks for content items for that game type
|
||||
└─> "Server Content (N)" button appears
|
||||
|
||||
User clicks button
|
||||
└─> user_addons.php — shows available category links
|
||||
└─> addons_installer.php?addon_type=<type>
|
||||
└─> user picks a specific item
|
||||
└─> state=start → agent.start_file_download(url, path, filename, "uncompress")
|
||||
└─> optional post_script runs on the agent after extraction
|
||||
└─> page auto-refreshes to show download/script progress
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Existing Database Fields (`OGP_DB_PREFIXaddons`)
|
||||
|
||||
| Column | Type | Description |
|
||||
|---------------|-----------------|--------------------------------------------------|
|
||||
| addon_id | INT UNSIGNED PK | Auto-increment primary key |
|
||||
| name | VARCHAR(80) | Display name shown to users |
|
||||
| url | VARCHAR(200) | Download URL (zip / tar.gz) |
|
||||
| path | VARCHAR(80) | Relative target path inside server home |
|
||||
| addon_type | VARCHAR(32)* | Content category key (plugin / mappack / config / …) |
|
||||
| home_cfg_id | VARCHAR(7) | Linked game configuration ID |
|
||||
| post_script | LONGTEXT | Bash script run by agent after install |
|
||||
| group_id | INT(11) NULL | Restrict visibility to a specific user group |
|
||||
|
||||
\* Expanded from VARCHAR(7) to VARCHAR(32) in db_version 2
|
||||
(migration runs automatically via the module update system).
|
||||
|
||||
---
|
||||
|
||||
## 3. Existing Flow: user_addons.php → addons_installer.php
|
||||
|
||||
1. `user_addons.php` queries all content items for the server's `home_cfg_id`.
|
||||
2. It groups items by `addon_type` and renders one link per category.
|
||||
3. `addons_installer.php` (page key: `addons`) receives `addon_type` and
|
||||
`home_id` in the query string.
|
||||
4. On first load (no `state`), it renders a dropdown of available items.
|
||||
5. On submit (`state=start`), it calls `$remote->start_file_download()` and
|
||||
begins polling.
|
||||
6. Subsequent loads with `state=refresh` poll the agent for download progress
|
||||
and script log output.
|
||||
|
||||
---
|
||||
|
||||
## 4. Current post_script Replacement Variables
|
||||
|
||||
| Variable | Replaced with |
|
||||
|--------------------|--------------------------------------------------------------|
|
||||
| `%home_path%` | Absolute filesystem path of the server home directory |
|
||||
| `%home_name%` | Human-readable name of the server home |
|
||||
| `%control_password%` | RCON / control password for this server instance |
|
||||
| `%max_players%` | Maximum player count for this mod slot |
|
||||
| `%ip%` | IP address bound to this server |
|
||||
| `%port%` | Game port |
|
||||
| `%query_port%` | Query/status port (derived from game XML rules) |
|
||||
| `%incremental%` | Internal incremental counter for this mod/home combination |
|
||||
|
||||
All replacements are case-insensitive (`preg_replace … /i`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Security Concerns
|
||||
|
||||
### Current risks
|
||||
|
||||
1. **No path validation in the panel** — the `path` field is passed directly
|
||||
to the agent without checking for `../`. The agent is the last line of
|
||||
defence. A malicious admin could craft a path that escapes the home
|
||||
directory if the agent's validation is insufficient.
|
||||
|
||||
2. **SQL injection in filter queries** — `addon_type` is interpolated into
|
||||
SQL strings in several places. A whitelist check via `in_array()` against
|
||||
the registered category keys prevents injection, but this must remain in
|
||||
place whenever new query sites are added.
|
||||
|
||||
3. **post_script is admin-only but powerful** — admins write arbitrary bash.
|
||||
This is intentional; users cannot supply scripts. However, the variable
|
||||
substitution should be audited to ensure no user-controlled value (e.g.
|
||||
a server name containing shell metacharacters) can affect the script.
|
||||
|
||||
### Recommended hardening (next phase)
|
||||
|
||||
- Add explicit `../` stripping / validation of `path` on the panel side before
|
||||
sending to the agent.
|
||||
- Sanitise all `%variable%` substitution inputs (strip shell metacharacters
|
||||
from home_name, ip, port before substitution).
|
||||
- Consider signing or hashing the post_script blob to detect tampering.
|
||||
- Rate-limit install actions per user to prevent abuse.
|
||||
|
||||
---
|
||||
|
||||
## 6. Proposed Next Database Fields
|
||||
|
||||
```sql
|
||||
ALTER TABLE OGP_DB_PREFIXaddons
|
||||
MODIFY addon_type VARCHAR(32) NOT NULL, -- already applied in db_version 2
|
||||
ADD COLUMN install_method VARCHAR(32) NOT NULL DEFAULT 'download_zip',
|
||||
ADD COLUMN content_version VARCHAR(64) NULL,
|
||||
ADD COLUMN requires_stop TINYINT(1) NOT NULL DEFAULT 1,
|
||||
ADD COLUMN backup_before_install TINYINT(1) NOT NULL DEFAULT 1,
|
||||
ADD COLUMN restart_after_install TINYINT(1) NOT NULL DEFAULT 0,
|
||||
ADD COLUMN is_profile TINYINT(1) NOT NULL DEFAULT 0,
|
||||
ADD COLUMN description TEXT NULL;
|
||||
```
|
||||
|
||||
Apply this as `$install_queries[2]` (db_version 3) in `module.php` when ready.
|
||||
|
||||
---
|
||||
|
||||
## 7. Proposed Install Methods
|
||||
|
||||
| install_method | Description |
|
||||
|-------------------|---------------------------------------------------------------------|
|
||||
| `download_zip` | Download a .zip / .tar.gz and extract into the server path (current default) |
|
||||
| `download_file` | Download a single file (no extraction) into the server path |
|
||||
| `post_script` | Run only the post_script — no download, no extraction |
|
||||
| `steam_workshop` | Pass Workshop item IDs to the agent's `steamcmd +workshop_download_item` helper |
|
||||
| `minecraft_jar` | Download a server jar from Mojang / Paper / Purpur / Fabric APIs |
|
||||
| `profile_copy` | Copy a stored profile directory tree into the server home |
|
||||
|
||||
---
|
||||
|
||||
## 8. Proposed Categories (server_content_categories.php)
|
||||
|
||||
| addon_type | Display label | Notes |
|
||||
|-------------|---------------------|------------------------------------|
|
||||
| `plugin` | Plugins / Mods | Original — always present |
|
||||
| `mappack` | Map Packs | Original — always present |
|
||||
| `config` | Config Packs | Original — always present |
|
||||
| `version` | Server Versions | e.g. Minecraft jar switcher |
|
||||
| `modpack` | Modpacks | CurseForge / ATLauncher packs |
|
||||
| `workshop` | Workshop Content | Steam Workshop (requires VARCHAR(32)) |
|
||||
| `script` | Scripted Installer | Admin-defined script only |
|
||||
| `profile` | Server Profiles | Full profile: configs + mods + scripts |
|
||||
|
||||
---
|
||||
|
||||
## 9. Recommended Phased Migration Plan
|
||||
|
||||
### Phase 1 (complete — this PR)
|
||||
- [x] UI labels renamed to "Server Content Manager / Server Content".
|
||||
- [x] Central category map created (`server_content_categories.php`).
|
||||
- [x] `addon_type` column expanded to VARCHAR(32) via db_version 2 migration.
|
||||
- [x] `addons_installer.php` and `user_addons.php` use category map for validation.
|
||||
- [x] Full TODO/comment blocks added to installer for next phase work.
|
||||
- [x] Module folder, table names, URL routes, function names unchanged.
|
||||
|
||||
### Phase 2 — Schema & install_method support
|
||||
- [ ] Apply the `$install_queries[2]` schema above (db_version 3).
|
||||
- [ ] Add `install_method` dropdown to admin create/edit form.
|
||||
- [ ] Implement `requires_stop` check in installer before download.
|
||||
- [ ] Implement `backup_before_install` using agent tar/zip helper.
|
||||
- [ ] Implement `restart_after_install` using existing server start logic.
|
||||
- [ ] Add install history table and log writes.
|
||||
|
||||
### Phase 3 — Steam Workshop integration
|
||||
See Part 6 below.
|
||||
|
||||
### Phase 4 — Minecraft jar / version switcher
|
||||
See Part 7 below.
|
||||
|
||||
### Phase 5 — DayZ / Arma profile switcher
|
||||
See Part 8 below.
|
||||
|
||||
---
|
||||
|
||||
## 10. Part 6: Steam Workshop Integration
|
||||
|
||||
### Concept
|
||||
Steam Workshop content is treated as a Server Content type (`addon_type=workshop`,
|
||||
`install_method=steam_workshop`).
|
||||
|
||||
### Browser UI
|
||||
- A "Workshop Browser" page within the module fetches the workshop item list
|
||||
from Steam's Web API and lets users select items.
|
||||
- Selected item IDs are stored as server content selections linked to the home.
|
||||
|
||||
### Agent side
|
||||
- The agent runs `steamcmd +login anonymous +workshop_download_item <appid> <item_id> +quit`
|
||||
for each selected item.
|
||||
- Downloaded content is moved into the correct server mod directory.
|
||||
- The agent reports progress back to the panel via the existing rsync_progress mechanism
|
||||
or a new workshop_progress RPC.
|
||||
|
||||
### Restart behaviour (configurable per content item)
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| 1 | Install immediately if server is stopped |
|
||||
| 2 | Queue installation to run on next restart |
|
||||
| 3 | Restart automatically if updates are available |
|
||||
| 4 | Notify only — do not install automatically |
|
||||
|
||||
---
|
||||
|
||||
## 11. Part 7: Minecraft Example
|
||||
|
||||
### Base game: Minecraft
|
||||
|
||||
### Server Content options (addon_type=version, install_method=minecraft_jar)
|
||||
|
||||
| Content Item | Source API / URL |
|
||||
|-------------------|---------------------------------------------------------------|
|
||||
| Vanilla 1.21.x | Mojang version manifest API |
|
||||
| Paper 1.21.x | papermc.io API |
|
||||
| Purpur 1.21.x | purpurmc.org API |
|
||||
| Forge 1.20.1 | files.minecraftforge.net |
|
||||
| Fabric 1.20.1 | meta.fabricmc.net |
|
||||
| Modpack installer | CurseForge / ATLauncher / FTB API (addon_type=modpack) |
|
||||
|
||||
### Install flow
|
||||
1. Admin creates a content item with `install_method=minecraft_jar` and sets
|
||||
`url` to the download endpoint (or a version ID for API-resolved URLs).
|
||||
2. User selects the version from the Server Content page.
|
||||
3. Installer downloads the jar to the server home path.
|
||||
4. post_script patches the startup command line with the new jar filename.
|
||||
5. If `restart_after_install=1`, the server restarts with the new jar.
|
||||
|
||||
---
|
||||
|
||||
## 12. Part 8: DayZ / Arma Example
|
||||
|
||||
### Base game: Arma 2 / DayZ-capable server
|
||||
|
||||
### Server Content options
|
||||
|
||||
| Content Item | Type | Description |
|
||||
|--------------|---------|--------------------------------------------------|
|
||||
| DayZ Vanilla | config | Vanilla DayZ config + mission files |
|
||||
| DayZ Epoch | profile | Epoch mod files + config profile |
|
||||
| Overpoch | profile | Combined Overwatch + Epoch profile |
|
||||
| Map Pack | mappack | Additional map files (Chernarus, Lingor, etc.) |
|
||||
| Config Pack | config | Server config preset (difficulty, loot tables) |
|
||||
|
||||
### Install flow
|
||||
1. Admin defines each option as a Server Content item with `install_method=download_zip`
|
||||
or `install_method=profile_copy`.
|
||||
2. post_script copies required files, patches `mission.sqm`, `server.cfg`, etc.
|
||||
3. If `requires_stop=1`, the server is stopped before applying changes.
|
||||
4. If `restart_after_install=1`, the server starts with the new profile.
|
||||
|
||||
---
|
||||
|
||||
## 13. Part 9: Security Direction
|
||||
|
||||
### Core principles
|
||||
|
||||
1. **Users must not be allowed to enter arbitrary commands.**
|
||||
Admins define Server Content items including scripts.
|
||||
Users only select from the approved list.
|
||||
|
||||
2. **Script execution is scoped to the assigned server.**
|
||||
The post_script runs with only the target server home path and the approved
|
||||
replacement variables. It cannot reference paths outside the home directory.
|
||||
|
||||
3. **All paths must be validated against the home directory boundary.**
|
||||
- Strip or reject any `../` sequences in the `path` field.
|
||||
- Reject absolute paths unless the content item is explicitly marked
|
||||
admin-only and the admin has been warned.
|
||||
- The agent enforces path containment at the OS level; the panel should
|
||||
add a redundant check as defence-in-depth.
|
||||
|
||||
4. **Replacement variable values must be shell-safe.**
|
||||
- Escape shell metacharacters in `home_name`, `ip`, `port`, `home_path`,
|
||||
etc. before substitution into post_script.
|
||||
- Consider wrapping each value in single quotes in the substituted script.
|
||||
|
||||
5. **Workshop and external API downloads must be verified.**
|
||||
- Check Content-Type and file signature/hash where possible.
|
||||
- Reject downloads that exceed a configurable size limit.
|
||||
|
||||
6. **Install history must be logged.**
|
||||
- Record who installed what, when, and the script exit code.
|
||||
- This log must be readable by admins but not modifiable by users.
|
||||
|
|
@ -1,25 +1,93 @@
|
|||
<?php
|
||||
/*
|
||||
*
|
||||
* OGP - Open Game Panel
|
||||
* Copyright (C) 2008 - 2018 The OGP Development Team
|
||||
* GSP - Game Server Panel (a heavily customized fork of OGP maintained by WDS)
|
||||
*
|
||||
* http://www.opengamepanel.org/
|
||||
* Server Content Installer (module: addonsmanager, page: addons)
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* This file handles the actual download+extraction and post-install script
|
||||
* execution for a Server Content item selected by a user.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or any later version.
|
||||
* CURRENT FLOW:
|
||||
* 1. User selects a content type (plugin / mappack / config / ...) from
|
||||
* user_addons.php which links here with addon_type=<type>.
|
||||
* 2. User picks a specific content item from a dropdown.
|
||||
* 3. On form submit, state=start is set and start_file_download() is called
|
||||
* on the remote agent with the configured URL and target path.
|
||||
* 4. The agent downloads and extracts the archive.
|
||||
* 5. If a post_script is defined it is run on the agent after extraction.
|
||||
* 6. The page auto-refreshes (state=refresh) to show download/script progress.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* POST-INSTALL SCRIPT REPLACEMENT VARIABLES:
|
||||
* %home_path% – absolute path of the game server home directory
|
||||
* %home_name% – display name of the game server home
|
||||
* %control_password% – RCON / control password for this server instance
|
||||
* %max_players% – maximum player count configured for this mod slot
|
||||
* %ip% – IP address bound to this server instance
|
||||
* %port% – game port bound to this server instance
|
||||
* %query_port% – query/status port (derived from game XML rules)
|
||||
* %incremental% – internal incremental run counter for this mod/home
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* SECURITY NOTES:
|
||||
* - Users CANNOT supply arbitrary scripts; only the admin-defined post_script
|
||||
* is executed. Users only pick from the approved list.
|
||||
* - Paths are passed to the agent which is responsible for enforcing that
|
||||
* all paths stay inside the assigned home directory.
|
||||
* - TODO (next phase): add explicit server-side path validation before
|
||||
* sending the command to the agent to block ../ traversal at the panel.
|
||||
*
|
||||
* ─── FUTURE WORK (TODO – next phase) ────────────────────────────────────────
|
||||
* The items below are intentionally NOT implemented here yet. They are
|
||||
* documented so the next contributor knows exactly where to add them.
|
||||
*
|
||||
* TODO: requires_stop flag
|
||||
* If the content item sets requires_stop=1, stop the server before
|
||||
* initiating the download. Poll is_server_running() and abort if it
|
||||
* cannot be stopped within a timeout.
|
||||
*
|
||||
* TODO: backup_before_install flag
|
||||
* If backup_before_install=1, call the agent's backup function or
|
||||
* compress the target path into a timestamped .tar.gz before extraction.
|
||||
*
|
||||
* TODO: restart_after_install flag
|
||||
* If restart_after_install=1, trigger a server start after a successful
|
||||
* install (i.e. after post_script completes with exit code 0).
|
||||
*
|
||||
* TODO: install_method field
|
||||
* Current method is always 'download_zip'. Future methods:
|
||||
* 'download_file' – single-file download, no extraction
|
||||
* 'post_script' – run only the post_script, no download
|
||||
* 'steam_workshop' – pass workshop item IDs to the agent's workshop helper
|
||||
* 'minecraft_jar' – download a Minecraft server jar + update start script
|
||||
* 'profile_copy' – copy a profile directory tree into the server home
|
||||
*
|
||||
* TODO: content_version field
|
||||
* Store the installed version tag so the UI can display "installed: 1.21.1"
|
||||
* and detect whether an update is available.
|
||||
*
|
||||
* TODO: safe script templates
|
||||
* Provide a set of admin-approved script templates so admins do not have to
|
||||
* write raw bash from scratch. Templates are stored in the DB and referenced
|
||||
* by content items.
|
||||
*
|
||||
* TODO: install history / logging
|
||||
* Write a row to a new install_history table (or log file) each time a
|
||||
* content item is installed:
|
||||
* home_id, addon_id, installed_by (user_id), installed_at, result, log_output
|
||||
*
|
||||
* TODO: user-friendly status output
|
||||
* Replace the raw progress-bar with a card-style status block showing:
|
||||
* content item name, version, download progress, script output, final status.
|
||||
*
|
||||
* TODO: Steam Workshop integration
|
||||
* When install_method='steam_workshop', pass the workshop item ID list to
|
||||
* the agent. See SERVER_CONTENT_ROADMAP.md – Part 6 for the full design.
|
||||
*
|
||||
* TODO: Minecraft jar / version switching
|
||||
* When install_method='minecraft_jar', download the jar from Mojang/Paper/
|
||||
* Purpur/Fabric API, place it at the configured server path, and patch the
|
||||
* startup command line. See SERVER_CONTENT_ROADMAP.md – Part 7.
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
*/
|
||||
|
||||
function do_progress($kbytes,$totalsize)
|
||||
|
|
@ -41,14 +109,16 @@ function do_progress($kbytes,$totalsize)
|
|||
require_once("includes/lib_remote.php");
|
||||
require_once("modules/config_games/server_config_parser.php");
|
||||
require_once("protocol/lgsl/lgsl_protocol.php");
|
||||
// Central category map — all valid addon_type values and their labels.
|
||||
require_once(dirname(__FILE__) . '/server_content_categories.php');
|
||||
|
||||
function exec_ogp_module() {
|
||||
|
||||
global $db,$view;
|
||||
$home_id = $_REQUEST['home_id'];
|
||||
$mod_id = $_REQUEST['mod_id'];
|
||||
$ip = $_REQUEST['ip'];
|
||||
$port = $_REQUEST['port'];
|
||||
$mod_id = $_REQUEST['mod_id'];
|
||||
$ip = $_REQUEST['ip'];
|
||||
$port = $_REQUEST['port'];
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
$isAdmin = $db->isAdmin( $_SESSION['user_id'] );
|
||||
|
|
@ -76,13 +146,15 @@ function exec_ogp_module() {
|
|||
}
|
||||
|
||||
$home_cfg_id = $home_info['home_cfg_id'];
|
||||
$server_xml = read_server_config(SERVER_CONFIG_LOCATION."/".$home_info['home_cfg_file']);
|
||||
$server_xml = read_server_config(SERVER_CONFIG_LOCATION."/".$home_info['home_cfg_file']);
|
||||
|
||||
$addon_types = array('plugin', 'mappack', 'config');
|
||||
$addon_type = isset($_REQUEST['addon_type']) ? $_REQUEST['addon_type'] : "";
|
||||
// Use the full category map so newly added types are accepted without
|
||||
// editing this file. The original three types are always present.
|
||||
$addon_types = get_server_content_type_keys();
|
||||
$addon_type = isset($_REQUEST['addon_type']) ? $_REQUEST['addon_type'] : "";
|
||||
|
||||
$state = isset($_REQUEST['state']) ? $_REQUEST['state'] : "";
|
||||
$pid = isset($_REQUEST['pid']) ? $_REQUEST['pid'] : -1;
|
||||
$pid = isset($_REQUEST['pid']) ? $_REQUEST['pid'] : -1;
|
||||
|
||||
if ( $state != "" )
|
||||
{
|
||||
|
|
@ -104,7 +176,11 @@ function exec_ogp_module() {
|
|||
$addon_info = $addons_rows[0];
|
||||
$url = $addon_info['url'];
|
||||
$filename = basename($url);
|
||||
#### This makes replacements to the bash script:
|
||||
#### Replace template variables in the post-install script with
|
||||
#### live server data before sending to the agent.
|
||||
#### Each variable is replaced case-insensitively.
|
||||
#### SECURITY: only admin-defined variables are substituted; users
|
||||
#### cannot inject additional commands through these fields.
|
||||
if($addon_info['post_script'] != "")
|
||||
{
|
||||
$addon_info['post_script'] = strip_real_escape_string($addon_info['post_script']);
|
||||
|
|
@ -153,7 +229,7 @@ function exec_ogp_module() {
|
|||
}
|
||||
}
|
||||
|
||||
#### end of replacememnts
|
||||
#### end of replacements
|
||||
if ( $state == "start" AND $addon_id != "" )
|
||||
$pid = $remote->start_file_download( $addon_info['url'], $home_info['home_path']."/".$addon_info['path'], $filename, "uncompress", $post_script);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,31 +2,40 @@
|
|||
<?php
|
||||
/*
|
||||
*
|
||||
* OGP - Open Game Panel
|
||||
* Copyright (C) 2008 - 2018 The OGP Development Team
|
||||
* GSP - Game Server Panel (a heavily customized fork of OGP maintained by WDS)
|
||||
*
|
||||
* http://www.opengamepanel.org/
|
||||
* Admin page: Server Content Manager (module: addonsmanager)
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* This page lets admins create, edit, and remove Server Content items.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or any later version.
|
||||
* A "Server Content item" is anything that can be pushed to a game server:
|
||||
* 1. A zip/file package extracted into the server directory.
|
||||
* 2. A downloaded file placed into the server directory.
|
||||
* 3. A script-driven installer (post_script only, no download required).
|
||||
* 4. A Minecraft server jar / version switcher (future: install_method=minecraft_jar).
|
||||
* 5. A DayZ/Epoch/Arma profile copy (future: install_method=profile_copy).
|
||||
* 6. A Steam Workshop content bundle (future: install_method=steam_workshop).
|
||||
* 7. A config preset (type=config).
|
||||
* 8. A full server profile built from multiple actions (type=profile).
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* DB table: OGP_DB_PREFIXaddons (unchanged for backward compatibility).
|
||||
* See SERVER_CONTENT_ROADMAP.md for the full migration plan.
|
||||
*
|
||||
*/
|
||||
|
||||
// Central category map — defines all valid addon_type values and their labels.
|
||||
require_once(dirname(__FILE__) . '/server_content_categories.php');
|
||||
|
||||
function exec_ogp_module() {
|
||||
|
||||
global $db;
|
||||
|
||||
|
||||
// Build the complete list of allowed content types from the category map.
|
||||
// Admins can create items of any registered type; the original three types
|
||||
// (plugin, mappack, config) are always included.
|
||||
$addon_types = get_server_content_type_keys(); // all keys
|
||||
$addon_type_labels = get_server_content_categories(); // key => label
|
||||
|
||||
if (isset($_POST['create_addon']) AND isset($_POST['name']) AND $_POST['url']=="")
|
||||
{
|
||||
print_failure(get_lang("fill_the_url_address_to_a_compressed_file"));
|
||||
|
|
@ -45,13 +54,13 @@ function exec_ogp_module() {
|
|||
}
|
||||
elseif (isset($_POST['create_addon']) AND isset($_POST['name']) AND isset($_POST['url']) AND isset($_POST['addon_type']) and isset($_POST['home_cfg_id']) )
|
||||
{
|
||||
$fields['name'] = $_POST['name'];
|
||||
$fields['url'] = $_POST['url'];
|
||||
$fields['path'] = $_POST['path'];
|
||||
$fields['addon_type'] = $_POST['addon_type'];
|
||||
$fields['name'] = $_POST['name'];
|
||||
$fields['url'] = $_POST['url'];
|
||||
$fields['path'] = $_POST['path'];
|
||||
$fields['addon_type'] = $_POST['addon_type'];
|
||||
$fields['home_cfg_id'] = $_POST['home_cfg_id'];
|
||||
$fields['post_script'] = $_POST['post_script'];
|
||||
$fields['group_id'] = $_POST['group_id'];
|
||||
$fields['group_id'] = $_POST['group_id'];
|
||||
if( is_numeric($db->resultInsertId( 'addons', $fields )) )
|
||||
{
|
||||
print_success(get_lang_f("addon_has_been_created",$_POST['name']));
|
||||
|
|
@ -61,14 +70,13 @@ function exec_ogp_module() {
|
|||
}
|
||||
|
||||
echo "<h2>".get_lang('addons_manager')."</h2>";
|
||||
$name = isset($_POST['name']) ? $_POST['name'] : "";
|
||||
$url = isset($_POST['url']) ? $_POST['url'] : "";
|
||||
$path = isset($_POST['path']) ? $_POST['path'] : "";
|
||||
$name = isset($_POST['name']) ? $_POST['name'] : "";
|
||||
$url = isset($_POST['url']) ? $_POST['url'] : "";
|
||||
$path = isset($_POST['path']) ? $_POST['path'] : "";
|
||||
$post_script = isset($_POST['post_script']) ? $_POST['post_script'] : "";
|
||||
$home_cfg_id = isset($_POST['home_cfg_id']) ? $_POST['home_cfg_id'] : "";
|
||||
$addon_type = isset($_POST['addon_type']) ? $_POST['addon_type'] : "";
|
||||
$group_id = isset($_POST['group_id']) ? $_POST['group_id'] : "";
|
||||
$addon_types = array('plugin', 'mappack', 'config');
|
||||
$addon_type = isset($_POST['addon_type']) ? $_POST['addon_type'] : "";
|
||||
$group_id = isset($_POST['group_id']) ? $_POST['group_id'] : "";
|
||||
|
||||
if (isset($_POST['addon_id']) && (int)$_POST['addon_id'] > 0 && isset($_POST['edit']))
|
||||
{
|
||||
|
|
@ -76,14 +84,14 @@ function exec_ogp_module() {
|
|||
if (!is_array($addons_rows)) {
|
||||
$addons_rows = [];
|
||||
}
|
||||
$addon_info = $addons_rows[0];
|
||||
$name = isset($addon_info['name']) ? $addon_info['name'] : "";
|
||||
$url = isset($addon_info['url']) ? $addon_info['url'] : "";
|
||||
$path = isset($addon_info['path']) ? $addon_info['path'] : "";
|
||||
$addon_info = $addons_rows[0];
|
||||
$name = isset($addon_info['name']) ? $addon_info['name'] : "";
|
||||
$url = isset($addon_info['url']) ? $addon_info['url'] : "";
|
||||
$path = isset($addon_info['path']) ? $addon_info['path'] : "";
|
||||
$post_script = isset($addon_info['post_script']) ? $addon_info['post_script'] : "";
|
||||
$home_cfg_id = isset($addon_info['home_cfg_id']) ? $addon_info['home_cfg_id'] : "";
|
||||
$addon_type = isset($addon_info['addon_type']) ? $addon_info['addon_type'] : "";
|
||||
$group_id = isset($addon_info['group_id']) ? $addon_info['group_id'] : "";
|
||||
$addon_type = isset($addon_info['addon_type']) ? $addon_info['addon_type'] : "";
|
||||
$group_id = isset($addon_info['group_id']) ? $addon_info['group_id'] : "";
|
||||
}
|
||||
?>
|
||||
<form action="" method="post">
|
||||
|
|
@ -104,7 +112,8 @@ function exec_ogp_module() {
|
|||
<input type="text" value="<?php echo $url; ?>" name="url" size="85" title="<?php print_lang('url_info'); ?>" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- If any, you can set the destination path, should be a relative path to the main game server folder. -->
|
||||
<!-- Destination path — must be relative to the game server home directory.
|
||||
Path traversal (../) is not allowed; the agent enforces this. -->
|
||||
<tr>
|
||||
<td align="right">
|
||||
<b><?php print_lang('path'); ?></b>
|
||||
|
|
@ -174,11 +183,12 @@ function exec_ogp_module() {
|
|||
</td>
|
||||
<td align="left">
|
||||
<?php
|
||||
$types = array( 'plugin', 'mappack', 'config' );
|
||||
foreach ((array)$types as $type)
|
||||
// Render a radio button for every registered content type.
|
||||
// New types automatically appear here once added to server_content_categories.php.
|
||||
foreach ((array)$addon_type_labels as $type_key => $type_label)
|
||||
{
|
||||
$checked = ( isset($addon_type) AND $type == $addon_type) ? 'checked' : '';
|
||||
echo '<input type="radio" name="addon_type" value="'.$type.'" '.$checked.'>'.get_lang($type);
|
||||
$checked = ( isset($addon_type) AND $type_key == $addon_type) ? 'checked' : '';
|
||||
echo '<input type="radio" name="addon_type" value="'.htmlspecialchars($type_key).'" '.$checked.'>'.htmlspecialchars($type_label).' ';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
|
|
@ -276,14 +286,14 @@ function exec_ogp_module() {
|
|||
<?php
|
||||
$option = '';
|
||||
|
||||
foreach ((array)$addon_types as $k) {
|
||||
foreach ((array)$addon_type_labels as $k => $label) {
|
||||
$option .= '<option';
|
||||
|
||||
if (isset($_GET['addon_type']) && $_GET['addon_type'] == $k) {
|
||||
$option .= ' selected';
|
||||
}
|
||||
|
||||
$option .= ' value="'. $k .'">'.get_lang($k).'</option>';
|
||||
$option .= ' value="'. htmlspecialchars($k) .'">'.htmlspecialchars($label).'</option>';
|
||||
}
|
||||
|
||||
echo $option;
|
||||
|
|
@ -324,8 +334,9 @@ function exec_ogp_module() {
|
|||
}
|
||||
|
||||
$home_cfg_id = !empty($_GET['home_cfg_id']) && (int)$_GET['home_cfg_id'] > 0 ? (int)$_GET['home_cfg_id'] : 0;
|
||||
$addon_type = !empty($_GET['addon_type']) && is_array($addon_types) && in_array($_GET['addon_type'], $addon_types) ? $_GET['addon_type'] : "";
|
||||
$group_id = isset($_GET['group_id']) && is_numeric($_GET['group_id']) ? (int)$_GET['group_id'] : 0;
|
||||
// Validate the requested addon_type against the full category map so new types are accepted.
|
||||
$addon_type = !empty($_GET['addon_type']) && in_array($_GET['addon_type'], $addon_types) ? $_GET['addon_type'] : "";
|
||||
$group_id = isset($_GET['group_id']) && is_numeric($_GET['group_id']) ? (int)$_GET['group_id'] : 0;
|
||||
|
||||
if ( isset($_GET['show']) )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,45 +1,51 @@
|
|||
<?php
|
||||
/*
|
||||
*
|
||||
* OGP - Open Game Panel
|
||||
* Copyright (C) 2008 - 2018 The OGP Development Team
|
||||
* GSP - Game Server Panel (a heavily customized fork of OGP maintained by WDS)
|
||||
*
|
||||
* http://www.opengamepanel.org/
|
||||
* Module: addonsmanager → Server Content Manager
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* The module folder and DB table names are intentionally unchanged for
|
||||
* backward compatibility. Only UI labels have been updated to the new
|
||||
* "Server Content" terminology.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* db_version history:
|
||||
* 1 – initial schema (addons table, addon_type VARCHAR(7))
|
||||
* 2 – expand addon_type to VARCHAR(32) to support extended content types
|
||||
* (workshop=8 chars, and any future type up to 32 chars)
|
||||
*
|
||||
*/
|
||||
|
||||
// Module general information
|
||||
$module_title = "Addons Manager";
|
||||
$module_version = "1.0";
|
||||
$db_version = 1;
|
||||
$module_title = "Server Content Manager";
|
||||
$module_version = "2.0";
|
||||
$db_version = 2;
|
||||
$module_required = TRUE;
|
||||
$module_menus = array( array( 'subpage' => 'addons_manager', 'name'=>'Addons Manager', 'group'=>'admin' ) );
|
||||
$module_menus = array(
|
||||
array( 'subpage' => 'addons_manager', 'name' => 'Server Content Manager', 'group' => 'admin' )
|
||||
);
|
||||
|
||||
$install_queries = array();
|
||||
// ── db_version 1 : initial install ───────────────────────────────────────────
|
||||
$install_queries = array();
|
||||
$install_queries[0] = array(
|
||||
"CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."addons` (
|
||||
`addon_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(80) NOT NULL,
|
||||
`url` VARCHAR(200) NOT NULL,
|
||||
`path` VARCHAR(80) NOT NULL,
|
||||
`addon_type` VARCHAR(7) NOT NULL,
|
||||
`home_cfg_id` VARCHAR(7) NOT NULL,
|
||||
`post_script` longtext NOT NULL,
|
||||
`group_id` int(11) NULL
|
||||
`addon_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(80) NOT NULL,
|
||||
`url` VARCHAR(200) NOT NULL,
|
||||
`path` VARCHAR(80) NOT NULL,
|
||||
`addon_type` VARCHAR(7) NOT NULL,
|
||||
`home_cfg_id` VARCHAR(7) NOT NULL,
|
||||
`post_script` longtext NOT NULL,
|
||||
`group_id` int(11) NULL
|
||||
) ENGINE=MyISAM;"
|
||||
);
|
||||
?>
|
||||
|
||||
// ── db_version 2 : expand addon_type to VARCHAR(32) ──────────────────────────
|
||||
// Required so extended content types such as 'workshop' (8 chars) can be stored.
|
||||
// MODIFY is safe on existing installs; existing 'plugin'/'mappack'/'config'
|
||||
// values are preserved without alteration.
|
||||
$install_queries[1] = array(
|
||||
"ALTER TABLE `".OGP_DB_PREFIX."addons`
|
||||
MODIFY `addon_type` VARCHAR(32) NOT NULL;"
|
||||
);
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,12 @@
|
|||
<?php
|
||||
/*
|
||||
*
|
||||
* OGP - Open Game Panel
|
||||
* Copyright (C) 2008 - 2018 The OGP Development Team
|
||||
* GSP - Game Server Panel (a heavily customized fork of OGP maintained by WDS)
|
||||
*
|
||||
* http://www.opengamepanel.org/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* Monitor button: Server Content (module: addonsmanager)
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* Injects a "Server Content" button into the game monitor toolbar when at
|
||||
* least one Server Content item is configured for the server's game type.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
82
Panel/modules/addonsmanager/server_content_categories.php
Normal file
82
Panel/modules/addonsmanager/server_content_categories.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/*
|
||||
*
|
||||
* GSP - Game Server Panel (a heavily customized fork of OGP maintained by WDS)
|
||||
*
|
||||
* Server Content Category Map
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* This file is the single source of truth for all Server Content types.
|
||||
* It maps internal addon_type DB values to human-readable display labels.
|
||||
*
|
||||
* BACKWARD COMPATIBILITY:
|
||||
* The three original types (plugin, mappack, config) are preserved exactly
|
||||
* as they exist in the addons table. Do not rename or remove them.
|
||||
*
|
||||
* ADDING NEW TYPES:
|
||||
* 1. Add the key/label pair below.
|
||||
* 2. Ensure the DB column addon_type is VARCHAR(32) (migration db_version 2
|
||||
* in module.php handles this automatically on the next module update).
|
||||
* 3. No other code changes are required for the type to appear in the admin
|
||||
* "Create Server Content Item" form.
|
||||
*
|
||||
* PLANNED INSTALL METHODS (see SERVER_CONTENT_ROADMAP.md for details):
|
||||
* download_zip – download a .zip/.tar.gz and extract into the server path
|
||||
* download_file – download a single file into the server path
|
||||
* post_script – run only a post-install bash script (no download)
|
||||
* steam_workshop – install/update via Steam Workshop item IDs through agent
|
||||
* minecraft_jar – download a Minecraft server jar and update startup config
|
||||
* profile_copy – copy a profile directory tree into the server home
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the full Server Content category map.
|
||||
*
|
||||
* Keys : addon_type values stored in OGP_DB_PREFIXaddons.addon_type
|
||||
* Values : Human-readable display label shown in admin and user UI
|
||||
*
|
||||
* @return array<string,string>
|
||||
*/
|
||||
function get_server_content_categories()
|
||||
{
|
||||
return array(
|
||||
// ── Original types (must remain for backward compatibility) ──────────
|
||||
'plugin' => 'Plugins / Mods',
|
||||
'mappack' => 'Map Packs',
|
||||
'config' => 'Config Packs',
|
||||
|
||||
// ── Extended types (require addon_type VARCHAR(32) – db_version 2) ──
|
||||
'version' => 'Server Versions', // e.g. Minecraft jar switcher
|
||||
'modpack' => 'Modpacks', // e.g. CurseForge / ATLauncher packs
|
||||
'workshop' => 'Workshop Content', // Steam Workshop item bundles
|
||||
'script' => 'Scripted Installer', // Admin-defined install-only scripts
|
||||
'profile' => 'Server Profiles', // Full profile: configs + mods + scripts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns only the original three types that existed before db_version 2.
|
||||
* Use this when you need to restrict to legacy values, e.g. for
|
||||
* installs that have not yet run the VARCHAR(32) migration.
|
||||
*
|
||||
* @return array<string,string>
|
||||
*/
|
||||
function get_legacy_addon_types()
|
||||
{
|
||||
return array(
|
||||
'plugin' => 'Plugins / Mods',
|
||||
'mappack' => 'Map Packs',
|
||||
'config' => 'Config Packs',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ordered list of addon_type keys only (no labels).
|
||||
* Useful as a whitelist for input validation.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function get_server_content_type_keys()
|
||||
{
|
||||
return array_keys(get_server_content_categories());
|
||||
}
|
||||
|
|
@ -1,33 +1,29 @@
|
|||
<?php
|
||||
/*
|
||||
*
|
||||
* OGP - Open Game Panel
|
||||
* Copyright (C) 2008 - 2018 The OGP Development Team
|
||||
* GSP - Game Server Panel (a heavily customized fork of OGP maintained by WDS)
|
||||
*
|
||||
* http://www.opengamepanel.org/
|
||||
* User page: Server Content (module: addonsmanager, page: user_addons)
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* Shows the available Server Content categories for a specific game server
|
||||
* home. Each category that has at least one content item configured for the
|
||||
* server's game type is displayed as a clickable link that takes the user to
|
||||
* the installer (addons_installer.php).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* Group filtering: non-admin users only see content items assigned to one of
|
||||
* their groups, or to the "All groups" (group_id=0 / NULL) bucket.
|
||||
*
|
||||
*/
|
||||
|
||||
// Central category map — load so we can iterate all types dynamically.
|
||||
require_once(dirname(__FILE__) . '/server_content_categories.php');
|
||||
|
||||
function exec_ogp_module() {
|
||||
global $db;
|
||||
$home_id = $_GET['home_id'];
|
||||
$mod_id = $_GET['mod_id'];
|
||||
$ip = $_GET['ip'];
|
||||
$port = $_GET['port'];
|
||||
$mod_id = $_GET['mod_id'];
|
||||
$ip = $_GET['ip'];
|
||||
$port = $_GET['port'];
|
||||
$user_id = $_SESSION['user_id'];
|
||||
// Check if user has some games.
|
||||
$isAdmin = $db->isAdmin( $user_id );
|
||||
|
|
@ -51,43 +47,49 @@ function exec_ogp_module() {
|
|||
$home_cfg_id = $home_info['home_cfg_id'];
|
||||
echo "<h2>".get_lang('user_addons').": ".htmlentities($home_info['home_name'])."</h2>\n".
|
||||
"<table class='center' >\n".
|
||||
"<tr><td>\n";
|
||||
$plugins = $db->resultQuery("SELECT DISTINCT addon_id, name, game_name ".
|
||||
"FROM OGP_DB_PREFIXaddons ".
|
||||
"NATURAL JOIN OGP_DB_PREFIXconfig_homes ".
|
||||
"WHERE addon_type='plugin' ".
|
||||
"AND home_cfg_id=".$home_cfg_id.$query_groups);
|
||||
$plugins_qty = is_array($plugins) ? count((array)$plugins) : 0;
|
||||
if($plugins and $plugins_qty >= 1)
|
||||
echo "<a href='?m=addonsmanager&p=addons&home_id=".$home_id.
|
||||
"&mod_id=".$mod_id."&addon_type=plugin&ip=".$ip.
|
||||
"&port=".$port."'>".get_lang('install_plugin')."(".$plugins_qty.")</a>\n";
|
||||
|
||||
$mappacks = $db->resultQuery("SELECT DISTINCT addon_id, name, game_name ".
|
||||
"FROM OGP_DB_PREFIXaddons ".
|
||||
"NATURAL JOIN OGP_DB_PREFIXconfig_homes ".
|
||||
"WHERE addon_type='mappack' ".
|
||||
"AND home_cfg_id=".$home_cfg_id.$query_groups);
|
||||
$mappacks_qty = is_array($mappacks) ? count((array)$mappacks) : 0;
|
||||
if($mappacks and $mappacks_qty >= 1){
|
||||
echo "</td><td>";
|
||||
echo "<a href='?m=addonsmanager&p=addons&home_id=".$home_id.
|
||||
"&mod_id=".$mod_id."&addon_type=mappack&ip=".$ip.
|
||||
"&port=".$port."'>".get_lang('install_mappack')."(".$mappacks_qty.")</a>\n";
|
||||
"<tr>\n";
|
||||
|
||||
// Iterate all registered content types. Each type that has at least
|
||||
// one item for this game generates a link to the installer page.
|
||||
// New types added to server_content_categories.php automatically
|
||||
// appear here without any further code changes.
|
||||
$categories = get_server_content_categories(); // key => label
|
||||
$printed_any_cell = false;
|
||||
|
||||
foreach ((array)$categories as $type_key => $type_label)
|
||||
{
|
||||
$items = $db->resultQuery(
|
||||
"SELECT DISTINCT addon_id, name, game_name " .
|
||||
"FROM OGP_DB_PREFIXaddons " .
|
||||
"NATURAL JOIN OGP_DB_PREFIXconfig_homes " .
|
||||
"WHERE addon_type='" . $db->realEscapeSingle($type_key) . "' " .
|
||||
"AND home_cfg_id=" . (int)$home_cfg_id . $query_groups
|
||||
);
|
||||
$items_qty = is_array($items) ? count((array)$items) : 0;
|
||||
if ($items && $items_qty >= 1)
|
||||
{
|
||||
if ($printed_any_cell)
|
||||
echo "</td><td>\n";
|
||||
else
|
||||
echo "<td>\n";
|
||||
$printed_any_cell = true;
|
||||
// Display label comes from the category map; the internal
|
||||
// addon_type key is passed in the URL for backward compatibility.
|
||||
echo "<a href='?m=addonsmanager&p=addons" .
|
||||
"&home_id=" . (int)$home_id .
|
||||
"&mod_id=" . (int)$mod_id .
|
||||
"&addon_type=" . urlencode($type_key) .
|
||||
"&ip=" . htmlspecialchars($ip) .
|
||||
"&port=" . htmlspecialchars($port) . "'>" .
|
||||
htmlspecialchars($type_label) . " (" . $items_qty . ")" .
|
||||
"</a>\n";
|
||||
}
|
||||
}
|
||||
$configs = $db->resultQuery("SELECT DISTINCT addon_id, name, game_name ".
|
||||
"FROM OGP_DB_PREFIXaddons ".
|
||||
"NATURAL JOIN OGP_DB_PREFIXconfig_homes ".
|
||||
"WHERE addon_type='config' ".
|
||||
"AND home_cfg_id=".$home_cfg_id.$query_groups);
|
||||
$configs_qty = is_array($configs) ? count((array)$configs) : 0;
|
||||
if($configs and $configs_qty >= 1){
|
||||
echo "</td><td>";
|
||||
echo "<a href='?m=addonsmanager&p=addons&home_id=".$home_id.
|
||||
"&mod_id=".$mod_id."&addon_type=config&ip=".$ip.
|
||||
"&port=".$port."'>".get_lang('install_config')."(".$configs_qty.")</a>\n";
|
||||
}
|
||||
echo "</td></tr>\n".
|
||||
|
||||
if ($printed_any_cell)
|
||||
echo "</td>\n";
|
||||
|
||||
echo "</tr>\n".
|
||||
"</table>\n".
|
||||
"<form action='?m=gamemanager&p=game_monitor&home_id-mod_id-ip-port=$home_id-$mod_id-$ip-$port' method='POST'>\n".
|
||||
"<input type='submit' value='".get_lang('back')."' />\n".
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue