AppController.java
/*
* Copyright 2020 Global Crop Diversity Trust
*
* 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.gringlobal.api.v1.impl;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.gringlobal.api.exception.NotFoundElement;
import org.gringlobal.api.v1.ApiBaseController;
import org.gringlobal.api.v1.CRUDController;
import org.gringlobal.api.v1.Pagination;
import org.gringlobal.custom.elasticsearch.SearchException;
import org.gringlobal.model.AppSetting;
import org.gringlobal.model.QAppSetting;
import org.gringlobal.model.SysLang;
import org.gringlobal.oauth2.server.TenantRepository;
import org.gringlobal.persistence.AppResourceRepository.AppResourceInfo;
import org.gringlobal.service.AppSettingsService;
import org.gringlobal.service.CodeValueService;
import org.gringlobal.service.CodeValueTranslationService.TranslatedCodeValue;
import org.gringlobal.service.LanguageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.querydsl.core.types.OrderSpecifier;
import io.swagger.v3.oas.annotations.Operation;
import org.springdoc.api.annotations.ParameterObject;
import io.swagger.v3.oas.annotations.tags.Tag;
@RestController("appConfigApi1")
@RequestMapping(AppController.API_URL)
@PreAuthorize("isAuthenticated()")
@Tag(name = AppController.API_TAG)
@Slf4j
public class AppController extends ApiBaseController {
public static final String API_TAG = "Application";
/** The Constant API_URL. */
public static final String API_URL = ApiBaseController.APIv1_BASE + "/app";
@Autowired
private AppSettingsService settingsService;
@Autowired
private CodeValueService codeValueService;
@Autowired
private LanguageService languageService;
@Autowired
private TenantRepository oauthTenantRegistrationRepository;
@GetMapping(value = "/server-info", produces = { MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> getServerInfo() throws SearchException {
var serverInfo = new HashMap<String, Object>();
serverInfo.put("time.timezone", TimeZone.getDefault().getDisplayName());
serverInfo.put("time.zoneId", ZoneId.systemDefault().toString());
serverInfo.put("time.zoneOffset", ZoneOffset.systemDefault().toString());
serverInfo.put("time.current.offsetDateTime", OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
serverInfo.put("time.current.localDateTime", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
serverInfo.put("time.current.zonedDateTime", ZonedDateTime.now().format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
return serverInfo;
}
@GetMapping(value = "/codes", produces = { MediaType.APPLICATION_JSON_VALUE })
public LookupMap<String, String, TranslatedCodeValue> codeValuesList() throws SearchException {
List<TranslatedCodeValue> codeInfos = codeValueService.listFiltered(null, Pageable.ofSize(Integer.MAX_VALUE)).getContent();
LookupMap<String, String, TranslatedCodeValue> l10n = new LookupMap<>();
codeInfos.forEach(ci -> {
l10n.add(ci.entity.getGroupName(), ci.entity.getValue(), ci);
});
return l10n;
}
@GetMapping(value = "/languages", produces = { MediaType.APPLICATION_JSON_VALUE })
public Iterable<SysLang> listLanguage() {
return languageService.listEnabledLanguages();
}
@GetMapping(value = "/resources/{appName}", produces = { MediaType.APPLICATION_JSON_VALUE })
public LookupMap<String, String, AppResourceInfo> appResourcesList(@PathVariable("appName") String appName) {
SysLang sysLang = languageService.getLanguage(LocaleContextHolder.getLocale());
LookupMap<String, String, AppResourceInfo> l10n = new LookupMap<>();
settingsService.listResources(appName, sysLang).forEach(appRes -> {
l10n.add(appRes.formName, appRes.resourceName, appRes);
});
if (l10n.size() == 0) {
throw new NotFoundElement("No resources for app " + appName);
}
return l10n;
}
@GetMapping(value = "/setting", produces = { MediaType.APPLICATION_JSON_VALUE })
@Operation(operationId = "getSettings", description = "Get settings by category and name", summary = "Get")
public List<AppSetting> getSettings(@RequestParam(value="categoryTag", required = false) final String categoryTag, @RequestParam(value="name") final String name) {
return settingsService.getSettings(categoryTag, name);
}
@GetMapping(value = "/client-registration", produces = { MediaType.APPLICATION_JSON_VALUE })
public Map<String, String> getClientRegistrations() {
var registrations = new HashMap<String, String>();
oauthTenantRegistrationRepository.forEach(registration -> registrations.put(registration.getRegistrationId(), registration.getClientName()));
return registrations;
}
public static class LookupMap<K1, K2, V> extends TreeMap<K1, Map<K2, V>> {
private static final long serialVersionUID = -533944504263416611L;
public V add(K1 key, K2 key2, V element) {
Map<K2, V> map = get(key);
if (map == null) {
put(key, map = new TreeMap<>());
}
map.put(key2, element);
return element;
}
}
@RestController("appSettingsCrudApi1")
@RequestMapping(AppSettingsCRUDController.API_URL)
@PreAuthorize("hasAuthority('GROUP_ADMINS')")
@Tag(name = AppController.API_TAG)
public static class AppSettingsCRUDController extends CRUDController<AppSetting, AppSettingsService> {
public static final String API_URL = AppController.API_URL + "/settings";
@Override
protected OrderSpecifier<?>[] defaultSort() {
return new OrderSpecifier[] { QAppSetting.appSetting.id.asc() };
}
@Override
public Page<AppSetting> list(@ParameterObject final Pagination page) {
return super.list(page);
}
@SuppressWarnings("unchecked")
@PreAuthorize("isAuthenticated()")
@GetMapping(value = "", produces = { MediaType.APPLICATION_JSON_VALUE })
public Map<String, Object> appSettingsMini() {
final Map<String, Object> settingsMap = new TreeMap<>();
for (AppSetting setting : crudService.settingList()) {
final String categoryTag = setting.getCategoryTag();
if (StringUtils.isBlank(categoryTag)) {
settingsMap.put(setting.getName(), setting.getValue());
continue;
}
Object categoryGroup = settingsMap.computeIfAbsent(categoryTag, k -> new TreeMap<>());
if (categoryGroup instanceof String) {
log.error("AppSetting {} conflicts with a categoryTag", categoryTag);
continue;
}
((TreeMap<String, String>) categoryGroup).put(setting.getName(), setting.getValue());
settingsMap.put(categoryTag, categoryGroup);
}
return settingsMap;
}
}
}