From 92e54aa49f1e97fd42888abc854c4c40099aae45 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Fri, 8 Mar 2024 12:58:01 +0100 Subject: [PATCH] chore: cleanups --- ...raphql-upload-automatic-folder.test.api.js | 319 ------------ .../content-api/graphql-upload.test.api.js | 474 ------------------ .../upload/content-api/graphql.test.api.js | 143 ++++++ .../src/api/address/routes/address.js | 9 +- packages/plugins/graphql/package.json | 2 - .../plugins/graphql/server/src/bootstrap.ts | 22 - .../builders/mutations/collection-type.ts | 6 +- .../services/builders/queries/single-type.ts | 2 - .../services/builders/response-collection.ts | 4 +- .../server/src/services/builders/type.ts | 1 + .../server/src/services/builders/utils.ts | 17 +- .../graphql/server/src/services/constants.ts | 2 - .../src/services/internals/scalars/index.ts | 3 - .../types/delete-mutation-response.ts | 4 - .../src/services/internals/types/index.ts | 2 - .../internals/types/publication-state.ts | 24 - .../internals/types/publication-status.ts | 4 +- packages/plugins/i18n/server/src/graphql.ts | 2 +- yarn.lock | 107 +--- 19 files changed, 175 insertions(+), 972 deletions(-) delete mode 100644 api-tests/core/upload/content-api/graphql-upload-automatic-folder.test.api.js delete mode 100644 api-tests/core/upload/content-api/graphql-upload.test.api.js create mode 100644 api-tests/core/upload/content-api/graphql.test.api.js delete mode 100644 packages/plugins/graphql/server/src/services/internals/types/publication-state.ts diff --git a/api-tests/core/upload/content-api/graphql-upload-automatic-folder.test.api.js b/api-tests/core/upload/content-api/graphql-upload-automatic-folder.test.api.js deleted file mode 100644 index 7c8ab5e43bb..00000000000 --- a/api-tests/core/upload/content-api/graphql-upload-automatic-folder.test.api.js +++ /dev/null @@ -1,319 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const { createStrapiInstance } = require('api-tests/strapi'); -const { createAuthRequest } = require('api-tests/request'); - -let strapi; -let rq; - -let rqAdmin; -let uploadFolder; - -describe('Uploads folder (GraphQL)', () => { - beforeAll(async () => { - strapi = await createStrapiInstance(); - rq = await createAuthRequest({ - strapi, - // header required for multipart requests - state: { headers: { 'x-apollo-operation-name': 'graphql-upload' } }, - }); - - rqAdmin = await createAuthRequest({ strapi }); - }); - - afterAll(async () => { - // delete all folders - const res = await rqAdmin({ - method: 'GET', - url: '/upload/folders', - }); - await rqAdmin({ - method: 'POST', - url: '/upload/actions/bulk-delete', - body: { - folderIds: res.body.data.map((f) => f.id), - }, - }); - - await strapi.destroy(); - }); - - describe('uploadFile', () => { - test('Uploaded file goes into a specific folder', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFile($file: Upload!) { - upload(file: $file) { - data { - id - } - } - } - `, - }), - map: JSON.stringify({ nFile1: ['variables.file'] }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - - const { body: file } = await rqAdmin({ - method: 'GET', - url: `/upload/files/${res.body.data.upload.data.id}`, - }); - - expect(file).toMatchObject({ - folder: { - name: 'API Uploads', - pathId: expect.any(Number), - }, - folderPath: `/${file.folder.pathId}`, - }); - - uploadFolder = file.folder; - }); - - test('Uploads folder is recreated if deleted', async () => { - await rqAdmin({ - method: 'POST', - url: '/upload/actions/bulk-delete', - body: { - folderIds: [uploadFolder.id], - }, - }); - - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFile($file: Upload!) { - upload(file: $file) { - data { - id - } - } - } - `, - }), - map: JSON.stringify({ nFile1: ['variables.file'] }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - - const { body: file } = await rqAdmin({ - method: 'GET', - url: `/upload/files/${res.body.data.upload.data.id}`, - }); - - expect(file).toMatchObject({ - folder: { - name: 'API Uploads', - pathId: expect.any(Number), - }, - folderPath: `/${file.folder.pathId}`, - }); - - uploadFolder = file.folder; - }); - - test('Uploads folder is recreated if deleted (handle duplicates)', async () => { - await rqAdmin({ - method: 'POST', - url: '/upload/actions/bulk-delete', - body: { - folderIds: [uploadFolder.id], - }, - }); - - await rqAdmin({ - method: 'POST', - url: '/upload/folders', - body: { - name: 'API Uploads', - parent: null, - }, - }); - - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFile($file: Upload!) { - upload(file: $file) { - data { - id - } - } - } - `, - }), - map: JSON.stringify({ nFile1: ['variables.file'] }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - - const { body: file } = await rqAdmin({ - method: 'GET', - url: `/upload/files/${res.body.data.upload.data.id}`, - }); - - expect(file).toMatchObject({ - folder: { - name: 'API Uploads (1)', - pathId: expect.any(Number), - }, - folderPath: `/${file.folder.pathId}`, - }); - - uploadFolder = file.folder; - }); - }); - - describe('multipleUploadFile', () => { - test('Uploaded file goes into a specific folder', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation multipleUploadFile($files: [Upload]!) { - multipleUpload(files: $files) { - data { - id - } - } - } - `, - }), - map: JSON.stringify({ nFile1: ['variables.files'] }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - - const { body: file } = await rqAdmin({ - method: 'GET', - url: `/upload/files/${res.body.data.multipleUpload[0].data.id}`, - }); - - expect(file).toMatchObject({ - folder: { - name: 'API Uploads (1)', - pathId: expect.any(Number), - }, - folderPath: `/${file.folder.pathId}`, - }); - - uploadFolder = file.folder; - }); - - test('Uploads folder is recreated if deleted', async () => { - await rqAdmin({ - method: 'POST', - url: '/upload/actions/bulk-delete', - body: { - folderIds: [uploadFolder.id], - }, - }); - - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation multipleUploadFile($files: [Upload]!) { - multipleUpload(files: $files) { - data { - id - } - } - } - `, - }), - map: JSON.stringify({ nFile1: ['variables.files'] }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - - const { body: file } = await rqAdmin({ - method: 'GET', - url: `/upload/files/${res.body.data.multipleUpload[0].data.id}`, - }); - - expect(file).toMatchObject({ - folder: { - name: 'API Uploads (1)', - pathId: expect.any(Number), - }, - folderPath: `/${file.folder.pathId}`, - }); - - uploadFolder = file.folder; - }); - - test('Uploads folder is recreated if deleted (handle duplicates)', async () => { - await rqAdmin({ - method: 'POST', - url: '/upload/actions/bulk-delete', - body: { - folderIds: [uploadFolder.id], - }, - }); - - await rqAdmin({ - method: 'POST', - url: '/upload/folders', - body: { - name: 'API Uploads (1)', - parent: null, - }, - }); - - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation multipleUploadFile($files: [Upload]!) { - multipleUpload(files: $files) { - data { - id - } - } - } - `, - }), - map: JSON.stringify({ nFile1: ['variables.files'] }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - - const { body: file } = await rqAdmin({ - method: 'GET', - url: `/upload/files/${res.body.data.multipleUpload[0].data.id}`, - }); - - expect(file).toMatchObject({ - folder: { - name: 'API Uploads (2)', - pathId: expect.any(Number), - }, - folderPath: `/${file.folder.pathId}`, - }); - - uploadFolder = file.folder; - }); - }); -}); diff --git a/api-tests/core/upload/content-api/graphql-upload.test.api.js b/api-tests/core/upload/content-api/graphql-upload.test.api.js deleted file mode 100644 index dcc7c81d6e4..00000000000 --- a/api-tests/core/upload/content-api/graphql-upload.test.api.js +++ /dev/null @@ -1,474 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const path = require('path'); - -const { createStrapiInstance } = require('api-tests/strapi'); -const { createAuthRequest } = require('api-tests/request'); - -let strapi; -let rq; - -const data = {}; - -describe('Upload plugin end to end tests', () => { - beforeAll(async () => { - strapi = await createStrapiInstance(); - rq = await createAuthRequest({ - strapi, - // header required for multipart requests - state: { headers: { 'x-apollo-operation-name': 'graphql-upload' } }, - }); - }); - - afterAll(async () => { - await strapi.destroy(); - }); - - test('Upload a single image', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFile($file: Upload!) { - upload(file: $file) { - data { - id - attributes { - name - mime - url - } - } - } - } - `, - variables: { - file: null, - }, - }), - map: JSON.stringify({ - nFile1: ['variables.file'], - }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - upload: { - data: { - id: expect.anything(), - attributes: { - name: 'rec.jpg', - mime: 'image/jpeg', - url: expect.any(String), - }, - }, - }, - }, - }); - - data.file = res.body.data.upload.data; - }); - - test('Upload multiple images', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFiles($files: [Upload]!) { - multipleUpload(files: $files) { - data { - id - attributes { - name - mime - url - } - } - } - } - `, - variables: { - files: [null, null], - }, - }), - map: JSON.stringify({ - nFile0: ['variables.files.0'], - nFile1: ['variables.files.1'], - }), - nFile0: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - expect(res.body.data.multipleUpload).toHaveLength(2); - expect(res.body).toEqual({ - data: { - multipleUpload: expect.arrayContaining([ - expect.objectContaining({ - data: { - id: expect.anything(), - attributes: { - name: 'rec.jpg', - mime: 'image/jpeg', - url: expect.any(String), - }, - }, - }), - ]), - }, - }); - }); - - test('Upload a single pdf', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFile($file: Upload!) { - upload(file: $file) { - data { - id - attributes { - name - mime - url - } - } - } - } - `, - variables: { - file: null, - }, - }), - map: JSON.stringify({ - nFile1: ['variables.file'], - }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - upload: { - data: { - id: expect.anything(), - attributes: { - name: 'rec.pdf', - mime: 'application/pdf', - url: expect.any(String), - }, - }, - }, - }, - }); - - data.file = res.body.data.upload.data; - }); - - test('Upload multiple pdf', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFiles($files: [Upload]!) { - multipleUpload(files: $files) { - data { - id - attributes { - name - mime - url - } - } - } - } - `, - variables: { - files: [null, null], - }, - }), - map: JSON.stringify({ - nFile0: ['variables.files.0'], - nFile1: ['variables.files.1'], - }), - nFile0: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - expect(res.body.data.multipleUpload).toHaveLength(2); - expect(res.body).toEqual({ - data: { - multipleUpload: expect.arrayContaining([ - expect.objectContaining({ - data: { - id: expect.anything(), - attributes: { - name: 'rec.pdf', - mime: 'application/pdf', - url: expect.any(String), - }, - }, - }), - ]), - }, - }); - }); - - test('Update file information', async () => { - const res = await rq({ - url: '/graphql', - method: 'POST', - body: { - query: /* GraphQL */ ` - mutation updateFileInfo($id: ID!, $info: FileInfoInput!) { - updateFileInfo(id: $id, info: $info) { - data { - id - attributes { - name - alternativeText - caption - } - } - } - } - `, - variables: { - id: data.file.id, - info: { - name: 'test name', - alternativeText: 'alternative text test', - caption: 'caption test', - }, - }, - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - updateFileInfo: { - data: { - id: data.file.id, - attributes: { - name: 'test name', - alternativeText: 'alternative text test', - caption: 'caption test', - }, - }, - }, - }, - }); - }); - - test('Delete a file', async () => { - const res = await rq({ - url: '/graphql', - method: 'POST', - body: { - query: /* GraphQL */ ` - mutation removeFile($id: ID!) { - removeFile(id: $id) { - data { - id - } - } - } - `, - variables: { - id: data.file.id, - }, - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - removeFile: { - data: { - id: data.file.id, - }, - }, - }, - }); - }); - - test('Delete a file that does not exist', async () => { - const res = await rq({ - url: '/graphql', - method: 'POST', - body: { - query: /* GraphQL */ ` - mutation removeFile($id: ID!) { - removeFile(id: $id) { - data { - id - } - } - } - `, - variables: { - id: '404', - }, - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - removeFile: null, - }, - }); - }); - - test('Upload a single image with info', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFilesWithInfo($file: Upload!, $info: FileInfoInput) { - upload(file: $file, info: $info) { - data { - id - attributes { - name - alternativeText - caption - } - } - } - } - `, - variables: { - file: null, - info: { - alternativeText: 'alternative text test', - caption: 'caption test', - }, - }, - }), - map: JSON.stringify({ - nFile1: ['variables.file'], - }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - upload: { - data: { - id: expect.anything(), - attributes: { - name: 'rec.jpg', - alternativeText: 'alternative text test', - caption: 'caption test', - }, - }, - }, - }, - }); - }); - - test('Upload a single pdf with info', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFilesWithInfo($file: Upload!, $info: FileInfoInput) { - upload(file: $file, info: $info) { - data { - id - attributes { - name - alternativeText - caption - } - } - } - } - `, - variables: { - file: null, - info: { - alternativeText: 'alternative text test', - caption: 'caption test', - }, - }, - }), - map: JSON.stringify({ - nFile1: ['variables.file'], - }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ - data: { - upload: { - data: { - id: expect.anything(), - attributes: { - name: 'rec.pdf', - alternativeText: 'alternative text test', - caption: 'caption test', - }, - }, - }, - }, - }); - }); - - test('Returns an error when required headers for csrf protection are missing', async () => { - const formData = { - operations: JSON.stringify({ - query: /* GraphQL */ ` - mutation uploadFile($file: Upload!) { - upload(file: $file) { - data { - id - attributes { - name - mime - url - } - } - } - } - `, - variables: { - file: null, - }, - }), - map: JSON.stringify({ - nFile1: ['variables.file'], - }), - nFile1: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }; - - const res = await rq({ method: 'POST', url: '/graphql', formData, headers: {} }); - - expect(res.statusCode).toBe(400); - expect(res.body.errors).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - message: expect.stringContaining('x-apollo-operation-name'), - extensions: expect.objectContaining({ - code: 'BAD_REQUEST', - }), - }), - ]) - ); - }); -}); diff --git a/api-tests/core/upload/content-api/graphql.test.api.js b/api-tests/core/upload/content-api/graphql.test.api.js new file mode 100644 index 00000000000..255567bd70b --- /dev/null +++ b/api-tests/core/upload/content-api/graphql.test.api.js @@ -0,0 +1,143 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const { createStrapiInstance } = require('api-tests/strapi'); +const { createAuthRequest } = require('api-tests/request'); + +let strapi; +let rq; + +const data = {}; + +describe('Upload plugin end to end tests', () => { + beforeAll(async () => { + strapi = await createStrapiInstance(); + rq = await createAuthRequest({ + strapi, + }); + + const res = await rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + }, + }); + + data.file = res.body[0]; + data.file.id = `${data.file.id}`; + }); + + afterAll(async () => { + await strapi.destroy(); + }); + + test('Update file information', async () => { + const res = await rq({ + url: '/graphql', + method: 'POST', + body: { + query: /* GraphQL */ ` + mutation updateFileInfo($id: ID!, $info: FileInfoInput!) { + updateUploadFile(id: $id, info: $info) { + data { + id + attributes { + name + alternativeText + caption + } + } + } + } + `, + variables: { + id: data.file.id, + info: { + name: 'test name', + alternativeText: 'alternative text test', + caption: 'caption test', + }, + }, + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ + data: { + updateUploadFile: { + data: { + id: data.file.id, + attributes: { + name: 'test name', + alternativeText: 'alternative text test', + caption: 'caption test', + }, + }, + }, + }, + }); + }); + + test('Delete a file', async () => { + const res = await rq({ + url: '/graphql', + method: 'POST', + body: { + query: /* GraphQL */ ` + mutation removeFile($id: ID!) { + deleteUploadFile(id: $id) { + data { + id + } + } + } + `, + variables: { + id: data.file.id, + }, + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ + data: { + deleteUploadFile: { + data: { + id: data.file.id, + }, + }, + }, + }); + }); + + test('Delete a file that does not exist', async () => { + const res = await rq({ + url: '/graphql', + method: 'POST', + body: { + query: /* GraphQL */ ` + mutation removeFile($id: ID!) { + deleteUploadFile(id: $id) { + data { + id + } + } + } + `, + variables: { + id: '404', + }, + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ + data: { + deleteUploadFile: null, + }, + }); + }); +}); diff --git a/examples/getstarted/src/api/address/routes/address.js b/examples/getstarted/src/api/address/routes/address.js index 8f90dda4e6f..549918452dd 100755 --- a/examples/getstarted/src/api/address/routes/address.js +++ b/examples/getstarted/src/api/address/routes/address.js @@ -2,4 +2,11 @@ const { createCoreRouter } = require('@strapi/strapi').factories; -module.exports = createCoreRouter('api::address.address'); +module.exports = createCoreRouter('api::address.address', { + config: { + find: { + // auth: false, + }, + }, + only: ['find', 'findOne'], +}); diff --git a/packages/plugins/graphql/package.json b/packages/plugins/graphql/package.json index e62becd7f35..1b03f8e6dbe 100644 --- a/packages/plugins/graphql/package.json +++ b/packages/plugins/graphql/package.json @@ -61,7 +61,6 @@ "graphql-depth-limit": "^1.1.0", "graphql-playground-middleware-koa": "^1.6.21", "graphql-scalars": "1.22.2", - "graphql-upload": "^15.0.0", "koa-bodyparser": "4.4.1", "koa-compose": "^4.1.0", "lodash": "4.17.21", @@ -72,7 +71,6 @@ "@strapi/strapi": "4.20.3", "@strapi/types": "4.20.3", "@types/graphql-depth-limit": "1.1.5", - "@types/graphql-upload": "15.0.2", "@types/koa-bodyparser": "4.3.12", "@types/koa__cors": "5.0.0", "cross-env": "^7.0.3", diff --git a/packages/plugins/graphql/server/src/bootstrap.ts b/packages/plugins/graphql/server/src/bootstrap.ts index 236c81d9758..1844f45bb85 100644 --- a/packages/plugins/graphql/server/src/bootstrap.ts +++ b/packages/plugins/graphql/server/src/bootstrap.ts @@ -6,8 +6,6 @@ import { } from '@apollo/server/plugin/landingPage/default'; import { koaMiddleware } from '@as-integrations/koa'; import depthLimit from 'graphql-depth-limit'; -// eslint-disable-next-line import/extensions -import graphqlUploadKoa from 'graphql-upload/graphqlUploadKoa.js'; import bodyParser from 'koa-bodyparser'; import cors from '@koa/cors'; @@ -22,23 +20,6 @@ const merge = mergeWith((a, b) => { } }); -/** - * Register the upload middleware powered by graphql-upload in Strapi - * @param {object} strapi - * @param {string} path - */ -const useUploadMiddleware = (strapi: Strapi, path: string): void => { - const uploadMiddleware = graphqlUploadKoa(); - - strapi.server.app.use((ctx, next) => { - if (ctx.path === path) { - return uploadMiddleware(ctx, next); - } - - return next(); - }); -}; - export async function bootstrap({ strapi }: { strapi: Strapi }) { // Generate the GraphQL schema for the content API const schema = strapi.plugin('graphql').service('content-api').buildSchema(); @@ -100,9 +81,6 @@ export async function bootstrap({ strapi }: { strapi: Strapi }) { // Create a new Apollo server const server = new ApolloServer(serverConfig); - // Register the upload middleware - useUploadMiddleware(strapi, path); - try { // server.start() must be called before using server.applyMiddleware() await server.start(); diff --git a/packages/plugins/graphql/server/src/services/builders/mutations/collection-type.ts b/packages/plugins/graphql/server/src/services/builders/mutations/collection-type.ts index 1a418d3e37e..265fb674aa9 100644 --- a/packages/plugins/graphql/server/src/services/builders/mutations/collection-type.ts +++ b/packages/plugins/graphql/server/src/services/builders/mutations/collection-type.ts @@ -1,4 +1,4 @@ -import { extendType, nonNull } from 'nexus'; +import { extendType, nonNull, idArg } from 'nexus'; import { sanitize } from '@strapi/utils'; import type * as Nexus from 'nexus'; import type { Schema } from '@strapi/types'; @@ -77,7 +77,7 @@ export default ({ strapi }: Context) => { }, args: { - documentId: nonNull('ID'), + documentId: nonNull(idArg()), status: args.PublicationStatusArg, data: nonNull(getContentTypeInputName(contentType)), }, @@ -120,7 +120,7 @@ export default ({ strapi }: Context) => { }, args: { - documentId: nonNull('ID'), + documentId: nonNull(idArg()), }, async resolve(parent, args) { diff --git a/packages/plugins/graphql/server/src/services/builders/queries/single-type.ts b/packages/plugins/graphql/server/src/services/builders/queries/single-type.ts index e61e5c54959..eab0cb448d5 100644 --- a/packages/plugins/graphql/server/src/services/builders/queries/single-type.ts +++ b/packages/plugins/graphql/server/src/services/builders/queries/single-type.ts @@ -45,8 +45,6 @@ export default ({ strapi }: Context) => { t: Nexus.blocks.ObjectDefinitionBlock, contentType: Schema.SingleType ) => { - // const { uid } = contentType; - const findQueryName = getFindOneQueryName(contentType); const typeName = getTypeName(contentType); diff --git a/packages/plugins/graphql/server/src/services/builders/response-collection.ts b/packages/plugins/graphql/server/src/services/builders/response-collection.ts index 25530ddde35..bb5d3dc27b8 100644 --- a/packages/plugins/graphql/server/src/services/builders/response-collection.ts +++ b/packages/plugins/graphql/server/src/services/builders/response-collection.ts @@ -42,10 +42,8 @@ export default ({ strapi }: Context) => { resolve: pipe(prop('nodes'), defaultTo([])), }); - // TODO: only add if v4 compat is enabled - // TODO: remove in next major t.nonNull.field('meta', { - deprecation: 'Use the `pagination` field instead', + deprecation: 'Use the `pageInfo` field instead', type: RESPONSE_COLLECTION_META_TYPE_NAME, resolve: identity, }); diff --git a/packages/plugins/graphql/server/src/services/builders/type.ts b/packages/plugins/graphql/server/src/services/builders/type.ts index ed82933f4ed..88170dd0fb6 100644 --- a/packages/plugins/graphql/server/src/services/builders/type.ts +++ b/packages/plugins/graphql/server/src/services/builders/type.ts @@ -329,6 +329,7 @@ export default (context: Context) => { return objectType({ name, definition(t) { + // add back the old id attribute on contentType if v4 compat is enabled if ( modelType !== 'component' && isNotDisabled(contentType)('id') && diff --git a/packages/plugins/graphql/server/src/services/builders/utils.ts b/packages/plugins/graphql/server/src/services/builders/utils.ts index c31891c596e..3ab709cfdd3 100644 --- a/packages/plugins/graphql/server/src/services/builders/utils.ts +++ b/packages/plugins/graphql/server/src/services/builders/utils.ts @@ -5,18 +5,19 @@ import type { Strapi, Schema } from '@strapi/types'; const { withDefaultPagination } = pagination; +type ContentTypeArgsOptions = { + multiple?: boolean; + isNested?: boolean; +}; + export default ({ strapi }: { strapi: Strapi }) => { const { service: getService } = strapi.plugin('graphql'); return { - /** - * Get every args for a given content type - * @param {object} contentType - * @param {object} options - * @param {boolean} options.multiple - * @return {object} - */ - getContentTypeArgs(contentType: Schema.Any, { multiple = true, isNested = false } = {}) { + getContentTypeArgs( + contentType: Schema.Any, + { multiple = true, isNested = false }: ContentTypeArgsOptions = {} + ) { const { naming } = getService('utils'); const { args } = getService('internals'); diff --git a/packages/plugins/graphql/server/src/services/constants.ts b/packages/plugins/graphql/server/src/services/constants.ts index 40b3547c118..4b6a1896581 100644 --- a/packages/plugins/graphql/server/src/services/constants.ts +++ b/packages/plugins/graphql/server/src/services/constants.ts @@ -1,6 +1,5 @@ const PAGINATION_TYPE_NAME = 'Pagination'; const DELETE_MUTATION_RESPONSE_TYPE_NAME = 'DeleteMutationResponse'; -const PUBLICATION_STATE_TYPE_NAME = 'PublicationState'; const PUBLICATION_STATUS_TYPE_NAME = 'PublicationStatus'; const ERROR_TYPE_NAME = 'Error'; @@ -156,7 +155,6 @@ export default () => ({ PAGINATION_TYPE_NAME, RESPONSE_COLLECTION_META_TYPE_NAME, DELETE_MUTATION_RESPONSE_TYPE_NAME, - PUBLICATION_STATE_TYPE_NAME, PUBLICATION_STATUS_TYPE_NAME, GRAPHQL_SCALARS, STRAPI_SCALARS, diff --git a/packages/plugins/graphql/server/src/services/internals/scalars/index.ts b/packages/plugins/graphql/server/src/services/internals/scalars/index.ts index b1bf710e79d..8e7517a44e6 100644 --- a/packages/plugins/graphql/server/src/services/internals/scalars/index.ts +++ b/packages/plugins/graphql/server/src/services/internals/scalars/index.ts @@ -1,6 +1,4 @@ import { GraphQLDateTime, GraphQLLong, GraphQLJSON } from 'graphql-scalars'; -// eslint-disable-next-line import/extensions -import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'; import { asNexusMethod } from 'nexus'; import TimeScalar from './time'; @@ -12,5 +10,4 @@ export default () => ({ Time: asNexusMethod(TimeScalar, 'time'), Date: asNexusMethod(GraphQLDate, 'date'), Long: asNexusMethod(GraphQLLong, 'long'), - Upload: asNexusMethod(GraphQLUpload as any, 'upload'), }); diff --git a/packages/plugins/graphql/server/src/services/internals/types/delete-mutation-response.ts b/packages/plugins/graphql/server/src/services/internals/types/delete-mutation-response.ts index 4eb63d9cca9..96fead810e3 100644 --- a/packages/plugins/graphql/server/src/services/internals/types/delete-mutation-response.ts +++ b/packages/plugins/graphql/server/src/services/internals/types/delete-mutation-response.ts @@ -5,10 +5,6 @@ export default ({ strapi }: Context) => { const { DELETE_MUTATION_RESPONSE_TYPE_NAME } = strapi.plugin('graphql').service('constants'); return { - /** - * Type definition for a Pagination object - * @type {NexusObjectTypeDef} - */ DeleteMutationResponse: objectType({ name: DELETE_MUTATION_RESPONSE_TYPE_NAME, diff --git a/packages/plugins/graphql/server/src/services/internals/types/index.ts b/packages/plugins/graphql/server/src/services/internals/types/index.ts index 2f7898d5680..652f766ab27 100644 --- a/packages/plugins/graphql/server/src/services/internals/types/index.ts +++ b/packages/plugins/graphql/server/src/services/internals/types/index.ts @@ -1,7 +1,6 @@ import pagination from './pagination'; import buildResponseCollectionMeta from './response-collection-meta'; import buildDeleteMutationResponse from './delete-mutation-response'; -import publicationState from './publication-state'; import publicationStatus from './publication-status'; import filters from './filters'; import error from './error'; @@ -21,7 +20,6 @@ export default (context: Context) => () => { }, [KINDS.enum]: { - publicationState: publicationState(context), publicationStatus: publicationStatus(context), }, diff --git a/packages/plugins/graphql/server/src/services/internals/types/publication-state.ts b/packages/plugins/graphql/server/src/services/internals/types/publication-state.ts deleted file mode 100644 index c9bbec5cec2..00000000000 --- a/packages/plugins/graphql/server/src/services/internals/types/publication-state.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { enumType } from 'nexus'; - -import type { Context } from '../../types'; - -export default ({ strapi }: Context) => { - const { PUBLICATION_STATE_TYPE_NAME } = strapi.plugin('graphql').service('constants'); - - return { - /** - * An enum type definition representing a publication state - * @type {NexusEnumTypeDef} - */ - PublicationState: enumType({ - name: PUBLICATION_STATE_TYPE_NAME, - - members: { - // Published only - LIVE: 'live', - // Published & draft - PREVIEW: 'preview', - }, - }), - }; -}; diff --git a/packages/plugins/graphql/server/src/services/internals/types/publication-status.ts b/packages/plugins/graphql/server/src/services/internals/types/publication-status.ts index d4ead7c06ae..2a8acc73ad7 100644 --- a/packages/plugins/graphql/server/src/services/internals/types/publication-status.ts +++ b/packages/plugins/graphql/server/src/services/internals/types/publication-status.ts @@ -6,16 +6,14 @@ export default ({ strapi }: Context) => { return { /** - * An enum type definition representing a publication state + * An enum type definition representing a publication status * @type {NexusEnumTypeDef} */ PublicationStatus: enumType({ name: PUBLICATION_STATUS_TYPE_NAME, members: { - // Published only DRAFT: 'draft', - // Published & draft PUBLISHED: 'published', }, }), diff --git a/packages/plugins/i18n/server/src/graphql.ts b/packages/plugins/i18n/server/src/graphql.ts index acc1a0312a7..1873a19de59 100644 --- a/packages/plugins/i18n/server/src/graphql.ts +++ b/packages/plugins/i18n/server/src/graphql.ts @@ -64,7 +64,7 @@ const getLocaleScalar = ({ nexus }: any) => { throw new ValidationError('Locale cannot represent non string type'); } - const isValidLocale = ast.value === 'all' || locales.find(propEq('code', ast.value)); + const isValidLocale = ast.value === '*' || locales.find(propEq('code', ast.value)); if (!isValidLocale) { throw new ValidationError('Unknown locale supplied'); diff --git a/yarn.lock b/yarn.lock index 91a7fd81aad..2a93be5e35e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7535,7 +7535,6 @@ __metadata: "@strapi/types": "npm:4.20.3" "@strapi/utils": "npm:4.20.3" "@types/graphql-depth-limit": "npm:1.1.5" - "@types/graphql-upload": "npm:15.0.2" "@types/koa-bodyparser": "npm:4.3.12" "@types/koa__cors": "npm:5.0.0" cross-env: "npm:^7.0.3" @@ -7544,7 +7543,6 @@ __metadata: graphql-depth-limit: "npm:^1.1.0" graphql-playground-middleware-koa: "npm:^1.6.21" graphql-scalars: "npm:1.22.2" - graphql-upload: "npm:^15.0.0" koa: "npm:2.13.4" koa-bodyparser: "npm:4.4.1" koa-compose: "npm:^4.1.0" @@ -8572,15 +8570,6 @@ __metadata: languageName: node linkType: hard -"@types/busboy@npm:^1.5.0": - version: 1.5.3 - resolution: "@types/busboy@npm:1.5.3" - dependencies: - "@types/node": "npm:*" - checksum: 9ec0a125723e594816d06f6ddf5a4f8dda4855734719bb6e38bdc6fdaf59416f270744862ee54c755075af26e9f5467cc00db803ae1d88f45c1431f61a48ae58 - languageName: node - linkType: hard - "@types/cacheable-request@npm:^6.0.1": version: 6.0.2 resolution: "@types/cacheable-request@npm:6.0.2" @@ -8802,18 +8791,6 @@ __metadata: languageName: node linkType: hard -"@types/graphql-upload@npm:15.0.2": - version: 15.0.2 - resolution: "@types/graphql-upload@npm:15.0.2" - dependencies: - "@types/express": "npm:*" - "@types/koa": "npm:*" - fs-capacitor: "npm:^8.0.0" - graphql: "npm:0.13.1 - 16" - checksum: 3e88a03082ce1e1de39b414a096fbd47cf1f97b6027c93cc71a216229bdfb248f54f1afc209e970e1ae3856153c20cf40d458febe348b287be237f62ea84ffc0 - languageName: node - linkType: hard - "@types/hoist-non-react-statics@npm:*, @types/hoist-non-react-statics@npm:^3.3.1": version: 3.3.1 resolution: "@types/hoist-non-react-statics@npm:3.3.1" @@ -9315,13 +9292,6 @@ __metadata: languageName: node linkType: hard -"@types/object-path@npm:^0.11.1": - version: 0.11.4 - resolution: "@types/object-path@npm:0.11.4" - checksum: 7f1f5cb18b651d21e7861da176d8f87526c936ed949a8126a2692195cbe65734ed1a1a22c06a24a54afe1890483a3d6b074b402ebfca7a7567c1c287b588f563 - languageName: node - linkType: hard - "@types/parse-json@npm:^4.0.0": version: 4.0.0 resolution: "@types/parse-json@npm:4.0.0" @@ -11825,15 +11795,6 @@ __metadata: languageName: node linkType: hard -"busboy@npm:^1.6.0": - version: 1.6.0 - resolution: "busboy@npm:1.6.0" - dependencies: - streamsearch: "npm:^1.1.0" - checksum: bee10fa10ea58e7e3e7489ffe4bda6eacd540a17de9f9cd21cc37e297b2dd9fe52b2715a5841afaec82900750d810d01d7edb4b2d456427f449b92b417579763 - languageName: node - linkType: hard - "byte-size@npm:7.0.0": version: 7.0.0 resolution: "byte-size@npm:7.0.0" @@ -16381,20 +16342,6 @@ __metadata: languageName: node linkType: hard -"fs-capacitor@npm:^6.2.0": - version: 6.2.0 - resolution: "fs-capacitor@npm:6.2.0" - checksum: a567b27ea93052cd926b7e218e644da7426bd245c43c1b61e3dcf382242be68d28cd193a859170ad5f87599aa037c7f5cca3e70587af9b2689ebd8afb06e4303 - languageName: node - linkType: hard - -"fs-capacitor@npm:^8.0.0": - version: 8.0.0 - resolution: "fs-capacitor@npm:8.0.0" - checksum: 836d3d662f2d057ce3697bb99feb0fa2eefbf953fef0a57977e609cc9b605b65f03bf7066ec943790a3dccf046c3b6a7630e41a4b7d60859ec618bbc20063597 - languageName: node - linkType: hard - "fs-constants@npm:^1.0.0": version: 1.0.0 resolution: "fs-constants@npm:1.0.0" @@ -17240,37 +17187,6 @@ __metadata: languageName: node linkType: hard -"graphql-upload@npm:^15.0.0": - version: 15.0.2 - resolution: "graphql-upload@npm:15.0.2" - dependencies: - "@types/busboy": "npm:^1.5.0" - "@types/node": "npm:*" - "@types/object-path": "npm:^0.11.1" - busboy: "npm:^1.6.0" - fs-capacitor: "npm:^6.2.0" - http-errors: "npm:^2.0.0" - object-path: "npm:^0.11.8" - peerDependencies: - "@types/express": ^4.0.29 - "@types/koa": ^2.11.4 - graphql: ^16.3.0 - peerDependenciesMeta: - "@types/express": - optional: true - "@types/koa": - optional: true - checksum: bf0a7f92842882ed982a625eaf0d8c2fa36f32096d75c80b89989f17cb10e8193a033f69192d457555974f187e2e8f4eb4bf3df94a86b86c19493f9bcc7849ef - languageName: node - linkType: hard - -"graphql@npm:0.13.1 - 16, graphql@npm:^16.8.1": - version: 16.8.1 - resolution: "graphql@npm:16.8.1" - checksum: 7a09d3ec5f75061afe2bd2421a2d53cf37273d2ecaad8f34febea1f1ac205dfec2834aec3419fa0a10fcc9fb345863b2f893562fb07ea825da2ae82f6392893c - languageName: node - linkType: hard - "graphql@npm:^14.5.3": version: 14.7.0 resolution: "graphql@npm:14.7.0" @@ -17287,6 +17203,13 @@ __metadata: languageName: node linkType: hard +"graphql@npm:^16.8.1": + version: 16.8.1 + resolution: "graphql@npm:16.8.1" + checksum: 7a09d3ec5f75061afe2bd2421a2d53cf37273d2ecaad8f34febea1f1ac205dfec2834aec3419fa0a10fcc9fb345863b2f893562fb07ea825da2ae82f6392893c + languageName: node + linkType: hard + "gzip-size@npm:^6.0.0": version: 6.0.0 resolution: "gzip-size@npm:6.0.0" @@ -17702,7 +17625,7 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:2.0.0, http-errors@npm:^2.0.0": +"http-errors@npm:2.0.0": version: 2.0.0 resolution: "http-errors@npm:2.0.0" dependencies: @@ -22760,13 +22683,6 @@ __metadata: languageName: node linkType: hard -"object-path@npm:^0.11.8": - version: 0.11.8 - resolution: "object-path@npm:0.11.8" - checksum: cbc41515ff97aa7515bd93a3d93d5b7307c95413345d83c66c60b7618429cfc935ff4049192c96701eeeb33a78678b15ee97b5fe0857e9eca4fcd7507dfafd36 - languageName: node - linkType: hard - "object-visit@npm:^1.0.0": version: 1.0.1 resolution: "object-visit@npm:1.0.1" @@ -26823,13 +26739,6 @@ __metadata: languageName: node linkType: hard -"streamsearch@npm:^1.1.0": - version: 1.1.0 - resolution: "streamsearch@npm:1.1.0" - checksum: 612c2b2a7dbcc859f74597112f80a42cbe4d448d03da790d5b7b39673c1197dd3789e91cd67210353e58857395d32c1e955a9041c4e6d5bae723436b3ed9ed14 - languageName: node - linkType: hard - "streamx@npm:^2.15.0": version: 2.15.1 resolution: "streamx@npm:2.15.1"