AdminController.java

/*
 * Copyright 2022 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.admin.v1;

import com.nimbusds.oauth2.sdk.GrantType;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.genesys.blocks.oauth.model.Authorization;
import org.genesys.blocks.oauth.model.QAuthorization;
import org.genesys.blocks.oauth.persistence.AuthorizationRepository;
import org.genesys.blocks.oauth.service.OAuthClientService;
import org.genesys.blocks.security.NoUserFoundException;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys.blocks.security.service.PasswordPolicy;
import org.genesys.filerepository.persistence.ImageGalleryPersistence;
import org.genesys.filerepository.persistence.RepositoryFilePersistence;
import org.genesys.filerepository.persistence.RepositoryFolderRepository;
import org.gringlobal.api.v1.ApiBaseController;
import org.gringlobal.api.v1.Pagination;
import org.gringlobal.model.SysUser;
import org.gringlobal.persistence.InventoryMaintenancePolicyRepository;
import org.gringlobal.persistence.SiteRepository;
import org.gringlobal.persistence.kpi.ExecutionRepository;
import org.gringlobal.service.AccessionService;
import org.gringlobal.service.InventoryService;
import org.gringlobal.service.UserService;
import org.gringlobal.worker.GenesysDownloader;
import org.gringlobal.worker.UsdaGeographyUpdater;
import org.gringlobal.worker.UsdaTaxonomyUpdater;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController("adminApi1")
@PreAuthorize("hasAuthority('GROUP_ADMINS')")
@RequestMapping(AdminController.API_URL)
@Api(tags = { "adminv1" })
@Slf4j
public class AdminController {

	/** The Constant API_URL. */
	public static final String API_URL = ApiBaseController.APIv1_BASE + "/admin";

	@Autowired(required = false)
	private UsdaTaxonomyUpdater usdaTaxonomyUpdater;

	@Autowired(required = false)
	private UsdaGeographyUpdater usdaGeographyUpdater;

	@Autowired(required = false)
	private GenesysDownloader genesysDownloader;

	@Autowired
	private UserService userService;

	@Autowired
	private CustomAclService aclService;

	@Autowired
	private SiteRepository siteRepository;

	@Autowired
	private InventoryMaintenancePolicyRepository inventoryPolicyRepository;

	@Autowired
	private RepositoryFolderRepository folderRepository;

	@Autowired
	private RepositoryFilePersistence fileRepository;

	@Autowired
	private ImageGalleryPersistence imageGalleryRepository;

	@Autowired
	private ExecutionRepository kpiExecutionRepository;

	@Autowired
	private AccessionService accessionService;

	@Autowired
	private InventoryService inventoryService;

	@Autowired
	private OAuthClientService oAuthClientService;

	@Autowired
	private AuthorizationRepository authorizationRepository;


	@PostMapping(path = "/taxonomy/update-usda")
	public void updateUsdaTaxonomy() throws Exception {
		log.info("Updating GRIN Taxonomy");
		usdaTaxonomyUpdater.update();
		log.info("Updating done");
	}

	@PostMapping(path = "/recalculate-accenumb")
	public void recalculateAccessionNumbers() {
		log.info("Recalculating accession numbers");
		accessionService.recalculateAllAccessionNumbers();
	}

	@PostMapping(path = "/recalculate-inventorynumb")
	public void recalculateInventoryNumbers() {
		log.info("Recalculating inventory numbers");
		inventoryService.recalculateAllInventoryNumbers();
	}

	@PostMapping(path = "/geo/update-usda")
	public void updateUsdaGeography() throws Exception {
		usdaGeographyUpdater.update();
	}

	@PostMapping(path = "/genesys/synchronize")
	public void downloadFromGenesys(@RequestParam(name = "instituteCode") String instituteCode, @RequestParam(name="authorizationToken") String authorizationToken) throws Exception {
		genesysDownloader.download(instituteCode, authorizationToken);
	}

	@PostMapping(path = "/add-user")
	public void addUser(@RequestParam(name="username") String username, @RequestParam(name="password") String password) throws PasswordPolicy.PasswordPolicyException {
		log.warn("Adding user {}", username);
		SysUser user = new SysUser();
		user.setUsername(username);
		user.setPassword(password);
		user = userService.create(user);
		log.warn("Added user id={} username={}", user.getId(), user.getUsername());
	}

	@PostMapping(value = "/site/fix-acl")
	@Transactional
	public void aclFixSiteAcl() {
		log.warn("Adding ACL for Sites");
		siteRepository.findAll().forEach(site -> aclService.createOrUpdatePermissions(site));
	}

	@PostMapping(value = "/inventory/fix-acl")
	@Transactional
	public void aclFixInventoryPolicyAcl() {
		log.warn("Adding ACL for InventoryMaintenancePolicies");
		inventoryPolicyRepository.findAll().forEach(policy -> aclService.createOrUpdatePermissions(policy));
	}

	@PostMapping(value = "/repository/fix-acl")
	@Transactional
	public void aclFixRepositoryAcl() {
		log.warn("Adding ACL for Repository folders");
		folderRepository.findAll().forEach(folder -> aclService.createOrUpdatePermissions(folder));

		log.warn("Adding ACL for Repository files");
		fileRepository.findAll().forEach(file -> aclService.createOrUpdatePermissions(file));

		log.warn("Adding ACL for Image galleries");
		imageGalleryRepository.findAll().forEach(gallery -> aclService.createOrUpdatePermissions(gallery));
	}

	@PostMapping(value = "/kpi/acl")
	@Transactional
	public void aclFixKPIAcl() {
		log.warn("Adding ACL support to KPI Execution");
		kpiExecutionRepository.findAll().forEach(execution -> {
			log.warn("Making KPI Execution {} ACL-ready", execution.getName());
			aclService.createOrUpdatePermissions(execution);
		});
	}
	
	@GetMapping(value = "/client/{clientId}/auth")
	@Transactional(readOnly = true)
	public Page<Authorization> findClientAuthorizations(@PathVariable String clientId, @Parameter(hidden = true) final Pagination page) {
		var client = oAuthClientService.getClient(clientId);
		Pageable pageable = ArrayUtils.isEmpty(page.getS()) ? page.toPageRequest(100, 100, Sort.Direction.ASC) : page.toPageRequest(100, 100);
		return authorizationRepository.findAll(QAuthorization.authorization.registeredClientId.eq(client.getId())
			.and(QAuthorization.authorization.authorizationGrantType.eq(GrantType.CLIENT_CREDENTIALS.getValue())), pageable);
	}

	@GetMapping(value = "/user/{userId}/auth")
	@Transactional(readOnly = true)
	public Page<Authorization> findUserAuthorizations(@PathVariable Long userId, @Parameter(hidden = true) final Pagination page) throws NoUserFoundException {
		var user = userService.loadSysUser(userId);
		Pageable pageable = ArrayUtils.isEmpty(page.getS()) ? page.toPageRequest(100, 100, Sort.Direction.ASC) : page.toPageRequest(100, 100);
		return authorizationRepository.findAll(QAuthorization.authorization.principalName.eq(user.getUsername())
			.and(QAuthorization.authorization.authorizationGrantType.eq(GrantType.AUTHORIZATION_CODE.getValue())), pageable);
	}

	@DeleteMapping(value = "/auth", produces = { MediaType.APPLICATION_JSON_VALUE })
	public void removeAuthorizations(@RequestBody final List<String> authIds) {
		var authorizations = authorizationRepository.findAll(QAuthorization.authorization.id.in(authIds));
		authorizationRepository.deleteAll(authorizations);
	}

	@PostMapping(value = "/inventory/ensure-system-inventories")
	public int ensureSystemInventories() {
		return inventoryService.ensureSystemInventories();
	}
}