mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-12 23:09:33 +01:00
object_store_users: fix specific bucket admin permission (#9014)
Fix an issue where seleting Sepecific Buckets with Admin permission while creating/editing an object store user would grant Admin permission on all buckets
This commit is contained in:
1 parent
c390448906
commit
41ff105f47
2 files changed
+72
-69
No files matched your search
@@ -16,8 +16,8 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
<p class="mb-0 text-muted">Manage S3 API users and their access credentials</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
<button type="button" class="btn btn-primary"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#createUserModal">
|
||||
<i class="fas fa-plus me-1"></i>Create User
|
||||
</button>
|
||||
@@ -269,7 +269,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Bucket Scope</label>
|
||||
<small class="form-text text-muted d-block mb-2">Apply selected permissions to specific buckets or all buckets</small>
|
||||
|
||||
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="bucketScope" id="allBuckets" value="all" checked onchange="toggleBucketList()">
|
||||
<label class="form-check-label" for="allBuckets">
|
||||
@@ -282,7 +282,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
Specific Buckets
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="bucketSelectionList" class="mt-2" style="display: none;">
|
||||
<select multiple class="form-select" id="selectedBuckets" size="5">
|
||||
<!-- Options loaded dynamically -->
|
||||
@@ -376,7 +376,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Bucket Scope</label>
|
||||
<small class="form-text text-muted d-block mb-2">Apply selected permissions to specific buckets or all buckets</small>
|
||||
|
||||
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="editBucketScope" id="editAllBuckets" value="all" checked onchange="toggleBucketList('edit')">
|
||||
<label class="form-check-label" for="editAllBuckets">
|
||||
@@ -389,7 +389,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
Specific Buckets
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="editBucketSelectionList" class="mt-2" style="display: none;">
|
||||
<select multiple class="form-select" id="editSelectedBuckets" size="5">
|
||||
<!-- Options loaded dynamically -->
|
||||
@@ -505,15 +505,15 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const STATUS_INACTIVE = 'Inactive';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
|
||||
// Event delegation for user action buttons
|
||||
document.addEventListener('click', function(e) {
|
||||
const button = e.target.closest('[data-action]');
|
||||
if (!button) return;
|
||||
|
||||
|
||||
const action = button.getAttribute('data-action');
|
||||
const username = button.getAttribute('data-username');
|
||||
|
||||
|
||||
switch (action) {
|
||||
case 'show-user-details':
|
||||
showUserDetails(username);
|
||||
@@ -553,7 +553,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
|
||||
// Load policies for dropdowns
|
||||
loadPolicies();
|
||||
|
||||
|
||||
// Load buckets for bucket permissions
|
||||
loadBuckets();
|
||||
});
|
||||
@@ -627,20 +627,20 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const policies = data.policies || [];
|
||||
|
||||
|
||||
const createSelect = document.getElementById('policies');
|
||||
const editSelect = document.getElementById('editPolicies');
|
||||
|
||||
|
||||
// Check if elements exist
|
||||
if (!createSelect || !editSelect) {
|
||||
console.warn('Policy select elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Clear existing options
|
||||
createSelect.innerHTML = '';
|
||||
editSelect.innerHTML = '';
|
||||
|
||||
|
||||
if (policies && policies.length > 0) {
|
||||
policies.forEach(policy => {
|
||||
const option = document.createElement('option');
|
||||
@@ -671,7 +671,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
mode = mode || 'create';
|
||||
const adminCheckbox = document.getElementById(mode === 'edit' ? 'editBucketAdmin' : 'bucketAdmin');
|
||||
const permissionFields = document.getElementById(mode === 'edit' ? 'editBucketPermissionFields' : 'bucketPermissionFields');
|
||||
|
||||
|
||||
if (adminCheckbox && permissionFields) {
|
||||
permissionFields.style.display = adminCheckbox.checked ? 'none' : 'block';
|
||||
}
|
||||
@@ -682,7 +682,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
mode = mode || 'create';
|
||||
const specificRadio = document.getElementById(mode === 'edit' ? 'editSpecificBuckets' : 'specificBuckets');
|
||||
const bucketList = document.getElementById(mode === 'edit' ? 'editBucketSelectionList' : 'bucketSelectionList');
|
||||
|
||||
|
||||
if (specificRadio && bucketList) {
|
||||
bucketList.style.display = specificRadio.checked ? 'block' : 'none';
|
||||
}
|
||||
@@ -710,7 +710,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
function populateBucketSelections() {
|
||||
const createSelect = document.getElementById('selectedBuckets');
|
||||
const editSelect = document.getElementById('editSelectedBuckets');
|
||||
|
||||
|
||||
[createSelect, editSelect].forEach(select => {
|
||||
if (select) {
|
||||
select.innerHTML = '';
|
||||
@@ -732,17 +732,17 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
applyToAll: false,
|
||||
specificBuckets: []
|
||||
};
|
||||
|
||||
|
||||
// Check if user has Admin permission
|
||||
if (actions.includes('Admin')) {
|
||||
result.isAdmin = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Separate bucket-scoped from global actions
|
||||
const bucketActions = [];
|
||||
const globalBucketPerms = [];
|
||||
|
||||
|
||||
actions.forEach(action => {
|
||||
if (action.startsWith('s3tables:')) {
|
||||
const actionValue = action.slice('s3tables:'.length);
|
||||
@@ -767,7 +767,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
globalBucketPerms.push(action);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// If we have global bucket permissions (no colon), they apply to all buckets
|
||||
if (globalBucketPerms.length > 0) {
|
||||
result.permissions = globalBucketPerms;
|
||||
@@ -776,12 +776,12 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
// Get unique permissions and buckets
|
||||
const perms = [...new Set(bucketActions.map(ba => ba.permission))];
|
||||
const buckets = [...new Set(bucketActions.map(ba => ba.bucketId))];
|
||||
|
||||
|
||||
result.permissions = perms;
|
||||
result.applyToAll = false;
|
||||
result.specificBuckets = buckets;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -805,34 +805,34 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
mode = mode || 'create';
|
||||
const selectId = mode === 'edit' ? 'editActions' : 'actions';
|
||||
const permSelect = document.getElementById(selectId);
|
||||
|
||||
|
||||
if (!permSelect) return [];
|
||||
|
||||
|
||||
// Get selected permissions from the original multi-select
|
||||
const selectedPerms = Array.from(permSelect.selectedOptions).map(opt => opt.value);
|
||||
|
||||
|
||||
const hasAdmin = selectedPerms.includes('Admin');
|
||||
const hasS3TablesAdmin = selectedPerms.includes('S3TablesAdmin');
|
||||
|
||||
|
||||
if (selectedPerms.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
// Check if applying to all buckets or specific ones
|
||||
// Use querySelector to find the checked radio button by name group
|
||||
const scopeName = mode === 'edit' ? 'editBucketScope' : 'bucketScope';
|
||||
|
||||
|
||||
// Try multiple methods to find the checked radio
|
||||
let checkedRadio = document.querySelector(`input[name="${scopeName}"]:checked`);
|
||||
|
||||
|
||||
// Fallback: check both radio buttons explicitly
|
||||
if (!checkedRadio) {
|
||||
const allBucketsId = mode === 'edit' ? 'editAllBuckets' : 'allBuckets';
|
||||
const specificBucketsId = mode === 'edit' ? 'editSpecificBuckets' : 'specificBuckets';
|
||||
|
||||
|
||||
const allBucketsRadio = document.getElementById(allBucketsId);
|
||||
const specificBucketsRadio = document.getElementById(specificBucketsId);
|
||||
|
||||
|
||||
if (specificBucketsRadio && specificBucketsRadio.checked) {
|
||||
checkedRadio = specificBucketsRadio;
|
||||
} else if (allBucketsRadio && allBucketsRadio.checked) {
|
||||
@@ -867,18 +867,21 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
// Get selected specific buckets
|
||||
const bucketSelect = document.getElementById(mode === 'edit' ? 'editSelectedBuckets' : 'selectedBuckets');
|
||||
if (!bucketSelect) return null;
|
||||
|
||||
|
||||
const selectedBuckets = [...new Set(Array.from(bucketSelect.selectedOptions).map(opt => opt.value))];
|
||||
|
||||
|
||||
// Return null to signal validation failure if no buckets selected
|
||||
if (selectedBuckets.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Build bucket-scoped permissions
|
||||
const actions = [];
|
||||
if (hasAdmin) {
|
||||
actions.push('Admin');
|
||||
selectedBuckets.forEach((bucket) => {
|
||||
const bucketInfo = parseBucketOptionValue(bucket);
|
||||
actions.push("Admin:" + bucketInfo.name);
|
||||
});
|
||||
}
|
||||
if (hasS3TablesAdmin) {
|
||||
actions.push('s3tables:*');
|
||||
@@ -898,7 +901,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return [...new Set(actions)];
|
||||
}
|
||||
}
|
||||
@@ -929,11 +932,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const response = await fetch(`/api/users/${encodedUsername}`);
|
||||
if (response.ok) {
|
||||
const user = await response.json();
|
||||
|
||||
|
||||
// Populate edit form
|
||||
document.getElementById('editUsername').value = username;
|
||||
document.getElementById('editEmail').value = user.email || '';
|
||||
|
||||
|
||||
// Set selected actions
|
||||
const actionsSelect = document.getElementById('editActions');
|
||||
Array.from(actionsSelect.options).forEach(option => {
|
||||
@@ -947,11 +950,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
option.selected = user.policy_names && user.policy_names.includes(option.value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Populate bucket permissions using original permissions dropdown
|
||||
if (user.actions && user.actions.length > 0) {
|
||||
const bucketPerms = parseBucketPermissions(user.actions);
|
||||
|
||||
|
||||
// Set permissions in the original multi-select
|
||||
const actionsSelect = document.getElementById('editActions');
|
||||
if (actionsSelect) {
|
||||
@@ -963,18 +966,18 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Set bucket scope (all or specific)
|
||||
const allBucketsRadio = document.getElementById('editAllBuckets');
|
||||
const specificBucketsRadio = document.getElementById('editSpecificBuckets');
|
||||
|
||||
|
||||
if (!bucketPerms.isAdmin) {
|
||||
if (bucketPerms.applyToAll) {
|
||||
if (allBucketsRadio) allBucketsRadio.checked = true;
|
||||
} else if (bucketPerms.specificBuckets.length > 0) {
|
||||
if (specificBucketsRadio) specificBucketsRadio.checked = true;
|
||||
toggleBucketList('edit');
|
||||
|
||||
|
||||
// Select specific buckets
|
||||
const bucketSelect = document.getElementById('editSelectedBuckets');
|
||||
if (bucketSelect) {
|
||||
@@ -985,7 +988,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Populate groups
|
||||
await populateEditUserGroups(username);
|
||||
|
||||
@@ -1029,7 +1032,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const response = await fetch(`/api/users/${encodedUsername}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
showSuccessMessage('User deleted successfully');
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
@@ -1048,10 +1051,10 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
async function handleCreateUser() {
|
||||
const form = document.getElementById('createUserForm');
|
||||
const formData = new FormData(form);
|
||||
|
||||
|
||||
// Get permissions with bucket scope applied
|
||||
const allActions = buildBucketPermissions('create');
|
||||
|
||||
|
||||
if (allActions === null) {
|
||||
showAlert('Please select at least one bucket when using specific bucket permissions', 'error');
|
||||
return;
|
||||
@@ -1061,7 +1064,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
showAlert('At least one permission must be selected', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const userData = {
|
||||
username: formData.get('username'),
|
||||
email: formData.get('email'),
|
||||
@@ -1069,7 +1072,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
policy_names: Array.from(document.getElementById('policies').selectedOptions).map(option => option.value),
|
||||
generate_key: document.getElementById('generateKey').checked
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/users', {
|
||||
method: 'POST',
|
||||
@@ -1078,16 +1081,16 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
},
|
||||
body: JSON.stringify(userData)
|
||||
});
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
showSuccessMessage('User created successfully');
|
||||
|
||||
|
||||
// Show the created access key if generated
|
||||
if (result.user && result.user.access_key) {
|
||||
showNewAccessKeyModal(result.user);
|
||||
}
|
||||
|
||||
|
||||
// Close modal and refresh page
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('createUserModal'));
|
||||
modal.hide();
|
||||
@@ -1210,28 +1213,28 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
showAlert('Username is required', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Get permissions with bucket scope applied
|
||||
const allActions = buildBucketPermissions('edit');
|
||||
|
||||
|
||||
// Check for null (validation failure from buildBucketPermissions)
|
||||
if (allActions === null) {
|
||||
showAlert('Please select at least one bucket when using specific bucket permissions', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Validate that permissions are not empty
|
||||
if (!allActions || allActions.length === 0) {
|
||||
showAlert('At least one permission must be selected', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const userData = {
|
||||
email: document.getElementById('editEmail').value,
|
||||
actions: allActions,
|
||||
policy_names: Array.from(document.getElementById('editPolicies').selectedOptions).map(option => option.value)
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
const encodedUsername = encodeURIComponent(username);
|
||||
const response = await fetch(`/api/users/${encodedUsername}`, {
|
||||
@@ -1241,10 +1244,10 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
},
|
||||
body: JSON.stringify(userData)
|
||||
});
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
showSuccessMessage('User updated successfully');
|
||||
|
||||
|
||||
// Close modal and refresh page
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('editUserModal'));
|
||||
modal.hide();
|
||||
@@ -1321,12 +1324,12 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
if (!user.access_keys || user.access_keys.length === 0) {
|
||||
return '<p class="text-muted">No access keys available</p>';
|
||||
}
|
||||
|
||||
|
||||
var keysHtml = '<div class="table-responsive">';
|
||||
keysHtml += '<table class="table table-sm">';
|
||||
keysHtml += '<thead><tr><th>Access Key</th><th>Status</th><th>Actions</th></tr></thead>';
|
||||
keysHtml += '<tbody>';
|
||||
|
||||
|
||||
user.access_keys.forEach(function(key) {
|
||||
keysHtml += '<tr>';
|
||||
keysHtml += '<td><code>' + escapeHtml(key.access_key) + '</code></td>';
|
||||
@@ -1348,11 +1351,11 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
keysHtml += '</td>';
|
||||
keysHtml += '</tr>';
|
||||
});
|
||||
|
||||
|
||||
keysHtml += '</tbody>';
|
||||
keysHtml += '</table>';
|
||||
keysHtml += '</div>';
|
||||
|
||||
|
||||
// Add delegated event listener for view secret buttons
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('.view-secret-btn').forEach(btn => {
|
||||
@@ -1363,7 +1366,7 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
});
|
||||
});
|
||||
}, 100);
|
||||
|
||||
|
||||
return keysHtml;
|
||||
}
|
||||
|
||||
@@ -1514,10 +1517,10 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
const response = await fetch(`/api/users/${encodedUsername}/access-keys/${encodedAccessKey}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
showSuccessMessage('Access key deleted successfully');
|
||||
|
||||
|
||||
// Refresh access keys display
|
||||
refreshAccessKeysList(username);
|
||||
} else {
|
||||
@@ -1552,4 +1555,4 @@ templ ObjectStoreUsers(data dash.ObjectStoreUsersData) {
|
||||
}
|
||||
|
||||
// Helper functions for template
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ func ObjectStoreUsers(data dash.ObjectStoreUsersData) templ.Component {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div><div class=\"mb-3\"><label for=\"email\" class=\"form-label\">Email</label> <input type=\"email\" class=\"form-control\" id=\"email\" name=\"email\"></div><div class=\"mb-3\"><label for=\"actions\" class=\"form-label\">Permissions</label> <select multiple class=\"form-control\" id=\"actions\" name=\"actions\" size=\"10\"><option value=\"Admin\">Admin (Full Access)</option> <option value=\"Read\">Read</option> <option value=\"Write\">Write</option> <option value=\"List\">List</option> <option value=\"Tagging\">Tagging</option> <optgroup label=\"Object Lock Permissions\"><option value=\"BypassGovernanceRetention\">Bypass Governance Retention</option> <option value=\"GetObjectRetention\">Get Object Retention</option> <option value=\"PutObjectRetention\">Put Object Retention</option> <option value=\"GetObjectLegalHold\">Get Object Legal Hold</option> <option value=\"PutObjectLegalHold\">Put Object Legal Hold</option> <option value=\"GetBucketObjectLockConfiguration\">Get Bucket Object Lock Configuration</option> <option value=\"PutBucketObjectLockConfiguration\">Put Bucket Object Lock Configuration</option></optgroup> <optgroup label=\"S3 Tables Permissions\"><option value=\"S3TablesAdmin\">S3 Tables Admin (Full Access)</option> <option value=\"CreateTableBucket\">Create Table Bucket</option> <option value=\"GetTableBucket\">Get Table Bucket</option> <option value=\"ListTableBuckets\">List Table Buckets</option> <option value=\"DeleteTableBucket\">Delete Table Bucket</option> <option value=\"PutTableBucketPolicy\">Put Table Bucket Policy</option> <option value=\"GetTableBucketPolicy\">Get Table Bucket Policy</option> <option value=\"DeleteTableBucketPolicy\">Delete Table Bucket Policy</option> <option value=\"CreateNamespace\">Create Namespace</option> <option value=\"GetNamespace\">Get Namespace</option> <option value=\"ListNamespaces\">List Namespaces</option> <option value=\"DeleteNamespace\">Delete Namespace</option> <option value=\"CreateTable\">Create Table</option> <option value=\"GetTable\">Get Table</option> <option value=\"ListTables\">List Tables</option> <option value=\"DeleteTable\">Delete Table</option> <option value=\"PutTablePolicy\">Put Table Policy</option> <option value=\"GetTablePolicy\">Get Table Policy</option> <option value=\"DeleteTablePolicy\">Delete Table Policy</option> <option value=\"TagResource\">Tag Resource</option> <option value=\"ListTagsForResource\">List Tags</option> <option value=\"UntagResource\">Untag Resource</option></optgroup></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple permissions</small></div><div class=\"mb-3\"><label class=\"form-label\">Bucket Scope</label> <small class=\"form-text text-muted d-block mb-2\">Apply selected permissions to specific buckets or all buckets</small><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"allBuckets\" value=\"all\" checked onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"allBuckets\">All Buckets</label></div><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"specificBuckets\" value=\"specific\" onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"specificBuckets\">Specific Buckets</label></div><div id=\"bucketSelectionList\" class=\"mt-2\" style=\"display: none;\"><select multiple class=\"form-select\" id=\"selectedBuckets\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple buckets</small></div></div><div class=\"mb-3\"><label for=\"policies\" class=\"form-label\">Attached Policies</label> <select multiple class=\"form-control\" id=\"policies\" name=\"policies\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple policies</small></div><div class=\"mb-3 form-check\"><input type=\"checkbox\" class=\"form-check-input\" id=\"generateKey\" name=\"generateKey\" checked> <label class=\"form-check-label\" for=\"generateKey\">Generate access key automatically</label></div></form></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" onclick=\"handleCreateUser()\">Create User</button></div></div></div></div><!-- Edit User Modal --><div class=\"modal fade\" id=\"editUserModal\" tabindex=\"-1\" role=\"dialog\"><div class=\"modal-dialog\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"fas fa-user-edit me-2\"></i>Edit User</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\"><form id=\"editUserForm\"><input type=\"hidden\" id=\"editUsername\" name=\"username\"><div class=\"mb-3\"Line truncated
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div><div class=\"mb-3\"><label for=\"email\" class=\"form-label\">Email</label> <input type=\"email\" class=\"form-control\" id=\"email\" name=\"email\"></div><div class=\"mb-3\"><label for=\"actions\" class=\"form-label\">Permissions</label> <select multiple class=\"form-control\" id=\"actions\" name=\"actions\" size=\"10\"><option value=\"Admin\">Admin (Full Access)</option> <option value=\"Read\">Read</option> <option value=\"Write\">Write</option> <option value=\"List\">List</option> <option value=\"Tagging\">Tagging</option> <optgroup label=\"Object Lock Permissions\"><option value=\"BypassGovernanceRetention\">Bypass Governance Retention</option> <option value=\"GetObjectRetention\">Get Object Retention</option> <option value=\"PutObjectRetention\">Put Object Retention</option> <option value=\"GetObjectLegalHold\">Get Object Legal Hold</option> <option value=\"PutObjectLegalHold\">Put Object Legal Hold</option> <option value=\"GetBucketObjectLockConfiguration\">Get Bucket Object Lock Configuration</option> <option value=\"PutBucketObjectLockConfiguration\">Put Bucket Object Lock Configuration</option></optgroup> <optgroup label=\"S3 Tables Permissions\"><option value=\"S3TablesAdmin\">S3 Tables Admin (Full Access)</option> <option value=\"CreateTableBucket\">Create Table Bucket</option> <option value=\"GetTableBucket\">Get Table Bucket</option> <option value=\"ListTableBuckets\">List Table Buckets</option> <option value=\"DeleteTableBucket\">Delete Table Bucket</option> <option value=\"PutTableBucketPolicy\">Put Table Bucket Policy</option> <option value=\"GetTableBucketPolicy\">Get Table Bucket Policy</option> <option value=\"DeleteTableBucketPolicy\">Delete Table Bucket Policy</option> <option value=\"CreateNamespace\">Create Namespace</option> <option value=\"GetNamespace\">Get Namespace</option> <option value=\"ListNamespaces\">List Namespaces</option> <option value=\"DeleteNamespace\">Delete Namespace</option> <option value=\"CreateTable\">Create Table</option> <option value=\"GetTable\">Get Table</option> <option value=\"ListTables\">List Tables</option> <option value=\"DeleteTable\">Delete Table</option> <option value=\"PutTablePolicy\">Put Table Policy</option> <option value=\"GetTablePolicy\">Get Table Policy</option> <option value=\"DeleteTablePolicy\">Delete Table Policy</option> <option value=\"TagResource\">Tag Resource</option> <option value=\"ListTagsForResource\">List Tags</option> <option value=\"UntagResource\">Untag Resource</option></optgroup></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple permissions</small></div><div class=\"mb-3\"><label class=\"form-label\">Bucket Scope</label> <small class=\"form-text text-muted d-block mb-2\">Apply selected permissions to specific buckets or all buckets</small><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"allBuckets\" value=\"all\" checked onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"allBuckets\">All Buckets</label></div><div class=\"form-check mb-2\"><input class=\"form-check-input\" type=\"radio\" name=\"bucketScope\" id=\"specificBuckets\" value=\"specific\" onchange=\"toggleBucketList()\"> <label class=\"form-check-label\" for=\"specificBuckets\">Specific Buckets</label></div><div id=\"bucketSelectionList\" class=\"mt-2\" style=\"display: none;\"><select multiple class=\"form-select\" id=\"selectedBuckets\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple buckets</small></div></div><div class=\"mb-3\"><label for=\"policies\" class=\"form-label\">Attached Policies</label> <select multiple class=\"form-control\" id=\"policies\" name=\"policies\" size=\"5\"><!-- Options loaded dynamically --></select> <small class=\"form-text text-muted\">Hold Ctrl/Cmd to select multiple policies</small></div><div class=\"mb-3 form-check\"><input type=\"checkbox\" class=\"form-check-input\" id=\"generateKey\" name=\"generateKey\" checked> <label class=\"form-check-label\" for=\"generateKey\">Generate access key automatically</label></div></form></div><div class=\"modal-footer\"><button type=\"button\" class=\"btn btn-secondary\" data-bs-dismiss=\"modal\">Cancel</button> <button type=\"button\" class=\"btn btn-primary\" onclick=\"handleCreateUser()\">Create User</button></div></div></div></div><!-- Edit User Modal --><div class=\"modal fade\" id=\"editUserModal\" tabindex=\"-1\" role=\"dialog\"><div class=\"modal-dialog\" role=\"document\"><div class=\"modal-content\"><div class=\"modal-header\"><h5 class=\"modal-title\"><i class=\"fas fa-user-edit me-2\"></i>Edit User</h5><button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"modal\"></button></div><div class=\"modal-body\"><form id=\"editUserForm\"><input type=\"hidden\" id=\"editUsername\" name=\"username\"><div class=\"mb-3\"Line truncated
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user