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

i_900: add support for multiple groups per team #909

Merged
merged 28 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
63cd2d4
i900 First frew modules converted to multiple groups
johnbrvc Dec 20, 2023
7d0c634
i900 fix multiple groups for ICPC tab file and accounts report
johnbrvc Dec 20, 2023
b3948a0
i900 Start work on NSA
johnbrvc Dec 21, 2023
4b00522
i900 Add notion of a primary group id
johnbrvc Dec 25, 2023
90d3bbb
i900 More updates to support multiple groups
johnbrvc Dec 27, 2023
83cd032
i900 more changes to support multiple groups
johnbrvc Dec 28, 2023
5043473
i900 completed adding multiple groups - testing still needed
johnbrvc Jan 2, 2024
7b48690
i900 - First round of testing bug fixes
johnbrvc Jan 3, 2024
2d57656
i900 - add self-signed certificate file to .gitignore
johnbrvc Jan 3, 2024
a79dac5
i900 - add support for per-group standings
johnbrvc Jan 4, 2024
38347ad
i900 -General code cleanup
johnbrvc Jan 4, 2024
c4b320a
i900 add group selection to HTML Standings Pane
johnbrvc Jan 7, 2024
b0a1aab
i900 Bug fixes found by unit tests
johnbrvc Jan 7, 2024
e0bd79f
i900 Fix junit to use primary group for clarification testing
johnbrvc Jan 7, 2024
82bd9b3
i900 Code cleanup
johnbrvc Jan 7, 2024
910af8a
i_900 - update scoreboard client and nogui client to support multiple…
johnbrvc Jan 10, 2024
b07c34d
i_900 fix issues with scoreboard generation and group name
johnbrvc Jan 10, 2024
73e22c9
i_900 add unit test byproducts to .gitignore
johnbrvc Jan 10, 2024
e40d910
i_900 fix to only show problems for a specific group in scoreboard files
johnbrvc Jan 10, 2024
b9298f9
i_900 fix junit for testing problem visibility by group
johnbrvc Jan 10, 2024
f7d32b9
i_900 Add group filtering to support filtered event feed
johnbrvc Jan 14, 2024
fc172f9
i900 Division filtering bug fixes
johnbrvc Jan 20, 2024
505566f
i_900 Code cleanup
johnbrvc Jan 21, 2024
6a85192
i_900 Include groups of filtered teams in EventFeed
johnbrvc Jan 21, 2024
70da196
i_900 Add flag to groups in grouplist indicating if group is included…
johnbrvc Jan 27, 2024
496b584
i_900 add group selection to event feed for remote users
johnbrvc Jan 28, 2024
732ec59
i_900 Unit test bug fixes
johnbrvc Jan 28, 2024
377a925
i_900 fix logic bug with clarification filtering on EF
johnbrvc Jan 30, 2024
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
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,23 @@
/profiles.properties
/profiles/
/testout/
/html/
/public_html/
/results/
/reports/
/log/
passwords.txt
pc2export.dat
results.xml
results_*.xml

/.classes
/realm.properties
/VERSION
/pc2ws.properties
cacerts.pc2

projects/*.gz
projects/*.zip
projects/WTI-UI/package-lock.json
projects/WTI-UI/.angular/
Binary file modified projects/EWTeam/lib/pc2.jar
Binary file not shown.
Binary file modified projects/WTI-API/WebContent/WEB-INF/lib/pc2.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
/**
* Contains various tests to insure proper operation of {@link ContestController} methods which
* fetch contest clarifications from the PC2 Contest.
*
*
* The setup() prior to running the JUnit tests injects into the ContestController a "mock" PC2 server
* connection, so that the test can be run without actually having a PC2 server/contest running.
*
* Each test method is responsible for configuring the "mock contest" values located as protected fields in
* in the {@link ContestControllerInjection} superclass (and therefore accessible by this class).
* (This is a somewhat poor use of inheritance, but it does provide a convenient way give all JUnit tests
*
* Each test method is responsible for configuring the "mock contest" values located as protected fields in
* in the {@link ContestControllerInjection} superclass (and therefore accessible by this class).
* (This is a somewhat poor use of inheritance, but it does provide a convenient way give all JUnit tests
* access to the mock PC2 server connection.)
*
*
* @author EWU WebTeamClient project team, with updates by John Clevenger, PC2 Development Team (pc2.ecs.csus.edu)
*
*/
Expand All @@ -36,7 +36,7 @@ public class Test_Contest_Get_Clarifications extends ContestControllerInjection{

private Response response;
private ContestController controller;

//a (mock) clarification
private String teamName = "Team1";
private String problem = "A. Dogzilla";
Expand All @@ -45,7 +45,7 @@ public class Test_Contest_Get_Clarifications extends ContestControllerInjection{

@Before
public void setUp() throws Exception {

//inject a Mock PC2 server connection into the ContestController
this.contestControllerInjection();
this.controller = new ContestController();
Expand All @@ -62,20 +62,20 @@ public void Test_Get_Clarifications_401_Unauthorized_User(){
this.response = this.controller.clarifications("inValidId");
assertEquals(401, this.response.getStatus());
}

/**
* Test that under normal circumstances (logged in, contest properly configured and running), requesting clarifications
* returns "200" (OK).
*
*
* @throws Exception
*/
@Test
public void Test_Get_Clarifications_200() throws Exception{
public void Test_Get_Clarifications_200() throws Exception{

Mockito.when(connection.getContest().getClarifications()).thenReturn(new IClarification[] {mockedClarification});
Mockito.when(mockedClarification.getTeam()).thenReturn(mockedTeam);
Mockito.when(mockedClarification.getTeam().getGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getGroup().getName()).thenReturn(teamName);
Mockito.when(mockedClarification.getTeam().getPrimaryGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getPrimaryGroup().getName()).thenReturn(teamName);
Mockito.when(mockedClarification.getTeam().getDisplayName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getTeam().getLoginName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getProblem()).thenReturn(mockedProblem);
Expand All @@ -85,44 +85,44 @@ public void Test_Get_Clarifications_200() throws Exception{
Mockito.when(mockedClarification.getSubmissionTime()).thenReturn(12345678L);
Mockito.when(mockedClarification.isAnswered()).thenReturn(true);
Mockito.when(connection.getMyClient().getLoginName()).thenReturn("Team1");

//make sure the mock says that the contest is running for this test
Mockito.when(connection.getContest().isContestClockRunning()).thenReturn(true);

this.response = this.controller.clarifications(testKey);
assertEquals(200, this.response.getStatus());
}

/**
* Test that, while properly logged in and the contest is running, when requesting a list of the clarifications submitted by a team
* but there is a clarification that has no problem associated with it,
* Test that, while properly logged in and the contest is running, when requesting a list of the clarifications submitted by a team
* but there is a clarification that has no problem associated with it,
* "500" (INTERNAL_SERVER_ERROR) is returned -- because the server should never have accepted a
* clarification that doesn't have a valid problem associated with it.
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void Test_Get_Clarifications_500_Clar_Has_No_Associated_Problem() throws Exception {
public void Test_Get_Clarifications_500_Clar_Has_No_Associated_Problem() throws Exception {

Mockito.when(connection.getContest().getClarifications()).thenReturn(new IClarification[] {mockedClarification});

Mockito.when(mockedClarification.getTeam()).thenReturn(mockedTeam);
Mockito.when(mockedClarification.getTeam().getGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getGroup().getName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getTeam().getPrimaryGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getPrimaryGroup().getName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getTeam().getDisplayName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getTeam().getLoginName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getProblem()).thenThrow(NullPointerException.class);

Mockito.when(connection.getMyClient().getLoginName()).thenReturn(teamName);
Mockito.when(connection.getContest().getProblems()).thenThrow(NullPointerException.class);

//make sure the mock says that the contest is running for this test
Mockito.when(connection.getContest().isContestClockRunning()).thenReturn(true);

this.response = this.controller.clarifications(testKey);
assertEquals(500, this.response.getStatus());
}

/**
* Test that an attempt to fetch clarifications when properly logged in but the contest is not running returns
* "401" (Unauthorized).
Expand All @@ -131,33 +131,33 @@ public void Test_Get_Clarifications_500_Clar_Has_No_Associated_Problem() throws
@SuppressWarnings("unchecked")
@Test
public void Test_Get_Clarifications_401_Contest_Not_Running() throws Exception{

//define some (mock) clarifications, even though we shouldn't be able to access them
Mockito.when(connection.getContest().getClarifications()).thenReturn(new IClarification[] {mockedClarification});

Mockito.when(mockedClarification.getTeam()).thenReturn(mockedTeam);
Mockito.when(mockedClarification.getTeam().getGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getGroup().getName()).thenReturn("Team1");
Mockito.when(mockedClarification.getTeam().getPrimaryGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getPrimaryGroup().getName()).thenReturn("Team1");
Mockito.when(mockedClarification.getTeam().getDisplayName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getTeam().getLoginName()).thenReturn(teamName.toLowerCase());

Mockito.when(connection.getMyClient().getLoginName()).thenReturn(teamName);
Mockito.when(connection.getContest().getProblems()).thenThrow(NotLoggedInException.class);
//make sure the mock says that the contest is not running for this test

//make sure the mock says that the contest is not running for this test
Mockito.when(connection.getContest().isContestClockRunning()).thenReturn(false);

this.response = this.controller.clarifications(testKey);
assertEquals(401, this.response.getStatus());
}

/**
* Test that requesting the first clarification from Site 1 returns a clarification with is "1-1"
* Test that requesting the first clarification from Site 1 returns a clarification with is "1-1"
* and a response code of "200" (OK).
* @throws Exception
*/
@Test public void Test_Get_Clarifications_200_Id_Received() throws Exception{

//return Mocked Clarification info when the server (via the userconnection) asks the contest for clarifications
Mockito.when(connection.getContest().getClarifications()).thenReturn(new IClarification[] {mockedClarification});
Mockito.when(mockedClarification.getQuestion()).thenReturn(question);
Expand All @@ -166,36 +166,36 @@ public void Test_Get_Clarifications_401_Contest_Not_Running() throws Exception{
Mockito.when(mockedClarification.isAnswered()).thenReturn(true);
Mockito.when(mockedClarification.getSiteNumber()).thenReturn(1);
Mockito.when(mockedClarification.getNumber()).thenReturn(1);
//return Mocked Team info when the server (via the userconnection) asks the Clarification for Team info

//return Mocked Team info when the server (via the userconnection) asks the Clarification for Team info
Mockito.when(mockedClarification.getTeam()).thenReturn(mockedTeam);
Mockito.when(mockedClarification.getTeam().getGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getGroup().getName()).thenReturn(teamName);
Mockito.when(mockedClarification.getTeam().getPrimaryGroup()).thenReturn(mockedGroup);
Mockito.when(mockedClarification.getTeam().getPrimaryGroup().getName()).thenReturn(teamName);
Mockito.when(mockedClarification.getTeam().getDisplayName()).thenReturn(teamName.toLowerCase());
Mockito.when(mockedClarification.getTeam().getLoginName()).thenReturn(teamName.toLowerCase());

//return Mocked Problem info when the server (via the userconnection) asks the Clarification for Problem info
Mockito.when(mockedClarification.getProblem()).thenReturn(mockedProblem);
Mockito.when(mockedClarification.getProblem().getName()).thenReturn(problem);

Mockito.when(connection.getMyClient().getLoginName()).thenReturn(teamName);

//make sure the mock says that the contest is running for this test
//make sure the mock says that the contest is running for this test
Mockito.when(connection.getContest().isContestClockRunning()).thenReturn(true);

this.response = this.controller.clarifications(testKey);
assertEquals(200, this.response.getStatus());

@SuppressWarnings("unchecked")
List<ClarificationModel> clars = (List<ClarificationModel>) this.response.getEntity();
assertEquals("1-1", clars.get(0).id);

}

@After
public void tearDown() throws Exception {
if(response != null)
this.response.close();
}

}
19 changes: 15 additions & 4 deletions src/edu/csus/ecs/pc2/api/ITeam.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
// Copyright (C) 1989-2019 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package edu.csus.ecs.pc2.api;

import java.util.HashMap;

import edu.csus.ecs.pc2.core.model.ElementId;

/**
* This interface describes the PC<sup>2</sup> API view of a contest <I>Team</i>.
* Note that every <I>Team</i> in the API view is a subclass of {@link IClient},
* so a &quot;team view&quot; also contains the general information described by
* {@link IClient}.
*
*
* <p>
* This documentation describes the current <I>draft</i> of the PC<sup>2</sup> API, which is subject to change.
*
*
* @author [email protected]
* @version $Id$
*/
Expand All @@ -19,9 +23,16 @@ public interface ITeam extends IClient {

/**
* Get the group associate with this team.
*
*
* @see IGroup
* @return group information.
*/
IGroup getGroup();
public HashMap<ElementId, IGroup> getGroups();

/**
* Get the primary (cms) group for a team
*
* @return id of the CMS supplied group (so-called primary group)
*/
public IGroup getPrimaryGroup();
}
39 changes: 30 additions & 9 deletions src/edu/csus/ecs/pc2/api/implementation/TeamImplementation.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// Copyright (C) 1989-2019 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package edu.csus.ecs.pc2.api.implementation;

import java.util.HashMap;

import edu.csus.ecs.pc2.api.IGroup;
import edu.csus.ecs.pc2.api.ITeam;
import edu.csus.ecs.pc2.core.model.Account;
import edu.csus.ecs.pc2.core.model.ClientId;
import edu.csus.ecs.pc2.core.model.ElementId;
import edu.csus.ecs.pc2.core.model.IInternalContest;

/**
* Implementation for ITeam.
*
*
* @author [email protected]
* @version $Id$
*/
Expand All @@ -21,7 +24,8 @@ public class TeamImplementation extends ClientImplementation implements ITeam {

private String shortName;

private IGroup group = null;
private HashMap<ElementId, IGroup> groups = null;
private IGroup primaryGroup = null;

public TeamImplementation(ClientId submitter, IInternalContest internalContest) {
super(submitter, internalContest);
Expand All @@ -38,12 +42,21 @@ public TeamImplementation(ClientId submitter, IInternalContest internalContest)
private void setAccountValues(Account account, IInternalContest contest) {
displayName = account.getDisplayName();
shortName = account.getClientId().getName();
if (account.getGroupId() != null) {
// SOMEDAY ensure that groupId is not null
// this happened on load of teams.tsv and groups.tsv
if (contest.getGroup(account.getGroupId()) != null){
group = new GroupImplementation(account.getGroupId(), contest);
if (account.getGroupIds() != null) {
for(ElementId elementId: account.getGroupIds()) {
if (contest.getGroup(elementId) != null){
if(groups == null) {
groups = new HashMap<ElementId, IGroup>();
}
GroupImplementation group = new GroupImplementation(elementId, contest);
groups.put(elementId, group);
if(primaryGroup == null && account.getPrimaryGroupId() == elementId) {
primaryGroup = group;
}
}
}
} else {
groups = null;
}
}

Expand All @@ -52,16 +65,24 @@ public TeamImplementation(Account account, IInternalContest contest) {
setAccountValues(account, contest);
}

@Override
public String getDisplayName() {
return displayName;
}

public IGroup getGroup() {
return group;
@Override
public HashMap<ElementId, IGroup> getGroups() {
return groups;
}

@Override
public String getLoginName() {
return shortName;
}

@Override
public IGroup getPrimaryGroup() {
return primaryGroup;
}

}
Loading
Loading