Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#11571] Cascade user updates/deletes to deadline maps #11688

Conversation

jayasting98
Copy link
Contributor

@jayasting98 jayasting98 commented Mar 29, 2022

Part of #11571

PR Checklist

Outline of Solution

Any user email address update or any user deletion is cascaded down to the deadline maps. This is implemented by finding all the feedback sessions in the course the user belongs to. For each feedback session, the email is updated or deleted accordingly in the respective deadline map if that map contains a selective deadline for that user.

@jayasting98 jayasting98 added the s.Ongoing The PR is being worked on by the author(s) label Mar 29, 2022
@jayasting98 jayasting98 marked this pull request as ready for review March 29, 2022 17:14
@jayasting98 jayasting98 added s.ToReview The PR is waiting for review(s) and removed s.Ongoing The PR is being worked on by the author(s) labels Mar 29, 2022
Copy link
Member

@samuelfangjw samuelfangjw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the FeedbackSessionLogic

  1. Let's group the delete methods and update methods together.
  2. I don't think we need so many methods for a simple update. The current implementation seems unnecessarily complex for this purpose.

I think something like this will be more suitable. I've tried to write it in your style.

    public void deleteFeedbackSessionsDeadlinesForUser(String courseId, String email, boolean isInstructor) {
        Consumer<Map<String, Instant>> deadlineUpdater = deadlines -> deadlines.remove(email);

        updateFeedbackSessionDeadlinesForUser(courseId, email, isInstructor, deadlineUpdater);
    }

    public void updateFeedbackSessionDeadlinesWithNewEmail(String courseId, String oldEmail, String newEmail, boolean isInstructor) {
        if (oldEmail.equals(newEmail)) {
            return;
        }

        Consumer<Map<String, Instant>> deadlineUpdater = deadlines -> deadlines.put(newEmail, deadlines.remove(oldEmail));

        updateFeedbackSessionDeadlinesForUser(courseId, oldEmail, isInstructor, deadlineUpdater);
    }

    private void updateFeedbackSessionDeadlinesForUser(String courseId, String email,
            boolean isInstructor, Consumer<Map<String, Instant>> deadlineUpdater) {
        List<FeedbackSessionAttributes> feedbackSessions = fsDb.getFeedbackSessionsForCourse(courseId);
        for (var session : feedbackSessions) {
            Map<String, Instant> studentDeadlines = session.getStudentDeadlines();
            Map<String, Instant> instructorDeadlines = session.getInstructorDeadlines();
            if (isInstructor && instructorDeadlines.containsKey(email)) {
                deadlineUpdater.accept(instructorDeadlines);
            } else if (!isInstructor && studentDeadlines.containsKey(email)) {
                deadlineUpdater.accept(studentDeadlines);
            } else {
                // No deadline found in session
                continue;
            }
            try {
                fsDb.updateFeedbackSession(FeedbackSessionAttributes
                        .updateOptionsBuilder(session.getFeedbackSessionName(), courseId)
                        .withStudentDeadlines(studentDeadlines)
                        .withInstructorDeadlines(instructorDeadlines)
                        .build());
            } catch (InvalidParametersException | EntityDoesNotExistException e) {
                // Both Exceptions should not be thrown
                log.severe("Unexpected error", e);
            }
        }
    }

Comment on lines +819 to +821
"instructorDeadlines": {
"[email protected]": "2027-04-30T23:00:00Z"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the test json files, let's add the corresponding DeadlineExtensions as well.

@jayasting98
Copy link
Contributor Author

jayasting98 commented Mar 30, 2022

@samuelfangjw I initially did it similarly to how you suggested, also to mirror your implementation for cascading for the deadline extension entity since it seemed pretty good. However, I felt that for your case, the reason why cascading to the entity can be implemented that way is because isInstructor is actually a property of the entity. On the other hand, in my case, all it was doing was changing the behaviour of the method, so I thought that meant isInstructor would be a flag argument. I decided to split it into different methods instead to avoid that. What are your thoughts on this?

Regardless, I think for right now, I will change deadlinesUpdater into a Consumer like you suggested because that seems much better.

Edit:

Also the log.severe

@samuelfangjw
Copy link
Member

@samuelfangjw I initially did it similarly to how you suggested, also to mirror your implementation for cascading for the deadline extension entity since it seemed pretty good. However, I felt that for your case, the reason why cascading to the entity can be implemented that way is because isInstructor is actually a property of the entity. On the other hand, in my case, all it was doing was changing the behaviour of the method, so I thought that meant isInstructor would be a flag argument. I decided to split it into different methods instead to avoid that. What are your thoughts on this?

If you can do it in a way that doesn't sacrifice readability I don't see any issues.

My personal thoughts are that we should have a pragmatic approach to refactoring and make sure any "rules" we apply actually makes sense in the context.

@jayasting98
Copy link
Contributor Author

Ok, I think if I cannot make it readable enough, I might consider putting your stuff as the underlying private methods instead.

Comment on lines 719 to 726
.reduce(new HashMap<>(), (counts, deadline) -> {
int count = counts.getOrDefault(deadline, 0);
counts.put(deadline, count + 1);
return counts;
}, (curr, next) -> {
curr.putAll(next);
return curr;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps you are looking for Collectors.GroupingBy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes that would be much better; I did not know it existed. Thanks.

@@ -700,6 +704,182 @@ public void testUpdateFeedbackSession_shouldAdjustEmailSendingStatusAccordingly(
typicalSession.getFeedbackSessionName(), typicalSession.getCourseId()).isSentPublishedEmail());
}

@Test
public void testUpdateFeedbackSessionsInstructorDeadlinesWithNewEmail() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the test case name can describe the input and the output, say updateInstructorEmail_transferDeadlinesToNewEmail?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the test method name gets a bit too long if I add it to the end:

public void testUpdateFeedbackSessionsInstructorDeadlinesWithNewEmail_updateInstructorEmail_transferDeadlinesToNewEmail()

Or do you mean replacing it completely? Wouldn't this be unconventional?

public void testUpdateInstructorEmail_transferDeadlinesToNewEmail()

Or how about using something like ______TS("Update instructor email; transfers deadlines to new email.")?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think TS will do. Indeed it isn't too conventional to just replace as such.

}

@Test
public void testUpdateFeedbackSessionsStudentDeadlinesWithNewEmail() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

.map(FeedbackSessionAttributes::getStudentDeadlines)
.filter(studentDeadlines -> studentDeadlines.containsKey(oldEmailAddress))
.map(studentDeadlines -> studentDeadlines.get(oldEmailAddress))
.reduce(new HashMap<>(), (counts, deadline) -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto?

.filter(feedbackSessionAttributes -> feedbackSessionAttributes.getInstructorDeadlines()
.containsKey(emailAddress))
.collect(Collectors.toSet());
assertEquals(2, oldSessionsWithInstructor1Deadlines.size());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can consider move to after line 819?

@moziliar moziliar added s.Ongoing The PR is being worked on by the author(s) and removed s.ToReview The PR is waiting for review(s) labels Apr 1, 2022
.map(FeedbackSessionAttributes::getInstructorDeadlines)
.filter(instructorDeadlines -> instructorDeadlines.containsKey(oldEmailAddress))
.map(instructorDeadlines -> instructorDeadlines.get(oldEmailAddress))
.reduce(new HashMap<>(), (counts, deadline) -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more places like this are unclear. Can apply the same fix here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, I forgot I did it in other files too.

Copy link
Contributor

@moziliar moziliar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I'm ok with the rest of the changes!

@moziliar moziliar added s.FinalReview The PR is ready for final review and removed s.Ongoing The PR is being worked on by the author(s) labels Apr 2, 2022
Copy link
Contributor

@halfwhole halfwhole left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@moziliar moziliar merged commit 3e81144 into TEAMMATES:selective-deadline-extension Apr 3, 2022
moziliar pushed a commit that referenced this pull request Apr 3, 2022
* Add methods for updating and deleting deadline maps for a user

* Add tests for updating and deleting deadline maps for a user

* Cascade instructor updates or deletes to deadline maps

* Test cascade of instructor updates or deletes to deadline maps

* Cascade student updates or deletes to deadline maps

* Test cascade of student updates or deletes to deadline maps

* Match deadline extension entities with deadline maps

* Change deadlinesUpdater into a Consumer

* Change unexpected error assertion into a severe log

* Improve readability of feedback session deadline map update code

* Clean code

* Clean code further
moziliar pushed a commit that referenced this pull request Apr 4, 2022
* Add methods for updating and deleting deadline maps for a user

* Add tests for updating and deleting deadline maps for a user

* Cascade instructor updates or deletes to deadline maps

* Test cascade of instructor updates or deletes to deadline maps

* Cascade student updates or deletes to deadline maps

* Test cascade of student updates or deletes to deadline maps

* Match deadline extension entities with deadline maps

* Change deadlinesUpdater into a Consumer

* Change unexpected error assertion into a severe log

* Improve readability of feedback session deadline map update code

* Clean code

* Clean code further
moziliar pushed a commit that referenced this pull request Apr 6, 2022
* Add methods for updating and deleting deadline maps for a user

* Add tests for updating and deleting deadline maps for a user

* Cascade instructor updates or deletes to deadline maps

* Test cascade of instructor updates or deletes to deadline maps

* Cascade student updates or deletes to deadline maps

* Test cascade of student updates or deletes to deadline maps

* Match deadline extension entities with deadline maps

* Change deadlinesUpdater into a Consumer

* Change unexpected error assertion into a severe log

* Improve readability of feedback session deadline map update code

* Clean code

* Clean code further
@wkurniawan07 wkurniawan07 added s.ToMerge The PR is approved by all reviewers including final reviewer; ready for merging c.Task Other non-user-facing works, e.g. refactoring, adding tests and removed s.FinalReview The PR is ready for final review labels Apr 6, 2022
@wkurniawan07 wkurniawan07 added this to the V8.13.0 milestone Apr 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c.Task Other non-user-facing works, e.g. refactoring, adding tests s.ToMerge The PR is approved by all reviewers including final reviewer; ready for merging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants