Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
id "jacoco"
}

version "0.8.7"
version "0.8.8"
group "com.objectcomputing.checkins"

repositories {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.objectcomputing.checkins.services.feedback_answer;

import com.objectcomputing.checkins.services.feedback_request.FeedbackRequest;
import io.micronaut.core.annotation.Nullable;

import java.util.List;
Expand All @@ -14,4 +15,6 @@ public interface FeedbackAnswerServices {
FeedbackAnswer getById(UUID id);

List<FeedbackAnswer> findByValues(@Nullable UUID questionId, @Nullable UUID requestId);

boolean getIsPermitted(FeedbackRequest feedbackRequest);
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public List<FeedbackAnswer> findByValues(@Nullable UUID questionId, @Nullable UU
boolean isRequesteesSupervisor = requesteeId != null ? memberProfileServices.getSupervisorsForId(requesteeId).stream().anyMatch(profile -> currentUserId.equals(profile.getId())) : false;
MemberProfile requestee = memberProfileServices.getById(requesteeId);
final UUID requesteePDL = requestee.getPdlId();
if (currentUserServices.isAdmin() || currentUserId.equals(requesteePDL) || isRequesteesSupervisor || requestCreatorId.equals(currentUserId) || recipientId.equals(currentUserId)) {
if (currentUserServices.isAdmin() || currentUserId.equals(requesteePDL) || isRequesteesSupervisor || requestCreatorId.equals(currentUserId) || recipientId.equals(currentUserId) || feedbackRequestServices.selfRevieweeIsCurrentUserReviewee(feedbackRequest, currentUserId)) {
response.addAll(feedbackAnswerRepository.getByQuestionIdAndRequestId(Util.nullSafeUUIDToString(questionId), Util.nullSafeUUIDToString(requestId)));
return response;
}
Expand Down Expand Up @@ -145,15 +145,36 @@ public boolean updateIsPermitted(FeedbackRequest feedbackRequest) {
}

public boolean getIsPermitted(FeedbackRequest feedbackRequest) {
final boolean isAdmin = currentUserServices.isAdmin();
final UUID requestCreatorId = feedbackRequest.getCreatorId();
UUID requesteeId = feedbackRequest.getRequesteeId();
MemberProfile requestee = memberProfileServices.getById(requesteeId);
// Admins can always get questions and answers.
if (currentUserServices.isAdmin()) {
return true;
}

// See if the current user is the requestee's supervisor.
final UUID requesteeId = feedbackRequest.getRequesteeId();
final UUID currentUserId = currentUserServices.getCurrentUser().getId();
if (requesteeId != null &&
memberProfileServices.getSupervisorsForId(requesteeId).stream().anyMatch(profile -> currentUserId.equals(profile.getId()))) {
return true;
}

// See if the current user is the requestee's PDL.
final MemberProfile requestee = memberProfileServices.getById(requesteeId);
if (currentUserId.equals(requestee.getPdlId())) {
return true;
}

// See if the current user is the request creator or the recipient of
// the request.
final UUID requestCreatorId = feedbackRequest.getCreatorId();
final UUID recipientId = feedbackRequest.getRecipientId();
boolean isRequesteesSupervisor = requesteeId != null ? memberProfileServices.getSupervisorsForId(requesteeId).stream().anyMatch(profile -> currentUserId.equals(profile.getId())) : false;
final UUID requesteePDL = requestee.getPdlId();
if (requestCreatorId.equals(currentUserId) ||
recipientId.equals(currentUserId)) {
return true;
}


return isAdmin || currentUserId.equals(requesteePDL) || isRequesteesSupervisor || requestCreatorId.equals(currentUserId) || recipientId.equals(currentUserId);
return feedbackRequestServices.selfRevieweeIsCurrentUserReviewee(
feedbackRequest, currentUserId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public QuestionAndAnswerServicesImpl(FeedbackAnswerServices feedbackAnswerServic
@Override
public List<Tuple> getAllQuestionsAndAnswers(UUID requestId) {
FeedbackRequest feedbackRequest = feedbackRequestServices.getById(requestId);
if (!getIsPermitted(feedbackRequest)) {
if (!feedbackAnswerServices.getIsPermitted(feedbackRequest)) {
throw new PermissionException(NOT_AUTHORIZED_MSG);
}
List<TemplateQuestion> templateQuestions = templateQuestionServices.findByFields(feedbackRequest.getTemplateId());
Expand Down Expand Up @@ -77,7 +77,7 @@ public Tuple getQuestionAndAnswer(@Nullable UUID requestId, @Nullable UUID quest
TemplateQuestion question = new TemplateQuestion();
FeedbackRequest feedbackRequest = feedbackRequestServices.getById(requestId);

if (!getIsPermitted(feedbackRequest)) {
if (!feedbackAnswerServices.getIsPermitted(feedbackRequest)) {
throw new PermissionException(NOT_AUTHORIZED_MSG);
}

Expand All @@ -101,18 +101,4 @@ public Tuple getQuestionAndAnswer(@Nullable UUID requestId, @Nullable UUID quest
}
return new Tuple(question, returnedAnswer);
}

public boolean getIsPermitted(FeedbackRequest feedbackRequest) {
final boolean isAdmin = currentUserServices.isAdmin();
final UUID requestCreatorId = feedbackRequest.getCreatorId();
UUID requesteeId = feedbackRequest.getRequesteeId();
MemberProfile requestee = memberProfileServices.getById(requesteeId);
final UUID currentUserId = currentUserServices.getCurrentUser().getId();
final UUID recipientId = feedbackRequest.getRecipientId();
boolean isRequesteesSupervisor = requesteeId != null ? memberProfileServices.getSupervisorsForId(requesteeId).stream().anyMatch(profile -> currentUserId.equals(profile.getId())) : false;
final UUID requesteePDL = requestee.getPdlId();

return isAdmin || currentUserId.equals(requesteePDL) || isRequesteesSupervisor || requestCreatorId.equals(currentUserId) || recipientId.equals(currentUserId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ public interface FeedbackRequestServices {
FeedbackRequest getById(UUID id);

List<FeedbackRequest> findByValues(UUID creatorId, UUID requesteeId, UUID recipientId, LocalDate oldestDate, UUID reviewPeriodId, UUID templateId, List<UUID> requesteeIds);
}

boolean selfRevieweeIsCurrentUserReviewee(FeedbackRequest request,
UUID currentUserId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,8 @@ public FeedbackRequest getById(UUID id) {
if (feedbackReq.isEmpty()) {
throw new NotFoundException("No feedback req with id " + id);
}
final LocalDate sendDate = feedbackReq.get().getSendDate();
final UUID requesteeId = feedbackReq.get().getRequesteeId();
final UUID recipientId = feedbackReq.get().getRecipientId();
if (!getIsPermitted(requesteeId, recipientId, sendDate)) {

if (!getIsPermitted(feedbackReq.get())) {
throw new PermissionException(NOT_AUTHORIZED_MSG);
}

Expand Down Expand Up @@ -303,9 +301,12 @@ public List<FeedbackRequest> findByValues(UUID creatorId, UUID requesteeId, UUID
if (currentUserServices.isAdmin()) {
visible = true;
} else if (request != null) {
if (currentUserId.equals(request.getCreatorId())) visible = true;
if (isSupervisor(request.getRequesteeId(), currentUserId)) visible = true;
if (currentUserId.equals(request.getRecipientId())) visible = true;
if (currentUserId.equals(request.getCreatorId()) ||
isSupervisor(request.getRequesteeId(), currentUserId) ||
currentUserId.equals(request.getRecipientId()) ||
selfRevieweeIsCurrentUserReviewee(request, currentUserId)) {
visible = true;
}
}
return visible;
}).toList();
Expand All @@ -318,6 +319,23 @@ private boolean isSupervisor(UUID requesteeId, UUID currentUserId) {
&& memberProfileServices.getSupervisorsForId(requesteeId).stream().anyMatch(profile -> currentUserId.equals(profile.getId()));
}

public boolean selfRevieweeIsCurrentUserReviewee(FeedbackRequest request,
UUID currentUserId) {
// If we are looking at a self-review request, see if there is a review
// request in the same review period that is assigned to the current
// user and the requestee is the same as the self-review request. If
// so, this user is allowed to see the self-review request.
if (request.getRecipientId().equals(request.getRequesteeId())) {
List<FeedbackRequest> other = feedbackReqRepository.findByValues(
null, request.getRecipientId().toString(),
currentUserId.toString(), null,
Util.nullSafeUUIDToString(request.getReviewPeriodId()),
null);
return (other.size() == 1);
}
return false;
}

private boolean createIsPermitted(UUID requesteeId) {
final boolean isAdmin = currentUserServices.isAdmin();
final UUID currentUserId = currentUserServices.getCurrentUser().getId();
Expand All @@ -329,16 +347,21 @@ private boolean createIsPermitted(UUID requesteeId) {
return isAdmin || currentUserId.equals(requesteePDL) || isRequesteesSupervisor || currentUserId.equals(requesteeId);
}

private boolean getIsPermitted(UUID requesteeId, UUID recipientId, LocalDate sendDate) {
LocalDate today = LocalDate.now();
private boolean getIsPermitted(FeedbackRequest feedbackReq) {
final LocalDate sendDate = feedbackReq.getSendDate();
final UUID requesteeId = feedbackReq.getRequesteeId();
final UUID recipientId = feedbackReq.getRecipientId();
final LocalDate today = LocalDate.now();
final UUID currentUserId = currentUserServices.getCurrentUser().getId();

// The recipient can only access the feedback request after it has been sent
if (sendDate.isAfter(today) && currentUserId.equals(recipientId)) {
throw new PermissionException("You are not permitted to access this request before the send date.");
}

return createIsPermitted(requesteeId) || currentUserId.equals(recipientId);
return createIsPermitted(requesteeId) ||
currentUserId.equals(recipientId) ||
selfRevieweeIsCurrentUserReviewee(feedbackReq, currentUserId);
}

private boolean updateDueDateIsPermitted(FeedbackRequest feedbackRequest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
public interface MemberProfileServices {
MemberProfile getById(UUID id);

MemberProfile findByWorkEmail(@NotNull String workEmail);

Set<MemberProfile> findByValues(String firstName, String lastName, String title,
UUID pdlId, String workEmail, UUID supervisorId, Boolean terminated);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.objectcomputing.checkins.services.role.RoleServices;
import com.objectcomputing.checkins.services.team.member.TeamMemberServices;
import io.micronaut.cache.annotation.CacheConfig;
import io.micronaut.cache.annotation.CacheInvalidate;
import io.micronaut.cache.annotation.Cacheable;
import io.micronaut.core.annotation.Nullable;
import jakarta.inject.Named;
Expand Down Expand Up @@ -55,6 +56,7 @@ public MemberProfileServicesImpl(MemberProfileRepository memberProfileRepository
}

@Override
@Cacheable
public MemberProfile getById(@NotNull UUID id) {
Optional<MemberProfile> optional = memberProfileRepository.findById(id);
if (optional.isEmpty()) {
Expand All @@ -67,6 +69,14 @@ public MemberProfile getById(@NotNull UUID id) {
return memberProfile;
}

@Cacheable
@Override
public MemberProfile findByWorkEmail(@NotNull String workEmail) {
return memberProfileRepository.findByWorkEmail(workEmail).orElseThrow(() ->
new NotFoundException("Member not found")
);
}

@Override
public Set<MemberProfile> findByValues(@Nullable String firstName,
@Nullable String lastName,
Expand All @@ -86,6 +96,7 @@ public Set<MemberProfile> findByValues(@Nullable String firstName,
}

@Override
@CacheInvalidate(cacheNames = {"member-cache"})
public MemberProfile saveProfile(MemberProfile memberProfile) {
MemberProfile emailProfile = memberProfileRepository.findByWorkEmail(memberProfile.getWorkEmail()).orElse(null);

Expand Down Expand Up @@ -152,6 +163,7 @@ public void emailAssignment(MemberProfile member, boolean isPDL) {
}

@Override
@CacheInvalidate(cacheNames = {"member-cache"})
public boolean deleteProfile(@NotNull UUID id) {
if (!currentUserServices.isAdmin()) {
throw new PermissionException("Requires admin privileges");
Expand Down Expand Up @@ -183,6 +195,7 @@ public boolean deleteProfile(@NotNull UUID id) {
}

@Override
@Cacheable(parameters = {"firstName", "lastName"})
public MemberProfile findByName(@NotNull String firstName, @NotNull String lastName) {
List<MemberProfile> searchResult = memberProfileRepository.search(firstName, null, lastName,
null, null, null, null, null, null);
Expand Down Expand Up @@ -222,6 +235,7 @@ public List<MemberProfile> getSubordinatesForId(UUID id) {
}

@Override
@CacheInvalidate(cacheNames = {"member-cache"})
public MemberProfile updateProfile(MemberProfile memberProfile) {
return memberProfileRepository.update(memberProfile);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.objectcomputing.checkins.services.reports;

import com.objectcomputing.checkins.services.memberprofile.MemberProfileRepository;
import com.objectcomputing.checkins.exceptions.BadArgException;

import com.objectcomputing.checkins.services.memberprofile.MemberProfileServices;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;

Expand All @@ -18,7 +18,7 @@

abstract class CSVProcessor {

public void load(MemberProfileRepository memberProfileRepository,
public void load(MemberProfileServices memberProfileServices,
ByteBuffer dataSource) throws IOException,
BadArgException {
ByteArrayInputStream stream = new ByteArrayInputStream(dataSource.array());
Expand All @@ -30,10 +30,10 @@ public void load(MemberProfileRepository memberProfileRepository,
.setNullString("")
.build()
.parse(input);
loadImpl(memberProfileRepository, csvParser);
loadImpl(memberProfileServices, csvParser);
}

protected abstract void loadImpl(MemberProfileRepository memberProfileRepository, CSVParser csvParser) throws BadArgException;
protected abstract void loadImpl(MemberProfileServices memberProfileServices, CSVParser csvParser) throws BadArgException;

protected LocalDate parseDate(String date) {
List<String> formatStrings = List.of("yyyy", "M/d/yyyy");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.objectcomputing.checkins.services.reports;

import com.objectcomputing.checkins.exceptions.NotFoundException;
import com.objectcomputing.checkins.services.memberprofile.MemberProfile;
import com.objectcomputing.checkins.services.memberprofile.MemberProfileRepository;
import com.objectcomputing.checkins.exceptions.BadArgException;

import com.objectcomputing.checkins.services.memberprofile.MemberProfileServices;
import io.micronaut.core.annotation.Introspected;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
Expand All @@ -12,10 +13,7 @@
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.Optional;
import java.util.*;

public class CompensationHistory extends CSVProcessor {

Expand All @@ -32,41 +30,39 @@ public record Compensation(
private final List<Compensation> history = new ArrayList<>();

@Override
protected void loadImpl(MemberProfileRepository memberProfileRepository,
protected void loadImpl(MemberProfileServices memberProfileServices,
CSVParser csvParser) throws BadArgException {
history.clear();
for (CSVRecord csvRecord : csvParser) {
try {
String emailAddress = csvRecord.get("emailAddress");
Optional<MemberProfile> memberProfile =
memberProfileRepository.findByWorkEmail(emailAddress);
if (memberProfile.isPresent()) {
String startDate = csvRecord.get("startDate");
LocalDate date = parseDate(startDate);
if (date == null) {
LOG.error("Unable to parse date: {}", startDate);
} else {
String value = csvRecord.get("compensation");
Compensation comp = new Compensation(
memberProfile.get().getId(),
date,
value == null ? null : value.replaceAll("[^\\d\\.,]", ""),
csvRecord.get("totalComp")
);
history.add(comp);
history.clear();
for (CSVRecord csvRecord : csvParser) {
String emailAddress = null;
try {
emailAddress = csvRecord.get("emailAddress");
MemberProfile memberProfile = memberProfileServices.findByWorkEmail(emailAddress);
String startDate = csvRecord.get("startDate");
LocalDate date = parseDate(startDate);
if (date == null) {
LOG.error("Unable to parse date: {}", startDate);
} else {
String value = csvRecord.get("compensation");
Compensation comp = new Compensation(
memberProfile.getId(),
date,
value == null ? null : value.replaceAll("[^\\d\\.,]", ""),
csvRecord.get("totalComp")
);
history.add(comp);
}
} catch (NotFoundException nfe) {
LOG.error("Unable to find a profile for {}", emailAddress);
} catch (IllegalArgumentException ex) {
throw new BadArgException("Unable to parse the compensation history");
}
} else {
LOG.error("Unable to find a profile for {}", emailAddress);
}
} catch(IllegalArgumentException ex) {
throw new BadArgException("Unable to parse the compensation history");
}
}
}

public List<Compensation> getHistory(UUID memberId) {
return history.stream()
.filter(entry -> entry.memberId().equals(memberId))
.toList();
return history.stream()
.filter(entry -> entry.memberId().equals(memberId))
.toList();
}
}
Loading
Loading