package br.com.conductor.heimdall.core.service; /*- * =========================LICENSE_START================================== * heimdall-core * ======================================================================== * Copyright (C) 2018 Conductor Tecnologia SA * ======================================================================== * 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. * ==========================LICENSE_END=================================== */ import static br.com.conductor.heimdall.core.exception.ExceptionMessage.ACCESS_TOKEN_ALREADY_EXISTS; import static br.com.conductor.heimdall.core.exception.ExceptionMessage.ACCESS_TOKEN_NOT_DEFINED; import static br.com.conductor.heimdall.core.exception.ExceptionMessage.APP_NOT_EXIST; import static br.com.conductor.heimdall.core.exception.ExceptionMessage.GLOBAL_RESOURCE_NOT_FOUND; import static br.com.conductor.heimdall.core.exception.ExceptionMessage.SOME_PLAN_NOT_PRESENT_IN_APP; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import br.com.conductor.heimdall.core.dto.ReferenceIdDTO; import org.modelmapper.PropertyMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Example; import org.springframework.data.domain.ExampleMatcher; import org.springframework.data.domain.ExampleMatcher.StringMatcher; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import br.com.conductor.heimdall.core.converter.GenericConverter; import br.com.conductor.heimdall.core.dto.PageDTO; import br.com.conductor.heimdall.core.dto.PageableDTO; import br.com.conductor.heimdall.core.dto.integration.AccessTokenDTO; import br.com.conductor.heimdall.core.dto.page.AccessTokenPage; import br.com.conductor.heimdall.core.dto.persist.AccessTokenPersist; import br.com.conductor.heimdall.core.dto.request.AccessTokenRequest; import br.com.conductor.heimdall.core.entity.AccessToken; import br.com.conductor.heimdall.core.entity.App; import br.com.conductor.heimdall.core.entity.Plan; import br.com.conductor.heimdall.core.exception.HeimdallException; import br.com.conductor.heimdall.core.repository.AccessTokenRepository; import br.com.conductor.heimdall.core.repository.AppRepository; import br.com.conductor.heimdall.core.repository.PlanRepository; import br.com.conductor.heimdall.core.service.amqp.AMQPCacheService; import br.com.conductor.heimdall.core.util.Pageable; import net.bytebuddy.utility.RandomString; /** * This class provides methods to create, read, update and delete the {@link AccessToken} resource. * * @author Filipe Germano * @author <a href="https://dijalmasilva.github.io" target="_blank">Dijalma Silva</a> */ @Service public class AccessTokenService { @Autowired private AccessTokenRepository accessTokenRepository; @Autowired private AppRepository appRespository; @Autowired private AppService appService; @Autowired private PlanRepository planRepository; @Autowired private AMQPCacheService amqpCacheService; /** * Looks for a {@link AccessToken} based on it's. * * @param id The id of the {@link AccessToken} * @return The {@link AccessToken} found */ @Transactional(readOnly = true) public AccessToken find(Long id) { AccessToken accessToken = accessTokenRepository.findOne(id); HeimdallException.checkThrow(accessToken == null, GLOBAL_RESOURCE_NOT_FOUND); return accessToken; } /** * Returns a paged list of all {@link AccessToken} from a request. * * @param accessTokenRequest {@link AccessTokenRequest} The request for {@link AccessToken} * @param pageableDTO {@link PageableDTO} The pageable DTO * @return The paged {@link AccessToken} list as a {@link AccessTokenPage} object */ @Transactional(readOnly = true) public AccessTokenPage list(AccessTokenRequest accessTokenRequest, PageableDTO pageableDTO) { AccessToken accessToken = GenericConverter.mapper(accessTokenRequest, AccessToken.class); Example<AccessToken> example = Example.of(accessToken, ExampleMatcher.matching().withIgnoreCase().withStringMatcher(StringMatcher.CONTAINING)); Pageable pageable = Pageable.setPageable(pageableDTO.getOffset(), pageableDTO.getLimit()); Page<AccessToken> page = accessTokenRepository.findAll(example, pageable); AccessTokenPage accessTokenPage = new AccessTokenPage(PageDTO.build(page)); return accessTokenPage; } /** * Returns a list of all {@link AccessToken} from a request * * @param accessTokenRequest {@link AccessTokenRequest} The request for {@link AccessToken} * @return The list of {@link AccessToken} */ @Transactional(readOnly = true) public List<AccessToken> list(AccessTokenRequest accessTokenRequest) { AccessToken accessToken = GenericConverter.mapper(accessTokenRequest, AccessToken.class); Example<AccessToken> example = Example.of(accessToken, ExampleMatcher.matching().withIgnoreCase().withStringMatcher(StringMatcher.CONTAINING)); List<AccessToken> accessTokens = accessTokenRepository.findAll(example); return accessTokens; } /** * Saves a new {@link AccessToken} for a {@link App}. If the {@link AccessToken} does not * have a token it generates a new token for it. * * @param accessTokenPersist {@link AccessTokenPersist} * @return The {@link AccessToken} that was saved to the repository */ @Transactional public AccessToken save(AccessTokenPersist accessTokenPersist) { AccessToken accessToken = GenericConverter.mapper(accessTokenPersist, AccessToken.class); App appRecover = appRespository.findOne(accessTokenPersist.getApp().getId()); HeimdallException.checkThrow(appRecover == null, APP_NOT_EXIST); HeimdallException.checkThrow(!verifyIfPlansContainsInApp(appRecover, accessTokenPersist.getPlans()), SOME_PLAN_NOT_PRESENT_IN_APP); AccessToken existAccessToken; if (accessToken.getCode() != null) { existAccessToken = accessTokenRepository.findByCode(accessToken.getCode()); HeimdallException.checkThrow(existAccessToken != null, ACCESS_TOKEN_ALREADY_EXISTS); } else { RandomString randomString = new RandomString(12); String token = randomString.nextString(); while (accessTokenRepository.findByCode(token) != null) { token = randomString.nextString(); } accessToken.setCode(token); } accessToken = accessTokenRepository.save(accessToken); return accessToken; } /** * Updates a {@link AccessToken} by its ID. * * @param id The ID of the {@link AccessToken} to be updated * @param accessTokenPersist {@link AccessTokenPersist} The request for {@link AccessToken} * @return The {@link AccessToken} updated */ @Transactional public AccessToken update(Long id, AccessTokenPersist accessTokenPersist) { AccessToken accessToken = accessTokenRepository.findOne(id); HeimdallException.checkThrow(accessToken == null, GLOBAL_RESOURCE_NOT_FOUND); App appRecover = appRespository.findOne(accessTokenPersist.getApp().getId()); HeimdallException.checkThrow(appRecover == null, APP_NOT_EXIST); HeimdallException.checkThrow(!verifyIfPlansContainsInApp(appRecover, accessTokenPersist.getPlans()), SOME_PLAN_NOT_PRESENT_IN_APP); PropertyMap<AccessTokenPersist, AccessToken> propertyMap = new PropertyMap<AccessTokenPersist, AccessToken>() { @Override protected void configure() { skip(destination.getCode()); } }; GenericConverter.convertWithMapping(accessTokenPersist, accessToken, propertyMap); accessToken = accessTokenRepository.save(accessToken); amqpCacheService.dispatchClean(); return accessToken; } /** * Deletes a {@link AccessToken} by its ID. * * @param id The ID of the {@link AccessToken} to be deleted */ @Transactional public void delete(Long id) { AccessToken accessToken = accessTokenRepository.findOne(id); HeimdallException.checkThrow(accessToken == null, GLOBAL_RESOURCE_NOT_FOUND); amqpCacheService.dispatchClean(); accessTokenRepository.delete(accessToken); } /** * Saves a new {@link AccessToken} for a {@link App}. * * @param reqBody The {@link AccessTokenDTO} * @return The {@link AccessToken} saved */ @Transactional public AccessToken save(AccessTokenDTO reqBody) { AccessToken accessToken = GenericConverter.mapper(reqBody, AccessToken.class); HeimdallException.checkThrow(accessToken.getCode() == null, ACCESS_TOKEN_NOT_DEFINED); App app = appService.save(reqBody.getApp()); AccessToken existAccessToken; existAccessToken = accessTokenRepository.findByCode(accessToken.getCode()); HeimdallException.checkThrow(existAccessToken != null, ACCESS_TOKEN_ALREADY_EXISTS); accessToken.setApp(app); Plan plan = planRepository.findOne(1L); if (plan != null) { accessToken.setPlans(new ArrayList<>(Collections.singletonList(plan))); } accessToken = accessTokenRepository.save(accessToken); return accessToken; } /** * Verify if all plans informed contains in {@link List}<{@link Plan}> of the {@link App} * * @param app The {@link App} * @param plansId {@link List}<{@link ReferenceIdDTO}> plansIds * @return True if contains all, false otherwise */ private boolean verifyIfPlansContainsInApp(App app, List<ReferenceIdDTO> plansId) { final List<Long> plansSelected = plansId.stream().map(ReferenceIdDTO::getId).collect(Collectors.toList()); return plansId.size() == app.getPlans().stream() .filter(plan -> Collections.frequency(plansSelected, plan.getId()) == 1) .count(); } }