diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..560ab073 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,30 @@ +## Overview + + +## Details + + +- Bulleted list with explanations + +## Testing + +- [ ] Added/updated unit tests +- [ ] Tested edge cases +- [ ] Manual testing (if needed) + +## Dependencies + + +## Future Work + + +## Additional Notes + diff --git a/README.md b/README.md index 7dc59b27..fd32b215 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Autograder for [BYU CS 240 Chess project](https://github.com/softwareconstructio ## Development and Contributing -This project relies on TAs like you to maintain and adapt the program! Come join the team! -Check out the [Contribution Guide](https://github.com/orgs/softwareconstruction240/projects/1/views/1?pane=issue&itemId=84732654&issue=softwareconstruction240%7Cautograder%7C448) to learn how to effectively contribute as a part of the Autograder Development Team! +This project relies on TAs like you to maintain and adapt the program. Come join the team! +Check out the [Contribution Guide](docs/CONTRIBUTING.md) to learn how to effectively contribute as a part of the Autograder Development Team. Read the [Getting Started Guide](docs/getting-started/getting-started.md) to get the project set up on your machine for development. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 00000000..84e22022 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,293 @@ +# Contribution Guide + +Hello there! Welcome to the CS 240 Autograder Repo. If you're new to the +Autograder Development team, we're glad to have you here. The CS 240 +Autograder relies on TAs like you to maintain and adapt the codebase +for our professors and students. + +This document will give you all the info you need to know to successfully +contribute to the best Autograder on campus! + +## Table of Contents +- Welcome (You already read that) +- [New Contributors [Start here if you're new]](#new-contributors) +- [Guiding Principles](#guiding-principles) +- [Development Pipeline](#development-pipeline) + - [1: Issues](#1-issues) + - [When to Create Issue](#when-to-create-an-issue) + - [Creating an Issue](#creating-an-issue) + - [Working on an Issue](#working-on-an-issue) + - [2: Branches](#2-branches) + - [Creating a Branch](#creating-a-branch) + - [3: Making Changes](#3-making-changes) + - [Writing Good Commit Messages](#writing-good-commit-messages) + - [4: Pull Requests](#4-pull-requests) + - [Creating a Pull Request](#creating-a-pull-request) + - [Scope of a Pull Request](#scope-of-a-pull-request) + - [Reviewing a Pull Request](#reviewing-a-pull-request) + - [After Merging](#after-merging) +- [About Page](#about-page) +- [Reminder About Ownership](#reminder-about-ownership) + +## Guiding Principles + +- We are building production quality software that accurately generates academic scores for hundreds of students. +- We are learning/practicing being participants on a small dev team. +- We thrive with contributions from many diverse perspectives. +- We serve fellow humans with divine purpose in this order: + 1. The Lord + 2. Class professors + 3. Class students + +## New Contributors +New to the Autograder Development team and not sure how to get +started? Try this: + +1. Finish reading this document +2. Get your dev environment set up by following the [Getting Started Guide](getting-started/getting-started.md) +3. Review the Sequence/Class Diagrams (_Coming soon_) +4. Look through some of the code, and try writing documentation for undocumented code +5. Find a section of under-tested code and add some unit tests +6. Take a look through the GitHub repo's [Issues](https://github.com/softwareconstruction240/autograder/issues) page + and find one you like, especially (but not limited to) ones labeled + ["good first issue"](https://github.com/softwareconstruction240/autograder/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) + +Don't be afraid to submit a PR, and most importantly, just get sucked in! + +## Development Pipeline + +As a broad overview, all changes to the Autograder start as an issue. Each +issue eventually gets a branch made to solve the issue. And each branch +gets made into a pull request before becoming part of the main branch of code. + +### 1. Issues + +Issues help us track what needs to be done and who's working on what. You can pick an already +existing issue to work on, or you can write your own. + +> [!TIP] +> Ideally, you should first work on issues in the `On Deck` column of the +[TA Project Board](https://github.com/orgs/softwareconstruction240/projects/1/views/9), +> but you are welcome to pick any unassigned issue + +#### When to Create an Issue + +An issue generally represents "a single goal or task." Discussion and decisions about how to accomplish the task (and +even if the task should be done) happens here. Usually, an issue should be fairly narrow in scope, so that it can be +resolved with a single Pull Request (PR). + +Even when you're not sure if the task should be done, or how to go about it, go ahead and create an issue. The issue +might be closed, but now that decision has been discussed, and the reasons for it are saved somewhere central in case +they are relevant in the future. + +#### Creating an Issue +- Create the issue from the [TA Projects Board](https://github.com/orgs/softwareconstruction240/projects/1) + - Click "add item" at the bottom of the `Todo` list + - Type `#autograder` to connect the issue to the Autograder + - Type a title and hit enter +- Use a clear, descriptive title that uses one of these prefixes (including the colon): + - `Backend:` server side changes + - `Frontend:` client (web) side changes + - `Fullstack:` for issues that require front and backend changes + - `Docs:` changes to documentation (either markdown files or JSDocs/JavaDocs) + - `Tests:` adding or modifying tests + - `Dev:` changes to enhance the Autograder development experience +- Provide a clear and complete PR description. Consider using the following sections: + - **Overview**: The two sentence of the key problem. + - **Discussion**: A brief history of the context or arguments related to the issue. + Provide enough context so others can understand the purpose. + - **Proposal**: Suggested ways the problem could be approached, solved, or implemented. + Include specific file/class/method names as appropriate. + - **Related Work**: Links to related issues, PRs, or other documentation. +- Add labels as appropriate using the built-in picker. +- Remember: Issues should be narrow in scope. + +#### Working on an Issue +- Assign the issue to yourself before beginning work (this is how we know + who is working on what, and gives you a sort of ownership over the issue) +- Create a new branch ([more info here](#2-branches)) +- If you find a new issue, file it separately (don't mix concerns) +- Leave a comment from time to time with updates on your progress + +### 2. Branches +Branches in `git` allow us to all work on separate things in the same codebase. +You will do all your work in a branch. + +#### Creating a branch +Create the branch directly from the issue so your work is linked. + +- Always branch from `main` + - (exceptions exist if you know what you're doing) +- Use descriptive names that reflect what you're working on: + - `add-late-submission` + - `admin-display-verification-status` + - `server-communicator` + - `extract-service-logic-from-controllers` +- If the issue name is clear and concise, the default branch name from clicking "Create a branch" from the issue page is + also fine. It usually looks something like `488-fullstack-add-code-coverage-for-unit-tests` +- Use kebab-case (lowercase with hyphens) +- Keep names concise but clear +- One branch per issue (don't mix different features/fixes) + +### 3. Making Changes +Now that you have a branch, you can start to code! Hurray! 🎉 +Here are important guidelines to follow: + +- Review and follow the Style Guide (_Coming Soon_) +- Write tests for your code. All new features and functionality should have tests demonstrating correctness + - Update existing tests if you change functionality + - _New contributors: A great way to better understand the codebase is to try writing tests for existing code_ +- Keep commits focused and meaningful + - Each commit should represent one logical change + - Write clear commit messages that describe that change ([See guidelines](#writing-good-commit-messages)) + - Commit frequently +- Update documentation as you go + - Add JSDoc/JavaDoc comments to new code + - _New contributors: Another great way to learn the codebase is to document existing code_ + - Update repo Markdown docs if needed + - Code should for the most part be self-documenting. If not, make sure to add inline comments +- Push your code to GitHub at the end of each coding session. This lets other team members see how you're doing + +#### Writing Good Commit Messages +- Start with an imperative statement that describes what the commit does: + - `add late submission validation` + - `fix grade calculation bug` + - `update setup instructions` + - `remove unused imports` + - `refactor test runner` + - `document API endpoints` +- Use lowercase letters +- Keep it concise but clear (aim for under 50 characters) +- Bad examples: + - `changes` (too vague) + - `Added new feature` (past tense) + - `WIP` (uninformative) + - `Fix stuff` (too vague) + +For bigger changes, you can add more details after the first line (leave a blank line between the first +line and the extra details). + +> [!TIP] +> A good commit message lets other developers know what changed without having to look at the code! + +### 4. Pull Requests +Pull requests are how you get your changes merged into the codebase. +You create a pull request once you feel your changes are ready for review by other devs. +You can also create a draft pull request if you would like some feedback on your code before then. + +![Pull Request Lifecycle Overview](https://docs.github.com/assets/images/help/repository/branching.png) + +#### Creating a Pull Request +- Make sure you have pushed all changes to GitHub first +- The title of your pull request should be simple, concise, and descriptive + - It should have a prefix just like an issue + - It can be basically the name of the branch + - Issue: `Frontend: refactor all server calls to one place` + - Branch: `refactor-server-calls-to-one-place` + - Pull Request: `Frontend: refactor server calls into ServerCommunicator` + - Ensure the PR + is [linked to the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue) + it resolves, if any +- Fill out the Pull Request template with enough detail for others to understand what + changed without having to read all the new code. +- Make sure all GitHub actions pass: + - Your pull request will be blocked from merging if all tests don't pass +- Move the connected issue into the `PR Submitted` column on the + [TA Project Board](https://github.com/orgs/softwareconstruction240/projects/1/views/9) +- Request a review from other Autograder developers + - If you're changing an existing system, request a review from the developer that + wrote it initially, or is most familiar with that system + - You can request multiple reviewers, but you're only required to get one approval to merge + +#### Scope of a Pull Request +- Pull Requests should represent a complete, reviewable unit of work +- In most cases, a pull request from one issue + - Multiple issues in one PR are fine and encouraged when they depend on each other, or form a cohesive change +- While there's no strict size limit, consider breaking up very large changes if: + - They touch multiple unrelated areas + - They're becoming difficult to review + - They could logically be shipped separately + +> [!TIP] +> A good PR represents a complete feature or fix, but shouldn't try to solve everything at once! + +#### Reviewing a Pull Request +A crucial part of this process is the code review. The repo has been set up so that _**no changes may be merged +into main without the review of at least one other developer.**_ If someone has requested a review from you, please +take some time to help out and ensure the Autograder has quality code. + +**As a Reviewer** +- Look for: + - Code quality and style guide compliance + - Test coverage + - Potential bugs or edge cases + - Documentation completeness +- Checkout the branch on your local machine and do some manual testing + - Specifically verify new/changed systems work. Try breaking it. + - Generally check other systems still work and haven't been broken + - (Student submissions on test student is most important) +- Be constructive and kind in your feedback. We're all learning here +- If changes are needed: + - Be specific about what needs to change + - Explain why the change is needed + - Suggest how to make the change if possible +- Approve the PR when you're satisfied with all changes + +**As a Pull Request Author** +- Respond to reviewer comments promptly +- Be open to feedback and suggestions +- Explain your decisions when asked +- Make requested changes or explain why they shouldn't be made +- Mark conversations as resolved _only_ once you have addressed the concern +- Re-request review from key individuals +- Thank reviewers for their time + +> [!IMPORTANT] +> Once the pull request is approved and ready to merge, it is the responsibility and privilege of the author +> (not the reviewer) to merge the request. + +> [!NOTE] +> Once a pull request is merged to main, it does not immediately deploy to the live Autograder. Changes will +> not be reflected in the live system until the head Autograder developer releases a new version of the system. + +#### After Merging +Congrats! You just added code to the Autograder! + +Make sure you move your issue on the [TA Project Board](https://github.com/orgs/softwareconstruction240/projects/1/views/9) +to the `Done` column. This will happen automatically if the PR was linked to issue it resolves when the PR was merged. + +Celebrate! + +## About Page +A lot of time and effort goes into developing and maintaining the Autograder. Thank you! + +If you're new to the team, add yourself to the Autograder's [About Page](../src/main/resources/frontend/src/components/AboutPage.vue). +(You can see the live one by doing the Konami Code anywhere on the Autograder front end.) + +Fill this component out and add it to the bottom of the current list of developers: +```vue + +``` +Most TAs just link to their GitHub profile on their URL. + +Tenure should indicate when you worked as a CS 240 TA, not just as an Autograder Developer. + +Write a short sentence describing your work on the Autograder. You can update this in the future as you make more contributions. + +FA-icon is a font-awesome icon. Search through [Font Awesome's free icon collection](https://fontawesome.com/search?o=r&m=free) +and choose one to represent you. + +## Reminder About Ownership +As BYU employees writing code for our job as TAs, all code you contribute becomes the +intellectual property of Brigham Young University. + +> Pursuant to law and university policy, **any work** (whether a Technical Work or a Creative Work) prepared by +> University Personnel within the scope of their employment, without an express agreement specifying otherwise, +> **is work for hire owned by the university**. +> +> — [BYU Intellectual Property Policy](https://policy.byu.edu/view/intellectual-property-policy) (emphasis added) diff --git a/docs/getting-started/getting-started.md b/docs/getting-started/getting-started.md index 3276d8a1..a58bb51f 100644 --- a/docs/getting-started/getting-started.md +++ b/docs/getting-started/getting-started.md @@ -1,5 +1,8 @@ # Getting Started +> [!TIP] +> Read through the [Contribution Guide](../CONTRIBUTING.md) before making contributions to the project. + ## Pre-requisites > [!IMPORTANT] 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 50921373..73f80c42 100644 --- a/src/main/java/edu/byu/cs/autograder/score/Scorer.java +++ b/src/main/java/edu/byu/cs/autograder/score/Scorer.java @@ -431,11 +431,7 @@ public Submission generateSubmissionObject(Rubric rubric, CommitVerificationResu 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) + "% "; + notes = makeLatePenaltyNotes(numDaysLate, maxLateDays, notes); ZonedDateTime handInDate = ScorerHelper.getHandInDateZoned(netId); Submission.VerifiedStatus verifiedStatus; @@ -467,6 +463,25 @@ else if (numDaysLate > 0) ); } + private String makeLatePenaltyNotes(int numDaysLate, int maxLateDays, String origNotes) { + if (numDaysLate <= 0) { + return origNotes; + } + + String penaltyPercentage = String.format("-%d%%", (int)(numDaysLate * PER_DAY_LATE_PENALTY * 100)); + String lateNotes; + if (numDaysLate >= maxLateDays) { + lateNotes = "Late penalty maxed out: " + penaltyPercentage; + } else { + lateNotes = String.format("%d days late: %s", numDaysLate, penaltyPercentage); + } + + if (origNotes == null || origNotes.isBlank()) { + return lateNotes; + } + return String.format("%s\n%s", origNotes, lateNotes); + } + private void sendToCanvas(int userId, int assignmentNum, CanvasRubricAssessment assessment, String notes) throws GradingException { sendToCanvas(userId, assignmentNum, assessment, notes, gradingContext.netId()); diff --git a/src/main/resources/frontend/getting-started.md b/src/main/resources/frontend/getting-started.md new file mode 120000 index 00000000..324427e4 --- /dev/null +++ b/src/main/resources/frontend/getting-started.md @@ -0,0 +1 @@ +../../../../docs/getting-started/getting-started.md \ No newline at end of file diff --git a/src/main/resources/frontend/src/components/AboutPage.vue b/src/main/resources/frontend/src/components/AboutPage.vue index 57e69044..4e7d4475 100644 --- a/src/main/resources/frontend/src/components/AboutPage.vue +++ b/src/main/resources/frontend/src/components/AboutPage.vue @@ -114,6 +114,10 @@ onUnmounted(() => { tenure="Jan 2024-Aug 2024" contributions="Wrote some systems that did pre-compiling verification of student code" fa-icon="fa-solid fa-face-grin-squint-tears"/> + diff --git a/src/main/resources/frontend/src/network/ServerCommunicator.ts b/src/main/resources/frontend/src/network/ServerCommunicator.ts index 2946e030..ee2bf7eb 100644 --- a/src/main/resources/frontend/src/network/ServerCommunicator.ts +++ b/src/main/resources/frontend/src/network/ServerCommunicator.ts @@ -31,13 +31,11 @@ export const ServerCommunicator = { * returns nothing or responds with a non-2XX code * @returns {Promise} Promise that resolves to the response data of type T */ -async function getRequestGuaranteed(endpoint: string, errorResponse: T): Promise { - try { - return await getRequest(endpoint, true) - } catch (e) { - return errorResponse - } +function getRequestGuaranteed(endpoint: string, errorResponse: T): Promise { + return getRequest(endpoint, true) + .catch(_error => Promise.resolve(errorResponse)); } + /** * Makes a GET request to the specified endpoint. * @template T - The type of the expected response (when expectResponse is true) @@ -61,15 +59,12 @@ function getRequest(endpoint: string, expectResponse: false): Promise; * @throws {ServerError} When the request fails (meaning the server returned a code other than 2XX) * @throws {Error} when expectResponse is true but no response is received */ -function getRequest(endpoint: string, expectResponse?: true): Promise; -async function getRequest( +function getRequest(endpoint: string, expectResponse?: boolean): Promise; +function getRequest( endpoint: string, expectResponse: boolean = true ): Promise { - if (expectResponse) { - return await doRequest("GET", endpoint, null, true); - } - return await doRequest("GET", endpoint, null, false); + return doRequest("GET", endpoint, null, expectResponse); } /** @@ -111,17 +106,13 @@ function postRequest(endpoint: string, bodyObject: Object | null, expectResponse * // Without response * await postRequest('/api/logs', { event: 'action' }, false); */ -function postRequest(endpoint: string, bodyObject?: Object | null, expectResponse?: true): Promise; -async function postRequest( +function postRequest(endpoint: string, bodyObject?: Object | null, expectResponse?: boolean): Promise; +function postRequest( endpoint: string, bodyObject: Object | null = null, expectResponse: boolean = true ): Promise { - if (expectResponse) { - return await doRequest("POST", endpoint, bodyObject, true); - } - return await doRequest("POST", endpoint, bodyObject, false); - + return doRequest("POST", endpoint, bodyObject, expectResponse); } /** @@ -163,7 +154,7 @@ function patchRequest(endpoint: string, bodyObject: Object | null, expectRespons * // Without response * await patchRequest('/api/users/123/status', { status: 'active' }, false); */ -function patchRequest(endpoint: string, bodyObject?: Object | null, expectResponse?: true): Promise; +function patchRequest(endpoint: string, bodyObject?: Object | null, expectResponse?: boolean): Promise; async function patchRequest( endpoint: string, bodyObject: Object | null = null, @@ -189,7 +180,7 @@ async function patchRequest( * @throws {Error} When expectResponse is true but no response is received * @internal */ -function doRequest( +function doRequest( method: string, endpoint: string, bodyObject: Object | null, @@ -213,7 +204,7 @@ function doRequest( method: string, endpoint: string, bodyObject?: Object | null, - expectResponse?: true + expectResponse?: boolean ): Promise; /** * Internal method to make an HTTP request. diff --git a/src/main/resources/frontend/src/network/ServerError.ts b/src/main/resources/frontend/src/network/ServerError.ts index 81ad25c2..91a004d7 100644 --- a/src/main/resources/frontend/src/network/ServerError.ts +++ b/src/main/resources/frontend/src/network/ServerError.ts @@ -22,4 +22,4 @@ export class ServerError extends Error { isHonorCodeViolation(): boolean { return this.status === 418; } isUnprocessableEntity(): boolean { return this.status === 422; } isInternalServerError(): boolean { return this.status === 500; } -} \ No newline at end of file +} diff --git a/src/main/resources/frontend/src/services/adminService.ts b/src/main/resources/frontend/src/services/adminService.ts index e2a15d8c..b34531ea 100755 --- a/src/main/resources/frontend/src/services/adminService.ts +++ b/src/main/resources/frontend/src/services/adminService.ts @@ -2,38 +2,37 @@ import type {CanvasSection, Phase, Submission, User } from '@/types/types' import type {Option} from "@/views/AdminView/Analytics.vue"; import { ServerCommunicator } from '@/network/ServerCommunicator' -export const usersGet = async (): Promise => { - return await ServerCommunicator.getRequestGuaranteed('/api/admin/users', []) +export const usersGet = (): Promise => { + return ServerCommunicator.getRequestGuaranteed('/api/admin/users', []) } -export const submissionsForUserGet = async (netId: string): Promise => { - return await ServerCommunicator.getRequestGuaranteed('/api/admin/submissions/student/' + netId, []) +export const submissionsForUserGet = (netId: string): Promise => { + return ServerCommunicator.getRequestGuaranteed('/api/admin/submissions/student/' + netId, []) } -export const approveSubmissionPost = async (netId: string, phase: Phase, penalize: boolean) => { - await ServerCommunicator.postRequest('/api/admin/submissions/approve', - { +export const approveSubmissionPost = (netId: string, phase: Phase, penalize: boolean) => { + return ServerCommunicator.postRequest('/api/admin/submissions/approve', { netId, phase, penalize, }) } -export const submissionsLatestGet = async (batchSize?: number): Promise => { +export const submissionsLatestGet = (batchSize?: number): Promise => { batchSize = batchSize ? batchSize : -1 - return await ServerCommunicator.getRequestGuaranteed('/api/admin/submissions/latest/' + batchSize, []) + return ServerCommunicator.getRequestGuaranteed('/api/admin/submissions/latest/' + batchSize, []) } -export const testStudentModeGet = async (): Promise => { - return await ServerCommunicator.getRequestGuaranteed('/api/admin/test_mode', null) +export const testStudentModeGet = (): Promise => { + return ServerCommunicator.getRequestGuaranteed('/api/admin/test_mode', null) } type QueueStatusResponse = { currentlyGrading: string[], inQueue: string[] } -export const getQueueStatus = async (): Promise => { - return await ServerCommunicator.getRequestGuaranteed( +export const getQueueStatus = (): Promise => { + return ServerCommunicator.getRequestGuaranteed( '/api/admin/submissions/active', { currentlyGrading: [], inQueue: [] @@ -56,6 +55,6 @@ export const honorCheckerZipGet = async (section: number): Promise => { } } -export const sectionsGet = async (): Promise => { - return await ServerCommunicator.getRequestGuaranteed('/api/admin/sections', []) +export const sectionsGet = (): Promise => { + return ServerCommunicator.getRequestGuaranteed('/api/admin/sections', []) } diff --git a/src/main/resources/frontend/src/services/authService.ts b/src/main/resources/frontend/src/services/authService.ts index 20194402..78360c7e 100644 --- a/src/main/resources/frontend/src/services/authService.ts +++ b/src/main/resources/frontend/src/services/authService.ts @@ -8,8 +8,8 @@ type MeResponse = { repoUrl: string, role: 'STUDENT' | 'ADMIN' } -export const meGet = async () => { - return await ServerCommunicator.getRequestGuaranteed('/api/me', null) +export const meGet = () => { + return ServerCommunicator.getRequestGuaranteed('/api/me', null) } export const loadUser = async () => { @@ -20,6 +20,6 @@ export const loadUser = async () => { useAuthStore().user = loggedInUser; } -export const logoutPost = async () => { - await ServerCommunicator.postRequest( "/auth/logout", null, false) +export const logoutPost = () => { + return ServerCommunicator.postRequest( "/auth/logout", null, false) } diff --git a/src/main/resources/frontend/src/services/configService.ts b/src/main/resources/frontend/src/services/configService.ts index 7eff61e2..14137f58 100644 --- a/src/main/resources/frontend/src/services/configService.ts +++ b/src/main/resources/frontend/src/services/configService.ts @@ -4,32 +4,32 @@ import { useAuthStore } from '@/stores/auth' import { ServerCommunicator } from '@/network/ServerCommunicator' import { ServerError } from '@/network/ServerError' -export const getConfig = async ():Promise => { +export const getConfig = (): Promise => { let endpoint = "/api" if (useAuthStore().user?.role == 'ADMIN') { endpoint += "/admin" } endpoint += "/config" - return await ServerCommunicator.getRequest(endpoint) + return ServerCommunicator.getRequest(endpoint) } -export const setPenalties = async (maxLateDaysPenalized: number, +export const setPenalties = (maxLateDaysPenalized: number, gitCommitPenalty: number, perDayLatePenalty: number, linesChangedPerCommit: number, clockForgivenessMinutes: number) => { - await doSetConfigItem("POST", '/api/admin/config/penalties', { - maxLateDaysPenalized: maxLateDaysPenalized, - gitCommitPenalty: gitCommitPenalty, - perDayLatePenalty: perDayLatePenalty, - linesChangedPerCommit: linesChangedPerCommit, - clockForgivenessMinutes: clockForgivenessMinutes + return doSetConfigItem("POST", '/api/admin/config/penalties', { + maxLateDaysPenalized, + gitCommitPenalty, + perDayLatePenalty, + linesChangedPerCommit, + clockForgivenessMinutes, }) } -export const setBanner = async (message: String, link: String, color: String, expirationTimestamp: String): Promise => { - await doSetConfigItem("POST", '/api/admin/config/banner', { +export const setBanner = (message: String, link: String, color: String, expirationTimestamp: String): Promise => { + return doSetConfigItem("POST", '/api/admin/config/banner', { "bannerMessage": message, "bannerLink": link, "bannerColor": color, @@ -38,32 +38,32 @@ export const setBanner = async (message: String, link: String, color: String, ex ); } -export const setLivePhases = async (phases: Array): Promise => { - await doSetConfigItem("POST", '/api/admin/config/phases', {"phases": phases}); +export const setLivePhases = (phases: Array): Promise => { + return doSetConfigItem("POST", '/api/admin/config/phases', {"phases": phases}); } -export const setGraderShutdown = async (shutdownTimestamp: string, shutdownWarningHours: number): Promise => { +export const setGraderShutdown = (shutdownTimestamp: string, shutdownWarningHours: number): Promise => { if (shutdownWarningHours < 0) shutdownWarningHours = 0 - await doSetConfigItem("POST", "/api/admin/config/phases/shutdown", { + return doSetConfigItem("POST", "/api/admin/config/phases/shutdown", { "shutdownTimestamp": shutdownTimestamp, "shutdownWarningMilliseconds": Math.trunc(shutdownWarningHours * 60 * 60 * 1000) // convert to milliseconds }) } -export const setCanvasCourseIds = async (): Promise => { - await doSetConfigItem("GET", "/api/admin/config/courseIds", {}); +export const setCanvasCourseIds = (): Promise => { + return doSetConfigItem("GET", "/api/admin/config/courseIds", {}); } -const convertRubricInfoToObj = (rubricInfo: Map>): object => { - const obj: any = {}; +const convertRubricInfoToObj = (rubricInfo: Map>): Record> => { + const obj = {} as Record>; rubricInfo.forEach((rubricTypeMap, phase) => { obj[phase] = Object.fromEntries(rubricTypeMap.entries()); }); return obj; } -export const setCourseIds = async ( +export const setCourseIds = ( courseNumber: number, assignmentIds: Map, rubricInfo: Map> @@ -73,7 +73,7 @@ export const setCourseIds = async ( "assignmentIds": Object.fromEntries(assignmentIds.entries()), "rubricInfo": convertRubricInfoToObj(rubricInfo) }; - await doSetConfigItem("POST", "/api/admin/config/courseIds", body); + return doSetConfigItem("POST", "/api/admin/config/courseIds", body); } const doSetConfigItem = async (method: string, path: string, body: Object): Promise => { diff --git a/src/main/resources/frontend/src/services/submissionService.ts b/src/main/resources/frontend/src/services/submissionService.ts index 9445bb95..e38571b2 100644 --- a/src/main/resources/frontend/src/services/submissionService.ts +++ b/src/main/resources/frontend/src/services/submissionService.ts @@ -2,21 +2,21 @@ import type {Submission} from "@/types/types"; import { Phase } from "@/types/types"; import { ServerCommunicator } from '@/network/ServerCommunicator' -export const submissionsGet = async (phase: Phase | null): Promise => { +export const submissionsGet = (phase: Phase | null): Promise => { const endpoint: string = '/api/submission' + (phase === null ? "" : "/" + Phase[phase]) - return await ServerCommunicator.getRequestGuaranteed(endpoint, []) + return ServerCommunicator.getRequestGuaranteed(endpoint, []) }; -export const lastSubmissionGet = async (): Promise => { - return await ServerCommunicator.getRequestGuaranteed("/api/latest", null) +export const lastSubmissionGet = (): Promise => { + return ServerCommunicator.getRequestGuaranteed("/api/latest", null) }; -export const submissionPost = async (phase: Phase): Promise => { - await ServerCommunicator.postRequest("/api/submit", { "phase": Phase[phase] }, false) +export const submissionPost = (phase: Phase): Promise => { + return ServerCommunicator.postRequest("/api/submit", { "phase": Phase[phase] }, false) } -export const adminSubmissionPost = async (phase: Phase, repoUrl: String): Promise => { - await ServerCommunicator.postRequest("/api/admin/submit", { +export const adminSubmissionPost = (phase: Phase, repoUrl: String): Promise => { + return ServerCommunicator.postRequest("/api/admin/submit", { "phase": Phase[phase], "repoUrl": repoUrl }, false) @@ -29,6 +29,6 @@ export const submitGet = async (): Promise => { return (await ServerCommunicator.getRequest("/api/submit")).inQueue } -export const reRunSubmissionsPost = async () => { - await ServerCommunicator.postRequest("/api/admin/submissions/rerun") +export const reRunSubmissionsPost = () => { + return ServerCommunicator.postRequest("/api/admin/submissions/rerun") } diff --git a/src/main/resources/frontend/src/services/userService.ts b/src/main/resources/frontend/src/services/userService.ts index a9b88591..3a945d24 100644 --- a/src/main/resources/frontend/src/services/userService.ts +++ b/src/main/resources/frontend/src/services/userService.ts @@ -1,20 +1,20 @@ import type { RepoUpdate } from '@/types/types' import { ServerCommunicator } from '@/network/ServerCommunicator' -export const repoHistoryGet = async (netId: String): Promise => { - return await ServerCommunicator.getRequestGuaranteed('/api/admin/repo/history?netId=' + netId, []) +export const repoHistoryGet = (netId: String): Promise => { + return ServerCommunicator.getRequestGuaranteed('/api/admin/repo/history?netId=' + netId, []) }; -export const studentUpdateRepoPatch = async (repoUrl: string): Promise => { - await updateRepoPatch(repoUrl, '/api/repo') +export const studentUpdateRepoPatch = (repoUrl: string): Promise => { + return updateRepoPatch(repoUrl, '/api/repo') } -export const adminUpdateRepoPatch = async (repoUrl: string, netId: String): Promise => { - await updateRepoPatch(repoUrl, "/api/admin/repo/" + netId) +export const adminUpdateRepoPatch = (repoUrl: string, netId: String): Promise => { + return updateRepoPatch(repoUrl, "/api/admin/repo/" + netId) } -const updateRepoPatch = async (repoUrl: string, endpoint: string): Promise => { - await ServerCommunicator.patchRequest(endpoint, { +const updateRepoPatch = (repoUrl: string, endpoint: string): Promise => { + return ServerCommunicator.patchRequest(endpoint, { "repoUrl": repoUrl }, false) } diff --git a/src/main/resources/frontend/src/stores/submissions.ts b/src/main/resources/frontend/src/stores/submissions.ts index eaf8076f..6dea1625 100644 --- a/src/main/resources/frontend/src/stores/submissions.ts +++ b/src/main/resources/frontend/src/stores/submissions.ts @@ -21,9 +21,7 @@ export const useSubmissionStore = defineStore('submission', () => { currentlyGrading.value = await submitGet(); } - const getLastSubmission = async () => { - return await lastSubmissionGet(); - } + const getLastSubmission = () => lastSubmissionGet(); return { submissionsByPhase,