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

Maak projecten automatisch zichtbaar op een bepaald tijdstip #269

Merged
merged 10 commits into from
May 19, 2024
8 changes: 8 additions & 0 deletions .env-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
backend/app/src/main/resources/application-secrets.properties,spring.datasource.username=<username>
backend/app/src/main/resources/application-secrets.properties,spring.datasource.password=<password>
backend/app/src/main/resources/application-secrets.properties,azure.activedirectory.client-id=<client-id>
backend/app/src/main/resources/application-secrets.properties,azure.activedirectory.b2c.client-secret=<client-secret>
backend/app/src/main/resources/application-secrets.properties,azure.activedirectory.tenant-id=<tenant-id>
docker.env,PGU=<username>
docker.env,PGP=<password>
docker.env,POSTGRES_USER=${PGU}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ docker.env
./startBackend.sh
startBackend.sh

/.env
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ public ResponseEntity<ApiErrorReponse> handleNoHandlerFoundException(HttpServlet
"Resource/endpoint doesn't exist", path));
}

@ExceptionHandler(NoResourceFoundException.class)
public ResponseEntity<ApiErrorReponse> handleNoResourceFoundException(HttpServletRequest request, Exception ex) {
logError(ex);
String path = request.getRequestURI();
HttpStatus status = HttpStatus.NOT_FOUND;
return ResponseEntity.status(status).body(new ApiErrorReponse(OffsetDateTime.now(), status.value(), status.getReasonPhrase(),
"Resource/endpoint doesn't exist", path));
}

/* Gets thrown when the method is not allowed */
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseEntity<ApiErrorReponse> handleMethodNotSupportedException(HttpServletRequest request, Exception ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -312,13 +314,24 @@ public static void removeDockerImage(String imageName) {
}

public static boolean imageExists(String image) {
DockerClient dockerClient = DockerClientInstance.getInstance();
try {
dockerClient.inspectImageCmd(image).exec();
} catch (Exception e) {
// Split the image into repository and tag
String[] parts = image.split(":");
String repository = parts[0];
String tag = parts.length > 1 ? parts[1] : "latest";

// Construct the URL for the Docker Hub API
String apiUrl = "https://hub.docker.com/v2/repositories/library/" + repository + "/tags/" + tag;
URL url = new URL(apiUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
int responseCode = connection.getResponseCode();

return (responseCode == 200);
} catch (IOException e) {
return false;
}
return true;
}

public static boolean isValidTemplate(String template) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ public CheckResult<Pair<TestEntity, ProjectEntity>> checkForTestUpdate(
}

// This returns false if the image isn't pullt yet! FIX PLS
// if(dockerImage != null && !DockerSubmissionTestModel.imageExists(dockerImage)) {
// return new CheckResult<>(HttpStatus.BAD_REQUEST, "A valid docker image is required in a docker test.", null);
// }
if(dockerImage != null && !DockerSubmissionTestModel.imageExists(dockerImage)) {
return new CheckResult<>(HttpStatus.BAD_REQUEST, "A valid docker image is required in a docker test.", null);
}

if (!httpMethod.equals(HttpMethod.PATCH) && dockerTemplate != null && dockerImage == null) {
return new CheckResult<>(HttpStatus.BAD_REQUEST, "A test script and image are required in a docker template test.", null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ void zipFileInputTest() throws IOException {
}
@Test
void dockerImageDoesNotExist(){
assertFalse(DockerSubmissionTestModel.imageExists("BADUBADUBADUBADUBADUBADUB"));
assertFalse(DockerSubmissionTestModel.imageExists("BADUBADUBADUBADUBADUBADUB - miauw :3"));
assertFalse(DockerSubmissionTestModel.imageExists("alpine:v69696969"));
assertTrue(DockerSubmissionTestModel.imageExists("alpine:latest"));
}

Expand Down
28 changes: 28 additions & 0 deletions envBuilder.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@echo off
setlocal EnableDelayedExpansion

set "prevFile="

for /F "tokens=1,2 delims=," %%a in (.env) do (
echo Processing line: %%a,%%b
for /F "tokens=1,2 delims==" %%c in ("%%b") do (
echo File: %%a
echo Variable: %%c
echo Value: %%d

if not "%%a"=="!prevFile!" (
if exist %%a (
del %%a
echo Deleted file: %%a
)
type nul > %%a
echo Created file: %%a
)

echo. >> %%a
echo %%c=%%d >> %%a
echo Added variable to file

set "prevFile=%%a"
)
)
18 changes: 18 additions & 0 deletions envBuilder.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ENV_FILE=".env"

while IFS= read -r line
do
echo "Processing line: $line"
IFS=',' read -r full_addr var <<< "$line"
IFS='=' read -r file env <<< "$full_addr"
echo "File: $file"
echo "Variable: $var"
echo "Value: $env"
touch "$file"
if ! grep -q "${var}=" "$file"; then
echo "Variable not set, appending to file..."
echo "${var}=${env}" >> "$file"
else
echo "Variable already set in file."
fi
done < "$ENV_FILE"
1 change: 1 addition & 0 deletions frontend/src/@types/requests.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ export type GET_Responses = {
testsUrl: string
maxScore: number | null
visible: boolean
visibleAfter?: Timestamp
status?: ProjectStatus
progress: {
completed: number
Expand Down
116 changes: 66 additions & 50 deletions frontend/src/components/forms/projectFormTabs/GeneralFormTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,72 @@ import { FC } from "react"
import MarkdownEditor from "../../input/MarkdownEditor"

const GeneralFormTab: FC<{ form: FormInstance }> = ({ form }) => {
const { t } = useTranslation()
const description = Form.useWatch("description", form)

return (
<>
<Form.Item
label={t("project.change.name")}
name="name"
rules={[{ required: true, message: t("project.change.nameMessage") }]}
>
<Input />
</Form.Item>

<Typography.Text>
{t("project.change.description")}
</Typography.Text>
<MarkdownEditor value={description} maxLength={5000} />

<Form.Item
label={t("project.change.visible")}
required
name="visible"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("project.change.maxScore")}
name="maxScore"
tooltip={t("project.change.maxScoreHelp")}
rules={[{ required: false, message: t("project.change.maxScoreMessage") }]}
>
<Input
min={1}
max={1000}
type="number"
/>
</Form.Item>
<Form.Item
label={t("project.change.deadline")}
name="deadline"
rules={[{ required: true }]}
>
<DatePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
/>
</Form.Item>
</>
)
const { t } = useTranslation()
const description = Form.useWatch("description", form)
const visible = Form.useWatch("visible", form)

return (
<>
<Form.Item
label={t("project.change.name")}
name="name"
rules={[{ required: true, message: t("project.change.nameMessage") }]}
>
<Input />
</Form.Item>

<Typography.Text>
{t("project.change.description")}
</Typography.Text>
<MarkdownEditor value={description} maxLength={5000} />

<Form.Item
label={t("project.change.visible")}
required
name="visible"
valuePropName="checked"
>
<Switch />
</Form.Item>

{!visible && (
<Form.Item
label={t("project.change.visibleAfter")}
name="visibleAfter"
>
<DatePicker
showTime
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hier moet nog allowClear staan omdat je het veld leeg mag laten.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ik heb het erbij gezet maar AllowClear is true by default

format="YYYY-MM-DD HH:mm:ss"
allowClear={true}
/>
</Form.Item>
)}

<Form.Item
label={t("project.change.maxScore")}
name="maxScore"
tooltip={t("project.change.maxScoreHelp")}
rules={[{ required: false, message: t("project.change.maxScoreMessage") }]}
>
<Input
min={1}
max={1000}
type="number"
/>
</Form.Item>

<Form.Item
label={t("project.change.deadline")}
name="deadline"
rules={[{ required: true }]}
>
<DatePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
/>
</Form.Item>
</>
)
}

export default GeneralFormTab
8 changes: 8 additions & 0 deletions frontend/src/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@
"showMore": "Show more",
"submit": "Submit",
"projectStatus": "Status",
"visibility": "Visibility",
"visibleStatus": {
"visible": "Visible",
"invisible": "Invisible",
"visibleFrom": "Visible from ",
"scheduled": "Scheduled"
},
"status": {
"completed": "Completed",
"failed": "Failed",
Expand Down Expand Up @@ -135,6 +142,7 @@
"groupClusterId": "Groups",
"groupClusterIdMessage": "Please enter the group cluster",
"visible": "Make the project visible",
"visibleAfter": "Choose when the project will be made visible to students, leaving this empty will keep the project invisible",
"maxScore": "Maximum score",
"maxScoreMessage": "Please enter the maximum score for the project",
"maxScoreHelp": "What is the maximum achievable score for this project? Leaving it empty means the project won't be graded.",
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/i18n/nl/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@
"deadline": "Deadline",
"deadlineNotPassed": "Toon enkel actieve projecten",
"showMore": "Toon meer",

"projectStatus": "Status",
"visibility": "Zichtbaarheid",
"visibleStatus": {
"visible": "Zichtbaar",
"invisible": "Onzichtbaar",
"visibleFrom": "Zichtbaar vanaf ",
"scheduled" : "gepland"
},
"status": {
"completed": "Voltooid",
"failed": "Verkeerd",
Expand Down Expand Up @@ -139,6 +145,7 @@
"groupClusterId": "Groepen",
"groupClusterIdMessage": "Vul de Groep cluster in",
"visible": "Project zichtbaar maken",
"visibleAfter": "Kies wanneer het project automatisch zichtbaar wordt voor studenten. Als je niets invult, blijft het project onzichtbaar",
"maxScore": "Maximum score",
"maxScoreMessage": "Vul de maximum score van het project in",
"maxScoreHelp": "Wat is de maximale score die je kunt behalen voor dit project? Als je het leeg laat, wordt het project niet beoordeeld",
Expand Down
Loading
Loading