Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
ee131aa
Add new `ACCESSIBILITY` pref field
jacbn Aug 6, 2025
c516f5d
Add migration to move some DISPLAY_SETTINGS to ACCESSIBILITY
jacbn Aug 6, 2025
45904fb
Don't use wildcard instructions for searchable content
axlewin Aug 13, 2025
25c0314
Require stricter matching for searching by id
axlewin Aug 13, 2025
e210166
Restore slight boost to searchable content
axlewin Aug 13, 2025
b810ce6
Prioritise exact matches on id/title/subtitle
axlewin Aug 15, 2025
93ce11e
Prioritise exact matches for question finder search
axlewin Aug 19, 2025
06180ad
Add null check for QF search string
axlewin Aug 19, 2025
2b3da1c
Change access modifier
axlewin Aug 19, 2025
39780ad
Fix indentation
axlewin Aug 19, 2025
2891e46
Fix indentation
axlewin Aug 19, 2025
5a0cf32
Load gameboard question limit from config
mwtrew Aug 27, 2025
802a8bf
Release v3.20.6
jsharkey13 Aug 28, 2025
fe62a63
Increment version
jsharkey13 Aug 28, 2025
c45783f
Respect `nofilter` in Set Tests
mwtrew Sep 1, 2025
4935eba
Enable workflows on main
mwtrew Sep 1, 2025
38f2b0d
Add container to compose file for authoring IT data
mwtrew Sep 2, 2025
c3d819b
Ignore nofilter for staff users
mwtrew Sep 2, 2025
8cc40c4
Add tests for nofilter tags for Tests
mwtrew Sep 2, 2025
6bae6f3
Merge pull request #719 from isaacphysics/improvement/respect-nofilte…
jsharkey13 Sep 2, 2025
0868b5e
Restore default generated gameboard size
mwtrew Sep 2, 2025
4d8e16e
Release v3.20.7
jacbn Sep 3, 2025
1eb38e4
Increment version
jacbn Sep 3, 2025
16b8c7a
Add maxMarks to LLMFreeTextQuestionDTO
sjd210 Sep 3, 2025
b5e848a
Merge pull request #722 from isaacphysics/hotfix/max-marks-dto
axlewin Sep 5, 2025
f4cd894
Merge branch 'main' of github.com:isaacphysics/isaac-api into improve…
mwtrew Sep 9, 2025
b26613c
Update README to reflect name change
jsharkey13 Sep 10, 2025
fab75b7
Release v3.20.8
barna-isaac Sep 11, 2025
40fe063
Increment version
barna-isaac Sep 11, 2025
02c48b4
Add tests for gameboard question limit
mwtrew Sep 12, 2025
c099b8d
Merge branch 'main' of github.com:isaacphysics/isaac-api into improve…
mwtrew Sep 12, 2025
7a6a9b9
Use default gameboard size as limit if config property absent
mwtrew Sep 15, 2025
b2a6e60
Merge pull request #718 from isaacphysics/improvement/increase-gamebo…
barna-isaac Sep 15, 2025
e4e68ce
Release v3.20.9
axlewin Sep 17, 2025
8df3ab8
Increment version
axlewin Sep 17, 2025
09e797d
Fix missing null check for fasttrack endpoint
jsharkey13 Sep 25, 2025
f6a2956
Update swagger, guava, jwks-rsa, geoip
mwtrew Sep 29, 2025
ae798c6
Update dependency-check
mwtrew Sep 29, 2025
80f37d7
Update log4j and swagger
mwtrew Oct 1, 2025
2c7c0a7
Update lang3, bouncycastle, junit-5
mwtrew Oct 1, 2025
9bd7f76
Update surefire, snakeyaml, assertj, postgres
mwtrew Oct 1, 2025
7909bc4
Update resteasy
mwtrew Oct 1, 2025
429b4ff
Update jetty
mwtrew Oct 1, 2025
1d30daa
Update jackson, use BOM package to align indirect dependencies
mwtrew Oct 1, 2025
2f39262
Resolve merge conflict
mwtrew Oct 1, 2025
e5e27b8
Release v3.20.10
mwtrew Oct 2, 2025
a40a129
Increment version
mwtrew Oct 2, 2025
aebd121
Separate searchable content logic out from fuzzy strategy
axlewin Oct 2, 2025
e6cf256
Allow `isSearchableContent` field strategy to be overridden by existi…
axlewin Oct 2, 2025
d514d78
Revert "Allow `isSearchableContent` field strategy to be overridden b…
axlewin Oct 2, 2025
018e936
Restore jackson-databind variable, add comments for BOM and jackson-a…
mwtrew Oct 2, 2025
c632c13
Resolve merge conflict
mwtrew Oct 2, 2025
246e630
Merge pull request #725 from isaacphysics/dependency-updates-09-25
jsharkey13 Oct 2, 2025
e2a11e6
Merge pull request #716 from isaacphysics/hotfix/improve-search-results
barna-isaac Oct 3, 2025
4a975e0
Add getters/setters for permissions & notes
axlewin Oct 3, 2025
bde34c2
Merge pull request #729 from isaacphysics/hotfix/notes-perms
sjd210 Oct 6, 2025
97e6687
Merge branch 'main' into feature/accessibility-user-preference
jacbn Oct 6, 2025
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
6 changes: 2 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ name: "CodeQL"

on:
push:
branches: [ "master", "redesign-2024" ]
branches: [ "main" ]
pull_request:
branches: [ "master", "redesign-2024" ]
schedule:
- cron: "44 13 * * 4"
branches: [ "main" ]

jobs:
analyze:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ name: Java CI with Maven

on:
push:
branches: [ "master", "redesign-2024" ]
branches: [ "main" ]
pull_request:
branches: [ "master", "redesign-2024" ]
branches: [ "main" ]

jobs:
build-and-test:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
[![codecov](https://codecov.io/gh/isaacphysics/isaac-api/branch/master/graph/badge.svg)](https://codecov.io/gh/isaacphysics/isaac-api)


`isaac-api` is the server and API for the [Isaac Physics](https://isaacphysics.org/about) and [Ada Computer Science](https://adacomputerscience.org/about) projects. Together with [`isaac-react-app`](https://github.com/isaacphysics/isaac-react-app), it forms the core stack of the Isaac platform.
`isaac-api` is the server and API for the [Isaac Science](https://isaacscience.org/about) and [Ada Computer Science](https://adacomputerscience.org/about) projects. Together with [`isaac-react-app`](https://github.com/isaacphysics/isaac-react-app), it forms the core stack of the Isaac platform.

The API runs on Jetty, and runs in [Docker](https://www.docker.com/) in production.
15 changes: 15 additions & 0 deletions compose-local-deps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ services:
ports:
- "5432:5432"

it-postgres:
network_mode: bridge
container_name: it-postgres
image: postgres:16
volumes:
- ./src/main/resources/db_scripts/postgres-rutherford-create-script.sql:/docker-entrypoint-initdb.d/00-isaac-create.sql:ro
- ./src/main/resources/db_scripts/postgres-rutherford-functions.sql:/docker-entrypoint-initdb.d/01-isaac-functions.sql:ro
- ./src/main/resources/db_scripts/quartz_scheduler_create_script.sql:/docker-entrypoint-initdb.d/02-isaac-quartz.sql:ro
- ./src/test/resources/test-postgres-rutherford-data-dump.sql:/docker-entrypoint-initdb.d/03-isaac-test-data.sql:ro
environment:
POSTGRES_USER: rutherford
POSTGRES_PASSWORD: rutherf0rd
ports:
- "5433:5432"

# app-physics:
# network_mode: bridge
# container_name: app-physics
Expand Down
71 changes: 33 additions & 38 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,33 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<segue.version>v3.20.6-SNAPSHOT</segue.version>
<log4j.version>2.25.1</log4j.version>
<resteasy.version>6.2.12.Final</resteasy.version>
<segue.version>v3.20.11-SNAPSHOT</segue.version>
<log4j.version>2.25.2</log4j.version>
<resteasy.version>6.2.14.Final</resteasy.version>
<guice.version>7.0.0</guice.version>
<oauth-client.version>1.39.0</oauth-client.version>
<jackson.version>2.19.2</jackson.version>
<jackson-databind.version>2.19.2</jackson-databind.version>
<jackson.version>2.20.0</jackson.version>
<!-- 'jackson-databind' is kept separate to make it easier to update to later patch versions for security
reasons. -->
<jackson-databind.version>2.20.0</jackson-databind.version>
<!-- todo: 'jackson-annotations' would normally have the same version string as 'jackson'. This looks like a
typo from the maintainers - hopefully we can remove this next update. -->
<jackson-annotations.version>2.20</jackson-annotations.version>
<powermock.version>2.0.9</powermock.version>
<junit-4.version>4.13.2</junit-4.version>
<junit-5.version>5.13.4</junit-5.version>
<junit-5.version>5.14.0</junit-5.version>
<swagger-ui-version>4.13.2</swagger-ui-version>
<prometheus.version>0.16.0</prometheus.version>
<jetty-version>11.0.25</jetty-version>
<jetty-version>11.0.26</jetty-version>
<jetty.port.api>8080</jetty.port.api>
<jetty.port.etl>8090</jetty.port.etl>
<testcontainers.version>1.21.3</testcontainers.version>
<web.xml>web-api-live.xml</web.xml>
<web.xml.etl>web-etl.xml</web.xml.etl>
<web.xml.local>web-api-local.xml</web.xml.local>
<dependency-check.version>12.1.3</dependency-check.version>
<dependency-check.version>12.1.6</dependency-check.version>
<ossindex.version>3.2.0</ossindex.version>
<swagger-core.version>2.2.34</swagger-core.version>
<swagger-core.version>2.2.38</swagger-core.version>
<jgit.version>6.10.1.202505221210-r</jgit.version>
<surefire.jacoco.args />
<failsafe.jacoco.args />
Expand All @@ -52,7 +57,7 @@
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.4</version>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.isaacphysics.thirdparty</groupId>
Expand Down Expand Up @@ -148,7 +153,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.8-jre</version>
<version>33.5.0-jre</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -223,7 +228,7 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.27.3</version>
<version>3.27.6</version>
<scope>test</scope>
</dependency>

Expand All @@ -235,7 +240,7 @@
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>0.22.2</version>
<version>0.23.0</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
Expand Down Expand Up @@ -314,7 +319,7 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
<version>${jackson-annotations.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
Expand All @@ -325,7 +330,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.18.0</version>
<version>3.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
Expand Down Expand Up @@ -382,7 +387,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.7</version>
<version>42.7.8</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -471,13 +476,13 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.81</version>
<version>1.82</version>
</dependency>

<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>4.3.1</version>
<version>4.4.0</version>
</dependency>

<!-- These two don't need to be included in the war package so their scope is "provided" which means we
Expand Down Expand Up @@ -557,7 +562,7 @@
See https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html#manually-specifying-a-provider -->
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>3.5.3</version>
<version>3.5.4</version>
</dependency>
</dependencies>
<configuration>
Expand Down Expand Up @@ -722,29 +727,19 @@
</resources>
</build>

<!-- This block pins versions of indirect dependencies - useful to address security issues -->
<!-- This block pins versions of indirect dependencies - useful to address security issues, or to resolve
incompatibilities. -->
<!-- TODO: When doing dependency updates, please make sure these are still necessary, and remove them if not -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jakarta-rs-base</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jakarta-xmlbind-annotations</artifactId>
<version>2.19.2</version>
<!-- This "BOM" package ensures we get a compatible set of Jackson plugins across our indirect
dependencies. More info here: https://github.com/FasterXML/jackson-bom -->
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Expand Down
7 changes: 1 addition & 6 deletions src/main/java/uk/ac/cam/cl/dtg/isaac/api/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ public final class Constants {
public static final Set<String> SEARCHABLE_DOC_TYPES = ImmutableSet.of(
QUESTION_TYPE, FAST_TRACK_QUESTION_TYPE, CONCEPT_TYPE, TOPIC_SUMMARY_PAGE_TYPE, BOOK_INDEX_TYPE, BOOK_DETAIL_TYPE, PAGE_TYPE, EVENT_TYPE);

/*
* Game specific variables.
*/
public static final int GAME_BOARD_TARGET_SIZE = 10;

public enum CompletionState {
ALL_CORRECT, ALL_ATTEMPTED, ALL_INCORRECT, IN_PROGRESS, NOT_ATTEMPTED;

Expand Down Expand Up @@ -230,7 +225,7 @@ public enum IsaacClientLogType implements LogType {
* User preference categories
*/
public enum IsaacUserPreferences {
BETA_FEATURE, EXAM_BOARD, PROGRAMMING_LANGUAGE, BOOLEAN_NOTATION, DISPLAY_SETTING, CONSENT
BETA_FEATURE, EXAM_BOARD, PROGRAMMING_LANGUAGE, BOOLEAN_NOTATION, DISPLAY_SETTING, ACCESSIBILITY, CONSENT
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ public final Response getFastTrackConceptFromHistory(@Context final Request requ
this.questionManager.getQuestionAttemptsByUser(currentUser);

List<GameboardItem> conceptQuestionsProgress = Lists.newArrayList();
if (upperQuestionId.isEmpty()) {
if (null == upperQuestionId || upperQuestionId.isEmpty()) {
List<FASTTRACK_LEVEL> upperAndLower = Arrays.asList(FASTTRACK_LEVEL.ft_upper, FASTTRACK_LEVEL.ft_lower);
conceptQuestionsProgress.addAll(fastTrackManger.getConceptProgress(
gameboard, upperAndLower, currentConceptTitle, userQuestionAttempts));
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/uk/ac/cam/cl/dtg/isaac/api/QuizFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,16 @@ public final Response getAvailableQuizzes(@Context final Request request,
try {

String userRoleString = Role.STUDENT.name(); // Allow anonymous users to list STUDENT quizzes.
boolean showNofilterQuizzes = false;

AbstractSegueUserDTO currentUser = userManager.getCurrentUser(httpServletRequest);
if (currentUser instanceof RegisteredUserDTO) {
userRoleString = ((RegisteredUserDTO) currentUser).getRole().name();
try {
showNofilterQuizzes = isUserStaff(userManager, (RegisteredUserDTO) currentUser);
} catch (final NoUserLoggedInException e) {
// Not possible inside this if block!
}
}

// Cache the list of quizzes based on current content version, user's role, and startIndex:
Expand All @@ -217,7 +224,7 @@ public final Response getAvailableQuizzes(@Context final Request request,
// FIXME: ** HARD-CODED DANGER AHEAD **
// The limit parameter in the following call is hard-coded and should be returned to a more reasonable
// number once we have a front-end pagination/load-more system in place.
ResultsWrapper<ContentSummaryDTO> summary = this.quizManager.getAvailableQuizzes(userRoleString, startIndex, 9000);
ResultsWrapper<ContentSummaryDTO> summary = this.quizManager.getAvailableQuizzes(userRoleString, startIndex, 9000, showNofilterQuizzes);

return ok(summary).tag(etag)
.cacheControl(getCacheControl(NEVER_CACHE_WITHOUT_ETAG_CHECK, false))
Expand Down
30 changes: 20 additions & 10 deletions src/main/java/uk/ac/cam/cl/dtg/isaac/api/managers/GameManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.cam.cl.dtg.isaac.api.Constants;
import uk.ac.cam.cl.dtg.isaac.dao.GameboardPersistenceManager;
import uk.ac.cam.cl.dtg.isaac.dos.AudienceContext;
import uk.ac.cam.cl.dtg.isaac.dos.GameboardContentDescriptor;
Expand Down Expand Up @@ -60,6 +59,8 @@

import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;
import uk.ac.cam.cl.dtg.util.AbstractConfigLoader;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -87,6 +88,8 @@ public class GameManager {
private static final float DEFAULT_QUESTION_PASS_MARK = 75;

private static final int MAX_QUESTIONS_TO_SEARCH = 20;
private static final int GAMEBOARD_QUESTIONS_DEFAULT = 10;
private static int gameboardQuestionsLimit;

private final GameboardPersistenceManager gameboardPersistenceManager;
private final Random randomGenerator;
Expand All @@ -109,14 +112,21 @@ public class GameManager {
@Inject
public GameManager(final GitContentManager contentManager,
final GameboardPersistenceManager gameboardPersistenceManager, final MapperFacade mapper,
final QuestionManager questionManager) {
final QuestionManager questionManager,
final AbstractConfigLoader properties) {
this.contentManager = contentManager;
this.gameboardPersistenceManager = gameboardPersistenceManager;
this.questionManager = questionManager;

this.randomGenerator = new Random();

this.mapper = mapper;

try {
GameManager.gameboardQuestionsLimit = Integer.parseInt(properties.getProperty(GAMEBOARD_QUESTION_LIMIT));
} catch (NumberFormatException e) {
GameManager.gameboardQuestionsLimit = GAMEBOARD_QUESTIONS_DEFAULT;
}
}

/**
Expand Down Expand Up @@ -995,7 +1005,7 @@ private List<GameboardItem> getSelectedGameboardQuestions(final GameFilter gameF
Set<GameboardItem> gameboardReadyQuestions = Sets.newHashSet();
List<GameboardItem> completedQuestions = Lists.newArrayList();
// choose the gameboard questions to include.
while (gameboardReadyQuestions.size() < GAME_BOARD_TARGET_SIZE && !selectionOfGameboardQuestions.isEmpty()) {
while (gameboardReadyQuestions.size() < GAMEBOARD_QUESTIONS_DEFAULT && !selectionOfGameboardQuestions.isEmpty()) {
for (GameboardItem gameboardItem : selectionOfGameboardQuestions) {
CompletionState questionState;
try {
Expand All @@ -1015,12 +1025,12 @@ private List<GameboardItem> getSelectedGameboardQuestions(final GameFilter gameF
}

// stop inner loop if we have reached our target
if (gameboardReadyQuestions.size() == GAME_BOARD_TARGET_SIZE) {
if (gameboardReadyQuestions.size() == GAMEBOARD_QUESTIONS_DEFAULT) {
break;
}
}

if (gameboardReadyQuestions.size() == GAME_BOARD_TARGET_SIZE) {
if (gameboardReadyQuestions.size() == GAMEBOARD_QUESTIONS_DEFAULT) {
break;
}

Expand All @@ -1032,11 +1042,11 @@ private List<GameboardItem> getSelectedGameboardQuestions(final GameFilter gameF
}

// Try and make up the difference with completed ones if we haven't reached our target size
if (gameboardReadyQuestions.size() < GAME_BOARD_TARGET_SIZE && !completedQuestions.isEmpty()) {
if (gameboardReadyQuestions.size() < GAMEBOARD_QUESTIONS_DEFAULT && !completedQuestions.isEmpty()) {
for (GameboardItem completedQuestion : completedQuestions) {
if (gameboardReadyQuestions.size() < GAME_BOARD_TARGET_SIZE) {
if (gameboardReadyQuestions.size() < GAMEBOARD_QUESTIONS_DEFAULT) {
gameboardReadyQuestions.add(completedQuestion);
} else if (gameboardReadyQuestions.size() == GAME_BOARD_TARGET_SIZE) {
} else if (gameboardReadyQuestions.size() == GAMEBOARD_QUESTIONS_DEFAULT) {
break;
}
}
Expand Down Expand Up @@ -1373,9 +1383,9 @@ private void validateGameboard(final GameboardDTO gameboardDTO) throws InvalidGa
"Your gameboard must not contain illegal characters e.g. spaces");
}

if (gameboardDTO.getContents().size() > Constants.GAME_BOARD_TARGET_SIZE) {
if (gameboardDTO.getContents().size() > gameboardQuestionsLimit) {
throw new InvalidGameboardException(String.format("Your gameboard must not contain more than %s questions",
GAME_BOARD_TARGET_SIZE));
gameboardQuestionsLimit));
}

if (gameboardDTO.getGameFilter() == null || !validateFilterQuery(gameboardDTO.getGameFilter())) {
Expand Down
Loading
Loading