Skip to content

Commit

Permalink
[#11362] [#11617] Use course institute fully for displays + to determ…
Browse files Browse the repository at this point in the history
…ine whether account can create course (#11654)

* Use course as the source of institute instead of account

* Remove institute information from footer

* Remove account institute information in admin account page

* Display course institute information in admin account page

* Display course institute in instructor/student course details page

* Extend GetCourseAction to be accessible by unregistered users

* Display course institute in session submission/results page

* Remove institute from account entity

* Check for institute validity when creating course

* Remove account isInstructor information in admin account page

* Remove function to downgrade instructor in admin accounts page

* Remove isInstructor from account entity

* Remove unused createAtTimestamp for account output
  • Loading branch information
wkurniawan07 authored Apr 6, 2022
1 parent ec73778 commit 6ef3fb2
Show file tree
Hide file tree
Showing 151 changed files with 1,375 additions and 2,120 deletions.
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ If you are certain that you are reporting a new issue, [open a new issue](https:
We welcome anyone manually testing our product and reporting bugs or suggestions for enhancements in the issue tracker.

If you want to undertake such a role without actually contributing code, [get an instructor account from TEAMMATES](https://teammatesv4.appspot.com/web/front/request).
Remember to mention the purpose of your request under "Any other comments/queries".
Remember to mention the purpose of your request under "Any other comments/queries". *Note that we may need to assign a different institute from your request in order to prevent fraudulent usages.*

### Submitting a pull request

Expand Down

This file was deleted.

35 changes: 0 additions & 35 deletions src/client/java/teammates/client/scripts/statistics/FileStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,48 +47,13 @@ public class FileStore {
new File(BASE_URI).mkdir();
}

private static final String COURSE_TO_INSTITUTE_CACHE_FILEPATH = BASE_URI + "CourseToInstituteCache.encrypted";
private static final String INSTITUTES_STATS_FILEPATH = BASE_URI + "InstitutesStats.encrypted";
private static final String INSTITUTES_STATS_METADATA_FILEPATH = BASE_URI + "InstitutesStatsMetadata.json";

private FileStore() {
// utility class
}

/**
* Gets the cache service.
*
* <p>If the cache is persisted to the disk, decrypts and parses it to warm up the cache.
*/
public static CourseToInstituteCache getCourseToInstituteCacheFromFileIfPossible() throws Exception {
// parse courseToInstituteCacheFile
File courseToInstituteCacheFile = new File(COURSE_TO_INSTITUTE_CACHE_FILEPATH);
CourseToInstituteCache courseToInstituteCache = new CourseToInstituteCache();
if (courseToInstituteCacheFile.isFile()) {
courseToInstituteCache = parseEncryptedJsonFile(COURSE_TO_INSTITUTE_CACHE_FILEPATH,
jsonReader -> {
CourseToInstituteCache cache = new CourseToInstituteCache();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
cache.populate(jsonReader.nextName(), jsonReader.nextString());
}
jsonReader.endObject();
return cache;
});
}

return courseToInstituteCache;
}

/**
* Encrypts and persists the cache to a file in disk.
*/
public static void saveCourseToInstituteCacheToFile(CourseToInstituteCache courseToInstituteCache)
throws Exception {
saveEncryptedJsonToFile(COURSE_TO_INSTITUTE_CACHE_FILEPATH, courseToInstituteCache.asMap(),
new TypeToken<Map<String, String>>(){}.getType());
}

/**
* Decrypts and parses the statistics bundle that is saved in the disk.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,40 @@

import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

import com.googlecode.objectify.cmd.Query;

import teammates.client.connector.DatastoreClient;
import teammates.client.util.LoopHelper;
import teammates.storage.entity.Account;
import teammates.common.util.Const;
import teammates.storage.entity.Course;
import teammates.storage.entity.CourseStudent;
import teammates.storage.entity.Instructor;

/**
* Script that calculates the number of unique students and instructors per institute.
*/
public class StatisticsPerInstitute extends DatastoreClient {

private StatisticsBundle bundle;
private CourseToInstituteCache courseToInstituteCache;
private final StatisticsBundle bundle;
private final Map<String, String> courseToInstituteCache = new HashMap<>();

StatisticsPerInstitute() throws Exception {
bundle = FileStore.getStatisticsBundleFromFileIfPossible();
courseToInstituteCache = FileStore.getCourseToInstituteCacheFromFileIfPossible();
}

public static void main(String[] args) throws Exception {
StatisticsPerInstitute statistics = new StatisticsPerInstitute();
statistics.doOperationRemotely();
}

private String getCourseInstitute(String courseId) {
Course course = ofy().load().type(Course.class).id(courseId).now();
return course == null || course.getInstitute() == null ? Const.UNKNOWN_INSTITUTION : course.getInstitute();
}

@Override
protected void doOperation() {
Instant now = Instant.now();
Expand All @@ -46,8 +54,8 @@ protected void doOperation() {
ofy().load().type(CourseStudent.class)
.filter("createdAt >", queryEntitiesFrom)
.filter("createdAt <=", queryEntitiesTo);
Query<Account> accountQuery =
ofy().load().type(Account.class)
Query<Instructor> instructorQuery =
ofy().load().type(Instructor.class)
.filter("createdAt >", queryEntitiesFrom)
.filter("createdAt <=", queryEntitiesTo);

Expand All @@ -56,20 +64,20 @@ protected void doOperation() {
"Counting institutions stats by scanning student entities...");
Iterable<CourseStudent> students = CursorIterator.iterate(studentQuery);
for (CourseStudent student : students) {
String instituteOfTheStudent = courseToInstituteCache.get(student.getCourseId());
String instituteOfTheStudent = courseToInstituteCache.computeIfAbsent(student.getCourseId(),
k -> getCourseInstitute(student.getCourseId()));
bundle.addStudentEmailToInstitute(instituteOfTheStudent, student.getEmail());
loopHelper.recordLoop();
}

// generate institute stats by scanning account (instructor) entities
loopHelper = new LoopHelper(100,
"Counting institutions stats by scanning account (instructor) entities...");
Iterable<Account> accounts = CursorIterator.iterate(accountQuery);
for (Account account : accounts) {
if (!account.isInstructor()) {
continue;
}
bundle.addInstructorEmailToInstitute(account.getInstitute(), account.getEmail());
"Counting institutions stats by scanning instructor entities...");
Iterable<Instructor> instructors = CursorIterator.iterate(instructorQuery);
for (Instructor instructor : instructors) {
String instituteOfTheInstructor = courseToInstituteCache.computeIfAbsent(instructor.getCourseId(),
k -> getCourseInstitute(instructor.getCourseId()));
bundle.addInstructorEmailToInstitute(instituteOfTheInstructor, instructor.getEmail());
loopHelper.recordLoop();
}

Expand Down Expand Up @@ -122,7 +130,6 @@ private void saveCheckpointOfData(Instant queryEntitiesFrom, Instant queryEntiti
try {
bundle.setStatsSince(queryEntitiesTo);
FileStore.saveStatisticsBundleToFile(bundle);
FileStore.saveCourseToInstituteCacheToFile(courseToInstituteCache);
} catch (Exception e) {
System.out.println("===== Error saving checkpoint when counting stats from %s to %s =====%n");
e.printStackTrace();
Expand Down
19 changes: 0 additions & 19 deletions src/e2e/java/teammates/e2e/cases/AdminAccountsPageE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,6 @@ public void testAll() {
accountsPage.verifyStatusMessage("Student is successfully deleted from course \"" + courseId + "\"");
verifyAbsentInDatabase(student);

______TS("action: downgrade instructor account");

InstructorAttributes instructor2 = testData.instructors.get("AAccounts.instr2-AAccounts.CS2104");
InstructorAttributes instructor3 = testData.instructors.get("AAccounts.instr2-AAccounts.CS1101");
verifyPresentInDatabase(instructor2);
verifyPresentInDatabase(instructor3);

accountsPage.clickDowngradeAccount();
accountsPage.verifyStatusMessage("Instructor account is successfully downgraded to student.");
accountsPage.waitForPageToLoad();

account = getAccount(googleId);
assertFalse(account.isInstructor());
accountsPage.verifyAccountDetails(account);

// instructor entities should also be deleted
verifyAbsentInDatabase(instructor2);
verifyAbsentInDatabase(instructor3);

______TS("action: delete account entirely");

StudentAttributes student2 = testData.students.get("AAccounts.instr2-student-CS2104");
Expand Down
17 changes: 8 additions & 9 deletions src/e2e/java/teammates/e2e/cases/AdminSearchPageE2ETest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import org.testng.annotations.Test;

import teammates.common.datatransfer.attributes.AccountAttributes;
import teammates.common.datatransfer.attributes.AccountRequestAttributes;
import teammates.common.datatransfer.attributes.CourseAttributes;
import teammates.common.datatransfer.attributes.FeedbackSessionAttributes;
import teammates.common.datatransfer.attributes.InstructorAttributes;
import teammates.common.datatransfer.attributes.StudentAttributes;
Expand Down Expand Up @@ -40,10 +40,9 @@ public void testAll() {
AppUrl url = createFrontendUrl(Const.WebPageURIs.ADMIN_SEARCH_PAGE);
AdminSearchPage searchPage = loginAdminToPage(url, AdminSearchPage.class);

CourseAttributes course = testData.courses.get("typicalCourse1");
StudentAttributes student = testData.students.get("student1InCourse1");
AccountAttributes studentAccount = testData.accounts.get("student1InCourse1");
InstructorAttributes instructor = testData.instructors.get("instructor1OfCourse1");
AccountAttributes instructorAccount = testData.accounts.get("instructor1OfCourse1");
AccountRequestAttributes accountRequest = testData.accountRequests.get("instructor1OfCourse1");

______TS("Typical case: Search student email");
Expand All @@ -54,7 +53,7 @@ public void testAll() {
String studentManageAccountLink = getExpectedStudentManageAccountLink(student);
String studentHomePageLink = getExpectedStudentHomePageLink(student);
int numExpandedRows = getExpectedNumExpandedRows(student);
searchPage.verifyStudentRowContent(student, studentAccount, studentDetails, studentManageAccountLink,
searchPage.verifyStudentRowContent(student, course, studentDetails, studentManageAccountLink,
studentHomePageLink);
searchPage.verifyStudentExpandedLinks(student, numExpandedRows);

Expand All @@ -63,7 +62,7 @@ public void testAll() {
student.setGoogleId(null);
studentManageAccountLink = getExpectedStudentManageAccountLink(student);
studentHomePageLink = getExpectedStudentHomePageLink(student);
searchPage.verifyStudentRowContent(student, studentAccount, studentDetails, studentManageAccountLink,
searchPage.verifyStudentRowContent(student, course, studentDetails, studentManageAccountLink,
studentHomePageLink);

______TS("Typical case: Regenerate registration key for a course student");
Expand All @@ -81,7 +80,7 @@ public void testAll() {
searchPage.clickSearchButton();
String instructorManageAccountLink = getExpectedInstructorManageAccountLink(instructor);
String instructorHomePageLink = getExpectedInstructorHomePageLink(instructor);
searchPage.verifyInstructorRowContent(instructor, instructorAccount, instructorManageAccountLink,
searchPage.verifyInstructorRowContent(instructor, course, instructorManageAccountLink,
instructorHomePageLink);
searchPage.verifyInstructorExpandedLinks(instructor);

Expand All @@ -90,7 +89,7 @@ public void testAll() {
instructor.setGoogleId(null);
instructorManageAccountLink = getExpectedInstructorManageAccountLink(instructor);
instructorHomePageLink = getExpectedInstructorHomePageLink(instructor);
searchPage.verifyInstructorRowContent(instructor, instructorAccount, instructorManageAccountLink,
searchPage.verifyInstructorRowContent(instructor, course, instructorManageAccountLink,
instructorHomePageLink);

______TS("Typical case: Regenerate registration key for an instructor");
Expand All @@ -114,9 +113,9 @@ public void testAll() {
searchContent = "Course1";
searchPage.inputSearchContent(searchContent);
searchPage.clickSearchButton();
searchPage.verifyStudentRowContent(student, studentAccount, studentDetails, studentManageAccountLink,
searchPage.verifyStudentRowContent(student, course, studentDetails, studentManageAccountLink,
studentHomePageLink);
searchPage.verifyInstructorRowContent(instructor, instructorAccount, instructorManageAccountLink,
searchPage.verifyInstructorRowContent(instructor, course, instructorManageAccountLink,
instructorHomePageLink);
searchPage.verifyAccountRequestRowContent(accountRequest);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.testng.annotations.Test;

import teammates.common.datatransfer.FeedbackParticipantType;
import teammates.common.datatransfer.attributes.CourseAttributes;
import teammates.common.datatransfer.attributes.FeedbackQuestionAttributes;
import teammates.common.datatransfer.attributes.FeedbackResponseAttributes;
import teammates.common.datatransfer.attributes.FeedbackResponseCommentAttributes;
Expand All @@ -25,6 +26,7 @@
*/
public class FeedbackResultsPageE2ETest extends BaseE2ETestCase {
private FeedbackResultsPage resultsPage;
private CourseAttributes course;
private FeedbackSessionAttributes openSession;
private List<FeedbackQuestionAttributes> questions = new ArrayList<>();

Expand All @@ -33,6 +35,7 @@ protected void prepareTestData() {
testData = loadDataBundle("/FeedbackResultsPageE2ETest.json");
removeAndRestoreDataBundle(testData);

course = testData.courses.get("FRes.CS2104");
openSession = testData.feedbackSessions.get("Open Session");
for (int i = 1; i <= testData.feedbackQuestions.size(); i++) {
questions.add(testData.feedbackQuestions.get("qn" + i));
Expand All @@ -52,7 +55,7 @@ public void testAll() {
.withRegistrationKey(getKeyForStudent(unregistered));
resultsPage = getNewPageInstance(url, FeedbackResultsPage.class);

resultsPage.verifyFeedbackSessionDetails(openSession);
resultsPage.verifyFeedbackSessionDetails(openSession, course);

______TS("unregistered student: questions with responses loaded");
verifyLoadedQuestions(unregistered);
Expand All @@ -64,7 +67,7 @@ public void testAll() {
.withSessionName(openSession.getFeedbackSessionName());
resultsPage = loginToPage(url, FeedbackResultsPage.class, student.getGoogleId());

resultsPage.verifyFeedbackSessionDetails(openSession);
resultsPage.verifyFeedbackSessionDetails(openSession, course);

______TS("registered student: questions with responses loaded");
verifyLoadedQuestions(student);
Expand Down Expand Up @@ -105,7 +108,7 @@ public void testAll() {
.withSessionName(openSession.getFeedbackSessionName());
resultsPage = loginToPage(url, FeedbackResultsPage.class, instructor.getGoogleId());

resultsPage.verifyFeedbackSessionDetails(openSession);
resultsPage.verifyFeedbackSessionDetails(openSession, course);

______TS("registered instructor: questions with responses loaded");
verifyLoadedQuestions(instructor);
Expand Down
Loading

0 comments on commit 6ef3fb2

Please sign in to comment.