UserApiServiceImpl.java

/*
 * Copyright 2024 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.v2.facade.impl;

import org.genesys.blocks.security.NoUserFoundException;
import org.genesys.blocks.security.UserException;
import org.genesys.blocks.security.service.PasswordPolicy;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.api.model.CooperatorDTO;
import org.gringlobal.api.model.SysGroupInfo;
import org.gringlobal.api.model.SysUserDTO;
import org.gringlobal.api.v2.facade.UserApiService;
import org.gringlobal.api.v2.mapper.MapstructMapper;
import org.gringlobal.model.SysUser;
import org.gringlobal.service.CooperatorService;
import org.gringlobal.service.SysGroupService;
import org.gringlobal.service.UserService;
import org.gringlobal.service.filter.SysUserFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;

@Service
@Transactional(readOnly = true)
public class UserApiServiceImpl implements UserApiService {

	@Autowired
	private UserService userService;

	@Autowired
	private CooperatorService cooperatorService;

	@Autowired
	private MapstructMapper mapper;
	
	@Autowired
	private SysGroupService sysGroupService;

	@Override
	public SysUserDTO getProfile() {
		return mapper.map(getProfileEntity());
	}

	@Override
	public SysUser getProfileEntity() {
		final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication instanceof AbstractOAuth2TokenAuthenticationToken<?>) {
			var oauthAuth = (AbstractOAuth2TokenAuthenticationToken<?>) authentication;
			if (oauthAuth != null) {
				final SysUser currentUser = (SysUser) oauthAuth.getPrincipal();
				return userService.loadUserByUsername(currentUser.getUsername());
			}
		}
		// This is added for unit test support
		if (authentication instanceof UsernamePasswordAuthenticationToken) {
			final SysUser currentUser = (SysUser) authentication.getPrincipal();
			return userService.loadUserByUsername(currentUser.getUsername());
		}
		throw new InvalidApiUsageException("Not using user authentication");
	}

	@Override
	public SysUserDTO loadSysUser(Long id) throws NoUserFoundException {
		return mapper.map(userService.loadSysUser(id));
	}

	@Override
	public SysUserDTO loadSysUserByEmail(String email) throws NoUserFoundException {
		return mapper.map(userService.loadSysUserByEmail(email));
	}

	@Override
	public SysUserDTO loadUserByUsername(String username) throws UsernameNotFoundException {
		return mapper.map(userService.loadUserByUsername(username));
	}

	@Override
	public SysUserDTO loadOrRegisterUser(OidcUser oidcUser, String provider) throws AuthenticationException {
		return mapper.map(userService.loadOrRegisterUser(oidcUser, provider));
	}

	@Override
	@Transactional
	public SysUserDTO setAccountActive(Long id, boolean enabled) throws UserException {
		return mapper.map(userService.setAccountActive(id, enabled));
	}

	@Override
	@Transactional
	public void setPassword(SysUserDTO user, String password) throws UserException {
		userService.setPassword(mapper.map(user), password);
	}

	@Override
	public Page<SysUserDTO> list(SysUserFilter filter, Pageable page) {
		return mapper.map(userService.list(filter, page), mapper::map);
	}

	@Override
	@Transactional
	public SysUserDTO create(String username, String pass, Long cooperatorId) throws PasswordPolicy.PasswordPolicyException {
		SysUser source = new SysUser();
		source.setUsername(username);
		source.setPassword(pass);
		source.setCooperator(cooperatorService.get(cooperatorId));
		return mapper.map(userService.create(source));
	}

	@Override
	@Transactional
	public SysUserDTO create(SysUserDTO source) throws PasswordPolicy.PasswordPolicyException {
		return mapper.map(userService.create(mapper.map(source)));
	}

	@Override
	@Transactional
	public SysUserDTO setSysGroups(SysUserDTO user, List<SysGroupInfo> sysGroups) throws NoUserFoundException {
		return mapper.map(userService.setSysGroups(mapper.map(user), mapper.map(sysGroups, mapper::mapInfo)));
	}

	@Override
	@Transactional
	public SysUserDTO update(SysUserDTO updated, SysUserDTO target) throws UserException {
		return mapper.map(userService.update(mapper.map(updated), mapper.map(target)));
	}

	@Override
	@Transactional
	public SysUserDTO update(SysUserDTO source) throws UserException {
		return loadSysUser(update(source, loadSysUser(source.getId())).getId());
	}

	@Override
	public List<SysUserDTO> autocompleteSysUsers(String username, int limit) {
		return mapper.map(userService.autocompleteSysUsers(username, limit), mapper::map);
	}

	@Override
	public SysUserDTO getUserForCooperator(CooperatorDTO cooperator) {
		return mapper.map(userService.getUserForCooperator(mapper.map(cooperator)));
	}

	@Override
	@Transactional
	public SysUserDTO remove(SysUserDTO user) throws UserException {
		return mapper.map(userService.remove(mapper.map(user)));
	}

	@Override
	@Transactional
	public SysUserDTO assignNewSysGroups(Long id, Set<Long> sysGroupIds) throws NoUserFoundException {
		return mapper.map(userService.setSysGroups(userService.loadSysUser(id), sysGroupService.listAllByIds(sysGroupIds)));
	}
}