From 88c9964a55a2e7934dee8131748dbd2789863259 Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:28:06 -0700 Subject: [PATCH 01/17] make frontend component --- .../frontend/src/views/AdminView/ConfigView.vue | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue index 5252c1d2..5f4db841 100644 --- a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue +++ b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue @@ -48,6 +48,17 @@ onMounted( async () => { + + + + + From 4c3bde49d9cdd4da672ca10918880a29e4941bca Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Thu, 14 Nov 2024 01:31:48 -0700 Subject: [PATCH 04/17] fix floating point math error on front end --- .../components/config/BannerConfigEditor.vue | 7 ++- .../config/LivePhaseConfigEditor.vue | 5 +- .../components/config/PenaltyConfigEditor.vue | 63 +++++++++++++++++++ .../frontend/src/services/configService.ts | 8 +++ .../src/views/AdminView/ConfigView.vue | 7 ++- 5 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue diff --git a/src/main/resources/frontend/src/components/config/BannerConfigEditor.vue b/src/main/resources/frontend/src/components/config/BannerConfigEditor.vue index f6729e96..7c800258 100644 --- a/src/main/resources/frontend/src/components/config/BannerConfigEditor.vue +++ b/src/main/resources/frontend/src/components/config/BannerConfigEditor.vue @@ -31,10 +31,11 @@ const submitBanner = async () => { } try { await setBanner(bannerMessageToSubmit.value, bannerLinkToSubmit.value, bannerColorToSubmit.value, combinedDateTime) + closeEditor() } catch (e) { + appConfigStore.updateConfig() alert("There was a problem in saving the updated banner message:\n" + e) } - closeEditor() } @@ -65,8 +66,8 @@ const submitBanner = async () => {
- - + +
diff --git a/src/main/resources/frontend/src/components/config/LivePhaseConfigEditor.vue b/src/main/resources/frontend/src/components/config/LivePhaseConfigEditor.vue index de746ea9..8ebee204 100644 --- a/src/main/resources/frontend/src/components/config/LivePhaseConfigEditor.vue +++ b/src/main/resources/frontend/src/components/config/LivePhaseConfigEditor.vue @@ -24,10 +24,11 @@ const submitLivePhases = async () => { try { await setLivePhases(livePhases) + closeEditor() } catch (e) { + appConfigStore.updateConfig() alert("There was a problem in saving live phases") } - closeEditor() } @@ -44,7 +45,7 @@ const submitLivePhases = async () => { - + diff --git a/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue b/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue new file mode 100644 index 00000000..859301fa --- /dev/null +++ b/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/main/resources/frontend/src/services/configService.ts b/src/main/resources/frontend/src/services/configService.ts index 605b266f..653c7206 100644 --- a/src/main/resources/frontend/src/services/configService.ts +++ b/src/main/resources/frontend/src/services/configService.ts @@ -13,6 +13,14 @@ export const getConfig = async ():Promise => { return await ServerCommunicator.getRequest(endpoint) } +export const setPenalties = async (maxLateDaysPenalized: number, gitCommitPenalty: number, perDayLatePenalty: number) => { + await doSetConfigItem("POST", '/api/admin/config/penalties', { + maxLateDaysPenalized: maxLateDaysPenalized, + gitCommitPenalty: gitCommitPenalty, + perDayLatePenalty: perDayLatePenalty, + }) +} + export const setBanner = async (message: String, link: String, color: String, expirationTimestamp: String): Promise => { await doSetConfigItem("POST", '/api/admin/config/banner', { "bannerMessage": message, diff --git a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue index 24f4c430..e0ef45f2 100644 --- a/src/main/resources/frontend/src/views/AdminView/ConfigView.vue +++ b/src/main/resources/frontend/src/views/AdminView/ConfigView.vue @@ -4,6 +4,7 @@ import { listOfPhases } from '@/types/types' import { useAppConfigStore } from '@/stores/appConfig' import { generateClickableLink, readableTimestamp } from '@/utils/utils' import ConfigSection from '@/components/config/ConfigSection.vue' +import PenaltyConfigEditor from '@/components/config/PenaltyConfigEditor.vue' // Lazy Load Editor Components const BannerConfigEditor = defineAsyncComponent(() => import('@/components/config/BannerConfigEditor.vue')) @@ -50,12 +51,12 @@ onMounted( async () => { From 603c3bc87107e538fdf696eef03c44794e0678dc Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Thu, 14 Nov 2024 01:46:07 -0700 Subject: [PATCH 05/17] add argument validation on front and backend --- src/main/java/edu/byu/cs/service/ConfigService.java | 12 ++++++++++++ .../src/components/config/PenaltyConfigEditor.vue | 13 +++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/byu/cs/service/ConfigService.java b/src/main/java/edu/byu/cs/service/ConfigService.java index 742b7df0..b1619cfe 100644 --- a/src/main/java/edu/byu/cs/service/ConfigService.java +++ b/src/main/java/edu/byu/cs/service/ConfigService.java @@ -223,6 +223,10 @@ public static void updateCourseIdsUsingCanvas(User user) throws CanvasException, } public static void setMaxLateDays(User user, Integer maxDays) throws DataAccessException { + if (maxDays < 0) { + throw new IllegalArgumentException("Max Late Days must be non-negative"); + } + ConfigurationDao dao = DaoService.getConfigurationDao(); dao.setConfiguration(ConfigurationDao.Configuration.MAX_LATE_DAYS_TO_PENALIZE, maxDays, Integer.class); logConfigChange("set maximum late days penalized to %s".formatted(maxDays), user.netId()); @@ -235,6 +239,10 @@ public static void setMaxLateDays(User user, Integer maxDays) throws DataAccessE * passed in as 0.1 */ public static void setPerDayLatePenalty(User user, Float perDayPenalty) throws DataAccessException { + if ((perDayPenalty < 0) || (perDayPenalty > 1)) { + throw new IllegalArgumentException("Per Day Late Penalty must be 0-1"); + } + ConfigurationDao dao = DaoService.getConfigurationDao(); dao.setConfiguration(ConfigurationDao.Configuration.PER_DAY_LATE_PENALTY, perDayPenalty, Float.class); logConfigChange("set the per day late penalty to %s".formatted(perDayPenalty), user.netId()); @@ -247,6 +255,10 @@ public static void setPerDayLatePenalty(User user, Float perDayPenalty) throws D * penalty per day should be passed in as 0.1 */ public static void setGitCommitPenalty(User user, Float gitCommitPenalty) throws DataAccessException { + if ((gitCommitPenalty < 0) || (gitCommitPenalty > 1)) { + throw new IllegalArgumentException("Git Commit Penalty must be 0-1"); + } + ConfigurationDao dao = DaoService.getConfigurationDao(); dao.setConfiguration(ConfigurationDao.Configuration.GIT_COMMIT_PENALTY, gitCommitPenalty, Float.class); logConfigChange("set the git commit penalty to %s".formatted(gitCommitPenalty), user.netId()); diff --git a/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue b/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue index 859301fa..6c5aa41c 100644 --- a/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue +++ b/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue @@ -13,6 +13,12 @@ const gitPenalty = ref(Math.round(appConfig.gitCommitPenalty * 100)) const latePenalty = ref(Math.round(appConfig.perDayLatePenalty * 100)) const maxLateDays = ref(appConfig.maxLateDaysPenalized) +const valuesReady = () => { + return (gitPenalty.value >= 0) && (gitPenalty.value <= 100) + && (latePenalty.value >= 0) && (latePenalty.value <= 100) + && (maxLateDays.value >= 0) +} + const submit = async () => { try { await setPenalties(maxLateDays.value, gitPenalty.value / 100, latePenalty.value / 100) @@ -43,7 +49,8 @@ const submit = async () => {

days

- + +

All values must be non-negative, and penalties must be equal to or less than 100%

From 94307a65c132f5b635b169b3ed885510b3d38dde Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Thu, 14 Nov 2024 01:57:15 -0700 Subject: [PATCH 06/17] skip logging if value didn't change --- .../java/edu/byu/cs/service/ConfigService.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/edu/byu/cs/service/ConfigService.java b/src/main/java/edu/byu/cs/service/ConfigService.java index b1619cfe..fde59159 100644 --- a/src/main/java/edu/byu/cs/service/ConfigService.java +++ b/src/main/java/edu/byu/cs/service/ConfigService.java @@ -22,17 +22,18 @@ import java.util.ArrayList; import java.util.EnumMap; import java.util.Map; +import java.util.Objects; public class ConfigService { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigService.class); private static void logConfigChange(String changeMessage, String adminNetId) { - LOGGER.info("[CONFIG] Admin {} has {}}", adminNetId, changeMessage); + LOGGER.info("[CONFIG] Admin {} has {}", adminNetId, changeMessage); } private static void logAutomaticConfigChange(String changeMessage) { - LOGGER.info("[CONFIG] Automatic change: {}}", changeMessage); + LOGGER.info("[CONFIG] Automatic change: {}", changeMessage); } /** @@ -228,6 +229,10 @@ public static void setMaxLateDays(User user, Integer maxDays) throws DataAccessE } ConfigurationDao dao = DaoService.getConfigurationDao(); + + Integer current = dao.getConfiguration(ConfigurationDao.Configuration.MAX_LATE_DAYS_TO_PENALIZE, Integer.class); + if (current.equals(maxDays)) { return; } + dao.setConfiguration(ConfigurationDao.Configuration.MAX_LATE_DAYS_TO_PENALIZE, maxDays, Integer.class); logConfigChange("set maximum late days penalized to %s".formatted(maxDays), user.netId()); } @@ -244,6 +249,10 @@ public static void setPerDayLatePenalty(User user, Float perDayPenalty) throws D } ConfigurationDao dao = DaoService.getConfigurationDao(); + + Float current = dao.getConfiguration(ConfigurationDao.Configuration.PER_DAY_LATE_PENALTY, Float.class); + if (current.equals(perDayPenalty)) { return; } + dao.setConfiguration(ConfigurationDao.Configuration.PER_DAY_LATE_PENALTY, perDayPenalty, Float.class); logConfigChange("set the per day late penalty to %s".formatted(perDayPenalty), user.netId()); } @@ -260,6 +269,10 @@ public static void setGitCommitPenalty(User user, Float gitCommitPenalty) throws } ConfigurationDao dao = DaoService.getConfigurationDao(); + + Float current = dao.getConfiguration(ConfigurationDao.Configuration.GIT_COMMIT_PENALTY, Float.class); + if (current.equals(gitCommitPenalty)) { return; } + dao.setConfiguration(ConfigurationDao.Configuration.GIT_COMMIT_PENALTY, gitCommitPenalty, Float.class); logConfigChange("set the git commit penalty to %s".formatted(gitCommitPenalty), user.netId()); } From 4b66a9f58c25b6ff53acc4bc9482d1929a04f03b Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:08:02 -0700 Subject: [PATCH 07/17] integrate late penalty values --- .../cs/autograder/score/LateDayCalculator.java | 8 +++----- .../edu/byu/cs/autograder/score/Scorer.java | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/edu/byu/cs/autograder/score/LateDayCalculator.java b/src/main/java/edu/byu/cs/autograder/score/LateDayCalculator.java index fe340f8b..d9aeafe2 100644 --- a/src/main/java/edu/byu/cs/autograder/score/LateDayCalculator.java +++ b/src/main/java/edu/byu/cs/autograder/score/LateDayCalculator.java @@ -3,6 +3,7 @@ import edu.byu.cs.autograder.GradingException; import edu.byu.cs.canvas.CanvasException; import edu.byu.cs.canvas.CanvasService; +import edu.byu.cs.dataAccess.ConfigurationDao; import edu.byu.cs.dataAccess.DaoService; import edu.byu.cs.dataAccess.DataAccessException; import edu.byu.cs.model.Phase; @@ -30,10 +31,6 @@ public class LateDayCalculator { private static final Logger LOGGER = Logger.getLogger(LateDayCalculator.class.getName()); - /** - * The max number of days that the late penalty should be applied for. - */ - private static final int MAX_LATE_DAYS_TO_PENALIZE = 5; private Set publicHolidays; public LateDayCalculator() { @@ -54,7 +51,8 @@ public int calculateLateDays(Phase phase, String netId) throws GradingException, } ZonedDateTime handInDate = ScorerHelper.getHandInDateZoned(netId); - return Math.min(getNumDaysLate(handInDate, dueDate), MAX_LATE_DAYS_TO_PENALIZE); + int maxLateDaysToPenalize = DaoService.getConfigurationDao().getConfiguration(ConfigurationDao.Configuration.MAX_LATE_DAYS_TO_PENALIZE, Integer.class); + return Math.min(getNumDaysLate(handInDate, dueDate), maxLateDaysToPenalize); } /** diff --git a/src/main/java/edu/byu/cs/autograder/score/Scorer.java b/src/main/java/edu/byu/cs/autograder/score/Scorer.java index b4402c08..4e747400 100644 --- a/src/main/java/edu/byu/cs/autograder/score/Scorer.java +++ b/src/main/java/edu/byu/cs/autograder/score/Scorer.java @@ -9,6 +9,7 @@ import edu.byu.cs.canvas.model.CanvasRubricAssessment; import edu.byu.cs.canvas.model.CanvasRubricItem; import edu.byu.cs.canvas.model.CanvasSubmission; +import edu.byu.cs.dataAccess.ConfigurationDao; import edu.byu.cs.dataAccess.DaoService; import edu.byu.cs.dataAccess.DataAccessException; import edu.byu.cs.dataAccess.UserDao; @@ -33,11 +34,17 @@ public class Scorer { * The penalty to be applied per day to a late submission. * This is out of 1. So putting 0.1 would be a 10% deduction per day */ - private static final float PER_DAY_LATE_PENALTY = 0.1F; + private final float PER_DAY_LATE_PENALTY; private final GradingContext gradingContext; public Scorer(GradingContext gradingContext) { this.gradingContext = gradingContext; + try { + PER_DAY_LATE_PENALTY = DaoService.getConfigurationDao().getConfiguration(ConfigurationDao.Configuration.PER_DAY_LATE_PENALTY, Float.class); + } catch (DataAccessException e) { + LOGGER.error("Error while getting Per Day Late Penalty for Scorer."); + throw new RuntimeException(e); + } } /** @@ -394,8 +401,13 @@ public Submission generateSubmissionObject(Rubric rubric, CommitVerificationResu String headHash = commitVerificationResult.headHash(); String netId = gradingContext.netId(); - if (numDaysLate > 0) - notes += " " + numDaysLate + " days late. -" + (int)(numDaysLate * PER_DAY_LATE_PENALTY * 100) + "%"; + Integer maxLateDays = DaoService.getConfigurationDao().getConfiguration(ConfigurationDao.Configuration.MAX_LATE_DAYS_TO_PENALIZE, Integer.class); + + if (numDaysLate >= maxLateDays) + notes += " Late penalty maxed out at " + numDaysLate + " days late: -"; + else if (numDaysLate > 0) + notes += " " + numDaysLate + " days late: -"; + notes += (int)(numDaysLate * PER_DAY_LATE_PENALTY * 100) + "%"; ZonedDateTime handInDate = ScorerHelper.getHandInDateZoned(netId); Submission.VerifiedStatus verifiedStatus; From e0c041b2ed40c47e1ae2a0b3615756ced24d6857 Mon Sep 17 00:00:00 2001 From: DallinFromEarth <112426674+DallinFromEarth@users.noreply.github.com> Date: Fri, 15 Nov 2024 19:39:04 -0700 Subject: [PATCH 08/17] add git commit penalty --- .../edu/byu/cs/autograder/score/Scorer.java | 2 +- .../edu/byu/cs/service/SubmissionService.java | 3 +- src/main/java/edu/byu/cs/util/PhaseUtils.java | 7 ++- .../src/components/config/ConfigSection.vue | 4 +- .../components/config/PenaltyConfigEditor.vue | 47 +++++++++++++------ 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/main/java/edu/byu/cs/autograder/score/Scorer.java b/src/main/java/edu/byu/cs/autograder/score/Scorer.java index 4e747400..4389f1f4 100644 --- a/src/main/java/edu/byu/cs/autograder/score/Scorer.java +++ b/src/main/java/edu/byu/cs/autograder/score/Scorer.java @@ -407,7 +407,7 @@ public Submission generateSubmissionObject(Rubric rubric, CommitVerificationResu notes += " Late penalty maxed out at " + numDaysLate + " days late: -"; else if (numDaysLate > 0) notes += " " + numDaysLate + " days late: -"; - notes += (int)(numDaysLate * PER_DAY_LATE_PENALTY * 100) + "%"; + notes += (int)(numDaysLate * PER_DAY_LATE_PENALTY * 100) + "% "; ZonedDateTime handInDate = ScorerHelper.getHandInDateZoned(netId); Submission.VerifiedStatus verifiedStatus; diff --git a/src/main/java/edu/byu/cs/service/SubmissionService.java b/src/main/java/edu/byu/cs/service/SubmissionService.java index 6ba4fc5c..f594c978 100644 --- a/src/main/java/edu/byu/cs/service/SubmissionService.java +++ b/src/main/java/edu/byu/cs/service/SubmissionService.java @@ -184,8 +184,7 @@ public static Collection getSubmissionsForUser(String netId) throws public static void approveSubmission(String adminNetId, ApprovalRequest request) throws GradingException, DataAccessException { int penalty = 0; if (request.penalize()) { - //TODO: Put somewhere better/more configurable - penalty = 10; + penalty = Math.round((DaoService.getConfigurationDao().getConfiguration(ConfigurationDao.Configuration.GIT_COMMIT_PENALTY, Float.class) * 100)); } SubmissionUtils.approveSubmission(request.netId(), request.phase(), adminNetId, penalty); diff --git a/src/main/java/edu/byu/cs/util/PhaseUtils.java b/src/main/java/edu/byu/cs/util/PhaseUtils.java index 03f6dad0..9c7f8879 100644 --- a/src/main/java/edu/byu/cs/util/PhaseUtils.java +++ b/src/main/java/edu/byu/cs/util/PhaseUtils.java @@ -170,7 +170,12 @@ public static float extraCreditValue(Phase phase) { public static CommitVerificationConfig verificationConfig(Phase phase) throws GradingException { int minimumLinesChanged = 5; - int penaltyPct = 10; + int penaltyPct; + try { + penaltyPct = Math.round(DaoService.getConfigurationDao().getConfiguration(ConfigurationDao.Configuration.GIT_COMMIT_PENALTY, Float.class) * 100); + } catch (DataAccessException e) { + throw new GradingException("Error getting git commit penalty", e); + } int forgivenessMinutesHead = 3; return switch (phase) { case Phase0, Phase1 -> new CommitVerificationConfig(8, 2, minimumLinesChanged, penaltyPct, forgivenessMinutesHead); diff --git a/src/main/resources/frontend/src/components/config/ConfigSection.vue b/src/main/resources/frontend/src/components/config/ConfigSection.vue index a35d2e74..8b14281a 100644 --- a/src/main/resources/frontend/src/components/config/ConfigSection.vue +++ b/src/main/resources/frontend/src/components/config/ConfigSection.vue @@ -57,7 +57,9 @@ const closeEditor = () => { v-if="editorPopup" @closePopUp="editorPopup = false">

Edit {{ title }}

- +
+ +
diff --git a/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue b/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue index 6c5aa41c..5d347513 100644 --- a/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue +++ b/src/main/resources/frontend/src/components/config/PenaltyConfigEditor.vue @@ -32,35 +32,54 @@ const submit = async () => {