You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							658 lines
						
					
					
						
							29 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							658 lines
						
					
					
						
							29 KiB
						
					
					
				| package app | |
| 
 | |
| import ( | |
|     "fmt" | |
|     "github.com/seaweedfs/seaweedfs/weed/admin/dash" | |
| ) | |
| 
 | |
| templ Policies(data dash.PoliciesData) { | |
|     <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> | |
|         <h1 class="h2"> | |
|             <i class="fas fa-shield-alt me-2"></i>IAM Policies | |
|         </h1> | |
|         <div class="btn-toolbar mb-2 mb-md-0"> | |
|             <div class="btn-group me-2"> | |
|                 <button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#createPolicyModal"> | |
|                     <i class="fas fa-plus me-1"></i>Create Policy | |
|                 </button> | |
|             </div> | |
|         </div> | |
|     </div> | |
| 
 | |
|     <div id="policies-content"> | |
|         <!-- Summary Cards --> | |
|         <div class="row mb-4"> | |
|             <div class="col-xl-4 col-md-6 mb-4"> | |
|                 <div class="card border-left-primary shadow h-100 py-2"> | |
|                     <div class="card-body"> | |
|                         <div class="row no-gutters align-items-center"> | |
|                             <div class="col mr-2"> | |
|                                 <div class="text-xs font-weight-bold text-primary text-uppercase mb-1"> | |
|                                     Total Policies | |
|                                 </div> | |
|                                 <div class="h5 mb-0 font-weight-bold text-gray-800"> | |
|                                     {fmt.Sprintf("%d", data.TotalPolicies)} | |
|                                 </div> | |
|                             </div> | |
|                             <div class="col-auto"> | |
|                                 <i class="fas fa-shield-alt fa-2x text-gray-300"></i> | |
|                             </div> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|             </div> | |
| 
 | |
|             <div class="col-xl-4 col-md-6 mb-4"> | |
|                 <div class="card border-left-success shadow h-100 py-2"> | |
|                     <div class="card-body"> | |
|                         <div class="row no-gutters align-items-center"> | |
|                             <div class="col mr-2"> | |
|                                 <div class="text-xs font-weight-bold text-success text-uppercase mb-1"> | |
|                                     Active Policies | |
|                                 </div> | |
|                                 <div class="h5 mb-0 font-weight-bold text-gray-800"> | |
|                                     {fmt.Sprintf("%d", data.TotalPolicies)} | |
|                                 </div> | |
|                             </div> | |
|                             <div class="col-auto"> | |
|                                 <i class="fas fa-check-circle fa-2x text-gray-300"></i> | |
|                             </div> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|             </div> | |
| 
 | |
|             <div class="col-xl-4 col-md-6 mb-4"> | |
|                 <div class="card border-left-info shadow h-100 py-2"> | |
|                     <div class="card-body"> | |
|                         <div class="row no-gutters align-items-center"> | |
|                             <div class="col mr-2"> | |
|                                 <div class="text-xs font-weight-bold text-info text-uppercase mb-1"> | |
|                                     Last Updated | |
|                                 </div> | |
|                                 <div class="h5 mb-0 font-weight-bold text-gray-800"> | |
|                                     {data.LastUpdated.Format("15:04")} | |
|                                 </div> | |
|                             </div> | |
|                             <div class="col-auto"> | |
|                                 <i class="fas fa-clock fa-2x text-gray-300"></i> | |
|                             </div> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|             </div> | |
|         </div> | |
| 
 | |
|         <!-- Policies Table --> | |
|         <div class="row"> | |
|             <div class="col-12"> | |
|                 <div class="card shadow mb-4"> | |
|                     <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between"> | |
|                         <h6 class="m-0 font-weight-bold text-primary"> | |
|                             <i class="fas fa-shield-alt me-2"></i>IAM Policies | |
|                         </h6> | |
|                         <div class="dropdown no-arrow"> | |
|                             <a class="dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"> | |
|                                 <i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i> | |
|                             </a> | |
|                             <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"> | |
|                                 <div class="dropdown-header">Actions:</div> | |
|                                 <a class="dropdown-item" href="#"> | |
|                                     <i class="fas fa-download me-2"></i>Export List | |
|                                 </a> | |
|                             </div> | |
|                         </div> | |
|                     </div> | |
|                     <div class="card-body"> | |
|                         <div class="table-responsive"> | |
|                             <table class="table table-hover" width="100%" cellspacing="0"> | |
|                                 <thead> | |
|                                     <tr> | |
|                                         <th>Policy Name</th> | |
|                                         <th>Version</th> | |
|                                         <th>Statements</th> | |
|                                         <th>Created</th> | |
|                                         <th>Updated</th> | |
|                                         <th>Actions</th> | |
|                                     </tr> | |
|                                 </thead> | |
|                                 <tbody> | |
|                                     for _, policy := range data.Policies { | |
|                                         <tr> | |
|                                             <td> | |
|                                                 <strong>{policy.Name}</strong> | |
|                                             </td> | |
|                                             <td> | |
|                                                 <span class="badge bg-info">{policy.Document.Version}</span> | |
|                                             </td> | |
|                                             <td> | |
|                                                 <span class="badge bg-secondary">{fmt.Sprintf("%d statements", len(policy.Document.Statement))}</span> | |
|                                             </td> | |
|                                             <td> | |
|                                                 <small class="text-muted">{policy.CreatedAt.Format("2006-01-02 15:04")}</small> | |
|                                             </td> | |
|                                             <td> | |
|                                                 <small class="text-muted">{policy.UpdatedAt.Format("2006-01-02 15:04")}</small> | |
|                                             </td> | |
|                                             <td> | |
|                                                 <div class="btn-group btn-group-sm" role="group"> | |
|                                                     <button type="button" class="btn btn-outline-info view-policy-btn" title="View Policy" data-policy-name={policy.Name}> | |
|                                                         <i class="fas fa-eye"></i> | |
|                                                     </button> | |
|                                                     <button type="button" class="btn btn-outline-primary edit-policy-btn" title="Edit Policy" data-policy-name={policy.Name}> | |
|                                                         <i class="fas fa-edit"></i> | |
|                                                     </button> | |
|                                                     <button type="button" class="btn btn-outline-danger delete-policy-btn" title="Delete Policy" data-policy-name={policy.Name}> | |
|                                                         <i class="fas fa-trash"></i> | |
|                                                     </button> | |
|                                                 </div> | |
|                                             </td> | |
|                                         </tr> | |
|                                     } | |
|                                     if len(data.Policies) == 0 { | |
|                                         <tr> | |
|                                             <td colspan="6" class="text-center text-muted py-4"> | |
|                                                 <i class="fas fa-shield-alt fa-3x mb-3 text-muted"></i> | |
|                                                 <div> | |
|                                                     <h5>No IAM policies found</h5> | |
|                                                     <p>Create your first policy to manage access permissions.</p> | |
|                                                     <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createPolicyModal"> | |
|                                                         <i class="fas fa-plus me-1"></i>Create Policy | |
|                                                     </button> | |
|                                                 </div> | |
|                                             </td> | |
|                                         </tr> | |
|                                     } | |
|                                 </tbody> | |
|                             </table> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|             </div> | |
|         </div> | |
|     </div> | |
| 
 | |
|     <!-- Create Policy Modal --> | |
|     <div class="modal fade" id="createPolicyModal" tabindex="-1" aria-labelledby="createPolicyModalLabel" aria-hidden="true"> | |
|         <div class="modal-dialog modal-lg"> | |
|             <div class="modal-content"> | |
|                 <div class="modal-header"> | |
|                     <h5 class="modal-title" id="createPolicyModalLabel"> | |
|                         <i class="fas fa-shield-alt me-2"></i>Create IAM Policy | |
|                     </h5> | |
|                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | |
|                 </div> | |
|                 <div class="modal-body"> | |
|                     <form id="createPolicyForm"> | |
|                         <div class="mb-3"> | |
|                             <label for="policyName" class="form-label">Policy Name</label> | |
|                             <input type="text" class="form-control" id="policyName" name="name" required placeholder="e.g., S3ReadOnlyPolicy"> | |
|                             <div class="form-text">Enter a unique name for this policy (alphanumeric and underscores only)</div> | |
|                         </div> | |
|                          | |
|                         <div class="mb-3"> | |
|                             <label for="policyDocument" class="form-label">Policy Document</label> | |
|                             <textarea class="form-control" id="policyDocument" name="document" rows="15" required placeholder="Enter IAM policy JSON document..."></textarea> | |
|                             <div class="form-text">Enter the policy document in AWS IAM JSON format</div> | |
|                         </div> | |
| 
 | |
|                         <div class="mb-3"> | |
|                             <div class="row"> | |
|                                 <div class="col-md-6"> | |
|                                     <button type="button" class="btn btn-outline-info btn-sm" onclick="insertSamplePolicy()"> | |
|                                         <i class="fas fa-file-alt me-1"></i>Use Sample Policy | |
|                                     </button> | |
|                                 </div> | |
|                                 <div class="col-md-6 text-end"> | |
|                                     <button type="button" class="btn btn-outline-secondary btn-sm" onclick="validatePolicyDocument()"> | |
|                                         <i class="fas fa-check me-1"></i>Validate JSON | |
|                                     </button> | |
|                                 </div> | |
|                             </div> | |
|                         </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="createPolicy()"> | |
|                         <i class="fas fa-plus me-1"></i>Create Policy | |
|                     </button> | |
|                 </div> | |
|             </div> | |
|         </div> | |
|     </div> | |
| 
 | |
|     <!-- View Policy Modal --> | |
|     <div class="modal fade" id="viewPolicyModal" tabindex="-1" aria-labelledby="viewPolicyModalLabel" aria-hidden="true"> | |
|         <div class="modal-dialog modal-lg"> | |
|             <div class="modal-content"> | |
|                 <div class="modal-header"> | |
|                     <h5 class="modal-title" id="viewPolicyModalLabel"> | |
|                         <i class="fas fa-eye me-2"></i>View IAM Policy | |
|                     </h5> | |
|                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | |
|                 </div> | |
|                 <div class="modal-body"> | |
|                     <div id="viewPolicyContent"> | |
|                         <div class="text-center"> | |
|                             <div class="spinner-border" role="status"> | |
|                                 <span class="visually-hidden">Loading...</span> | |
|                             </div> | |
|                             <p class="mt-2">Loading policy...</p> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|                 <div class="modal-footer"> | |
|                     <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> | |
|                     <button type="button" class="btn btn-primary" id="editFromViewBtn"> | |
|                         <i class="fas fa-edit me-1"></i>Edit Policy | |
|                     </button> | |
|                 </div> | |
|             </div> | |
|         </div> | |
|     </div> | |
| 
 | |
|     <!-- Edit Policy Modal --> | |
|     <div class="modal fade" id="editPolicyModal" tabindex="-1" aria-labelledby="editPolicyModalLabel" aria-hidden="true"> | |
|         <div class="modal-dialog modal-lg"> | |
|             <div class="modal-content"> | |
|                 <div class="modal-header"> | |
|                     <h5 class="modal-title" id="editPolicyModalLabel"> | |
|                         <i class="fas fa-edit me-2"></i>Edit IAM Policy | |
|                     </h5> | |
|                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | |
|                 </div> | |
|                 <div class="modal-body"> | |
|                     <form id="editPolicyForm"> | |
|                         <div class="mb-3"> | |
|                             <label for="editPolicyName" class="form-label">Policy Name</label> | |
|                             <input type="text" class="form-control" id="editPolicyName" name="name" readonly> | |
|                             <div class="form-text">Policy name cannot be changed</div> | |
|                         </div> | |
|                          | |
|                         <div class="mb-3"> | |
|                             <label for="editPolicyDocument" class="form-label">Policy Document</label> | |
|                             <textarea class="form-control" id="editPolicyDocument" name="document" rows="15" required></textarea> | |
|                             <div class="form-text">Edit the policy document in AWS IAM JSON format</div> | |
|                         </div> | |
| 
 | |
|                         <div class="mb-3"> | |
|                             <div class="row"> | |
|                                 <div class="col-md-6"> | |
|                                     <button type="button" class="btn btn-outline-info btn-sm" onclick="insertSamplePolicyEdit()"> | |
|                                         <i class="fas fa-file-alt me-1"></i>Reset to Sample | |
|                                     </button> | |
|                                 </div> | |
|                                 <div class="col-md-6 text-end"> | |
|                                     <button type="button" class="btn btn-outline-secondary btn-sm" onclick="validateEditPolicyDocument()"> | |
|                                         <i class="fas fa-check me-1"></i>Validate JSON | |
|                                     </button> | |
|                                 </div> | |
|                             </div> | |
|                         </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="updatePolicy()"> | |
|                         <i class="fas fa-save me-1"></i>Save Changes | |
|                     </button> | |
|                 </div> | |
|             </div> | |
|         </div> | |
|     </div> | |
| 
 | |
|     <!-- JavaScript for Policy Management --> | |
|     <script> | |
|     // Current policy being viewed/edited | |
|     let currentPolicy = null; | |
|      | |
|     // Event listeners for policy actions | |
|     document.addEventListener('DOMContentLoaded', function() { | |
|         // View policy buttons | |
|         document.querySelectorAll('.view-policy-btn').forEach(button => { | |
|             button.addEventListener('click', function() { | |
|                 const policyName = this.getAttribute('data-policy-name'); | |
|                 viewPolicy(policyName); | |
|             }); | |
|         }); | |
|          | |
|         // Edit policy buttons | |
|         document.querySelectorAll('.edit-policy-btn').forEach(button => { | |
|             button.addEventListener('click', function() { | |
|                 const policyName = this.getAttribute('data-policy-name'); | |
|                 editPolicy(policyName); | |
|             }); | |
|         }); | |
|          | |
|         // Delete policy buttons | |
|         document.querySelectorAll('.delete-policy-btn').forEach(button => { | |
|             button.addEventListener('click', function() { | |
|                 const policyName = this.getAttribute('data-policy-name'); | |
|                 deletePolicy(policyName); | |
|             }); | |
|         }); | |
|          | |
|         // Edit from view button | |
|         document.getElementById('editFromViewBtn').addEventListener('click', function() { | |
|             if (currentPolicy) { | |
|                 const viewModal = bootstrap.Modal.getInstance(document.getElementById('viewPolicyModal')); | |
|                 if (viewModal) viewModal.hide(); | |
|                 editPolicy(currentPolicy.name); | |
|             } | |
|         }); | |
|     }); | |
|      | |
|     function createPolicy() { | |
|         const form = document.getElementById('createPolicyForm'); | |
|         const formData = new FormData(form); | |
|          | |
|         const policyName = formData.get('name'); | |
|         const policyDocumentText = formData.get('document'); | |
|          | |
|         if (!policyName || !policyDocumentText) { | |
|             alert('Please fill in all required fields'); | |
|             return; | |
|         } | |
|          | |
|         let policyDocument; | |
|         try { | |
|             policyDocument = JSON.parse(policyDocumentText); | |
|         } catch (e) { | |
|             alert('Invalid JSON in policy document: ' + e.message); | |
|             return; | |
|         } | |
|          | |
|         const requestData = { | |
|             name: policyName, | |
|             document: policyDocument | |
|         }; | |
|          | |
|         fetch('/api/object-store/policies', { | |
|             method: 'POST', | |
|             headers: { | |
|                 'Content-Type': 'application/json', | |
|             }, | |
|             body: JSON.stringify(requestData) | |
|         }) | |
|         .then(response => response.json()) | |
|         .then(data => { | |
|             if (data.success) { | |
|                 alert('Policy created successfully!'); | |
|                 const modal = bootstrap.Modal.getInstance(document.getElementById('createPolicyModal')); | |
|                 if (modal) modal.hide(); | |
|                 location.reload(); // Refresh the page to show the new policy | |
|             } else { | |
|                 alert('Error creating policy: ' + (data.error || 'Unknown error')); | |
|             } | |
|         }) | |
|         .catch(error => { | |
|             console.error('Error:', error); | |
|             alert('Error creating policy: ' + error.message); | |
|         }); | |
|     } | |
|      | |
|     function viewPolicy(policyName) { | |
|         // Show the modal first | |
|         const modal = new bootstrap.Modal(document.getElementById('viewPolicyModal')); | |
|         modal.show(); | |
|          | |
|         // Reset content to loading state | |
|         document.getElementById('viewPolicyContent').innerHTML = ` | |
|             <div class="text-center"> | |
|                 <div class="spinner-border" role="status"> | |
|                     <span class="visually-hidden">Loading...</span> | |
|                 </div> | |
|                 <p class="mt-2">Loading policy...</p> | |
|             </div> | |
|         `; | |
|          | |
|         // Fetch policy data | |
|         fetch('/api/object-store/policies/' + encodeURIComponent(policyName)) | |
|         .then(response => { | |
|             if (!response.ok) { | |
|                 throw new Error('Policy not found'); | |
|             } | |
|             return response.json(); | |
|         }) | |
|         .then(policy => { | |
|             currentPolicy = policy; | |
|             displayPolicyDetails(policy); | |
|         }) | |
|         .catch(error => { | |
|             console.error('Error:', error); | |
|             document.getElementById('viewPolicyContent').innerHTML = ` | |
|                 <div class="alert alert-danger" role="alert"> | |
|                     <i class="fas fa-exclamation-triangle me-2"></i> | |
|                     Error loading policy: ${error.message} | |
|                 </div> | |
|             `; | |
|         }); | |
|     } | |
|      | |
|     function displayPolicyDetails(policy) { | |
|         const content = document.getElementById('viewPolicyContent'); | |
|          | |
|         let statementsHtml = ''; | |
|         if (policy.document && policy.document.Statement) { | |
|             statementsHtml = policy.document.Statement.map((stmt, index) => ` | |
|                 <div class="card mb-2"> | |
|                     <div class="card-header py-2"> | |
|                         <h6 class="mb-0">Statement ${index + 1}</h6> | |
|                     </div> | |
|                     <div class="card-body py-2"> | |
|                         <div class="row"> | |
|                             <div class="col-md-6"> | |
|                                 <strong>Effect:</strong>  | |
|                                 <span class="badge ${stmt.Effect === 'Allow' ? 'bg-success' : 'bg-danger'}">${stmt.Effect}</span> | |
|                             </div> | |
|                             <div class="col-md-6"> | |
|                                 <strong>Actions:</strong> ${Array.isArray(stmt.Action) ? stmt.Action.join(', ') : stmt.Action} | |
|                             </div> | |
|                         </div> | |
|                         <div class="row mt-2"> | |
|                             <div class="col-12"> | |
|                                 <strong>Resources:</strong> ${Array.isArray(stmt.Resource) ? stmt.Resource.join(', ') : stmt.Resource} | |
|                             </div> | |
|                         </div> | |
|                     </div> | |
|                 </div> | |
|             `).join(''); | |
|         } | |
|          | |
|         content.innerHTML = ` | |
|             <div class="row mb-3"> | |
|                 <div class="col-md-6"> | |
|                     <strong>Policy Name:</strong> ${policy.name || 'Unknown'} | |
|                 </div> | |
|                 <div class="col-md-6"> | |
|                     <strong>Version:</strong> <span class="badge bg-info">${policy.document?.Version || 'Unknown'}</span> | |
|                 </div> | |
|             </div> | |
|              | |
|             <div class="mb-3"> | |
|                 <strong>Statements:</strong> | |
|                 <div class="mt-2"> | |
|                     ${statementsHtml || '<p class="text-muted">No statements found</p>'} | |
|                 </div> | |
|             </div> | |
|              | |
|             <div class="mb-3"> | |
|                 <strong>Raw Policy Document:</strong> | |
|                 <pre class="bg-light p-3 border rounded mt-2"><code>${JSON.stringify(policy.document, null, 2)}</code></pre> | |
|             </div> | |
|         `; | |
|     } | |
|      | |
|     function editPolicy(policyName) { | |
|         // Show the modal first | |
|         const modal = new bootstrap.Modal(document.getElementById('editPolicyModal')); | |
|         modal.show(); | |
|          | |
|         // Set policy name | |
|         document.getElementById('editPolicyName').value = policyName; | |
|         document.getElementById('editPolicyDocument').value = 'Loading...'; | |
|          | |
|         // Fetch policy data | |
|         fetch('/api/object-store/policies/' + encodeURIComponent(policyName)) | |
|         .then(response => { | |
|             if (!response.ok) { | |
|                 throw new Error('Policy not found'); | |
|             } | |
|             return response.json(); | |
|         }) | |
|         .then(policy => { | |
|             currentPolicy = policy; | |
|             document.getElementById('editPolicyDocument').value = JSON.stringify(policy.document, null, 2); | |
|         }) | |
|         .catch(error => { | |
|             console.error('Error:', error); | |
|             alert('Error loading policy for editing: ' + error.message); | |
|             const editModal = bootstrap.Modal.getInstance(document.getElementById('editPolicyModal')); | |
|             if (editModal) editModal.hide(); | |
|         }); | |
|     } | |
|      | |
|     function updatePolicy() { | |
|         const policyName = document.getElementById('editPolicyName').value; | |
|         const policyDocumentText = document.getElementById('editPolicyDocument').value; | |
|          | |
|         if (!policyName || !policyDocumentText) { | |
|             alert('Please fill in all required fields'); | |
|             return; | |
|         } | |
|          | |
|         let policyDocument; | |
|         try { | |
|             policyDocument = JSON.parse(policyDocumentText); | |
|         } catch (e) { | |
|             alert('Invalid JSON in policy document: ' + e.message); | |
|             return; | |
|         } | |
|          | |
|         const requestData = { | |
|             document: policyDocument | |
|         }; | |
|          | |
|         fetch('/api/object-store/policies/' + encodeURIComponent(policyName), { | |
|             method: 'PUT', | |
|             headers: { | |
|                 'Content-Type': 'application/json', | |
|             }, | |
|             body: JSON.stringify(requestData) | |
|         }) | |
|         .then(response => response.json()) | |
|         .then(data => { | |
|             if (data.success) { | |
|                 alert('Policy updated successfully!'); | |
|                 const modal = bootstrap.Modal.getInstance(document.getElementById('editPolicyModal')); | |
|                 if (modal) modal.hide(); | |
|                 location.reload(); // Refresh the page to show the updated policy | |
|             } else { | |
|                 alert('Error updating policy: ' + (data.error || 'Unknown error')); | |
|             } | |
|         }) | |
|         .catch(error => { | |
|             console.error('Error:', error); | |
|             alert('Error updating policy: ' + error.message); | |
|         }); | |
|     } | |
|      | |
|     function insertSamplePolicy() { | |
|         const samplePolicy = { | |
|             "Version": "2012-10-17", | |
|             "Statement": [ | |
|                 { | |
|                     "Effect": "Allow", | |
|                     "Action": [ | |
|                         "s3:GetObject", | |
|                         "s3:PutObject" | |
|                     ], | |
|                     "Resource": [ | |
|                         "arn:aws:s3:::my-bucket/*" | |
|                     ] | |
|                 } | |
|             ] | |
|         }; | |
|          | |
|         document.getElementById('policyDocument').value = JSON.stringify(samplePolicy, null, 2); | |
|     } | |
|      | |
|     function insertSamplePolicyEdit() { | |
|         const samplePolicy = { | |
|             "Version": "2012-10-17", | |
|             "Statement": [ | |
|                 { | |
|                     "Effect": "Allow", | |
|                     "Action": [ | |
|                         "s3:GetObject", | |
|                         "s3:PutObject" | |
|                     ], | |
|                     "Resource": [ | |
|                         "arn:aws:s3:::my-bucket/*" | |
|                     ] | |
|                 } | |
|             ] | |
|         }; | |
|          | |
|         document.getElementById('editPolicyDocument').value = JSON.stringify(samplePolicy, null, 2); | |
|     } | |
|      | |
|     function validatePolicyDocument() { | |
|         const policyText = document.getElementById('policyDocument').value; | |
|         validatePolicyJSON(policyText); | |
|     } | |
|      | |
|     function validateEditPolicyDocument() { | |
|         const policyText = document.getElementById('editPolicyDocument').value; | |
|         validatePolicyJSON(policyText); | |
|     } | |
|      | |
|     function validatePolicyJSON(policyText) { | |
|         if (!policyText) { | |
|             alert('Please enter a policy document first'); | |
|             return; | |
|         } | |
|          | |
|         try { | |
|             const policy = JSON.parse(policyText); | |
|              | |
|             // Basic validation | |
|             if (!policy.Version) { | |
|                 alert('Policy must have a Version field'); | |
|                 return; | |
|             } | |
|              | |
|             if (!policy.Statement || !Array.isArray(policy.Statement)) { | |
|                 alert('Policy must have a Statement array'); | |
|                 return; | |
|             } | |
|              | |
|             alert('Policy document is valid JSON!'); | |
|         } catch (e) { | |
|             alert('Invalid JSON: ' + e.message); | |
|         } | |
|     } | |
|      | |
|     function deletePolicy(policyName) { | |
|         if (confirm('Are you sure you want to delete policy "' + policyName + '"?')) { | |
|             fetch('/api/object-store/policies/' + encodeURIComponent(policyName), { | |
|                 method: 'DELETE' | |
|             }) | |
|             .then(response => response.json()) | |
|             .then(data => { | |
|                 if (data.success) { | |
|                     alert('Policy deleted successfully!'); | |
|                     location.reload(); // Refresh the page | |
|                 } else { | |
|                     alert('Error deleting policy: ' + (data.error || 'Unknown error')); | |
|                 } | |
|             }) | |
|             .catch(error => { | |
|                 console.error('Error:', error); | |
|                 alert('Error deleting policy: ' + error.message); | |
|             }); | |
|         } | |
|     } | |
|     </script> | |
| }  |