From 6dd50886130398d95a5ed45e913e1ff8955eb20a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 16:47:47 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20redesign=20SCM=20workshop=20handling=20?= =?UTF-8?q?=E2=80=93=20remove=20workshop=5Fitem=5Fid=20requirement,=20add?= =?UTF-8?q?=20user=20ID=20entry,=20deprecate=20steam=5Fworkshop=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - server_content_helpers.php: remove workshop_item_id from required fields/validation; support newline-separated IDs; add scm_validate_workshop_user_ids(); update help text; add new template policy columns to ensure_phase2_schema; add content_id guard to ensure_workshop_schema - addons_manager.php: rename admin workshop_item_id row to "Default Workshop IDs (Optional)" with updated label - user_addons.php: route workshop_item type to workshop_content page instead of addons installer - workshop_content.php: accept addon_id param; show template info; use textarea for multi-ID entry; update heading/help text - workshop_action.php: accept addon_id param; resolve workshop_app_id from addon template; pass extra_manifest to manifest-and-run; store content_id on insert; use newline/comma-separated IDs - addons_installer.php: redirect workshop_item addon_type to workshop_content page - module.php: db_version 6 with allow_user_workshop_ids, max_workshop_ids, required_workshop_ids, blocked_workshop_ids on addons; content_id on server_content_workshop - server_content_categories.php: rename "Steam Workshop Item" → "Steam Workshop Mods" - steam_workshop/module.php: empty $module_menus, mark deprecated, bump version to 3.3 - addonsmanager.js: remove #scm-row-workshop-id from steam_workshop admin rows Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/6a328ac8-2f82-4943-93a9-7660bf42a2fd Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com> --- Panel/js/modules/addonsmanager.js | 2 +- .../addonsmanager/addons_installer.php | 21 ++++++ .../modules/addonsmanager/addons_manager.php | 6 +- Panel/modules/addonsmanager/module.php | 68 ++++++++++++++++- .../server_content_categories.php | 2 +- .../addonsmanager/server_content_helpers.php | 73 +++++++++++++++---- Panel/modules/addonsmanager/user_addons.php | 32 +++++--- .../modules/addonsmanager/workshop_action.php | 65 +++++++++++++---- .../addonsmanager/workshop_content.php | 42 +++++++++-- Panel/modules/steam_workshop/module.php | 11 ++- 10 files changed, 263 insertions(+), 59 deletions(-) diff --git a/Panel/js/modules/addonsmanager.js b/Panel/js/modules/addonsmanager.js index b8ccc7ab..ab52e9df 100644 --- a/Panel/js/modules/addonsmanager.js +++ b/Panel/js/modules/addonsmanager.js @@ -9,7 +9,7 @@ $(function() { var methodToRows = { download_zip: ['#scm-row-url', '#scm-row-path'], - steam_workshop: ['#scm-row-workshop-id', '#scm-row-workshop-app-id', '#scm-row-target-path-template', '#scm-row-optional-folder-name', '#scm-row-post-script', '#scm-row-launch-param-additions'], + steam_workshop: ['#scm-row-workshop-app-id', '#scm-row-target-path-template', '#scm-row-optional-folder-name', '#scm-row-post-script', '#scm-row-launch-param-additions'], post_script: ['#scm-row-post-script'], config_edit: ['#scm-row-path', '#scm-row-config-edit-rule'] }; diff --git a/Panel/modules/addonsmanager/addons_installer.php b/Panel/modules/addonsmanager/addons_installer.php index f22fbe01..8dd78e70 100644 --- a/Panel/modules/addonsmanager/addons_installer.php +++ b/Panel/modules/addonsmanager/addons_installer.php @@ -544,6 +544,27 @@ function exec_ogp_module() { return; } + + // Workshop items are managed through the dedicated workshop_content page + // where users enter their own Workshop IDs. Redirect there immediately. + if ($addon_type === 'workshop_item') { + $first_addon_id = 0; + $wk_addons = $db->resultQuery( + "SELECT addon_id FROM OGP_DB_PREFIXaddons + WHERE addon_type='workshop_item' AND home_cfg_id=" . (int)$home_cfg_id . $query_groups . " + ORDER BY name ASC LIMIT 1" + ); + if (is_array($wk_addons) && !empty($wk_addons[0]['addon_id'])) { + $first_addon_id = (int)$wk_addons[0]['addon_id']; + } + $redirect = "?m=addonsmanager&p=workshop_content&home_id=" . (int)$home_id . + "&mod_id=" . (int)$mod_id . "&ip=" . urlencode($ip) . "&port=" . urlencode($port) . + ($first_addon_id > 0 ? "&addon_id=" . $first_addon_id : ''); + $view->refresh($redirect); + echo "

Redirecting to Workshop Content manager…
"; + echo "Click here if not redirected.

"; + return; + } ?> - + Default Workshop IDs (Optional) - - Example Arma 3 Workshop ID: 450814997 + + Optional. Users enter the actual Workshop IDs they want installed from their own server page. This field is not required. diff --git a/Panel/modules/addonsmanager/module.php b/Panel/modules/addonsmanager/module.php index 2118d570..eac60521 100644 --- a/Panel/modules/addonsmanager/module.php +++ b/Panel/modules/addonsmanager/module.php @@ -18,13 +18,20 @@ * backup_before_install / restart_after_install / is_cacheable / * description columns to addons table; add server_content_manifest * and server_content_install_history tables + * 5 – add workshop_item_id / workshop_app_id / target_path_template / + * optional_folder_name / config_edit_rule / launch_param_additions + * columns to addons table + * 6 – add admin template policy columns to addons table + * (allow_user_workshop_ids, max_workshop_ids, required_workshop_ids, + * blocked_workshop_ids); add content_id column to + * server_content_workshop so user installs link to their template * */ // Module general information $module_title = "Server Content Manager"; -$module_version = "2.3"; -$db_version = 5; +$module_version = "2.4"; +$db_version = 6; $module_required = TRUE; $module_menus = array( array( 'subpage' => 'addons_manager', 'name' => 'Server Content Manager', 'group' => 'admin' ) @@ -196,4 +203,61 @@ $install_queries[4] = array( return true; }, ); +// ── db_version 6 : admin template policy columns + content_id on workshop rows ── +// +// allow_user_workshop_ids – whether users may enter their own IDs (default 1) +// max_workshop_ids – optional cap on how many IDs a user may install +// required_workshop_ids – JSON list of IDs that must always be installed +// blocked_workshop_ids – JSON list of IDs that must not be installed +// content_id on server_content_workshop – links a user install row back to +// the admin content template so the correct workshop_app_id is used. +// +$install_queries[5] = array( + function ($db) { + $prefix = OGP_DB_PREFIX; + + // ── New policy columns on the addons (content template) table ───────── + $addon_columns = array( + 'allow_user_workshop_ids' => "TINYINT(1) NOT NULL DEFAULT 1 AFTER `blocked_workshop_ids`", + 'max_workshop_ids' => "INT NULL AFTER `allow_user_workshop_ids`", + 'required_workshop_ids' => "TEXT NULL AFTER `max_workshop_ids`", + 'blocked_workshop_ids' => "TEXT NULL AFTER `launch_param_additions`", + ); + foreach ($addon_columns as $col => $definition) { + $escaped_col = $db->realEscapeSingle($col); + $escaped_table = $db->realEscapeSingle($prefix . 'addons'); + $check = $db->resultQuery( + "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '{$escaped_table}' + AND COLUMN_NAME = '{$escaped_col}'" + ); + if (empty($check)) { + if (!$db->query("ALTER TABLE `{$prefix}addons` ADD COLUMN `{$col}` {$definition}")) { + return false; + } + } + } + + // ── content_id on server_content_workshop ───────────────────────────── + $wk_table = $db->realEscapeSingle($prefix . 'server_content_workshop'); + $col_check = $db->resultQuery( + "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '{$wk_table}' + AND COLUMN_NAME = 'content_id'" + ); + if (empty($col_check)) { + if (!$db->query( + "ALTER TABLE `{$prefix}server_content_workshop` + ADD COLUMN `content_id` INT NULL AFTER `id`, + ADD KEY `idx_content_id` (`content_id`)" + )) { + return false; + } + } + + return true; + }, +); ?> diff --git a/Panel/modules/addonsmanager/server_content_categories.php b/Panel/modules/addonsmanager/server_content_categories.php index aee6dff8..6f6e3988 100644 --- a/Panel/modules/addonsmanager/server_content_categories.php +++ b/Panel/modules/addonsmanager/server_content_categories.php @@ -41,7 +41,7 @@ function get_server_content_categories() { return array( 'file_download' => 'Downloadable Mod', - 'workshop_item' => 'Steam Workshop Item', + 'workshop_item' => 'Steam Workshop Mods', 'config_edit' => 'Configuration Package', 'scripted_installer' => 'Scripted Installer', ); diff --git a/Panel/modules/addonsmanager/server_content_helpers.php b/Panel/modules/addonsmanager/server_content_helpers.php index 9d4fc234..7b6cb46b 100644 --- a/Panel/modules/addonsmanager/server_content_helpers.php +++ b/Panel/modules/addonsmanager/server_content_helpers.php @@ -21,7 +21,7 @@ function scm_ensure_workshop_schema($db) $schema_checked = true; $db->query("ALTER TABLE `".OGP_DB_PREFIX."addons` MODIFY `addon_type` VARCHAR(32) NOT NULL"); - return (bool)$db->query( + $ok = (bool)$db->query( "CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."server_content_workshop` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, `home_id` INT NOT NULL, @@ -43,6 +43,24 @@ function scm_ensure_workshop_schema($db) KEY `idx_install_state` (`install_state`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" ); + + // Idempotently add content_id column (db_version 6). + $wk_table = $db->realEscapeSingle(OGP_DB_PREFIX . 'server_content_workshop'); + $col_check = $db->resultQuery( + "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '{$wk_table}' + AND COLUMN_NAME = 'content_id'" + ); + if (empty($col_check)) { + $db->query( + "ALTER TABLE `".OGP_DB_PREFIX."server_content_workshop` + ADD COLUMN `content_id` INT NULL AFTER `id`, + ADD KEY `idx_content_id` (`content_id`)" + ); + } + + return $ok; } function scm_get_home_for_user($db, $home_id, $user_id) @@ -89,7 +107,9 @@ function scm_parse_workshop_ids($raw, &$invalid = array()) { $invalid = array(); $ids = array(); - $parts = explode(',', (string)$raw); + // Accept IDs separated by commas, newlines, or a mix of both. + $normalized = str_replace(array("\r\n", "\r", "\n"), ',', (string)$raw); + $parts = explode(',', $normalized); foreach ((array)$parts as $part) { $value = trim((string)$part); if ($value === '') { @@ -323,7 +343,7 @@ function scm_get_install_methods() { return array( 'download_zip' => 'Downloadable Mod', - 'steam_workshop' => 'Steam Workshop Item', + 'steam_workshop' => 'Steam Workshop Mods', 'config_edit' => 'Configuration Package', 'post_script' => 'Scripted Installer', ); @@ -333,7 +353,7 @@ function scm_get_install_method_help_text() { return array( 'download_zip' => 'Download and extract a ZIP, RAR, or archive file.', - 'steam_workshop' => 'Install a Steam Workshop mod using Workshop ID.', + 'steam_workshop' => 'Configure how users may install Steam Workshop items for this game. Users enter the actual Workshop IDs from their server page.', 'config_edit' => 'Install configuration files, profiles, or templates.', 'post_script' => 'Run a custom scripted installation process.', ); @@ -342,20 +362,20 @@ function scm_get_install_method_help_text() function scm_get_install_method_required_fields() { return array( - 'download_zip' => array('url'), - 'steam_workshop' => array('workshop_item_id'), - 'post_script' => array('post_script'), - 'config_edit' => array('path', 'config_edit_rule'), + 'download_zip' => array('url'), + 'steam_workshop' => array(), // No required fields; users provide Workshop IDs on their server page + 'post_script' => array('post_script'), + 'config_edit' => array('path', 'config_edit_rule'), ); } function scm_get_install_method_validation_errors() { return array( - 'download_zip' => 'Please enter a download URL.', - 'steam_workshop' => 'Please enter a Workshop ID.', - 'config_edit' => 'Please enter the config target and edit action.', - 'post_script' => 'Please enter the installer script/action.', + 'download_zip' => 'Please enter a download URL.', + 'steam_workshop' => 'Please configure Workshop App ID or ensure the game XML provides one.', + 'config_edit' => 'Please enter the config target and edit action.', + 'post_script' => 'Please enter the installer script/action.', ); } @@ -433,9 +453,8 @@ function scm_validate_download_content(array $payload, &$message = '') function scm_validate_workshop_content(array $payload, &$message = '') { - if (!scm_validate_numeric_content_value(isset($payload['workshop_item_id']) ? $payload['workshop_item_id'] : '', 'Please enter a Workshop ID.', $message, false)) { - return false; - } + // workshop_item_id is NOT required for admin content templates. + // Users supply Workshop IDs on their server page (workshop_content.php). if (!scm_validate_numeric_content_value(isset($payload['workshop_app_id']) ? $payload['workshop_app_id'] : '', 'Workshop App ID must be numeric.', $message, true)) { return false; } @@ -448,6 +467,22 @@ function scm_validate_workshop_content(array $payload, &$message = '') return true; } +function scm_validate_workshop_user_ids($raw_ids, &$message = '') +{ + $invalid = array(); + $ids = scm_parse_workshop_ids($raw_ids, $invalid); + if (!empty($invalid)) { + $message = 'Invalid Workshop IDs: ' . implode(', ', $invalid); + return false; + } + if (empty($ids)) { + $message = 'Enter at least one numeric Workshop ID.'; + return false; + } + $message = ''; + return true; +} + function scm_validate_scripted_installer(array $payload, &$message = '') { $script = isset($payload['post_script']) ? trim((string)$payload['post_script']) : ''; @@ -497,11 +532,13 @@ function scm_validate_install_method_payload($install_method, array $payload, &$ function scm_build_workshop_runtime_context($db, array $home_info, $server_xml, array $payload, &$message = '') { + // workshop_item_id is now optional in admin templates; validate only the + // numeric format constraints (workshop_app_id, optional_folder_name). if (!scm_validate_workshop_content($payload, $message)) { return false; } - $workshop_item_id = trim((string)$payload['workshop_item_id']); + $workshop_item_id = trim((string)(isset($payload['workshop_item_id']) ? $payload['workshop_item_id'] : '')); $target_path_template = trim((string)$payload['target_path_template']); $optional_folder_name = trim((string)$payload['optional_folder_name']); $workshop_app_id_override = trim((string)$payload['workshop_app_id']); @@ -662,6 +699,10 @@ function scm_ensure_phase2_schema($db) 'optional_folder_name' => "VARCHAR(255) NULL", 'config_edit_rule' => "TEXT NULL", 'launch_param_additions'=> "VARCHAR(255) NULL", + 'allow_user_workshop_ids' => "TINYINT(1) NOT NULL DEFAULT 1", + 'max_workshop_ids' => "INT NULL", + 'required_workshop_ids' => "TEXT NULL", + 'blocked_workshop_ids' => "TEXT NULL", ); foreach ($new_columns as $col => $definition) { $escaped_col = $db->realEscapeSingle($col); diff --git a/Panel/modules/addonsmanager/user_addons.php b/Panel/modules/addonsmanager/user_addons.php index 6eb36a47..9217f8da 100644 --- a/Panel/modules/addonsmanager/user_addons.php +++ b/Panel/modules/addonsmanager/user_addons.php @@ -75,16 +75,28 @@ function exec_ogp_module() { else echo "\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 "" . - htmlspecialchars($type_label) . " (" . $items_qty . ")" . - "\n"; + // Workshop items route to the workshop_content page where users + // enter their own Workshop IDs. All other types use the installer. + if ($type_key === 'workshop_item') { + $first_addon_id = isset($items[0]['addon_id']) ? (int)$items[0]['addon_id'] : 0; + echo "" . + htmlspecialchars($type_label) . " (" . $items_qty . ")" . + "\n"; + } else { + echo "" . + htmlspecialchars($type_label) . " (" . $items_qty . ")" . + "\n"; + } } } diff --git a/Panel/modules/addonsmanager/workshop_action.php b/Panel/modules/addonsmanager/workshop_action.php index c0b94b7e..f4d735ef 100644 --- a/Panel/modules/addonsmanager/workshop_action.php +++ b/Panel/modules/addonsmanager/workshop_action.php @@ -141,7 +141,7 @@ function scm_workshop_write_manifest_and_run($db, array $home_info, $server_xml, return true; } -function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $raw_ids, array $selected_ids, &$message, &$is_error) +function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $raw_ids, array $selected_ids, &$message, &$is_error, $addon_id = 0) { $message = ''; $is_error = true; @@ -150,14 +150,32 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r return false; } - $home_id = (int)$home_info['home_id']; - $user_id = (int)$user_id; + $home_id = (int)$home_info['home_id']; + $user_id = (int)$user_id; + $addon_id = (int)$addon_id; $server_xml = read_server_config(SERVER_CONFIG_LOCATION . "/" . $home_info['home_cfg_file']); if ($server_xml === false) { $message = 'Unable to read server configuration for workshop action.'; return false; } + // Resolve the workshop_app_id: prefer the admin content template, fall + // back to the game XML. + $template_workshop_app_id = ''; + if ($addon_id > 0) { + $tpl = $db->resultQuery( + "SELECT workshop_app_id FROM `" . OGP_DB_PREFIX . "addons` + WHERE addon_id=" . $addon_id . " AND install_method='steam_workshop'" + ); + if (is_array($tpl) && !empty($tpl[0]['workshop_app_id'])) { + $template_workshop_app_id = trim((string)$tpl[0]['workshop_app_id']); + } + } + $extra_manifest = array(); + if ($template_workshop_app_id !== '') { + $extra_manifest['workshop_app_id'] = $template_workshop_app_id; + } + if ($action === 'install_new') { $invalid = array(); $item_ids = scm_parse_workshop_ids($raw_ids, $invalid); @@ -170,19 +188,36 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r return false; } + // Determine the resolved workshop_app_id for storage (template first, then XML). + $resolved_app_id = $template_workshop_app_id !== '' + ? $template_workshop_app_id + : scm_extract_workshop_app_id($server_xml); + + // Check whether the content_id column exists (added in db_version 6). + $has_content_id_col = (bool)$db->resultQuery( + "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '" . $db->realEscapeSingle(OGP_DB_PREFIX . 'server_content_workshop') . "' + AND COLUMN_NAME = 'content_id'" + ); + foreach ($item_ids as $item_id) { + $content_id_col = $has_content_id_col && $addon_id > 0 ? ", content_id" : ''; + $content_id_val = $has_content_id_col && $addon_id > 0 ? ", " . $addon_id : ''; + $content_id_upd = $has_content_id_col && $addon_id > 0 ? ", content_id=VALUES(content_id)" : ''; $query = "INSERT INTO `".OGP_DB_PREFIX."server_content_workshop` - (home_id, home_cfg_id, remote_server_id, workshop_app_id, workshop_item_id, install_state, created_by, created_at, updated_at) + (home_id, home_cfg_id, remote_server_id, workshop_app_id, workshop_item_id, install_state, created_by, created_at, updated_at" . $content_id_col . ") VALUES ( ".$home_id.", ".(int)$home_info['home_cfg_id'].", ".(int)$home_info['remote_server_id'].", - '".$db->realEscapeSingle(scm_extract_workshop_app_id($server_xml))."', + '".$db->realEscapeSingle($resolved_app_id)."', '".$db->realEscapeSingle($item_id)."', 'selected', ".$user_id.", NOW(), NOW() + " . $content_id_val . " ) ON DUPLICATE KEY UPDATE home_cfg_id=VALUES(home_cfg_id), @@ -190,22 +225,22 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r workshop_app_id=VALUES(workshop_app_id), install_state='selected', last_error=NULL, - updated_at=NOW()"; + updated_at=NOW()" . $content_id_upd; $db->query($query); } scm_workshop_update_rows_state($db, $home_id, $item_ids, 'installing', null, false, false); $error = ''; - $ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, 'install', $item_ids, $error); + $ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, 'install', $item_ids, $error, $extra_manifest); if ($ok) { scm_workshop_update_rows_state($db, $home_id, $item_ids, 'installed', null, true, true); - scm_workshop_log_action($db, $home_id, $user_id, "install_new ids=".implode(',', $item_ids)." status=success"); + scm_workshop_log_action($db, $home_id, $user_id, "install_new ids=".implode(',', $item_ids)." addon_id=".$addon_id." status=success"); $is_error = false; $message = 'Workshop IDs installed successfully.'; return true; } scm_workshop_update_rows_state($db, $home_id, $item_ids, 'failed', $error, false, false); - scm_workshop_log_action($db, $home_id, $user_id, "install_new ids=".implode(',', $item_ids)." status=failed error=".$error); + scm_workshop_log_action($db, $home_id, $user_id, "install_new ids=".implode(',', $item_ids)." addon_id=".$addon_id." status=failed error=".$error); $message = $error; return false; } @@ -219,20 +254,20 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r $target_action = ($action === 'remove_selected') ? 'remove' : 'update'; scm_workshop_update_rows_state($db, $home_id, $item_ids, 'installing', null, false, false); $error = ''; - $ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, $target_action, $item_ids, $error); + $ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, $target_action, $item_ids, $error, $extra_manifest); if ($ok) { if ($target_action === 'remove') { scm_workshop_update_rows_state($db, $home_id, $item_ids, 'removed', null, false, true); } else { scm_workshop_update_rows_state($db, $home_id, $item_ids, 'installed', null, false, true); } - scm_workshop_log_action($db, $home_id, $user_id, $action." ids=".implode(',', $item_ids)." status=success"); + scm_workshop_log_action($db, $home_id, $user_id, $action." ids=".implode(',', $item_ids)." addon_id=".$addon_id." status=success"); $is_error = false; $message = ($target_action === 'remove') ? 'Selected Workshop IDs marked removed.' : 'Selected Workshop IDs updated successfully.'; return true; } scm_workshop_update_rows_state($db, $home_id, $item_ids, 'failed', $error, false, false); - scm_workshop_log_action($db, $home_id, $user_id, $action." ids=".implode(',', $item_ids)." status=failed error=".$error); + scm_workshop_log_action($db, $home_id, $user_id, $action." ids=".implode(',', $item_ids)." addon_id=".$addon_id." status=failed error=".$error); $message = $error; return false; } @@ -255,16 +290,16 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r } scm_workshop_update_rows_state($db, $home_id, $item_ids, 'installing', null, false, false); $error = ''; - $ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, 'update', $item_ids, $error); + $ok = scm_workshop_write_manifest_and_run($db, $home_info, $server_xml, 'update', $item_ids, $error, $extra_manifest); if ($ok) { scm_workshop_update_rows_state($db, $home_id, $item_ids, 'installed', null, false, true); - scm_workshop_log_action($db, $home_id, $user_id, "update_all ids=".implode(',', $item_ids)." status=success"); + scm_workshop_log_action($db, $home_id, $user_id, "update_all ids=".implode(',', $item_ids)." addon_id=".$addon_id." status=success"); $is_error = false; $message = 'All saved Workshop IDs updated successfully.'; return true; } scm_workshop_update_rows_state($db, $home_id, $item_ids, 'failed', $error, false, false); - scm_workshop_log_action($db, $home_id, $user_id, "update_all ids=".implode(',', $item_ids)." status=failed error=".$error); + scm_workshop_log_action($db, $home_id, $user_id, "update_all ids=".implode(',', $item_ids)." addon_id=".$addon_id." status=failed error=".$error); $message = $error; return false; } diff --git a/Panel/modules/addonsmanager/workshop_content.php b/Panel/modules/addonsmanager/workshop_content.php index b5f915a3..17aeb9d7 100644 --- a/Panel/modules/addonsmanager/workshop_content.php +++ b/Panel/modules/addonsmanager/workshop_content.php @@ -1,7 +1,10 @@ 0) { + $template_rows = $db->resultQuery( + "SELECT addon_id, name, workshop_app_id, target_path_template, optional_folder_name, description + FROM `" . OGP_DB_PREFIX . "addons` + WHERE addon_id=" . $addon_id . " AND install_method='steam_workshop'" + ); + if (is_array($template_rows) && !empty($template_rows)) { + $addon_template = $template_rows[0]; + } + } + $message = ''; $is_error = false; $entered_ids = ''; @@ -45,6 +62,7 @@ function exec_ogp_module() { $entered_ids = isset($_POST['workshop_ids']) ? (string)$_POST['workshop_ids'] : ''; $selected_ids = isset($_POST['selected_ids']) ? $_POST['selected_ids'] : array(); $action = isset($_POST['workshop_action']) ? (string)$_POST['workshop_action'] : ''; + $posted_addon_id = isset($_POST['addon_id']) ? (int)$_POST['addon_id'] : 0; if ($posted_home_id !== $home_id) { $is_error = true; @@ -55,14 +73,22 @@ function exec_ogp_module() { $message = 'Invalid CSRF token for workshop action.'; } else { - scm_workshop_handle_action($db, $home_info, $user_id, $action, $entered_ids, (array)$selected_ids, $message, $is_error); + scm_workshop_handle_action($db, $home_info, $user_id, $action, $entered_ids, (array)$selected_ids, $message, $is_error, $posted_addon_id > 0 ? $posted_addon_id : $addon_id); } } $rows = scm_get_workshop_rows($db, $home_id); $csrf_token = scm_get_csrf_token(); - echo "

Workshop Content: ".scm_h($home_info['home_name'])."

"; + echo "

Workshop Mods: " . scm_h($home_info['home_name']) . "

"; + if ($addon_template !== null) { + echo "

Content template: " . scm_h($addon_template['name']) . ""; + if (!empty($addon_template['description'])) { + echo " – " . scm_h($addon_template['description']); + } + echo "

"; + } + if ($message !== '') { if ($is_error) { print_failure($message); @@ -83,16 +109,18 @@ function exec_ogp_module() { + - + -
Enter Workshop IDsWorkshop Item IDs - + +
Enter one or more Steam Workshop IDs, one per line or comma-separated.
Example for Arma 3 CBA_A3: 450814997
- + +
diff --git a/Panel/modules/steam_workshop/module.php b/Panel/modules/steam_workshop/module.php index 7698d2f8..495a0249 100644 --- a/Panel/modules/steam_workshop/module.php +++ b/Panel/modules/steam_workshop/module.php @@ -10,12 +10,15 @@ */ $module_title = "Steam Workshop"; -$module_version = "3.2"; +$module_version = "3.3"; $db_version = 5; $module_required = FALSE; -$module_menus = array( - array('subpage' => 'admin', 'name' => 'Steam Workshop', 'group' => 'admin'), -); +// DEPRECATED: The Steam Workshop standalone module has been superseded by +// Server Content Manager (addonsmanager). Navigation access is removed so +// users are directed to the new unified workshop workflow. The DB tables +// and helper functions are preserved for backward compatibility. +// See Panel/modules/addonsmanager/ for the replacement implementation. +$module_menus = array(); if (!function_exists('sw_module_db_prefix')) { function sw_module_db_prefix()