fix #2657 tag support

This commit is contained in:
Shinsuke Sugaya 2022-05-26 10:48:41 +09:00
parent 029fefa48e
commit 27e51af84e
15 changed files with 390 additions and 58 deletions

View file

@ -21,6 +21,7 @@ import java.io.InputStream;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -45,12 +46,14 @@ import org.lastaflute.web.ruts.process.ActionRuntime;
import org.lastaflute.web.servlet.request.stream.WrittenStreamOut;
import io.minio.GetObjectArgs;
import io.minio.GetObjectTagsArgs;
import io.minio.ListObjectsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.Result;
import io.minio.SetObjectTagsArgs;
import io.minio.errors.ErrorResponseException;
import io.minio.messages.Item;
@ -85,10 +88,7 @@ public class AdminStorageAction extends FessAdminAction {
@Secured({ ROLE, ROLE + VIEW })
public ActionResponse list(final OptionalThing<String> id) {
saveToken();
if (id.isPresent() && id.get() != null) {
return asListHtml(decodePath(id.get()));
}
return redirect(getClass());
return id.filter(StringUtil::isNotBlank).map(s -> asListHtml(decodePath(s))).orElse(redirect(getClass()));
}
@Execute
@ -116,12 +116,12 @@ public class AdminStorageAction extends FessAdminAction {
@Execute
@Secured({ ROLE, ROLE + VIEW })
public ActionResponse download(final String id) {
final String[] values = decodeId(id);
if (StringUtil.isEmpty(values[1])) {
throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(encodeId(values[0])));
final PathInfo pi = convertToItem(id);
if (StringUtil.isEmpty(pi.getName())) {
throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(encodeId(pi.getPath())));
}
final StreamResponse response = new StreamResponse(StringUtil.EMPTY);
final String name = values[1];
final String name = pi.getName();
final String encodedName = URLEncoder.encode(name, Constants.UTF_8_CHARSET).replace("+", "%20");
response.header("Content-Disposition", "attachment; filename=\"" + name + "\"; filename*=utf-8''" + encodedName);
response.header("Pragma", "no-cache");
@ -130,13 +130,13 @@ public class AdminStorageAction extends FessAdminAction {
response.contentTypeOctetStream();
return response.stream(out -> {
try {
downloadObject(getObjectName(values[0], values[1]), out);
downloadObject(getObjectName(pi.getPath(), pi.getName()), out);
} catch (final StorageException e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to download {}", values[1], e);
logger.debug("Failed to download {}", pi.getName(), e);
}
throwValidationError(messages -> messages.addErrorsStorageFileDownloadFailure(GLOBAL, values[1]),
() -> asListHtml(encodeId(values[0])));
throwValidationError(messages -> messages.addErrorsStorageFileDownloadFailure(GLOBAL, pi.getName()),
() -> asListHtml(encodeId(pi.getPath())));
}
});
}
@ -144,20 +144,20 @@ public class AdminStorageAction extends FessAdminAction {
@Execute
@Secured({ ROLE })
public HtmlResponse delete(final String id) {
final String[] values = decodeId(id);
if (StringUtil.isEmpty(values[1])) {
throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(encodeId(values[0])));
final PathInfo pi = convertToItem(id);
if (StringUtil.isEmpty(pi.getName())) {
throwValidationError(messages -> messages.addErrorsStorageFileNotFound(GLOBAL), () -> asListHtml(encodeId(pi.getPath())));
}
final String objectName = getObjectName(values[0], values[1]);
final String objectName = getObjectName(pi.getPath(), pi.getName());
try {
deleteObject(objectName);
} catch (final StorageException e) {
logger.debug("Failed to delete {}", values[1], e);
throwValidationError(messages -> messages.addErrorsFailedToDeleteFile(GLOBAL, values[1]),
() -> asListHtml(encodeId(values[0])));
logger.debug("Failed to delete {}", pi.getName(), e);
throwValidationError(messages -> messages.addErrorsFailedToDeleteFile(GLOBAL, pi.getName()),
() -> asListHtml(encodeId(pi.getPath())));
}
saveInfo(messages -> messages.addSuccessDeleteFile(GLOBAL, values[1]));
return redirectWith(getClass(), moreUrl("list/" + encodeId(values[0])));
saveInfo(messages -> messages.addSuccessDeleteFile(GLOBAL, pi.getName()));
return redirectWith(getClass(), moreUrl("list/" + encodeId(pi.getPath())));
}
@Execute
@ -170,6 +170,62 @@ public class AdminStorageAction extends FessAdminAction {
return redirectWith(getClass(), moreUrl("list/" + encodeId(getObjectName(form.path, form.name))));
}
@Execute
@Secured({ ROLE })
public HtmlResponse editTags(final TagForm form) {
validate(form, messages -> {}, () -> asEditTagsHtml(form.path, form.name));
saveToken();
return asEditTagsHtml(form.path, form.name);
}
@Execute
@Secured({ ROLE })
public HtmlResponse updateTags(final TagForm form) {
validate(form, messages -> {}, () -> asEditTagsHtml(form.path, form.name));
final String objectName = getObjectName(form.path, form.name);
try {
updateObjectTags(objectName, form.tags);
} catch (final StorageException e) {
logger.debug("Failed to update tags in {}", form.path, e);
throwValidationError(messages -> messages.addErrorsStorageTagsUpdateFailure(GLOBAL, objectName),
() -> asEditTagsHtml(form.path, form.name));
}
saveInfo(messages -> messages.addSuccessUpdateStorageTags(GLOBAL, objectName));
return redirectWith(getClass(), moreUrl("list/" + encodeId(form.path)));
}
public static void updateObjectTags(final String objectName, final Map<String, String> tagItems) {
final Map<String, String> tags = new HashMap<>();
tagItems.keySet().stream().filter(s -> s.startsWith("name")).forEach(nameKey -> {
final String valueKey = nameKey.replace("name", "value");
final String name = tagItems.get(nameKey);
if (StringUtil.isNotBlank(name)) {
tags.put(name, tagItems.get(valueKey));
}
});
if (logger.isDebugEnabled()) {
logger.debug("tags: {} -> {}", tagItems, tags);
}
try {
final FessConfig fessConfig = ComponentUtil.getFessConfig();
final SetObjectTagsArgs args =
SetObjectTagsArgs.builder().bucket(fessConfig.getStorageBucket()).object(objectName).tags(tags).build();
createClient(fessConfig).setObjectTags(args);
} catch (final Exception e) {
throw new StorageException("Failed to update tags for " + objectName, e);
}
}
public static Map<String, String> getObjectTags(final String objectName) {
try {
final FessConfig fessConfig = ComponentUtil.getFessConfig();
final GetObjectTagsArgs args = GetObjectTagsArgs.builder().bucket(fessConfig.getStorageBucket()).object(objectName).build();
return createClient(fessConfig).getObjectTags(args).get();
} catch (final Exception e) {
throw new StorageException("Failed to get tags from " + objectName, e);
}
}
public static void uploadObject(final String objectName, final MultipartFormFile uploadFile) {
try (final InputStream in = uploadFile.getInputStream()) {
final FessConfig fessConfig = ComponentUtil.getFessConfig();
@ -214,7 +270,8 @@ public class AdminStorageAction extends FessAdminAction {
public static List<Map<String, Object>> getFileItems(final String prefix) {
final FessConfig fessConfig = ComponentUtil.getFessConfig();
final ArrayList<Map<String, Object>> list = new ArrayList<>();
final List<Map<String, Object>> list = new ArrayList<>();
final List<Map<String, Object>> fileList = new ArrayList<>();
try {
final MinioClient minioClient = createClient(fessConfig);
final ListObjectsArgs args = ListObjectsArgs.builder().bucket(fessConfig.getStorageBucket())
@ -225,15 +282,18 @@ public class AdminStorageAction extends FessAdminAction {
final Item item = result.get();
final String objectName = item.objectName();
map.put("id", encodeId(objectName));
map.put("path", prefix);
map.put("name", getName(objectName));
map.put("hashCode", item.hashCode());
map.put("size", item.size());
map.put("directory", item.isDir());
if (!item.isDir()) {
map.put("lastModified", item.lastModified());
fileList.add(map);
} else {
list.add(map);
}
list.add(map);
if (list.size() > fessConfig.getStorageMaxItemsInPageAsInteger()) {
if (list.size() + fileList.size() > fessConfig.getStorageMaxItemsInPageAsInteger()) {
break;
}
}
@ -256,6 +316,7 @@ public class AdminStorageAction extends FessAdminAction {
logger.debug("Failed to access {}", fessConfig.getStorageEndpoint(), e);
}
}
list.addAll(fileList);
return list;
}
@ -268,25 +329,25 @@ public class AdminStorageAction extends FessAdminAction {
}
public static String decodePath(final String id) {
final String[] values = decodeId(id);
if (StringUtil.isEmpty(values[0]) && StringUtil.isEmpty(values[1])) {
final PathInfo pi = convertToItem(id);
if (StringUtil.isEmpty(pi.getPath()) && StringUtil.isEmpty(pi.getName())) {
return StringUtil.EMPTY;
}
if (StringUtil.isEmpty(values[0])) {
return values[1];
if (StringUtil.isEmpty(pi.getPath())) {
return pi.getName();
}
return values[0] + "/" + values[1];
return pi.getPath() + "/" + pi.getName();
}
public static String[] decodeId(final String id) {
final String value = urlDecode(urlDecode(id));
public static PathInfo convertToItem(final String id) {
final String value = decodeId(id);
final String[] values = split(value, "/").get(stream -> stream.filter(StringUtil::isNotEmpty).toArray(n -> new String[n]));
if (values.length == 0) {
// invalid?
return new String[] { StringUtil.EMPTY, StringUtil.EMPTY };
return new PathInfo(StringUtil.EMPTY, StringUtil.EMPTY);
}
if (values.length == 1) {
return new String[] { StringUtil.EMPTY, values[0] };
return new PathInfo(StringUtil.EMPTY, values[0]);
}
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < values.length - 1; i++) {
@ -295,7 +356,7 @@ public class AdminStorageAction extends FessAdminAction {
}
buf.append(values[i]);
}
return new String[] { buf.toString(), values[values.length - 1] };
return new PathInfo(buf.toString(), values[values.length - 1]);
}
protected static String createParentId(final String prefix) {
@ -311,7 +372,7 @@ public class AdminStorageAction extends FessAdminAction {
}
buf.append(values[i]);
}
return urlEncode(buf.toString());
return encodeId(buf.toString());
}
return StringUtil.EMPTY;
}
@ -325,7 +386,7 @@ public class AdminStorageAction extends FessAdminAction {
}
buf.append(s);
final Map<String, String> map = new HashMap<>();
map.put("id", urlEncode(buf.toString()));
map.put("id", encodeId(buf.toString()));
map.put("name", s);
list.add(map);
}));
@ -340,6 +401,7 @@ public class AdminStorageAction extends FessAdminAction {
return getPathPrefix(path) + name;
}
@Deprecated
protected static String urlEncode(final String str) {
if (str == null) {
return StringUtil.EMPTY;
@ -347,6 +409,7 @@ public class AdminStorageAction extends FessAdminAction {
return URLEncoder.encode(str, Constants.UTF_8_CHARSET);
}
@Deprecated
protected static String urlDecode(final String str) {
if (str == null) {
return StringUtil.EMPTY;
@ -355,18 +418,63 @@ public class AdminStorageAction extends FessAdminAction {
}
protected static String encodeId(final String objectName) {
return urlEncode(urlEncode(objectName));
if (objectName == null) {
return StringUtil.EMPTY;
}
return new String(Base64.getUrlEncoder().encode(objectName.getBytes(Constants.UTF_8_CHARSET)), Constants.UTF_8_CHARSET);
}
private HtmlResponse asListHtml(final String prefix) {
protected static String decodeId(final String id) {
if (id == null) {
return StringUtil.EMPTY;
}
return new String(Base64.getUrlDecoder().decode(id.getBytes(Constants.UTF_8_CHARSET)), Constants.UTF_8_CHARSET);
}
private HtmlResponse asListHtml(final String path) {
return asHtml(path_AdminStorage_AdminStorageJsp).useForm(ItemForm.class).renderWith(data -> {
RenderDataUtil.register(data, "endpoint", fessConfig.getStorageEndpoint());
RenderDataUtil.register(data, "bucket", fessConfig.getStorageBucket());
RenderDataUtil.register(data, "path", prefix);
RenderDataUtil.register(data, "pathItems", createPathItems(prefix));
RenderDataUtil.register(data, "parentId", createParentId(prefix));
RenderDataUtil.register(data, "fileItems", getFileItems(prefix));
RenderDataUtil.register(data, "path", path);
RenderDataUtil.register(data, "pathItems", createPathItems(path));
RenderDataUtil.register(data, "parentId", createParentId(path));
RenderDataUtil.register(data, "fileItems", getFileItems(path));
});
}
private HtmlResponse asEditTagsHtml(final String path, final String name) {
return asHtml(path_AdminStorage_AdminStorageTagEditJsp).renderWith(data -> {
RenderDataUtil.register(data, "endpoint", fessConfig.getStorageEndpoint());
RenderDataUtil.register(data, "bucket", fessConfig.getStorageBucket());
RenderDataUtil.register(data, "pathItems", createPathItems(path));
RenderDataUtil.register(data, "parentId", encodeId(path));
RenderDataUtil.register(data, "path", path);
RenderDataUtil.register(data, "name", name);
final Map<String, String> tags = new HashMap<>();
getObjectTags(getObjectName(path, name)).entrySet().forEach(e -> {
int index = tags.size() / 2 + 1;
tags.put("name" + index, e.getKey());
tags.put("value" + index, e.getValue());
});
RenderDataUtil.register(data, "savedTags", tags);
});
}
public static class PathInfo {
private final String path;
private final String name;
public PathInfo(final String path, final String name) {
this.path = path;
this.name = name;
}
public String getPath() {
return path;
}
public String getName() {
return name;
}
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright 2012-2022 CodeLibs Project and the Others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.codelibs.fess.app.web.admin.storage;
import java.util.HashMap;
import java.util.Map;
import javax.validation.constraints.Size;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
public class TagForm {
@Required
public String path;
@Required
@Size(max = 100)
public String name;
public Map<String, String> tags = new HashMap<>();
}

View file

@ -15,7 +15,7 @@
*/
package org.codelibs.fess.app.web.api.admin.storage;
import static org.codelibs.fess.app.web.admin.storage.AdminStorageAction.decodeId;
import static org.codelibs.fess.app.web.admin.storage.AdminStorageAction.convertToItem;
import static org.codelibs.fess.app.web.admin.storage.AdminStorageAction.decodePath;
import static org.codelibs.fess.app.web.admin.storage.AdminStorageAction.deleteObject;
import static org.codelibs.fess.app.web.admin.storage.AdminStorageAction.downloadObject;
@ -29,6 +29,7 @@ import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.codelibs.core.lang.StringUtil;
import org.codelibs.fess.app.web.admin.storage.AdminStorageAction.PathInfo;
import org.codelibs.fess.app.web.api.ApiResult;
import org.codelibs.fess.app.web.api.admin.FessApiAdminAction;
import org.codelibs.fess.exception.ResultOffsetExceededException;
@ -62,18 +63,18 @@ public class ApiAdminStorageAction extends FessApiAdminAction {
// GET /api/admin/storage/download/{id}/
@Execute
public StreamResponse get$download(final String id) {
final String[] values = decodeId(id);
if (StringUtil.isEmpty(values[1])) {
final PathInfo pi = convertToItem(id);
if (StringUtil.isEmpty(pi.getName())) {
throwValidationErrorApi(messages -> messages.addErrorsStorageFileNotFound(GLOBAL));
}
return asStream(values[1]).contentTypeOctetStream().stream(out -> {
return asStream(pi.getName()).contentTypeOctetStream().stream(out -> {
try {
downloadObject(getObjectName(values[0], values[1]), out);
downloadObject(getObjectName(pi.getPath(), pi.getName()), out);
} catch (final StorageException e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to download {}", id, e);
}
throwValidationErrorApi(messages -> messages.addErrorsStorageFileDownloadFailure(GLOBAL, values[1]));
throwValidationErrorApi(messages -> messages.addErrorsStorageFileDownloadFailure(GLOBAL, pi.getName()));
}
});
}
@ -81,20 +82,20 @@ public class ApiAdminStorageAction extends FessApiAdminAction {
// DELETE /api/admin/storage/delete/{id}/
@Execute
public JsonResponse<ApiResult> delete$delete(final String id) {
final String[] values = decodeId(id);
if (StringUtil.isEmpty(values[1])) {
final PathInfo pi = convertToItem(id);
if (StringUtil.isEmpty(pi.getName())) {
throwValidationErrorApi(messages -> messages.addErrorsStorageAccessError(GLOBAL, "id is invalid"));
}
final String objectName = getObjectName(values[0], values[1]);
final String objectName = getObjectName(pi.getPath(), pi.getName());
try {
deleteObject(objectName);
saveInfo(messages -> messages.addSuccessDeleteFile(GLOBAL, values[1]));
saveInfo(messages -> messages.addSuccessDeleteFile(GLOBAL, pi.getName()));
return asJson(new ApiResult.ApiResponse().status(ApiResult.Status.OK).result());
} catch (final StorageException e) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to delete {}", id, e);
}
throwValidationErrorApi(messages -> messages.addErrorsFailedToDeleteFile(GLOBAL, values[1]));
throwValidationErrorApi(messages -> messages.addErrorsFailedToDeleteFile(GLOBAL, pi.getName()));
}
return null;
}

View file

@ -355,6 +355,9 @@ public interface FessHtmlPath {
/** The path of the HTML: /admin/storage/admin_storage.jsp */
HtmlNext path_AdminStorage_AdminStorageJsp = new HtmlNext("/admin/storage/admin_storage.jsp");
/** The path of the HTML: /admin/storage/admin_storage_tag_edit.jsp */
HtmlNext path_AdminStorage_AdminStorageTagEditJsp = new HtmlNext("/admin/storage/admin_storage_tag_edit.jsp");
/** The path of the HTML: /admin/suggest/admin_suggest.jsp */
HtmlNext path_AdminSuggest_AdminSuggestJsp = new HtmlNext("/admin/suggest/admin_suggest.jsp");

View file

@ -3162,6 +3162,18 @@ public class FessLabels extends UserMessages {
/** The key of the message: Download */
public static final String LABELS_storage_button_download = "{labels.storage_button_download}";
/** The key of the message: Tags */
public static final String LABELS_storage_button_tags = "{labels.storage_button_tags}";
/** The key of the message: Tag: */
public static final String LABELS_storage_title_tag = "{labels.storage_title_tag}";
/** The key of the message: Tag Key */
public static final String LABELS_storage_tag_key = "{labels.storage_tag_key}";
/** The key of the message: Tag Value */
public static final String LABELS_storage_tag_value = "{labels.storage_tag_value}";
/** The key of the message: Your password needs to be updated. */
public static final String LABELS_LOGIN_NEWPASSWORD = "{labels.login.newpassword}";

View file

@ -434,6 +434,9 @@ public class FessMessages extends FessLabels {
/** The key of the message: Directory name is invalid. */
public static final String ERRORS_storage_directory_name_is_invalid = "{errors.storage_directory_name_is_invalid}";
/** The key of the message: Failed to update tags for {0} */
public static final String ERRORS_storage_tags_update_failure = "{errors.storage_tags_update_failure}";
/** The key of the message: Updated parameters. */
public static final String SUCCESS_update_crawler_params = "{success.update_crawler_params}";
@ -524,6 +527,9 @@ public class FessMessages extends FessLabels {
/** The key of the message: Logged out. */
public static final String SUCCESS_sso_logout = "{success.sso_logout}";
/** The key of the message: Updated tags for {0}. */
public static final String SUCCESS_update_storage_tags = "{success.update_storage_tags}";
/** The key of the message: Created data. */
public static final String SUCCESS_crud_create_crud_table = "{success.crud_create_crud_table}";
@ -2506,6 +2512,21 @@ public class FessMessages extends FessLabels {
return this;
}
/**
* Add the created action message for the key 'errors.storage_tags_update_failure' with parameters.
* <pre>
* message: Failed to update tags for {0}
* </pre>
* @param property The property name for the message. (NotNull)
* @param arg0 The parameter arg0 for message. (NotNull)
* @return this. (NotNull)
*/
public FessMessages addErrorsStorageTagsUpdateFailure(String property, String arg0) {
assertPropertyNotNull(property);
add(property, new UserMessage(ERRORS_storage_tags_update_failure, arg0));
return this;
}
/**
* Add the created action message for the key 'success.update_crawler_params' with parameters.
* <pre>
@ -2935,6 +2956,21 @@ public class FessMessages extends FessLabels {
return this;
}
/**
* Add the created action message for the key 'success.update_storage_tags' with parameters.
* <pre>
* message: Updated tags for {0}.
* </pre>
* @param property The property name for the message. (NotNull)
* @param arg0 The parameter arg0 for message. (NotNull)
* @return this. (NotNull)
*/
public FessMessages addSuccessUpdateStorageTags(String property, String arg0) {
assertPropertyNotNull(property);
add(property, new UserMessage(SUCCESS_update_storage_tags, arg0));
return this;
}
/**
* Add the created action message for the key 'success.crud_create_crud_table' with parameters.
* <pre>

View file

@ -1076,7 +1076,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. true */
String SMB_ROLE_FROM_FILE = "smb.role.from.file";
/** The key of the configuration. e.g. 1,2,4:2 */
/** The key of the configuration. e.g. 1,2,4:2,5:1 */
String SMB_AVAILABLE_SID_TYPES = "smb.available.sid.types";
/** The key of the configuration. e.g. true */
@ -5011,7 +5011,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/**
* Get the value for the key 'smb.available.sid.types'. <br>
* The value is, e.g. 1,2,4:2 <br>
* The value is, e.g. 1,2,4:2,5:1 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSmbAvailableSidTypes();
@ -10449,7 +10449,7 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
defaultMap.put(FessConfig.QUERY_FACET_QUERIES,
"labels.facet_timestamp_title:labels.facet_timestamp_1day=timestamp:[now/d-1d TO *]\tlabels.facet_timestamp_1week=timestamp:[now/d-7d TO *]\tlabels.facet_timestamp_1month=timestamp:[now/d-1M TO *]\tlabels.facet_timestamp_1year=timestamp:[now/d-1y TO *]\nlabels.facet_contentLength_title:labels.facet_contentLength_10k=content_length:[0 TO 9999]\tlabels.facet_contentLength_10kto100k=content_length:[10000 TO 99999]\tlabels.facet_contentLength_100kto500k=content_length:[100000 TO 499999]\tlabels.facet_contentLength_500kto1m=content_length:[500000 TO 999999]\tlabels.facet_contentLength_1m=content_length:[1000000 TO *]\nlabels.facet_filetype_title:labels.facet_filetype_html=filetype:html\tlabels.facet_filetype_word=filetype:word\tlabels.facet_filetype_excel=filetype:excel\tlabels.facet_filetype_powerpoint=filetype:powerpoint\tlabels.facet_filetype_odt=filetype:odt\tlabels.facet_filetype_ods=filetype:ods\tlabels.facet_filetype_odp=filetype:odp\tlabels.facet_filetype_pdf=filetype:pdf\tlabels.facet_filetype_txt=filetype:txt\tlabels.facet_filetype_others=filetype:others\n");
defaultMap.put(FessConfig.SMB_ROLE_FROM_FILE, "true");
defaultMap.put(FessConfig.SMB_AVAILABLE_SID_TYPES, "1,2,4:2");
defaultMap.put(FessConfig.SMB_AVAILABLE_SID_TYPES, "1,2,4:2,5:1");
defaultMap.put(FessConfig.FILE_ROLE_FROM_FILE, "true");
defaultMap.put(FessConfig.FTP_ROLE_FROM_FILE, "true");
defaultMap.put(FessConfig.INDEX_BACKUP_TARGETS,

View file

@ -1045,6 +1045,10 @@ labels.storage_bucket_name=Bucket Name
labels.storage_file=File
labels.storage_folder_name=Folder Name
labels.storage_button_download=Download
labels.storage_button_tags=Tags
labels.storage_title_tag=Tag:
labels.storage_tag_key=Tag Key
labels.storage_tag_value=Tag Value
labels.login.newpassword=Your password needs to be updated.
labels.login.placeholder_new_password=New Password
labels.login.placeholder_confirm_new_password=Confirm New Password

View file

@ -1045,6 +1045,10 @@ labels.storage_bucket_name=Bucket Name
labels.storage_file=File
labels.storage_folder_name=Folder Name
labels.storage_button_download=Download
labels.storage_button_tags=Tags
labels.storage_title_tag=Tag:
labels.storage_tag_key=Tag Key
labels.storage_tag_value=Tag Value
labels.login.newpassword=Your password needs to be updated.
labels.login.placeholder_new_password=New Password
labels.login.placeholder_confirm_new_password=Confirm New Password

View file

@ -1045,6 +1045,10 @@ labels.storage_bucket_name=バケット名
labels.storage_file=ファイル
labels.storage_folder_name=フォルダ名
labels.storage_button_download=ダウンロード
labels.storage_button_tags=タグ
labels.storage_title_tag=タグ:
labels.storage_tag_key=タグキー
labels.storage_tag_value=タグ値
labels.login.newpassword=パスワードを更新する必要があります
labels.login.placeholder_new_password=新しいパスワード
labels.login.placeholder_confirm_new_password=新しいパスワードの確認

View file

@ -170,6 +170,7 @@ errors.storage_file_download_failure=Failed to download {0}.
errors.storage_access_error=Storage access error: {0}
errors.storage_no_upload_file=Upload file is required.
errors.storage_directory_name_is_invalid=Directory name is invalid.
errors.storage_tags_update_failure=Failed to update tags for {0}
success.update_crawler_params=Updated parameters.
success.delete_doc_from_index=Started a process to delete the document from index.
@ -201,6 +202,7 @@ success.install_plugin=Installing {0} plugin.
success.delete_plugin=Deleting {0} plugin.
success.upload_file_to_storage=Uploaded {0}
success.sso_logout=Logged out.
success.update_storage_tags=Updated tags for {0}.
success.crud_create_crud_table=Created data.
success.crud_update_crud_table=Updated data.

View file

@ -166,6 +166,7 @@ errors.storage_file_download_failure=Failed to download {0}.
errors.storage_access_error=Storage access error: {0}
errors.storage_no_upload_file=Upload file is required.
errors.storage_directory_name_is_invalid=Directory name is invalid.
errors.storage_tags_update_failure=Failed to update tags for {0}
success.update_crawler_params=Updated parameters.
success.delete_doc_from_index=Started a process to delete the document from index.
@ -197,6 +198,7 @@ success.install_plugin=Installing {0} plugin.
success.delete_plugin=Deleting {0} plugin.
success.upload_file_to_storage=Uploaded {0}
success.sso_logout=Logged out.
success.update_storage_tags=Updated tags for {0}.
success.crud_create_crud_table=Created data.
success.crud_update_crud_table=Updated data.

View file

@ -159,6 +159,7 @@ errors.storage_file_download_failure={0} のダウンロードに失敗しまし
errors.storage_access_error=ストレージアクセスエラー: {0}
errors.storage_no_upload_file=アップロードするファイルを指定してください。
errors.storage_directory_name_is_invalid=ディレクトリ名が正しくありません。
errors.storage_tags_update_failure={0}のタグの更新に失敗しました。
success.update_crawler_params = パラメータを更新しました。
success.delete_doc_from_index = インデックスから文書を削除するプロセスを開始しました。
@ -190,6 +191,7 @@ success.install_plugin=プラグイン {0} をインストールしています
success.delete_plugin=プラグイン {0} を削除しています。
success.upload_file_to_storage={0} をアップロードしました。
success.sso_logout=ログアウトしました。
success.update_storage_tags={0}のタグを更新しました。
success.crud_create_crud_table = データを作成しました。
success.crud_update_crud_table = データを更新しました。

View file

@ -155,7 +155,7 @@
</thead>
<tbody>
<c:if test="${not empty path and not empty parentId}">
<tr data-href="${contextPath}/admin/storage/list/${f:u(data.parentId)}/">
<tr data-href="${contextPath}/admin/storage/list/${f:u(data.parentId)}/">
<td>..</td>
<td></td>
<td></td>
@ -163,7 +163,7 @@
</tr>
</c:if>
<c:if test="${not empty path and empty parentId}">
<tr data-href="${contextPath}/admin/storage/">
<tr data-href="${contextPath}/admin/storage/">
<td>..</td>
<td></td>
<td></td>
@ -199,6 +199,13 @@
<la:message key="labels.storage_button_download"/>
</a>
<c:if test="${editable}">
<a class="btn btn-primary btn-xs" role="button" name="editTags"
href="${contextPath}/admin/storage/editTags?path=${f:u(data.path)}&name=${f:u(data.name)}"
value="<la:message key="labels.storage_button_tags" />"
>
<em class="fa fa-tags"></em>
<la:message key="labels.storage_button_tags"/>
</a>
<button type="button" class="btn btn-danger btn-xs"
name="delete" data-toggle="modal"
data-target="#confirmToDelete-${f:h(data.hashCode)}"

View file

@ -0,0 +1,111 @@
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><la:message key="labels.admin_brand_title" /> | <la:message key="labels.storage_configuration" /></title>
<jsp:include page="/WEB-INF/view/common/admin/head.jsp"></jsp:include>
</head>
<body class="hold-transition sidebar-mini">
<div class="wrapper">
<jsp:include page="/WEB-INF/view/common/admin/header.jsp"></jsp:include>
<jsp:include page="/WEB-INF/view/common/admin/sidebar.jsp">
<jsp:param name="menuCategoryType" value="system" />
<jsp:param name="menuType" value="storage" />
</jsp:include>
<div class="content-wrapper">
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1>
<la:message key="labels.storage_configuration" />
</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><la:link href="/admin/storage/">
<la:message key="labels.crud_link_list" />
</la:link></li>
<li class="breadcrumb-item active"><la:message key="labels.crud_link_edit" /></li>
</ol>
</div>
</div>
</div>
</div>
<section class="content">
<la:form action="/admin/storage/">
<input type="hidden" name="path" value="${f:h(path)}">
<input type="hidden" name="name" value="${f:h(name)}">
<div class="row">
<div class="col-md-12">
<div class="card card-outline card-success">
<div class="card-header">
<h3 class="card-title">
<la:message key="labels.storage_title_tag" />
<c:if test="${path!=null}">${f:h(path)}/</c:if>${f:h(name)}
</h3>
</div>
<div class="card-body">
<div>
<la:info id="msg" message="true">
<div class="alert alert-info">${msg}</div>
</la:info>
<la:errors property="_global" />
</div>
<div class="form-group row">
<div class="col-sm-6">
<la:message key="labels.storage_tag_key" />
</div>
<div class="col-sm-6">
<la:message key="labels.storage_tag_value" />
</div>
</div>
<c:forEach var="position" begin="1" end="${savedTags.size()/2}">
<c:set var="nameKey">name${position}</c:set>
<c:set var="valueKey">value${position}</c:set>
<div class="form-group row">
<div class="col-sm-6">
<input type="text" id="tags.${f:h(nameKey)}" name="tags.${f:h(nameKey)}" value="${f:h(savedTags.get(nameKey))}" class="form-control" placeholder="Name" >
</div>
<div class="col-sm-6">
<input type="text" id="tags.${f:h(valueKey)}" name="tags.${f:h(valueKey)}" value="${f:h(savedTags.get(valueKey))}" class="form-control" placeholder="Value" >
</div>
</div>
</c:forEach>
<c:set var="nameKey">name${Double.valueOf(savedTags.size()/2).intValue()+1}</c:set>
<c:set var="valueKey">value${Double.valueOf(savedTags.size()/2).intValue()+1}</c:set>
<div class="form-group row">
<div class="col-sm-6">
<input type="text" id="tags.${f:h(nameKey)}" name="tags.${f:h(nameKey)}" value="${f:h(savedTags.get(nameKey))}" class="form-control" placeholder="Name" >
</div>
<div class="col-sm-6">
<input type="text" id="tags.${f:h(valueKey)}" name="tags.${f:h(valueKey)}" value="${f:h(savedTags.get(valueKey))}" class="form-control" placeholder="Value" >
</div>
</div>
</div>
<div class="card-footer">
<la:link styleClass="btn btn-default" href="list/${parentId}">
<em class="fa fa-arrow-circle-left"></em>
<la:message key="labels.crud_button_back" />
</la:link>
<c:if test="${editable}">
<button type="submit" class="btn btn-success" name="updateTags"
value="<la:message key="labels.crud_button_update" />"
>
<em class="fa fa-pencil-alt"></em>
<la:message key="labels.crud_button_update" />
</button>
</c:if>
</div>
</div>
</div>
</div>
</la:form>
</section>
</div>
<jsp:include page="/WEB-INF/view/common/admin/footer.jsp"></jsp:include>
</div>
<jsp:include page="/WEB-INF/view/common/admin/foot.jsp"></jsp:include>
</body>
</html>