package com.ciandt.techgallery.service.impl;
import com.google.api.server.spi.response.BadRequestException;
import com.google.api.server.spi.response.InternalServerErrorException;
import com.google.api.server.spi.response.NotFoundException;
import com.google.appengine.api.oauth.OAuthRequestException;
import com.google.appengine.api.users.User;
import com.googlecode.objectify.Ref;
import com.ciandt.techgallery.persistence.dao.EndorsementDAO;
import com.ciandt.techgallery.persistence.dao.TechGalleryUserDAO;
import com.ciandt.techgallery.persistence.dao.TechnologyDAO;
import com.ciandt.techgallery.persistence.dao.impl.EndorsementDAOImpl;
import com.ciandt.techgallery.persistence.dao.impl.TechGalleryUserDAOImpl;
import com.ciandt.techgallery.persistence.dao.impl.TechnologyDAOImpl;
import com.ciandt.techgallery.persistence.model.Endorsement;
import com.ciandt.techgallery.persistence.model.Skill;
import com.ciandt.techgallery.persistence.model.TechGalleryUser;
import com.ciandt.techgallery.persistence.model.Technology;
import com.ciandt.techgallery.service.EmailService;
import com.ciandt.techgallery.service.EndorsementService;
import com.ciandt.techgallery.service.SkillService;
import com.ciandt.techgallery.service.TechnologyService;
import com.ciandt.techgallery.service.UserServiceTG;
import com.ciandt.techgallery.service.impl.profile.UserProfileServiceImpl;
import com.ciandt.techgallery.service.model.EndorsementResponse;
import com.ciandt.techgallery.service.model.EndorsementsGroupedByEndorsedTransient;
import com.ciandt.techgallery.service.model.EndorsementsResponse;
import com.ciandt.techgallery.service.model.Response;
import com.ciandt.techgallery.service.model.ShowEndorsementsResponse;
import com.ciandt.techgallery.service.profile.UserProfileService;
import com.ciandt.techgallery.utils.i18n.I18n;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Services for Endorsement Endpoint requests.
*
* @author felipers
*
*/
public class EndorsementServiceImpl implements EndorsementService {
/*
* Constants --------------------------------------------
*/
private static final I18n i18n = I18n.getInstance();
/*
* Attributes --------------------------------------------
*/
private static EndorsementServiceImpl instance;
/** technology dao for getting technologies. */
TechnologyDAO techDao = TechnologyDAOImpl.getInstance();
/** tech gallery user service for getting PEOPLE API user. */
UserServiceTG userService = UserServiceTGImpl.getInstance();
/** user dao for getting users. */
TechGalleryUserDAO userDao = TechGalleryUserDAOImpl.getInstance();
/** endorsement dao. */
EndorsementDAO endorsementDao = EndorsementDAOImpl.getInstance();
/** skill service. */
SkillService skillService = SkillServiceImpl.getInstance();
/** Technology service. */
TechnologyService techService = TechnologyServiceImpl.getInstance();
/** Email service. */
EmailService emailService = EmailServiceImpl.getInstance();
/** User Profile service. */
UserProfileService userProfileService = UserProfileServiceImpl.getInstance();
/*
* Constructors --------------------------------------------
*/
private EndorsementServiceImpl() {}
/**
* Singleton method for the service.
*
* @author <a href="mailto:joaom@ciandt.com"> João Felipe de Medeiros Moreira </a>
* @since 09/10/2015
*
* @return EndorsementServiceImpl instance.
*/
public static EndorsementServiceImpl getInstance() {
if (instance == null) {
instance = new EndorsementServiceImpl();
}
return instance;
}
/*
* Methods --------------------------------------------
*/
/**
* POST for adding a endorsement. TODO: Refactor - Extract Method
*
* @throws InternalServerErrorException in case something goes wrong
* @throws NotFoundException in case the information are not founded
* @throws BadRequestException in case a request with problem were made.
* @throws OAuthRequestException in case of authentication problem
*/
@Override
public Endorsement addOrUpdateEndorsement(EndorsementResponse endorsement, User user)
throws InternalServerErrorException, BadRequestException, NotFoundException,
OAuthRequestException {
// endorser user google id
String googleId;
// endorser user from techgallery datastore
TechGalleryUser tgEndorserUser;
// endorsed user from techgallery datastore
TechGalleryUser tgEndorsedUser;
// endorsed email
String endorsedEmail;
// technology from techgallery datastore
Technology technology;
// User from endpoint (endorser) can't be null
if (user == null) {
throw new OAuthRequestException(i18n.t("OAuth error, null user reference!"));
} else {
googleId = user.getUserId();
}
// TechGalleryUser can't be null and must exists on datastore
if (googleId == null || googleId.equals("")) {
throw new NotFoundException(i18n.t("Current user was not found!"));
} else {
// get the TechGalleryUser from datastore
tgEndorserUser = userDao.findByGoogleId(googleId);
if (tgEndorserUser == null) {
throw new BadRequestException(i18n.t("Endorser user do not exists on datastore!"));
}
tgEndorserUser.setGoogleId(googleId);
}
// endorsed email can't be null.
endorsedEmail = endorsement.getEndorsed();
if (endorsedEmail == null || endorsedEmail.equals("")) {
throw new BadRequestException(i18n.t("Endorsed email was not especified!"));
} else {
// get user from PEOPLE
tgEndorsedUser = userService.getUserSyncedWithProvider(endorsedEmail);
if (tgEndorsedUser == null) {
throw new BadRequestException(i18n.t("Endorsed email was not found on PEOPLE!"));
}
}
// technology id can't be null and must exists on datastore
final String technologyId = endorsement.getTechnology();
if (technologyId == null || technologyId.equals("")) {
throw new BadRequestException(i18n.t("Technology was not especified!"));
} else {
technology = techDao.findById(technologyId);
if (technology == null) {
throw new BadRequestException(i18n.t("Technology do not exists!"));
}
}
// final checks and persist
// user cannot endorse itself
if (tgEndorserUser.getId().equals(tgEndorsedUser.getId())) {
throw new BadRequestException(i18n.t("You cannot endorse yourself!"));
}
// user cannot endorse the same people twice
if (endorsementDao.findActivesByUsers(tgEndorserUser, tgEndorsedUser, technology).size() > 0) {
throw new BadRequestException(i18n.t("You already endorsed this user for this technology"));
}
// create endorsement and save it
final Endorsement entity = new Endorsement();
entity.setEndorser(Ref.create(tgEndorserUser));
entity.setEndorsed(Ref.create(tgEndorsedUser));
entity.setTimestamp(new Date());
entity.setTechnology(Ref.create(technology));
entity.setActive(true);
endorsementDao.add(entity);
userProfileService.handleEndorsement(entity);
return getEndorsement(entity.getId());
}
/**
* POST for adding a endorsement. TODO: Refactor - Extract Method. Same in
* {@link #addOrUpdateEndorsement(EndorsementResponse, User)}
*
* @throws InternalServerErrorException in case something goes wrong
* @throws NotFoundException in case the information are not founded
* @throws BadRequestException in case a request with problem were made.
* @throws OAuthRequestException in case of authentication problem
*/
@Override
public Endorsement addOrUpdateEndorsementPlusOne(EndorsementResponse endorsement, User user)
throws InternalServerErrorException, BadRequestException, NotFoundException,
OAuthRequestException {
// endorser user google id
String googleId;
// endorser user from techgallery datastore
TechGalleryUser tgEndorserUser;
// endorsed user from techgallery datastore
TechGalleryUser tgEndorsedUser;
// endorsed email
String endorsedEmail;
// technology from techgallery datastore
Technology technology;
// User from endpoint (endorser) can't be null
if (user == null) {
throw new OAuthRequestException(i18n.t("OAuth error, null user reference!"));
} else {
googleId = user.getUserId();
}
// TechGalleryUser can't be null and must exists on datastore
if (googleId == null || googleId.equals("")) {
throw new NotFoundException(i18n.t("Current user was not found!"));
} else {
// get the TechGalleryUser from datastore
tgEndorserUser = userDao.findByGoogleId(googleId);
if (tgEndorserUser == null) {
throw new BadRequestException(i18n.t("Endorser user do not exists on datastore!"));
}
tgEndorserUser.setGoogleId(googleId);
}
// endorsed email can't be null.
endorsedEmail = endorsement.getEndorsed();
if (endorsedEmail == null || endorsedEmail.equals("")) {
throw new BadRequestException(i18n.t("Endorsed email was not especified!"));
} else {
// get user from PEOPLE
tgEndorsedUser = userService.getUserSyncedWithProvider(endorsedEmail);
if (tgEndorsedUser == null) {
throw new BadRequestException(i18n.t("Endorsed email was not found on PEOPLE!"));
}
}
// technology id can't be null and must exists on datastore
final String technologyId = endorsement.getTechnology();
if (technologyId == null || technologyId.equals("")) {
throw new BadRequestException(i18n.t("Technology was not especified!"));
} else {
technology = techDao.findById(technologyId);
if (technology == null) {
throw new BadRequestException(i18n.t("Technology do not exists!"));
}
}
// final checks and persist
// user cannot endorse itself
if (tgEndorserUser.getId().equals(tgEndorsedUser.getId())) {
throw new BadRequestException(i18n.t("You cannot endorse yourself!"));
}
// should exist only one active endorsement per endorser/endorsed/technology. the others are
// saved for history purpose. if already exist one active endorsement, set to inactive.
// if not, add a new one as active
final List<Endorsement> endorsements =
endorsementDao.findActivesByUsers(tgEndorserUser, tgEndorsedUser, technology);
if (endorsements.size() == 1) {
endorsements.get(0).setInactivatedDate(new Date());
endorsements.get(0).setActive(false);
endorsementDao.update(endorsements.get(0));
UserProfileServiceImpl.getInstance().handleEndorsement(endorsements.get(0));
return getEndorsement(endorsements.get(0).getId());
} else if (endorsements.size() > 1) {
throw new BadRequestException(
i18n.t("More than one active endorserment for the same endorser/endorsed/technology!"));
}
// create endorsement and save it
final Endorsement entity = new Endorsement();
entity.setEndorser(Ref.create(tgEndorserUser));
entity.setEndorsed(Ref.create(tgEndorsedUser));
entity.setTimestamp(new Date());
entity.setTechnology(Ref.create(technology));
entity.setActive(true);
endorsementDao.add(entity);
UserProfileServiceImpl.getInstance().handleEndorsement(entity);
return getEndorsement(entity.getId());
}
/**
* GET for getting all endorsements.
*/
@Override
public Response getEndorsements() throws InternalServerErrorException, NotFoundException {
final List<Endorsement> endrsEntities = endorsementDao.findAll();
// if list is null, return a not found exception
if (endrsEntities == null) {
throw new NotFoundException(i18n.t("No endorsement was found."));
} else {
final EndorsementsResponse response = new EndorsementsResponse();
response.setEndorsements(endrsEntities);
return response;
}
}
/**
* GET for getting one endorsement.
*/
@Override
public Endorsement getEndorsement(Long id) throws NotFoundException {
final Endorsement endorseEntity = endorsementDao.findById(id);
// if technology is null, return a not found exception
if (endorseEntity == null) {
throw new NotFoundException(i18n.t("No endorsement was found."));
} else {
return endorseEntity;
}
}
/**
* GET for getting one endorsement.
*
* @throws InternalServerErrorException in case something goes wrong
* @throws OAuthRequestException in case of authentication problem
* @throws NotFoundException in case the information are not founded
* @throws BadRequestException in case a request with problem were made.
*/
@Override
public Response getEndorsementsByTech(String techId, User user)
throws InternalServerErrorException, BadRequestException, NotFoundException,
OAuthRequestException {
final List<Endorsement> endorsementsByTech = endorsementDao.findAllActivesByTechnology(techId);
final List<EndorsementsGroupedByEndorsedTransient> grouped =
groupEndorsementByEndorsed(endorsementsByTech, techId);
final Technology technology = techService.getTechnologyById(techId, user);
techService.updateEdorsedsCounter(technology, grouped.size());
groupUsersWithSkill(grouped, technology);
Collections.sort(grouped, new EndorsementsGroupedByEndorsedTransient());
final ShowEndorsementsResponse response = new ShowEndorsementsResponse();
response.setEndorsements(grouped);
return response;
}
private void groupUsersWithSkill(final List<EndorsementsGroupedByEndorsedTransient> grouped,
final Technology technology) throws BadRequestException {
List<Skill> techSkills = skillService.getSkillsByTech(technology);
for (Skill skill : techSkills) {
boolean isGrouped = false;
for (EndorsementsGroupedByEndorsedTransient groupedEndorsements : grouped) {
if (skill.getTechGalleryUser().get().equals(groupedEndorsements.getEndorsed())) {
isGrouped = true;
break;
}
}
if (!isGrouped) {
EndorsementsGroupedByEndorsedTransient newEndorsed =
new EndorsementsGroupedByEndorsedTransient();
newEndorsed.setEndorsed(skill.getTechGalleryUser().get());
newEndorsed.setEndorsedSkill(skill.getValue());
newEndorsed.setEndorsers(new ArrayList<TechGalleryUser>());
grouped.add(newEndorsed);
}
}
}
@Override
public List<EndorsementsGroupedByEndorsedTransient> groupEndorsementByEndorsed(
List<Endorsement> endorsements, String techId) throws BadRequestException, NotFoundException,
InternalServerErrorException, OAuthRequestException {
final Map<TechGalleryUser, List<TechGalleryUser>> mapUsersGrouped =
new HashMap<TechGalleryUser, List<TechGalleryUser>>();
for (final Endorsement endorsement : endorsements) {
final TechGalleryUser endorsed = endorsement.getEndorsedEntity();
if (mapUsersGrouped.containsKey(endorsed)) {
final List<TechGalleryUser> endorsersList = mapUsersGrouped.get(endorsed);
endorsersList.add(endorsement.getEndorserEntity());
mapUsersGrouped.put(endorsed, endorsersList);
} else {
final List<TechGalleryUser> endorsersList = new ArrayList<TechGalleryUser>();
endorsersList.add(endorsement.getEndorserEntity());
mapUsersGrouped.put(endorsed, endorsersList);
}
}
return transformGroupedUserMapIntoList(mapUsersGrouped, techId);
}
private List<EndorsementsGroupedByEndorsedTransient> transformGroupedUserMapIntoList(
Map<TechGalleryUser, List<TechGalleryUser>> mapUsersGrouped, String techId)
throws BadRequestException, NotFoundException, InternalServerErrorException,
OAuthRequestException {
final List<EndorsementsGroupedByEndorsedTransient> groupedList =
new ArrayList<EndorsementsGroupedByEndorsedTransient>();
for (final Map.Entry<TechGalleryUser, List<TechGalleryUser>> entry : mapUsersGrouped
.entrySet()) {
final EndorsementsGroupedByEndorsedTransient grouped =
new EndorsementsGroupedByEndorsedTransient();
grouped.setEndorsed(entry.getKey());
final Skill response = skillService.getUserSkill(techId, entry.getKey());
if (response != null) {
grouped.setEndorsedSkill(response.getValue());
} else {
grouped.setEndorsedSkill(0);
}
grouped.setEndorsers(entry.getValue());
groupedList.add(grouped);
}
return groupedList;
}
}