diff --git a/backend/webserver/views/project_views.py b/backend/webserver/views/project_views.py index 351199b..683885d 100644 --- a/backend/webserver/views/project_views.py +++ b/backend/webserver/views/project_views.py @@ -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: diff --git a/frontend/src/components/NavBar/ProjectCreationContent.tsx b/frontend/src/components/NavBar/ProjectCreationContent.tsx index 5e0867c..c4a261e 100644 --- a/frontend/src/components/NavBar/ProjectCreationContent.tsx +++ b/frontend/src/components/NavBar/ProjectCreationContent.tsx @@ -13,12 +13,15 @@ import {useNotification} from "../../context/NotificationContext"; const CreationContent: React.FunctionComponent = (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 @@ -52,42 +55,59 @@ const CreationContent: React.FunctionComponent = (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( ) => setProjectId(e.target.value)} + onChange={(e: ChangeEvent) => { + setProjectId(e.target.value) + setProjectIdTouched(true) + }} /> = (dialogCont @@ -120,4 +140,4 @@ const buttonContainerStyle = { justifyContent: "center" } -export default CreationContent \ No newline at end of file +export default CreationContent diff --git a/frontend/src/queries/project-requests.tsx b/frontend/src/queries/project-requests.tsx index 4c1be3f..52ca4b5 100644 --- a/frontend/src/queries/project-requests.tsx +++ b/frontend/src/queries/project-requests.tsx @@ -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) } @@ -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) -} \ No newline at end of file +} diff --git a/frontend/src/utilities/localization.tsx b/frontend/src/utilities/localization.tsx index cec5165..b180308 100644 --- a/frontend/src/utilities/localization.tsx +++ b/frontend/src/utilities/localization.tsx @@ -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.", @@ -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.", diff --git a/scripts/run-backend.bash b/scripts/run-backend.bash index c72bdca..ee24fc3 100755 --- a/scripts/run-backend.bash +++ b/scripts/run-backend.bash @@ -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