From d9cc30c839dfe5a5114bf813c8e387d0d0677128 Mon Sep 17 00:00:00 2001
From: Takeshi Kimata <117462761+kimatata@users.noreply.github.com>
Date: Wed, 5 Jun 2024 22:38:57 +0900
Subject: [PATCH] feat: inplement auth for cases
---
backend/middleware/auth.js | 49 +++++++++++++++----
backend/routes/cases/new.js | 20 +++-----
.../folders/[folderId]/cases/CasesPane.tsx | 18 +++----
.../[folderId]/cases/TestCaseTable.tsx | 33 +++++++------
.../folders/[folderId]/cases/caseControl.ts | 29 ++---------
5 files changed, 76 insertions(+), 73 deletions(-)
diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js
index c223d65..29452a9 100644
--- a/backend/middleware/auth.js
+++ b/backend/middleware/auth.js
@@ -5,6 +5,7 @@ const defineUser = require('../models/users');
const defineMember = require('../models/members');
const defineProject = require('../models/projects');
const defineFolder = require('../models/folders');
+const defineCase = require('../models/cases');
function authMiddleware(sequelize) {
/**
@@ -56,12 +57,24 @@ function authMiddleware(sequelize) {
*/
async function verifyProjectVisible(req, res, next) {
const Project = defineProject(sequelize, DataTypes);
+ const Folder = defineFolder(sequelize, DataTypes);
const Member = defineMember(sequelize, DataTypes);
Project.hasMany(Member, { foreignKey: 'projectId' });
- const projectId = req.params.projectId || req.query.projectId;
+ let projectId = req.params.projectId || req.query.projectId;
+ const folderId = req.params.folderId || req.query.folderId;
+ if (!projectId && !folderId) {
+ return res.status(400).json({ error: 'projectId or folderId is required' });
+ }
+
if (!projectId) {
- return res.status(400).json({ error: 'projectId is required' });
+ // find project id from folderId
+ const folder = await Folder.findByPk(folderId);
+ if (folder && folder.projectId) {
+ projectId = folder.projectId;
+ } else {
+ return res.status(404).send('failed to find project from folderId');
+ }
}
const project = await Project.findOne({
@@ -173,22 +186,40 @@ function authMiddleware(sequelize) {
async function verifyProjectDeveloper(req, res, next) {
const Project = defineProject(sequelize, DataTypes);
const Folder = defineFolder(sequelize, DataTypes);
+ const Case = defineCase(sequelize, DataTypes);
const Member = defineMember(sequelize, DataTypes);
Project.hasMany(Member, { foreignKey: 'projectId' });
+ Folder.hasMany(Case, { foreignKey: 'folderId' });
let projectId = req.params.projectId || req.query.projectId;
const folderId = req.params.folderId || req.query.folderId;
- if (!projectId && !folderId) {
- return res.status(400).json({ error: 'projectId or folderId is required' });
+ const caseId = req.params.caseId || req.query.caseId;
+ if (!projectId && !folderId && !caseId) {
+ return res.status(400).json({ error: 'projectId, folderId or caseId is required' });
}
if (!projectId) {
- // find project id from folderId
- const folder = await Folder.findByPk(folderId);
- if (folder && folder.projectId) {
- projectId = folder.projectId;
+ if (folderId) {
+ // find project id from folderId
+ const folder = await Folder.findByPk(folderId);
+ if (folder && folder.projectId) {
+ projectId = folder.projectId;
+ } else {
+ return res.status(404).send('failed to find project from folderId');
+ }
+ }
+ } else if (caseId) {
+ // find project id from caseId
+ const testCase = await Case.findByPk(caseId, {
+ include: {
+ model: Folder,
+ include: Project,
+ },
+ });
+ if (testCase && testCase.Folder && testCase.Folder.Project) {
+ projectId = testCase.Folder.Project.id;
} else {
- return res.status(404).send('failed to find project from folderId');
+ return res.status(404).send('Failed to find project from caseId');
}
}
diff --git a/backend/routes/cases/new.js b/backend/routes/cases/new.js
index d83643c..d9239c6 100644
--- a/backend/routes/cases/new.js
+++ b/backend/routes/cases/new.js
@@ -3,7 +3,7 @@ const router = express.Router();
const defineCase = require('../../models/cases');
const { DataTypes } = require('sequelize');
-const requiredFields = ['title', 'state', 'priority', 'type', 'automationStatus', 'template', 'folderId'];
+const requiredFields = ['title', 'state', 'priority', 'type', 'automationStatus', 'template'];
function isEmpty(value) {
if (value === null || value === undefined) {
@@ -18,6 +18,8 @@ module.exports = function (sequelize) {
const Case = defineCase(sequelize, DataTypes);
router.post('/', verifySignedIn, verifyProjectDeveloper, async (req, res) => {
+ const folderId = req.query.folderId;
+
try {
if (
requiredFields.some((field) => {
@@ -25,22 +27,12 @@ module.exports = function (sequelize) {
})
) {
return res.status(400).json({
- error: 'Title, state, priority, type, automationStatus, template, and folderId are required',
+ error: 'Title, state, priority, type, automationStatus, and template are required',
});
}
- const {
- title,
- state,
- priority,
- type,
- automationStatus,
- description,
- template,
- preConditions,
- expectedResults,
- folderId,
- } = req.body;
+ const { title, state, priority, type, automationStatus, description, template, preConditions, expectedResults } =
+ req.body;
const newCase = await Case.create({
title,
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx
index 65355bb..069c8af 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/CasesPane.tsx
@@ -24,8 +24,6 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
}
try {
const data = await fetchCases(context.token.access_token, folderId);
- console.log(data);
-
setCases(data);
} catch (error: any) {
console.error('Error in effect:', error.message);
@@ -50,19 +48,19 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
setDeleteCaseIds([]);
};
- const onDeleteCases = (deleteCaseIds: number[]) => {
- setDeleteCaseIds(deleteCaseIds);
- setIsDeleteConfirmDialogOpen(true);
- };
-
const onDeleteCase = async (deleteCaseId: number) => {
setDeleteCaseIds([deleteCaseId]);
setIsDeleteConfirmDialogOpen(true);
};
+ const onDeleteCases = (deleteCaseIds: number[]) => {
+ setDeleteCaseIds(deleteCaseIds);
+ setIsDeleteConfirmDialogOpen(true);
+ };
+
const onConfirm = async () => {
if (deleteCaseIds.length > 0) {
- await deleteCases(context.token.access_token, deleteCaseIds);
+ await deleteCases(context.token.access_token, deleteCaseIds, projectId);
setCases(cases.filter((entry) => !deleteCaseIds.includes(entry.id)));
closeDeleteConfirmDialog();
}
@@ -74,8 +72,8 @@ export default function CasesPane({ projectId, folderId, messages, locale }: Pro
projectId={projectId}
cases={cases}
onCreateCase={() => handleCreateCase(folderId)}
- onDeleteCase={() => onDeleteCase}
- onDeleteCases={() => onDeleteCases}
+ onDeleteCase={onDeleteCase}
+ onDeleteCases={onDeleteCases}
messages={messages}
locale={locale}
/>
diff --git a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx
index 6a61c37..c55d04e 100644
--- a/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx
+++ b/frontend/src/app/[locale]/projects/[projectId]/folders/[folderId]/cases/TestCaseTable.tsx
@@ -24,7 +24,7 @@ type Props = {
cases: CaseType[];
onCreateCase: () => void;
onDeleteCase: (caseId: number) => void;
- onDeleteCases: (selectedCases: string[]) => void;
+ onDeleteCases: (caseIds: number[]) => void;
messages: CasesMessages;
locale: string;
};
@@ -61,6 +61,10 @@ export default function TestCaseTable({
});
}, [sortDescriptor, cases]);
+ const handleDeleteCase = (deleteCaseId: number) => {
+ onDeleteCase(deleteCaseId);
+ };
+
const renderCell = useCallback((testCase: Case, columnKey: Key) => {
const cellValue = testCase[columnKey as keyof Case];
@@ -95,7 +99,7 @@ export default function TestCaseTable({