mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +00:00
Merge branch 'main' into STRAP-54
This commit is contained in:
commit
d3c8267cf2
10
README.md
10
README.md
@ -91,10 +91,12 @@ Complete installation requirements can be found in the documentation under <a hr
|
||||
|
||||
**Database:**
|
||||
|
||||
- MySQL >= 5.7.8
|
||||
- MariaDB >= 10.2.7
|
||||
- PostgreSQL >= 10
|
||||
- SQLite >= 3
|
||||
| Database | Minimum | Recommended |
|
||||
| ---------- | ------- | ----------- |
|
||||
| MySQL | 5.7.8 | 8.0 |
|
||||
| MariaDB | 10.3 | 10.6 |
|
||||
| PostgreSQL | 11.0 | 14.0 |
|
||||
| SQLite | 3 | 3 |
|
||||
|
||||
**We recommend always using the latest version of Strapi to start your new projects**.
|
||||
|
||||
|
@ -759,7 +759,7 @@
|
||||
"global.table.header.roles": "Roles",
|
||||
"global.table.header.username": "Nombre de usuario",
|
||||
"global.type": "Tipo",
|
||||
"global.users": "Useuarios",
|
||||
"global.users": "Usuarios",
|
||||
"notification.warning.404": "404 - No Encontrado"
|
||||
|
||||
}
|
||||
|
@ -776,7 +776,6 @@ const createEntityManager = (db) => {
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: support multiple relations at once with the populate syntax
|
||||
// TODO: add lifecycle events
|
||||
async populate(uid, entity, populate) {
|
||||
const entry = await this.findOne(uid, {
|
||||
@ -788,30 +787,37 @@ const createEntityManager = (db) => {
|
||||
return { ...entity, ...entry };
|
||||
},
|
||||
|
||||
// TODO: support multiple relations at once with the populate syntax
|
||||
// TODO: add lifecycle events
|
||||
async load(uid, entity, field, params) {
|
||||
async load(uid, entity, fields, params) {
|
||||
const { attributes } = db.metadata.get(uid);
|
||||
|
||||
const attribute = attributes[field];
|
||||
const fieldsArr = _.castArray(fields);
|
||||
fieldsArr.forEach((field) => {
|
||||
const attribute = attributes[field];
|
||||
|
||||
if (!attribute || attribute.type !== 'relation') {
|
||||
throw new Error('Invalid load. Expected a relational attribute');
|
||||
}
|
||||
if (!attribute || attribute.type !== 'relation') {
|
||||
throw new Error(`Invalid load. Expected ${field} to be a relational attribute`);
|
||||
}
|
||||
});
|
||||
|
||||
const entry = await this.findOne(uid, {
|
||||
select: ['id'],
|
||||
where: { id: entity.id },
|
||||
populate: {
|
||||
[field]: params || true,
|
||||
},
|
||||
populate: fieldsArr.reduce((acc, field) => {
|
||||
acc[field] = params || true;
|
||||
return acc;
|
||||
}, {}),
|
||||
});
|
||||
|
||||
if (!entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return entry[field];
|
||||
if (Array.isArray(fields)) {
|
||||
return _.pick(fields, entry);
|
||||
}
|
||||
|
||||
return entry[fields];
|
||||
},
|
||||
|
||||
// cascading
|
||||
|
@ -1,8 +1,12 @@
|
||||
<p align="center">
|
||||
<a href="https://strapi.io">
|
||||
<a href="https://strapi.io/#gh-light-mode-only">
|
||||
<img src="https://strapi.io/assets/strapi-logo-dark.svg" width="318px" alt="Strapi logo" />
|
||||
</a>
|
||||
<a href="https://strapi.io/#gh-dark-mode-only">
|
||||
<img src="https://strapi.io/assets/strapi-logo-light.svg" width="318px" alt="Strapi logo" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h3 align="center">API creation made simple, secure and fast.</h3>
|
||||
<p align="center">The most advanced open-source headless CMS to build powerful APIs with no effort.</p>
|
||||
<p align="center"><a href="https://strapi.io/demo">Try live demo</a></p>
|
||||
@ -18,6 +22,9 @@
|
||||
<a href="https://discord.strapi.io">
|
||||
<img src="https://img.shields.io/discord/811989166782021633?label=Discord" alt="Strapi on Discord" />
|
||||
</a>
|
||||
<a href="https://github.com/strapi/strapi/actions/workflows/nightly.yml">
|
||||
<img src="https://github.com/strapi/strapi/actions/workflows/nightly.yml/badge.svg" alt="Strapi Nightly Release Build Status" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
@ -79,15 +86,17 @@ Complete installation requirements can be found in the documentation under <a hr
|
||||
|
||||
**Node:**
|
||||
|
||||
- NodeJS >= 12 <= 16
|
||||
- NodeJS >= 14 <= 16
|
||||
- NPM >= 6.x
|
||||
|
||||
**Database:**
|
||||
|
||||
- MySQL >= 5.7.8
|
||||
- MariaDB >= 10.2.7
|
||||
- PostgreSQL >= 10
|
||||
- SQLite >= 3
|
||||
| Database | Minimum | Recommended |
|
||||
| ---------- | ------- | ----------- |
|
||||
| MySQL | 5.7.8 | 8.0 |
|
||||
| MariaDB | 10.3 | 10.6 |
|
||||
| PostgreSQL | 11.0 | 14.0 |
|
||||
| SQLite | 3 | 3 |
|
||||
|
||||
**We recommend always using the latest version of Strapi to start your new projects**.
|
||||
|
||||
@ -114,7 +123,7 @@ For general help using Strapi, please refer to [the official Strapi documentatio
|
||||
- [Discord](https://discord.strapi.io) (For live discussion with the Community and Strapi team)
|
||||
- [GitHub](https://github.com/strapi/strapi) (Bug reports, Contributions)
|
||||
- [Community Forum](https://forum.strapi.io) (Questions and Discussions)
|
||||
- [Roadmap & Feature Requests](https://feedback.strapi.io/)
|
||||
- [Feedback section](https://feedback.strapi.io) (Roadmap, Feature requests)
|
||||
- [Twitter](https://twitter.com/strapijs) (Get the news fast)
|
||||
- [Facebook](https://www.facebook.com/Strapi-616063331867161)
|
||||
- [YouTube Channel](https://www.youtube.com/strapi) (Learn from Video Tutorials)
|
||||
@ -125,7 +134,7 @@ Follow our [migration guides](https://docs.strapi.io/developer-docs/latest/updat
|
||||
|
||||
## Roadmap
|
||||
|
||||
Check out our [roadmap](https://feedback.strapi.io/) to get informed of the latest features released and the upcoming ones. You may also give us insights and vote for a specific feature.
|
||||
Check out our [roadmap](https://feedback.strapi.io) to get informed of the latest features released and the upcoming ones. You may also give us insights and vote for a specific feature.
|
||||
|
||||
## Documentation
|
||||
|
||||
|
@ -5,6 +5,7 @@ const { has, prop, omit, toString } = require('lodash/fp');
|
||||
|
||||
const { contentTypes: contentTypesUtils } = require('@strapi/utils');
|
||||
const { ApplicationError } = require('@strapi/utils').errors;
|
||||
const { getComponentAttributes } = require('@strapi/utils').contentTypes;
|
||||
|
||||
const omitComponentData = (contentType, data) => {
|
||||
const { attributes } = contentType;
|
||||
@ -100,6 +101,18 @@ const createComponents = async (uid, data) => {
|
||||
return componentBody;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {str} uid
|
||||
* @param {object} entity
|
||||
* @return {Promise<{uid: string, entity: object}>}
|
||||
*/
|
||||
const getComponents = async (uid, entity) => {
|
||||
const componentAttributes = getComponentAttributes(strapi.getModel(uid));
|
||||
|
||||
if (_.isEmpty(componentAttributes)) return {};
|
||||
return strapi.query(uid).load(entity, componentAttributes);
|
||||
};
|
||||
|
||||
/*
|
||||
delete old components
|
||||
create or update
|
||||
@ -270,7 +283,10 @@ const deleteComponents = async (uid, entityToDelete) => {
|
||||
if (attribute.type === 'component') {
|
||||
const { component: componentUID } = attribute;
|
||||
|
||||
const value = await strapi.query(uid).load(entityToDelete, attributeName);
|
||||
// Load attribute value if it's not already loaded
|
||||
const value =
|
||||
entityToDelete[attributeName] ||
|
||||
(await strapi.query(uid).load(entityToDelete, attributeName));
|
||||
|
||||
if (!value) {
|
||||
continue;
|
||||
@ -286,7 +302,9 @@ const deleteComponents = async (uid, entityToDelete) => {
|
||||
}
|
||||
|
||||
if (attribute.type === 'dynamiczone') {
|
||||
const value = await strapi.query(uid).load(entityToDelete, attributeName);
|
||||
const value =
|
||||
entityToDelete[attributeName] ||
|
||||
(await strapi.query(uid).load(entityToDelete, attributeName));
|
||||
|
||||
if (!value) {
|
||||
continue;
|
||||
@ -352,7 +370,9 @@ const deleteComponent = async (uid, componentToDelete) => {
|
||||
|
||||
module.exports = {
|
||||
omitComponentData,
|
||||
getComponents,
|
||||
createComponents,
|
||||
updateComponents,
|
||||
deleteComponents,
|
||||
deleteComponent,
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ const uploadFiles = require('../utils/upload-files');
|
||||
|
||||
const {
|
||||
omitComponentData,
|
||||
getComponents,
|
||||
createComponents,
|
||||
updateComponents,
|
||||
deleteComponents,
|
||||
@ -213,8 +214,10 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
||||
return null;
|
||||
}
|
||||
|
||||
const componentsToDelete = await getComponents(uid, entityToDelete);
|
||||
|
||||
await db.query(uid).delete({ where: { id: entityToDelete.id } });
|
||||
await deleteComponents(uid, entityToDelete);
|
||||
await deleteComponents(uid, { ...entityToDelete, ...componentsToDelete });
|
||||
|
||||
await this.emitEvent(uid, ENTRY_DELETE, entityToDelete);
|
||||
|
||||
@ -234,8 +237,12 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
||||
return null;
|
||||
}
|
||||
|
||||
const componentsToDelete = await Promise.all(
|
||||
entitiesToDelete.map((entityToDelete) => getComponents(uid, entityToDelete))
|
||||
);
|
||||
|
||||
const deletedEntities = await db.query(uid).deleteMany(query);
|
||||
await Promise.all(entitiesToDelete.map((entity) => deleteComponents(uid, entity)));
|
||||
await Promise.all(componentsToDelete.map((compos) => deleteComponents(uid, compos)));
|
||||
|
||||
// Trigger webhooks. One for each entity
|
||||
await Promise.all(entitiesToDelete.map((entity) => this.emitEvent(uid, ENTRY_DELETE, entity)));
|
||||
|
@ -158,6 +158,15 @@ describe('Core API - Basic + compo + draftAndPublish', () => {
|
||||
data.productsWithCompoAndDP.shift();
|
||||
});
|
||||
|
||||
describe('database state', () => {
|
||||
test('components have been removed from the database', async () => {
|
||||
const dbComponents = await strapi.db
|
||||
.query('default.compo')
|
||||
.findMany({ name: 'compo name updated' });
|
||||
expect(dbComponents).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validation', () => {
|
||||
test('Cannot create product with compo - compo required', async () => {
|
||||
const product = {
|
||||
|
@ -106,6 +106,20 @@ const isPrivateAttribute = (model = {}, attributeName) => {
|
||||
const isScalarAttribute = (attribute) => {
|
||||
return !['media', 'component', 'relation', 'dynamiczone'].includes(attribute.type);
|
||||
};
|
||||
const isMediaAttribute = (attribute) => attribute.type === 'media';
|
||||
const isRelationalAttribute = (attribute) => attribute.type === 'relation';
|
||||
const isComponentAttribute = (attribute) => ['component', 'dynamiczone'].includes(attribute.type);
|
||||
|
||||
const getComponentAttributes = (schema) => {
|
||||
return _.reduce(
|
||||
schema.attributes,
|
||||
(acc, attr, attrName) => {
|
||||
if (isComponentAttribute(attr)) acc.push(attrName);
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
};
|
||||
|
||||
const getScalarAttributes = (schema) => {
|
||||
return _.reduce(
|
||||
@ -118,10 +132,6 @@ const getScalarAttributes = (schema) => {
|
||||
);
|
||||
};
|
||||
|
||||
const isMediaAttribute = (attribute) => attribute.type === 'media';
|
||||
const isRelationalAttribute = (attribute) => attribute.type === 'relation';
|
||||
const isComponentAttribute = (attribute) => ['component', 'dynamiczone'].includes(attribute.type);
|
||||
|
||||
/**
|
||||
* Checks if an attribute is of type `type`
|
||||
* @param {object} attribute
|
||||
@ -152,6 +162,7 @@ module.exports = {
|
||||
isPrivateAttribute,
|
||||
constants,
|
||||
getNonWritableAttributes,
|
||||
getComponentAttributes,
|
||||
getScalarAttributes,
|
||||
getWritableAttributes,
|
||||
isWritableAttribute,
|
||||
|
@ -102,6 +102,13 @@ paths:
|
||||
tags:
|
||||
- Users-Permissions - Auth
|
||||
summary: Default Callback from provider auth
|
||||
parameters:
|
||||
- name: provider
|
||||
in: path
|
||||
required: true
|
||||
description: Provider name
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Returns a jwt token and user info
|
||||
@ -196,15 +203,16 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- password
|
||||
- currentPassword
|
||||
- passwordConfirmation
|
||||
properties:
|
||||
password:
|
||||
required: true
|
||||
type: string
|
||||
currentPassword:
|
||||
required: true
|
||||
type: string
|
||||
passwordConfirmation:
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
@ -219,7 +227,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
/auth/email-confirmation:
|
||||
get:
|
||||
tags:
|
||||
@ -228,7 +235,8 @@ paths:
|
||||
parameters:
|
||||
- in: query
|
||||
name: confirmation
|
||||
type: string
|
||||
schema:
|
||||
type: string
|
||||
description: confirmation token received by email
|
||||
responses:
|
||||
301:
|
||||
@ -319,7 +327,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
/users-permissions/roles:
|
||||
get:
|
||||
tags:
|
||||
@ -364,7 +371,7 @@ paths:
|
||||
- Users-Permissions - Users & Roles
|
||||
summary: Create a role
|
||||
requestBody:
|
||||
$ref: '#/components/schemas/Users-Permissions-RoleRequest'
|
||||
$ref: '#/components/requestBodies/Users-Permissions-RoleRequest'
|
||||
responses:
|
||||
200:
|
||||
description: Returns ok if the role was create
|
||||
@ -391,10 +398,13 @@ paths:
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
type: string
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: role Id
|
||||
responses:
|
||||
200:
|
||||
description: Returns the role
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -431,10 +441,12 @@ paths:
|
||||
parameters:
|
||||
- in: path
|
||||
name: role
|
||||
type: string
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: role Id
|
||||
requestBody:
|
||||
$ref: '#/components/schemas/Users-Permissions-RoleRequest'
|
||||
$ref: '#/components/requestBodies/Users-Permissions-RoleRequest'
|
||||
responses:
|
||||
200:
|
||||
description: Returns ok if the role was udpated
|
||||
@ -460,7 +472,9 @@ paths:
|
||||
parameters:
|
||||
- in: path
|
||||
name: role
|
||||
type: string
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: role Id
|
||||
responses:
|
||||
200:
|
||||
@ -487,7 +501,7 @@ paths:
|
||||
summary: Get list of users
|
||||
responses:
|
||||
200:
|
||||
summary: Returns an array of users
|
||||
description: Returns an array of users
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -520,17 +534,17 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- email
|
||||
- password
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
required: true
|
||||
username:
|
||||
type: string
|
||||
required: true
|
||||
password:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
example:
|
||||
username: foo
|
||||
email: foo@strapi.io
|
||||
@ -569,7 +583,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
/users/{id}:
|
||||
get:
|
||||
tags:
|
||||
@ -578,10 +591,13 @@ paths:
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
type: string
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: user Id
|
||||
responses:
|
||||
200:
|
||||
description: Returns a user
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -601,7 +617,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- Users-Permissions - Users & Roles
|
||||
@ -609,7 +624,9 @@ paths:
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
type: string
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: user Id
|
||||
requestBody:
|
||||
required: true
|
||||
@ -617,17 +634,17 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- email
|
||||
- password
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
required: true
|
||||
username:
|
||||
type: string
|
||||
required: true
|
||||
password:
|
||||
type: string
|
||||
required: true
|
||||
|
||||
example:
|
||||
username: foo
|
||||
email: foo@strapi.io
|
||||
@ -666,13 +683,19 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Users-Permissions - Users & Roles
|
||||
summary: Delete a user
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: user Id
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
description: Returns deleted user info
|
||||
content:
|
||||
application/json:
|
||||
@ -817,6 +840,10 @@ components:
|
||||
policy:
|
||||
type: string
|
||||
|
||||
parameters:
|
||||
responses:
|
||||
examples:
|
||||
requestBodies:
|
||||
Users-Permissions-RoleRequest:
|
||||
required: true
|
||||
content:
|
||||
@ -842,7 +869,3 @@ components:
|
||||
find:
|
||||
enabled: true
|
||||
|
||||
parameters:
|
||||
responses:
|
||||
examples:
|
||||
requestBodies:
|
||||
|
@ -37,7 +37,7 @@
|
||||
"test": "echo \"no tests yet\""
|
||||
},
|
||||
"dependencies": {
|
||||
"aws-sdk": "2.1188.0",
|
||||
"aws-sdk": "2.1208.0",
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -7493,10 +7493,10 @@ available-typed-arrays@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
|
||||
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
|
||||
|
||||
aws-sdk@2.1188.0:
|
||||
version "2.1188.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1188.0.tgz#94b710948ef2924093a8d6fe42443a792385afa2"
|
||||
integrity sha512-4KXwjRjbCzU1luTOeH+ded92H51I4UuHaZzx2EI+JA0II1+q48heTxFlFd7yp7jGz9UwjPb6k12Jv1W3r0JWxA==
|
||||
aws-sdk@2.1208.0:
|
||||
version "2.1208.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1208.0.tgz#7dc8c877652d2b1ea126a3c256157c1cbd2e20e2"
|
||||
integrity sha512-Wyq9TJyvRZMcHmcGwmOJag5/94m+Gq3BHcK2klwFvgUf1OWWJc4OYqmi90d7qJ09ydTeGGMeodNJildQdkOrYQ==
|
||||
dependencies:
|
||||
buffer "4.9.2"
|
||||
events "1.1.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user