Skip to content

Commit

Permalink
Merge pull request #223 from scireum/feature/jvo/issues/184
Browse files Browse the repository at this point in the history
Action Menus and Properties List
  • Loading branch information
jakobvogel committed Mar 2, 2023
2 parents f4ac9bf + 4eff950 commit b610623
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 14 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -17,7 +17,7 @@

<properties>
<sirius.kernel>dev-35.0.1</sirius.kernel>
<sirius.web>dev-64.0.1</sirius.web>
<sirius.web>dev-64.0.2</sirius.web>
</properties>

<repositories>
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/ninja/NinjaController.java
Expand Up @@ -14,6 +14,7 @@
import io.netty.handler.codec.http.HttpResponseStatus;
import sirius.kernel.commons.Hasher;
import sirius.kernel.commons.PriorityCollector;
import sirius.kernel.commons.Strings;
import sirius.kernel.di.std.Part;
import sirius.kernel.di.std.Register;
import sirius.kernel.health.Exceptions;
Expand Down Expand Up @@ -170,12 +171,20 @@ public void bucket(WebContext webContext, String bucketName) {
return;
}

// we only accept known paths below /ui as return address
String address = webContext.getParameter("return");
if (Strings.areEqual(address, "/ui") || Strings.areEqual(address, "/ui/") || Strings.areEqual(address, "ui")) {
address = "/ui";
} else {
address = "/ui/" + bucket.getEncodedName();
}

// handle /ui/[bucket]?make-public
if (webContext.hasParameter("make-public")) {
bucket.makePublic();

UserContext.message(Message.info().withTextMessage("ACLs successfully changed"));
webContext.respondWith().redirectTemporarily("/ui/" + bucket.getEncodedName());
webContext.respondWith().redirectTemporarily(address);
return;
}

Expand All @@ -184,7 +193,7 @@ public void bucket(WebContext webContext, String bucketName) {
bucket.makePrivate();

UserContext.message(Message.info().withTextMessage("ACLs successfully changed"));
webContext.respondWith().redirectTemporarily("/ui/" + bucket.getEncodedName());
webContext.respondWith().redirectTemporarily(address);
return;
}

Expand Down
9 changes: 3 additions & 6 deletions src/main/java/ninja/S3Dispatcher.java
Expand Up @@ -87,7 +87,6 @@ public class S3Dispatcher implements WebDispatcher {

private static final String HTTP_HEADER_NAME_ETAG = "ETag";
private static final String HTTP_HEADER_NAME_CONTENT_TYPE = "Content-Type";
private static final String HTTP_HEADER_NAME_AMAZON_ACL = "x-amz-acl";
private static final String CONTENT_TYPE_XML = "application/xml";
private static final String RESPONSE_DISPLAY_NAME = "DisplayName";
private static final String RESPONSE_BUCKET = "Bucket";
Expand Down Expand Up @@ -475,7 +474,7 @@ private void bucket(WebContext webContext, String bucketName) {
bucket.create();

// in order to allow creation of public buckets, we support a single canned access control list
String cannedAccessControlList = webContext.getHeader(HTTP_HEADER_NAME_AMAZON_ACL);
String cannedAccessControlList = webContext.getHeader("x-amz-acl");
if (Strings.areEqual(cannedAccessControlList, "public-read-write")) {
bucket.makePublic();
}
Expand Down Expand Up @@ -737,8 +736,7 @@ private Map<String, String> parseUploadProperties(WebContext webContext) {
Map<String, String> properties = Maps.newTreeMap();
for (String name : webContext.getRequest().headers().names()) {
String nameLower = name.toLowerCase();
if (nameLower.startsWith("x-amz-meta-") || "content-md5".equals(nameLower) || "content-type".equals(
nameLower) || HTTP_HEADER_NAME_AMAZON_ACL.equals(nameLower)) {
if (nameLower.startsWith("x-amz-") || "content-md5".equals(nameLower) || "content-type".equals(nameLower)) {
properties.put(name, webContext.getHeader(name));
}
}
Expand Down Expand Up @@ -872,8 +870,7 @@ private void startMultipartUpload(WebContext webContext, Bucket bucket, String i
Map<String, String> properties = Maps.newTreeMap();
for (String name : webContext.getRequest().headers().names()) {
String nameLower = name.toLowerCase();
if (nameLower.startsWith("x-amz-meta-") || "content-md5".equals(nameLower) || "content-type".equals(
nameLower) || HTTP_HEADER_NAME_AMAZON_ACL.equals(nameLower)) {
if (nameLower.startsWith("x-amz-") || "content-md5".equals(nameLower) || "content-type".equals(nameLower)) {
properties.put(name, webContext.getHeader(name));
response.addHeader(name, webContext.getHeader(name));
}
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/ninja/StoredObject.java
Expand Up @@ -22,6 +22,7 @@
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Properties;

Expand Down Expand Up @@ -181,11 +182,11 @@ public File getPropertiesFile() {
/**
* Returns all meta information stored along with the object.
* <p>
* This is the <tt>Content-MD5</tt>, <tt>Content-Type</tt> and any <tt>x-amz-meta-*</tt> header.
* These are the <tt>Content-MD5</tt>, <tt>Content-Type</tt> and any <tt>x-amz-*</tt> headers.
* <p>
* Internally, a {@link Properties} file is loaded from disk and converted to a {@link Map}.
*
* @return name value pairs representing all properties stored for this object, or an empty map if no properties
* @return name-value-pairs representing all properties stored for this object, or an empty map if no properties
* could be read
*/
public Map<String, String> getProperties() {
Expand All @@ -203,6 +204,16 @@ public Map<String, String> getProperties() {
return map;
}

/**
* Returns a sorted list of all property names.
*
* @return a list of property names
* @see #getProperties()
*/
public List<String> getPropertyNames() {
return getProperties().keySet().stream().sorted(String::compareToIgnoreCase).toList();
}

/**
* Stores the given meta information for this object.
* <p>
Expand Down
43 changes: 41 additions & 2 deletions src/main/resources/templates/bucket.html.pasta
Expand Up @@ -79,8 +79,47 @@
<div class="text-muted small">@obj.getLastModified()</div>
</td>
<td class="text-right pr-0">
<t:deleteButton
url="@apply('/ui/%s/%s?delete', bucket.getEncodedName(), obj.getEncodedKey())"/>
<i:local name="modalId"
value="generateId('object_info_%s')"/>
<i:local name="propertyNames"
value="obj.getPropertyNames()"/>
<i:local name="properties"
value="obj.getProperties()"/>
<t:modal name="@modalId"
title="@obj.getKey()"
cancel="Close"
class="modal-lg modal-dialog-centered">
<div class="text-left"
style="margin-bottom: -1rem;">
<i:if test="properties.isEmpty()">
<p class="text-muted">
(No properties)
</p>
</i:if>
<i:for type="ninja.StoredObject"
var="propertyName"
items="propertyNames">
<i:local name="propertyValue"
value="properties.get(propertyName)"/>
<p>
<span class="text-muted">
@propertyName
</span>
<br/>
<span>
@propertyValue
</span>
</p>
</i:for>
</div>
</t:modal>
<t:additionalActions label="Actions">
<t:dropdownItem url="@apply('javascript:$(document.querySelector(\'#%s\')).modal()', modalId)"
icon="fa-solid fa-circle-info"
label="Properties"/>
<t:dropdownDeleteItem
url="@apply('/ui/%s/%s?delete', bucket.getEncodedName(), obj.getEncodedKey())"/>
</t:additionalActions>
</td>
</tr>
</i:for>
Expand Down
14 changes: 13 additions & 1 deletion src/main/resources/templates/index.html.pasta
Expand Up @@ -168,7 +168,19 @@
</i:if>
</td>
<td class="text-right pr-0">
<t:deleteButton url="@apply('/ui/%s?delete', bucket.getEncodedName())"/>
<t:additionalActions label="Actions">
<i:if test="bucket.isPrivate()">
<t:dropdownItem url="@apply('/ui/%s?make-public&return=%%2Fui', bucket.getEncodedName())"
icon="fa-solid fa-lock-open"
label="Make public" />
<i:else>
<t:dropdownItem url="@apply('/ui/%s?make-private&return=%%2Fui', bucket.getEncodedName())"
icon="fa-solid fa-lock"
label="Make private" />
</i:else>
</i:if>
<t:dropdownDeleteItem url="@apply('/ui/%s?delete', bucket.getEncodedName())" />
</t:additionalActions>
</td>
</tr>
</i:for>
Expand Down

0 comments on commit b610623

Please sign in to comment.