diff --git a/SECURITY.md b/SECURITY.md index 9d6cf6b81f5..dc920c827a8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,7 +7,7 @@ As of September 2024 (and until this document is updated), only the v4.x.x and v **Note**: The v4.x.x LTS version will only receive high/critical severity fixes until April 2026. Any Medium/Low severity issues will not be fixed unless specific exceptions are made. | Version | Release Tag | Support Starts | Support Ends | Security Updates Until | Notes | -|---------|-------------|----------------|----------------|------------------------|--------------------------------| +| ------- | ----------- | -------------- | -------------- | ---------------------- | ------------------------------ | | 5.x.x | GA / Stable | September 2024 | Further Notice | Further Notice | LTS | | 5.x.x | RC | N/A | September 2024 | N/A | Not Supported | | 5.x.x | Beta | N/A | N/A | N/A | Not Supported | diff --git a/packages/core/upload/admin/.eslintrc b/packages/core/upload/admin/.eslintrc new file mode 100644 index 00000000000..46fc0d13cb4 --- /dev/null +++ b/packages/core/upload/admin/.eslintrc @@ -0,0 +1,12 @@ +{ + "root": true, + "overrides": [ + { + "files": ["**/*.js", "**/*.jsx"], + "extends": ["custom/front"], + "rules": { + "import/extensions": "off" + } + } + ] +} \ No newline at end of file diff --git a/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.jsx b/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.jsx index f863ede6e14..ad687f57f72 100644 --- a/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.jsx +++ b/packages/core/upload/admin/src/components/Breadcrumbs/CrumbSimpleMenuAsync.jsx @@ -1,8 +1,7 @@ import React, { useState } from 'react'; import { useQueryParams } from '@strapi/admin/strapi-admin'; -import { Loader } from '@strapi/design-system'; -import { CrumbSimpleMenu, MenuItem } from '@strapi/design-system'; +import { CrumbSimpleMenu, Loader, MenuItem } from '@strapi/design-system'; import PropTypes from 'prop-types'; import { useIntl } from 'react-intl'; import { NavLink, useLocation } from 'react-router-dom'; diff --git a/packages/core/upload/admin/src/components/FolderCard/tests/FolderCard.test.jsx b/packages/core/upload/admin/src/components/FolderCard/tests/FolderCard.test.jsx index 43aa8a8a796..da07039c877 100644 --- a/packages/core/upload/admin/src/components/FolderCard/tests/FolderCard.test.jsx +++ b/packages/core/upload/admin/src/components/FolderCard/tests/FolderCard.test.jsx @@ -19,7 +19,7 @@ const ComponentFixture = ({ to, ...props }) => { } + startAction={null} onClick={() => {}} to={to} {...props} diff --git a/packages/core/upload/admin/src/pages/App/ConfigureTheView/state/reducer.js b/packages/core/upload/admin/src/pages/App/ConfigureTheView/state/reducer.js index c24678d5fb9..baf069bff6c 100644 --- a/packages/core/upload/admin/src/pages/App/ConfigureTheView/state/reducer.js +++ b/packages/core/upload/admin/src/pages/App/ConfigureTheView/state/reducer.js @@ -5,7 +5,12 @@ import set from 'lodash/set'; import { ON_CHANGE, SET_LOADED } from './actionTypes'; import { init, initialState } from './init'; -const reducer = (state = initialState, action) => +const reducer = ( + state = initialState, + action = { + type: '', + } +) => // eslint-disable-next-line consistent-return produce(state, (draftState) => { switch (action.type) { diff --git a/packages/core/upload/admin/src/utils/urlYupSchema.js b/packages/core/upload/admin/src/utils/urlYupSchema.js index c33a043b6e1..70330926a0f 100644 --- a/packages/core/upload/admin/src/utils/urlYupSchema.js +++ b/packages/core/upload/admin/src/utils/urlYupSchema.js @@ -6,6 +6,7 @@ import getTrad from './getTrad'; export const urlSchema = yup.object().shape({ urls: yup.string().test({ name: 'isUrlValid', + // eslint-disable-next-line no-template-curly-in-string message: '${path}', test(values = '') { const urls = values.split(/\r?\n/); diff --git a/packages/core/upload/admin/tests/handlers.js b/packages/core/upload/admin/tests/handlers.ts similarity index 90% rename from packages/core/upload/admin/tests/handlers.js rename to packages/core/upload/admin/tests/handlers.ts index c8de7cc25fe..b4051630d40 100644 --- a/packages/core/upload/admin/tests/handlers.js +++ b/packages/core/upload/admin/tests/handlers.ts @@ -1,6 +1,13 @@ import { rest } from 'msw'; import qs from 'qs'; +// Define the expected structure of your query parameters +interface CustomQuery extends qs.ParsedQs { + filters?: { + $and?: Array<{ parent: { id: string } }>; + }; +} + const handlers = [ rest.get('/upload/configuration', async (req, res, ctx) => { return res( @@ -48,7 +55,7 @@ const handlers = [ ); }), rest.get('/upload/folders', async (req, res, ctx) => { - const query = qs.parse(req.url.search.slice(1)); + const query: CustomQuery = qs.parse(req.url.search.slice(1)); if (query._q) { return res( @@ -183,13 +190,13 @@ const handlers = [ }), rest.get('*/an-image.png', (req, res, ctx) => - res(ctx.set('Content-Type', 'image/png'), ctx.body()) + res(ctx.set('Content-Type', 'image/png'), ctx.body('Successful response')) ), rest.get('*/a-pdf.pdf', (req, res, ctx) => - res(ctx.set('Content-Type', 'application/pdf'), ctx.body()) + res(ctx.set('Content-Type', 'application/pdf'), ctx.body('Successful response')) ), rest.get('*/a-video.mp4', (req, res, ctx) => - res(ctx.set('Content-Type', 'video/mp4'), ctx.body()) + res(ctx.set('Content-Type', 'video/mp4'), ctx.body('Successful response')) ), rest.get('*/not-working-like-cors.lutin', (req, res, ctx) => res(ctx.json({}))), rest.get('*/some-where-not-existing.jpg', (req, res) => res.networkError('Failed to fetch')), diff --git a/packages/core/upload/admin/tests/setup.js b/packages/core/upload/admin/tests/setup.ts similarity index 100% rename from packages/core/upload/admin/tests/setup.js rename to packages/core/upload/admin/tests/setup.ts diff --git a/packages/core/upload/admin/tests/utils.jsx b/packages/core/upload/admin/tests/utils.ts similarity index 100% rename from packages/core/upload/admin/tests/utils.jsx rename to packages/core/upload/admin/tests/utils.ts diff --git a/packages/core/upload/admin/tsconfig.build.json b/packages/core/upload/admin/tsconfig.build.json new file mode 100644 index 00000000000..6af52a63b95 --- /dev/null +++ b/packages/core/upload/admin/tsconfig.build.json @@ -0,0 +1,10 @@ +{ + "extends": "tsconfig/client.json", + "compilerOptions": { + "rootDir": "../", + "baseUrl": ".", + "outDir": "./dist" + }, + "include": ["./src", "../shared", "../package.json"], + "exclude": ["**/__mocks__", "./src/**/tests", "**/*.test.*"] +} diff --git a/packages/core/upload/admin/tsconfig.json b/packages/core/upload/admin/tsconfig.json new file mode 100644 index 00000000000..17d69ac5c6f --- /dev/null +++ b/packages/core/upload/admin/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "tsconfig/client.json", + "compilerOptions": { + "rootDir": "../", + "baseUrl": ".", + "paths": { + "@tests/*": ["./tests/*"] + } + }, + "include": ["../package.json", "./src", "../shared", "./tests"] +} diff --git a/packages/core/upload/jest.config.front.js b/packages/core/upload/jest.config.front.js index ccb2e583219..1d67f26ac95 100644 --- a/packages/core/upload/jest.config.front.js +++ b/packages/core/upload/jest.config.front.js @@ -6,5 +6,5 @@ module.exports = { moduleNameMapper: { '^@tests/(.*)$': '/admin/tests/$1', }, - setupFilesAfterEnv: ['./admin/tests/setup.js'], + setupFilesAfterEnv: ['./admin/tests/setup.ts'], }; diff --git a/packages/core/upload/jsconfig.json b/packages/core/upload/jsconfig.json deleted file mode 100644 index 986fd6eba52..00000000000 --- a/packages/core/upload/jsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@tests/*": ["./admin/tests/*"] - } - } -} diff --git a/packages/core/upload/package.json b/packages/core/upload/package.json index f2191b188dc..ec8eeb80fd7 100644 --- a/packages/core/upload/package.json +++ b/packages/core/upload/package.json @@ -17,11 +17,19 @@ ], "exports": { "./strapi-admin": { + "types": "./dist/admin/src/index.d.ts", "source": "./admin/src/index.js", "import": "./dist/admin/index.mjs", "require": "./dist/admin/index.js", "default": "./dist/admin/index.js" }, + "./_internal/shared": { + "types": "./dist/shared/index.d.ts", + "source": "./shared/index.ts", + "import": "./dist/shared/index.mjs", + "require": "./dist/shared/index.js", + "default": "./dist/shared/index.js" + }, "./strapi-server": { "types": "./dist/server/src/index.d.ts", "source": "./server/src/index.ts", @@ -41,6 +49,9 @@ "lint": "run -T eslint .", "test:front": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js", "test:unit": "run -T jest", + "test:ts:back": "run -T tsc --noEmit -p server/tsconfig.json", + "test:ts:front": "run -T tsc -p admin/tsconfig.json", + "test:front:watch": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js --watch", "test:unit:watch": "run -T jest --watch", "watch": "pack-up watch" }, diff --git a/packages/core/upload/packup.config.ts b/packages/core/upload/packup.config.ts index b531c51a21f..2c398928e51 100644 --- a/packages/core/upload/packup.config.ts +++ b/packages/core/upload/packup.config.ts @@ -3,9 +3,11 @@ import { Config, defineConfig } from '@strapi/pack-up'; const config: Config = defineConfig({ bundles: [ { - source: './admin/src/index.js', + types: './dist/admin/src/index.d.ts', + source: './admin/src/index.js', // TODO: change it with the .ts file import: './dist/admin/index.mjs', require: './dist/admin/index.js', + tsconfig: './admin/tsconfig.build.json', runtime: 'web', }, { diff --git a/packages/core/upload/server/src/bootstrap.ts b/packages/core/upload/server/src/bootstrap.ts index 5e41bb2e435..af3bb3712f1 100644 --- a/packages/core/upload/server/src/bootstrap.ts +++ b/packages/core/upload/server/src/bootstrap.ts @@ -25,6 +25,7 @@ export async function bootstrap({ strapi }: { strapi: Core.Strapi }) { config && Object.keys(defaultValue).every((key) => Object.prototype.hasOwnProperty.call(config, key)) ) { + // eslint-disable-next-line no-continue continue; } diff --git a/packages/core/upload/server/src/controllers/validation/admin/folder-file.ts b/packages/core/upload/server/src/controllers/validation/admin/folder-file.ts index d0f0b3363ad..ed4378ea43a 100644 --- a/packages/core/upload/server/src/controllers/validation/admin/folder-file.ts +++ b/packages/core/upload/server/src/controllers/validation/admin/folder-file.ts @@ -29,7 +29,7 @@ const validateStructureMoveManyFoldersFilesSchema = yup const validateDuplicatesMoveManyFoldersFilesSchema = yup .object() - .test('are-folders-unique', 'some folders already exist', async function (value) { + .test('are-folders-unique', 'some folders already exist', async function areFoldersUnique(value) { const { folderIds, destinationFolderId } = value; if (isEmpty(folderIds)) return true; @@ -58,7 +58,7 @@ const validateMoveFoldersNotInsideThemselvesSchema = yup .test( 'dont-move-inside-self', 'folders cannot be moved inside themselves or one of its children', - async function (value) { + async function validateMoveFoldersNotInsideThemselves(value) { const { folderIds, destinationFolderId } = value; if (destinationFolderId === null || isEmpty(folderIds)) return true; diff --git a/packages/core/upload/server/src/services/__tests__/upload/uploadImage.test.ts b/packages/core/upload/server/src/services/__tests__/upload/uploadImage.test.ts index 8256cceb3aa..4ef3439c87e 100644 --- a/packages/core/upload/server/src/services/__tests__/upload/uploadImage.test.ts +++ b/packages/core/upload/server/src/services/__tests__/upload/uploadImage.test.ts @@ -47,7 +47,7 @@ const getFileData = (filePath: string) => ({ alternativeText: 'image.png', caption: 'image.png', ext: '.png', - folder: null, + folder: undefined, folderPath: '/', filepath: filePath, getStream: () => fs.createReadStream(filePath), @@ -56,6 +56,7 @@ const getFileData = (filePath: string) => ({ size: 4, width: 1500, tmpWorkingDirectory, + name: 'image.png', }); describe('Upload image', () => { diff --git a/packages/core/upload/server/src/services/extensions/__tests__/sign-media.test.ts b/packages/core/upload/server/src/services/extensions/__tests__/sign-media.test.ts index 3e78e176cc9..ab1569d9f92 100644 --- a/packages/core/upload/server/src/services/extensions/__tests__/sign-media.test.ts +++ b/packages/core/upload/server/src/services/extensions/__tests__/sign-media.test.ts @@ -1,10 +1,11 @@ +import type { UID } from '@strapi/types'; import { signEntityMedia } from '../utils'; import { getService } from '../../../utils'; jest.mock('../../../utils'); describe('Upload | extensions | entity-manager', () => { - const modelUID = 'model'; + const modelUID = 'model' as UID.Schema; const componentUID = 'component'; const models = { @@ -71,6 +72,18 @@ describe('Upload | extensions | entity-manager', () => { spySignFileUrls = jest.fn(); jest.mocked(getService).mockImplementation(() => ({ signFileUrls: spySignFileUrls, + getFolderPath: jest.fn(), + deleteByIds: jest.fn(), + computeMetrics: jest.fn().mockResolvedValue({ + assetNumber: 0, + folderNumber: 0, + averageDepth: 0, + maxDepth: 0, + averageDeviationDepth: 0, + }), + sendMetrics: jest.fn().mockResolvedValue(undefined), + ensureWeeklyStoredCronSchedule: jest.fn().mockResolvedValue(undefined), + registerCron: jest.fn().mockResolvedValue(undefined), })); global.strapi = {