All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gravitee.rest.api.service.impl.RatingServiceImpl Maven / Gradle / Ivy

There is a newer version: 3.10.0
Show newest version
/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * 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 io.gravitee.rest.api.service.impl;

import static java.util.Comparator.comparing;
import static java.util.Comparator.reverseOrder;
import static java.util.stream.Collectors.*;
import static org.apache.commons.lang3.StringUtils.isBlank;

import io.gravitee.common.data.domain.Page;
import io.gravitee.repository.exceptions.TechnicalException;
import io.gravitee.repository.management.api.RatingAnswerRepository;
import io.gravitee.repository.management.api.RatingRepository;
import io.gravitee.repository.management.api.search.Pageable;
import io.gravitee.repository.management.api.search.builder.PageableBuilder;
import io.gravitee.repository.management.model.Rating;
import io.gravitee.repository.management.model.RatingAnswer;
import io.gravitee.repository.management.model.RatingReferenceType;
import io.gravitee.rest.api.model.*;
import io.gravitee.rest.api.model.parameters.Key;
import io.gravitee.rest.api.model.parameters.ParameterReferenceType;
import io.gravitee.rest.api.service.*;
import io.gravitee.rest.api.service.common.RandomString;
import io.gravitee.rest.api.service.exceptions.ApiRatingUnavailableException;
import io.gravitee.rest.api.service.exceptions.RatingAlreadyExistsException;
import io.gravitee.rest.api.service.exceptions.RatingNotFoundException;
import io.gravitee.rest.api.service.exceptions.TechnicalManagementException;
import io.gravitee.rest.api.service.notification.ApiHook;
import io.gravitee.rest.api.service.notification.NotificationParamsBuilder;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author Azize ELAMRANI (azize at graviteesource.com)
 * @author GraviteeSource Team
 */
@Component
public class RatingServiceImpl extends AbstractService implements RatingService {

    private static final Logger LOGGER = LoggerFactory.getLogger(RatingServiceImpl.class);

    @Autowired
    private RatingRepository ratingRepository;

    @Autowired
    private RatingAnswerRepository ratingAnswerRepository;

    @Autowired
    private UserService userService;

    @Autowired
    private AuditService auditService;

    @Autowired
    private ParameterService parameterService;

    @Autowired
    private NotifierService notifierService;

    @Autowired
    private ApiService apiService;

    @Override
    public RatingEntity create(final NewRatingEntity ratingEntity) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final Optional ratingOptional = ratingRepository.findByReferenceIdAndReferenceTypeAndUser(
                ratingEntity.getApi(),
                RatingReferenceType.API,
                getAuthenticatedUsername()
            );
            if (ratingOptional.isPresent()) {
                throw new RatingAlreadyExistsException(ratingEntity.getApi(), getAuthenticatedUsername());
            }
            Rating rating = ratingRepository.create(convert(ratingEntity));
            auditService.createApiAuditLog(
                rating.getReferenceId(),
                null,
                Rating.RatingEvent.RATING_CREATED,
                rating.getCreatedAt(),
                null,
                rating
            );

            notifierService.trigger(
                ApiHook.NEW_RATING,
                rating.getReferenceId(),
                new NotificationParamsBuilder().api(apiService.findById(rating.getReferenceId())).build()
            );

            return convert(rating);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to create rating on api {}", ratingEntity.getApi(), ex);
            throw new TechnicalManagementException("An error occurred while trying to create rating on api " + ratingEntity.getApi(), ex);
        }
    }

    @Override
    public RatingEntity createAnswer(final NewRatingAnswerEntity answerEntity) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final Rating rating = findModelById(answerEntity.getRatingId());

            final RatingAnswer ratingAnswer = new RatingAnswer();
            ratingAnswer.setId(RandomString.generate());
            ratingAnswer.setRating(answerEntity.getRatingId());
            ratingAnswer.setUser(getAuthenticatedUsername());
            ratingAnswer.setComment(answerEntity.getComment());
            ratingAnswer.setCreatedAt(new Date());
            ratingAnswerRepository.create(ratingAnswer);
            auditService.createApiAuditLog(
                rating.getReferenceId(),
                null,
                RatingAnswer.RatingAnswerEvent.RATING_ANSWER_CREATED,
                ratingAnswer.getCreatedAt(),
                null,
                ratingAnswer
            );

            notifierService.trigger(
                ApiHook.NEW_RATING_ANSWER,
                rating.getReferenceId(),
                new NotificationParamsBuilder().api(apiService.findById(rating.getReferenceId())).build()
            );

            return convert(rating);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to create a rating answer on rating {}", answerEntity.getRatingId(), ex);
            throw new TechnicalManagementException(
                "An error occurred while trying to create a rating answer on rating" + answerEntity.getRatingId(),
                ex
            );
        }
    }

    @Override
    public RatingEntity findById(String id) {
        return convert(findModelById(id));
    }

    @Override
    public Page findByApi(final String api, final Pageable pageable) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final Page pageRating = ratingRepository.findByReferenceIdAndReferenceTypePageable(
                api,
                RatingReferenceType.API,
                new PageableBuilder().pageNumber(pageable.pageNumber() - 1).pageSize(pageable.pageSize()).build()
            );
            final List ratingEntities = pageRating.getContent().stream().map(this::convert).collect(toList());
            return new Page<>(
                ratingEntities,
                pageRating.getPageNumber(),
                (int) pageRating.getPageElements(),
                pageRating.getTotalElements()
            );
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to find ratings for api {}", api, ex);
            throw new TechnicalManagementException("An error occurred while trying to find ratings for api " + api, ex);
        }
    }

    @Override
    public List findByApi(String api) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final List ratings = ratingRepository.findByReferenceIdAndReferenceType(api, RatingReferenceType.API);
            final List ratingEntities = ratings.stream().map(this::convert).collect(toList());
            return ratingEntities;
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to find ratings for api {}", api, ex);
            throw new TechnicalManagementException("An error occurred while trying to find ratings for api " + api, ex);
        }
    }

    @Override
    public RatingSummaryEntity findSummaryByApi(final String api) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final List ratings = ratingRepository.findByReferenceIdAndReferenceType(api, RatingReferenceType.API);
            final RatingSummaryEntity ratingSummary = new RatingSummaryEntity();
            ratingSummary.setApi(api);
            ratingSummary.setNumberOfRatings(ratings.size());
            final OptionalDouble optionalAvg = ratings.stream().mapToInt(Rating::getRate).average();
            if (optionalAvg.isPresent()) {
                ratingSummary.setAverageRate(optionalAvg.getAsDouble());
            }
            ratingSummary.setNumberOfRatingsByRate(ratings.stream().collect(groupingBy(Rating::getRate, counting())));
            return ratingSummary;
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to find summary rating for api {}", api, ex);
            throw new TechnicalManagementException("An error occurred while trying to find summary rating for api " + api, ex);
        }
    }

    @Override
    public RatingEntity findByApiForConnectedUser(final String api) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final Optional ratingOptional = ratingRepository.findByReferenceIdAndReferenceTypeAndUser(
                api,
                RatingReferenceType.API,
                getAuthenticatedUsername()
            );
            if (ratingOptional.isPresent()) {
                return convert(ratingOptional.get());
            }
            return null;
        } catch (final TechnicalException ex) {
            final String message =
                "An error occurred while trying to find rating for api " + api + " and user " + getAuthenticatedUsername();
            LOGGER.error(message, ex);
            throw new TechnicalManagementException(message, ex);
        }
    }

    @Override
    public RatingEntity update(final UpdateRatingEntity ratingEntity) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final Rating rating = findModelById(ratingEntity.getId());
            final Rating oldRating = new Rating(rating);
            if (!rating.getReferenceId().equals(ratingEntity.getApi())) {
                throw new RatingNotFoundException(ratingEntity.getId(), ratingEntity.getApi());
            }
            final Date now = new Date();
            rating.setUpdatedAt(now);
            rating.setRate(ratingEntity.getRate());

            // we can save a title/comment only once
            if (isBlank(rating.getTitle())) {
                rating.setTitle(ratingEntity.getTitle());
            }
            if (isBlank(rating.getComment())) {
                rating.setComment(ratingEntity.getComment());
            }
            Rating updatedRating = ratingRepository.update(rating);
            auditService.createApiAuditLog(
                rating.getReferenceId(),
                null,
                Rating.RatingEvent.RATING_UPDATED,
                updatedRating.getUpdatedAt(),
                oldRating,
                updatedRating
            );
            return convert(updatedRating);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to update rating {}", ratingEntity.getId(), ex);
            throw new TechnicalManagementException("An error occurred while trying to update rating " + ratingEntity.getId(), ex);
        }
    }

    @Override
    public void delete(final String id) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            Rating rating = findModelById(id);
            ratingRepository.delete(id);
            auditService.createApiAuditLog(rating.getReferenceId(), null, Rating.RatingEvent.RATING_DELETED, new Date(), rating, null);
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to delete rating {}", id, ex);
            throw new TechnicalManagementException("An error occurs while trying to delete rating " + id, ex);
        }
    }

    @Override
    public void deleteAnswer(final String ratingId, final String answerId) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            Rating rating = findModelById(ratingId);
            ratingAnswerRepository.delete(answerId);
            auditService.createApiAuditLog(
                rating.getReferenceId(),
                null,
                RatingAnswer.RatingAnswerEvent.RATING_ANSWER_DELETED,
                new Date(),
                rating,
                null
            );
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurs while trying to delete rating answer {}", answerId, ex);
            throw new TechnicalManagementException("An error occurs while trying to delete rating answer " + answerId, ex);
        }
    }

    @Override
    public boolean isEnabled() {
        return parameterService.findAsBoolean(Key.PORTAL_RATING_ENABLED, ParameterReferenceType.ENVIRONMENT);
    }

    private Rating findModelById(String id) {
        if (!isEnabled()) {
            throw new ApiRatingUnavailableException();
        }
        try {
            final Optional ratingOptional = ratingRepository.findById(id);
            if (!ratingOptional.isPresent()) {
                throw new RatingNotFoundException(id);
            }
            return ratingOptional.get();
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to find a rating by id {}", id, ex);
            throw new TechnicalManagementException("An error occurred while trying to find a rating by id " + id, ex);
        }
    }

    private RatingEntity convert(final Rating rating) {
        final RatingEntity ratingEntity = new RatingEntity();

        final UserEntity user = userService.findById(rating.getUser());
        ratingEntity.setUser(user.getId());
        ratingEntity.setUserDisplayName(user.getDisplayName());
        ratingEntity.setId(rating.getId());
        ratingEntity.setApi(rating.getReferenceId());
        ratingEntity.setTitle(rating.getTitle());
        ratingEntity.setComment(rating.getComment());
        ratingEntity.setRate(rating.getRate());
        ratingEntity.setCreatedAt(rating.getCreatedAt());
        ratingEntity.setUpdatedAt(rating.getUpdatedAt());

        try {
            final List ratingAnswers = ratingAnswerRepository.findByRating(rating.getId());
            if (ratingAnswers != null) {
                ratingEntity.setAnswers(
                    ratingAnswers
                        .stream()
                        .map(
                            ratingAnswer -> {
                                final RatingAnswerEntity ratingAnswerEntity = new RatingAnswerEntity();
                                ratingAnswerEntity.setId(ratingAnswer.getId());
                                final UserEntity userAnswer = userService.findById(ratingAnswer.getUser());
                                ratingAnswerEntity.setUser(userAnswer.getId());

                                if (userAnswer.getFirstname() != null && userAnswer.getLastname() != null) {
                                    ratingAnswerEntity.setUserDisplayName(userAnswer.getFirstname() + ' ' + userAnswer.getLastname());
                                } else {
                                    ratingAnswerEntity.setUserDisplayName(userAnswer.getEmail());
                                }
                                ratingAnswerEntity.setComment(ratingAnswer.getComment());
                                ratingAnswerEntity.setCreatedAt(ratingAnswer.getCreatedAt());
                                return ratingAnswerEntity;
                            }
                        )
                        .sorted(comparing(RatingAnswerEntity::getCreatedAt, reverseOrder()))
                        .collect(toList())
                );
            }
        } catch (TechnicalException ex) {
            LOGGER.error("An error occurred while trying to find rating answers by rating id {}", rating.getId(), ex);
            throw new TechnicalManagementException(
                "An error occurred while trying to find rating answers by rating id " + rating.getId(),
                ex
            );
        }
        return ratingEntity;
    }

    private Rating convert(final NewRatingEntity ratingEntity) {
        final Rating rating = new Rating();
        rating.setId(RandomString.generate());
        rating.setReferenceId(ratingEntity.getApi());
        rating.setReferenceType(RatingReferenceType.API);
        rating.setRate(ratingEntity.getRate());
        rating.setTitle(ratingEntity.getTitle());
        rating.setComment(ratingEntity.getComment());
        rating.setUser(getAuthenticatedUsername());
        final Date now = new Date();
        rating.setCreatedAt(now);
        rating.setUpdatedAt(now);
        return rating;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy