Merge pull request #166 from GameServerPanel/copilot/redesign-server-content-manager-workshop-handling

This commit is contained in:
Frank Harris 2026-05-20 11:50:41 -05:00 committed by GitHub
commit 15a457cbef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 263 additions and 59 deletions

View file

@ -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']
};

View file

@ -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 "<p>Redirecting to Workshop Content manager…<br>";
echo "<a href='" . htmlspecialchars($redirect, ENT_QUOTES, 'UTF-8') . "'>Click here if not redirected.</a></p>";
return;
}
?>
<?php
$category_labels = get_server_content_categories();

View file

@ -198,11 +198,11 @@ function exec_ogp_module() {
</tr>
<tr id="scm-row-workshop-id">
<td align="right">
<b><?php print_lang('workshop_id'); ?></b>
<b>Default Workshop IDs (Optional)</b>
</td>
<td align="left">
<input type="text" value="<?php echo htmlspecialchars($workshop_item_id, ENT_QUOTES, 'UTF-8'); ?>" name="workshop_item_id" size="85" placeholder="e.g. 450814997" />
<small style="color:#666;">Example Arma 3 Workshop ID: 450814997</small>
<input type="text" value="<?php echo htmlspecialchars($workshop_item_id, ENT_QUOTES, 'UTF-8'); ?>" name="workshop_item_id" size="85" placeholder="Leave blank users enter Workshop IDs on their server page" />
<small style="color:#666;">Optional. Users enter the actual Workshop IDs they want installed from their own server page. This field is not required.</small>
</td>
</tr>
<tr id="scm-row-workshop-app-id">

View file

@ -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;
},
);
?>

View file

@ -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',
);

View file

@ -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.',
);
@ -343,7 +363,7 @@ function scm_get_install_method_required_fields()
{
return array(
'download_zip' => array('url'),
'steam_workshop' => array('workshop_item_id'),
'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'),
);
@ -353,7 +373,7 @@ function scm_get_install_method_validation_errors()
{
return array(
'download_zip' => 'Please enter a download URL.',
'steam_workshop' => 'Please enter a Workshop ID.',
'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);

View file

@ -75,8 +75,19 @@ function exec_ogp_module() {
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.
// 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 "<a href='?m=addonsmanager&amp;p=workshop_content" .
"&amp;home_id=" . (int)$home_id .
"&amp;mod_id=" . (int)$mod_id .
($first_addon_id > 0 ? "&amp;addon_id=" . $first_addon_id : '') .
"&amp;ip=" . htmlspecialchars($ip) .
"&amp;port=" . htmlspecialchars($port) . "'>" .
htmlspecialchars($type_label) . " (" . $items_qty . ")" .
"</a>\n";
} else {
echo "<a href='?m=addonsmanager&amp;p=addons" .
"&amp;home_id=" . (int)$home_id .
"&amp;mod_id=" . (int)$mod_id .
@ -87,6 +98,7 @@ function exec_ogp_module() {
"</a>\n";
}
}
}
if ($printed_any_cell)
echo "</td>\n";

View file

@ -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;
@ -152,12 +152,30 @@ function scm_workshop_handle_action($db, array $home_info, $user_id, $action, $r
$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;
}

View file

@ -1,7 +1,10 @@
<?php
/*
*
* GSP - Server Content Workshop page (Phase 1)
* GSP - Server Content Workshop page
*
* Users enter Steam Workshop IDs to install on their server.
* The admin defines the content template (game, app ID, install path).
*
*/
@ -16,6 +19,7 @@ function exec_ogp_module() {
$mod_id = isset($_REQUEST['mod_id']) ? (int)$_REQUEST['mod_id'] : 0;
$ip = isset($_REQUEST['ip']) ? (string)$_REQUEST['ip'] : '';
$port = isset($_REQUEST['port']) ? (string)$_REQUEST['port'] : '';
$addon_id = isset($_REQUEST['addon_id']) ? (int)$_REQUEST['addon_id'] : 0;
if ($home_id <= 0 || $user_id <= 0) {
print_failure(get_lang('no_rights'));
@ -35,6 +39,19 @@ function exec_ogp_module() {
return;
}
// Load the admin content template if an addon_id was provided.
$addon_template = null;
if ($addon_id > 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 "<h2>Workshop Content: ".scm_h($home_info['home_name'])."</h2>";
echo "<h2>Workshop Mods: " . scm_h($home_info['home_name']) . "</h2>";
if ($addon_template !== null) {
echo "<p class='info'>Content template: <strong>" . scm_h($addon_template['name']) . "</strong>";
if (!empty($addon_template['description'])) {
echo " " . scm_h($addon_template['description']);
}
echo "</p>";
}
if ($message !== '') {
if ($is_error) {
print_failure($message);
@ -83,16 +109,18 @@ function exec_ogp_module() {
<input type='hidden' name='mod_id' value='<?php echo (int)$mod_id; ?>' />
<input type='hidden' name='ip' value='<?php echo scm_h($ip); ?>' />
<input type='hidden' name='port' value='<?php echo scm_h($port); ?>' />
<input type='hidden' name='addon_id' value='<?php echo (int)$addon_id; ?>' />
<input type='hidden' name='workshop_csrf' value='<?php echo scm_h($csrf_token); ?>' />
<table class='center'>
<tr>
<td align='right'><strong>Enter Workshop IDs</strong></td>
<td align='right'><strong>Workshop Item IDs</strong></td>
<td align='left'>
<input type='text' name='workshop_ids' size='72' value='<?php echo scm_h($entered_ids); ?>' placeholder='1234567890, 9876543210, 555555555' />
<textarea name='workshop_ids' rows='4' cols='72' placeholder='450814997&#10;463939057&#10;...'><?php echo scm_h($entered_ids); ?></textarea>
<br><small style="color:#666;">Enter one or more Steam Workshop IDs, one per line or comma-separated.<br>Example for Arma 3 CBA_A3: <code>450814997</code></small>
</td>
<td align='left'>
<button type='submit' name='workshop_action' value='install_new'>Install New</button>
<td align='left' style='vertical-align:top;padding-top:4px;'>
<button type='submit' name='workshop_action' value='install_new'>Install / Queue</button>
</td>
</tr>
</table>

View file

@ -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()