WebUserRegistrationController.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 io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.validator.routines.EmailValidator;
import org.genesys.blocks.security.UserException;
import org.gringlobal.api.exception.InvalidApiUsageException;
import org.gringlobal.api.v1.ApiBaseController;
import org.gringlobal.model.WebUser;
import org.gringlobal.service.EMailVerificationService;
import org.gringlobal.service.LanguageService;
import org.gringlobal.service.TokenVerificationService;
import org.gringlobal.service.WebUserService;
import org.gringlobal.util.ReCaptchaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController("webUserRegistrationApi1")
@RequestMapping(WebUserRegistrationController.API_URL)
@PreAuthorize("isAuthenticated()")
@Tag(name = "WebUserRegistration")
@Slf4j
public class WebUserRegistrationController extends ApiBaseController {

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

	@Value("${captcha.privateKey}")
	private String captchaPrivateKey;

	@Autowired
	private LanguageService languageService;

	@Autowired
	private WebUserService crudService;

	@Autowired
	private EMailVerificationService emailVerificationService;

	private final EmailValidator emailValidator = EmailValidator.getInstance();

	/**
	 * Register new web user
	 *
	 * @param captchaResponse the captchaResponse
	 * @param email the email
	 * @param password the password
	 * @return the web user
	 */
	@PostMapping(value = "/register")
	public WebUser registerUser(@RequestParam(value = "g-recaptcha-response", required = true) final String captchaResponse,
			@RequestParam(name = "email", required = true) final String email, @RequestParam(name = "pass", required = true) final String password,
			final HttpServletRequest request) throws Exception {

		// Validate the reCAPTCHA
		if (!ReCaptchaUtil.isValid(captchaResponse, request.getRemoteAddr(), captchaPrivateKey)) {
			log.warn("Invalid captcha.");
			throw new InvalidApiUsageException("Captcha check failed.");
		}

		if (!emailValidator.isValid(email)) {
			log.warn("Invalid email provided: {}", email);
			throw new InvalidApiUsageException("Invalid email provided: " + email);
		}

		try {
			if (crudService.loadUserByUsername(email) != null)
				throw new InvalidApiUsageException("E-mail already taken.");
		} catch (UsernameNotFoundException e) {
			// it's fine
		}

		WebUser source = new WebUser();
		source.setIsEnabled("N");
		source.setUsername(email);
		source.setPassword(password);
		source.setSysLang(languageService.getLanguage(LocaleContextHolder.getLocale()));
		WebUser savedWebUser = crudService.create(source);

		emailVerificationService.sendVerificationEmail(savedWebUser);
		return savedWebUser;
	}

	@PostMapping(value = "/{tokenUuid:.+}/validate")
	public boolean validateEMail(@PathVariable("tokenUuid") String tokenUuid, @RequestParam(value = "key", required = true) String key) throws Exception {
		try {
			emailVerificationService.validateEMail(tokenUuid, key);
			return true;
		} catch (final TokenVerificationService.NoSuchVerificationTokenException e) {
			throw new Exception("Verification token is not valid");
		} catch (final TokenVerificationService.TokenExpiredException e) {
			throw new Exception("Verification token has expired");
		}
	}

	@PostMapping(value = "/{tokenUuid:.+}/cancel")
	public boolean cancelValidation(@PathVariable("tokenUuid") String tokenUuid, @RequestParam(value = "g-recaptcha-response") String response,
			HttpServletRequest request) throws Exception {

		// Validate the reCAPTCHA
		if (!ReCaptchaUtil.isValid(response, request.getRemoteAddr(), captchaPrivateKey)) {
			log.warn("Invalid captcha.");
			throw new UserException("Captcha check failed.");
		}

		emailVerificationService.cancelValidation(tokenUuid);
		return true;
	}
}