Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions backend/webserver/views/project_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ def post(self, request, project_id):
else:
raise InvalidValueError(project_id)

if len(request.data.get("projectName", "")) > 50:
raise InvalidValueError("Project name exceeds the maximum length of 50 characters")

return Response(f"Creation of {project_id} successful!")

except AlreadyExists as ae:
Expand Down
60 changes: 40 additions & 20 deletions frontend/src/components/NavBar/ProjectCreationContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {useNotification} from "../../context/NotificationContext";
const CreationContent: React.FunctionComponent<DialogContentProps> = (dialogContentProps: DialogContentProps) => {
const notification = useNotification();
const {data} = useQuery("allProjectsFlat", getAllProjectsFlat)
const [isInvalid, setInvalid] = useState(false);
const [isIdInvalid, setIdInvalid] = useState(true);
const [isNameInvalid, setNameInvalid] = useState(false);
const [isProjectIdTouched, setProjectIdTouched] = useState(false);
const [projectId, setProjectId] = useState("");
const [projectName, setProjectName] = useState("");
const [threshold, setThreshold] = useState("HIGH");
const queryClient = useQueryClient()
const [helperText, setHelperText] = useState("")
const [projectIdHelperText, setProjectIdHelperText] = useState("")
const [projectNameHelperText, setProjectNameHelperText] = useState("")
const handleSave = useMutation(() => createProject(projectId, {
projectName: projectName,
deploymentThreshold: threshold
Expand Down Expand Up @@ -52,42 +55,59 @@ const CreationContent: React.FunctionComponent<DialogContentProps> = (dialogCont
}

useEffect(() => {
if (!isProjectIdTouched) {
return;
}
if (projectId.length < 1){
setInvalid(true);
setHelperText(localization.dialog.projectIdHelperNotEmpty)
setIdInvalid(true);
setProjectIdHelperText(localization.dialog.projectIdHelperNotEmpty)
}else if (projectId.includes(" ")){
setInvalid(true);
setHelperText(localization.dialog.projectIdHelperNoSpaces)
}else if (projectId.length > 20){
setInvalid(true);
setHelperText(localization.dialog.projectIdHelperToLong)
setIdInvalid(true);
setProjectIdHelperText(localization.dialog.projectIdHelperNoSpaces)
}else if (projectId.length > 50){
setIdInvalid(true);
setProjectIdHelperText(localization.dialog.projectIdHelperToLong)
}else {
if (data?.data !== undefined) {
if (allProjectIds.includes(projectId.toLowerCase())) {
setInvalid(true);
setHelperText(localization.dialog.projectIdHelperIdAlreadyUsed)
setIdInvalid(true);
setProjectIdHelperText(localization.dialog.projectIdHelperIdAlreadyUsed)
} else {
setInvalid(false);
setHelperText("")
setIdInvalid(false);
setProjectIdHelperText("")
}
}
}
}, [projectId])
}, [projectId, isProjectIdTouched, allProjectIds])

useEffect(() => {
if (projectName.length > 50) {
setNameInvalid(true);
setProjectNameHelperText(localization.dialog.projectNameHelperToLong);
} else {
setNameInvalid(false);
setProjectNameHelperText("Optional");
}
}, [projectName]);

return(
<Stack>
<Stack direction={"column"} sx={{width: "20rem", margin: "0px 25px 0px 25px"}}>
<TextField
helperText={helperText}
error={isInvalid}
helperText={projectIdHelperText}
error={isProjectIdTouched && isIdInvalid}
label={localization.dialog.projectId}
value={projectId}
variant="filled"
onChange={(e: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => setProjectId(e.target.value)}
onChange={(e: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
setProjectId(e.target.value)
setProjectIdTouched(true)
}}
/>
<TextField
style={{marginTop: "1rem"}}
helperText={"Optional"}
helperText={projectNameHelperText}
error={isNameInvalid}
label={localization.dialog.projectName}
value={projectName}
variant="filled"
Expand All @@ -105,7 +125,7 @@ const CreationContent: React.FunctionComponent<DialogContentProps> = (dialogCont
<Button color={"error"}
onClick={() => dialogContentProps.setOpen(false)}>{localization.misc.cancel}</Button>
<Button color={"success"}
disabled={isInvalid}
disabled={isIdInvalid || isNameInvalid}
onClick={() => handleSave.mutate()}>{localization.misc.save}</Button>
</Stack>
</Stack>
Expand All @@ -120,4 +140,4 @@ const buttonContainerStyle = {
justifyContent: "center"
}

export default CreationContent
export default CreationContent
10 changes: 8 additions & 2 deletions frontend/src/queries/project-requests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export function updateProject(projectId: string, projectData: {}): AxiosPromise
return apiClient.put(urlAddress.api.project(projectId), projectData)
}

export function createProject(projectId: string, projectData: {}): AxiosPromise {
export function createProject(projectId: string, projectData: {
projectName: string,
deploymentThreshold: string
}): AxiosPromise {
if (projectData.projectName && projectData.projectName.length > 50) {
return Promise.reject(new Error("Project name exceeds the maximum length of 50 characters"));
}
return apiClient.post(urlAddress.api.createProject(projectId), projectData)
}

Expand All @@ -45,4 +51,4 @@ export function updateProjectCves(projectId: string): AxiosPromise {
export function deleteProjects(projectIds: string[]): AxiosPromise {
let data = {projectIds: projectIds}
return apiClient.post(urlAddress.api.deleteProjects, data)
}
}
4 changes: 2 additions & 2 deletions frontend/src/utilities/localization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ const language = {
projectId: "Projekt ID",
projectIdHelperNotEmpty: "Projekt ID darf nicht leer sein.",
projectIdHelperNoSpaces: "Projekt ID darf keine Leerzeichen beinhalten.",
projectIdHelperToLong: "Projekt ID ist länger als 20 Zeichen lang.",
projectIdHelperToLong: "Projekt ID ist länger als 50 Zeichen lang.",
projectIdHelperIdAlreadyUsed: "Projekt ID bereits vergeben.",
projectName: "Projektname",
projectNameHelperToLong: "Projektname zu lang.",
Expand Down Expand Up @@ -596,7 +596,7 @@ const language = {
projectId: "Project ID",
projectIdHelperNotEmpty: "Project ID mustn't be empty.",
projectIdHelperNoSpaces: "Project ID mustn't contain spaces.",
projectIdHelperToLong: "Project ID is longer than 20 characters.",
projectIdHelperToLong: "Project ID is longer than 50 characters.",
projectIdHelperIdAlreadyUsed: "Project ID already in use.",
projectName: "Project name",
projectNameHelperToLong: "Project name to long.",
Expand Down
2 changes: 1 addition & 1 deletion scripts/run-backend.bash
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ python manage.py createcachetable rate_limit
python manage.py migrate
python manage.py collectstatic --no-input

if [[ ${IS_DEV} == "true" ]] ; then
if [[ ${IS_DEV} == "True" ]] ; then
python manage.py runserver
else
gunicorn securecheckplus.wsgi:application --bind 0.0.0.0:8000 --workers=2 --threads=2 --log-level INFO
Expand Down
Loading