mirror of
https://github.com/strapi/strapi.git
synced 2025-09-27 09:25:46 +00:00
Merge branch 'master' into njb/fix-strapi-new
This commit is contained in:
commit
a739f67a17
@ -92,7 +92,7 @@ The controllers are defined in each `./api/**/controllers/` folders. Every JavaS
|
|||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
|
|
||||||
Filters are a handy way to request data according to generic parameters. It makes filtering, sorting and paginating easy and reusable (eg. `GET /user?_limit=30&name=John`).
|
Filters are a handy way to request data according to generic parameters. It makes filtering, sorting and paginating easy and reusable (eg. `GET /users?_limit=30&name=John`).
|
||||||
|
|
||||||
> Please refer to the [filters' guide](../guides/filters.md) for more informations.
|
> Please refer to the [filters' guide](../guides/filters.md) for more informations.
|
||||||
|
|
||||||
|
@ -137,16 +137,16 @@ In order to do so, you'll need to allow access to other users (identified as 'Gu
|
|||||||
|
|
||||||
### List entries (GET)
|
### List entries (GET)
|
||||||
|
|
||||||
To retrieve the list of products, use the `GET /your-content-type` route.
|
To retrieve the list of products, use the `GET /products` route.
|
||||||
|
|
||||||
Generated APIs provide a handy way to filter and order queries. In that way, ordering products by price is as easy as `GET http://localhost:1337/product?_sort=price:asc`. For more informations, read the [filters documentation](../guides/filters.md)
|
Generated APIs provide a handy way to filter and order queries. In that way, ordering products by price is as easy as `GET http://localhost:1337/products?_sort=price:asc`. For more informations, read the [filters documentation](../guides/filters.md)
|
||||||
|
|
||||||
Here is an example using jQuery.
|
Here is an example using jQuery.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: 'http://localhost:1337/product?_sort=price:asc', // Order by price.
|
url: 'http://localhost:1337/products?_sort=price:asc', // Order by price.
|
||||||
done: function(products) {
|
done: function(products) {
|
||||||
console.log('Well done, here is the list of products: ', products);
|
console.log('Well done, here is the list of products: ', products);
|
||||||
},
|
},
|
||||||
@ -163,7 +163,7 @@ If you want to get a specific entry, add the `id` of the wanted product at the e
|
|||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: 'http://localhost:1337/product/123', // Where `123` is the `id` of the product.
|
url: 'http://localhost:1337/products/123', // Where `123` is the `id` of the product.
|
||||||
done: function(product) {
|
done: function(product) {
|
||||||
console.log('Well done, here is the product having the `id` 123: ', product);
|
console.log('Well done, here is the product having the `id` 123: ', product);
|
||||||
},
|
},
|
||||||
@ -182,7 +182,7 @@ jQuery example:
|
|||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: 'http://localhost:1337/product',
|
url: 'http://localhost:1337/products',
|
||||||
data: {
|
data: {
|
||||||
name: 'Cheese cake',
|
name: 'Cheese cake',
|
||||||
description: 'Chocolate cheese cake with ice cream',
|
description: 'Chocolate cheese cake with ice cream',
|
||||||
@ -206,7 +206,7 @@ jQuery example:
|
|||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'PUT',
|
type: 'PUT',
|
||||||
url: 'http://localhost:1337/product/123', // Where `123` is the `id` of the product.
|
url: 'http://localhost:1337/products/123', // Where `123` is the `id` of the product.
|
||||||
data: {
|
data: {
|
||||||
description: 'This is the new description'
|
description: 'This is the new description'
|
||||||
},
|
},
|
||||||
@ -228,7 +228,7 @@ jQuery example:
|
|||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'DELETE',
|
type: 'DELETE',
|
||||||
url: 'http://localhost:1337/product/123', // Where `123` is the `id` of the product.
|
url: 'http://localhost:1337/products/123', // Where `123` is the `id` of the product.
|
||||||
done: function(product) {
|
done: function(product) {
|
||||||
console.log('Congrats, your product has been successfully deleted: ', product);
|
console.log('Congrats, your product has been successfully deleted: ', product);
|
||||||
},
|
},
|
||||||
|
@ -97,7 +97,7 @@ By default, each API request is identified as `guest` role (see permissions of `
|
|||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: 'http://localhost:1337/article',
|
url: 'http://localhost:1337/articles',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`
|
Authorization: `Bearer ${token}`
|
||||||
},
|
},
|
||||||
@ -117,7 +117,8 @@ This action sends an email to a user with the link of you reset password page. T
|
|||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
- `email` is your user email.
|
- `email` is your user email.
|
||||||
- `url` is the url link that user will receive.
|
- `url` is the url link that user will receive. After the user triggers a new password reset,
|
||||||
|
it is used to redirect the user to the new-password form.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -125,7 +126,7 @@ $.ajax({
|
|||||||
url: 'http://localhost:1337/auth/forgot-password',
|
url: 'http://localhost:1337/auth/forgot-password',
|
||||||
data: {
|
data: {
|
||||||
email: 'user@strapi.io',
|
email: 'user@strapi.io',
|
||||||
url: 'http://mon-site.com/rest-password'
|
url: 'http:/localhost:1337/admin/plugins/users-permissions/auth/reset-password'
|
||||||
},
|
},
|
||||||
done: function() {
|
done: function() {
|
||||||
console.log('Your user received an email');
|
console.log('Your user received an email');
|
||||||
@ -136,8 +137,6 @@ $.ajax({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
> Received link url format http://mon-site.com/rest-password?code=privateCode
|
|
||||||
|
|
||||||
## Reset user password.
|
## Reset user password.
|
||||||
|
|
||||||
This action will reset the user password.
|
This action will reset the user password.
|
||||||
@ -165,7 +164,7 @@ $.ajax({
|
|||||||
```
|
```
|
||||||
|
|
||||||
## User Object In Strapi Context
|
## User Object In Strapi Context
|
||||||
The User object is available to successfully authenticated requests.
|
The `user` object is available to successfully authenticated requests.
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
- The authenticated `user` object is a property of `ctx.state`.
|
- The authenticated `user` object is a property of `ctx.state`.
|
||||||
@ -189,10 +188,9 @@ The User object is available to successfully authenticated requests.
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Add a new provider
|
## Add a new provider
|
||||||
|
|
||||||
To add a new provider on strapi, you will need to perform changes onto the following files:
|
To add a new provider on Strapi, you will need to perform changes onto the following files:
|
||||||
|
|
||||||
```
|
```
|
||||||
packages/strapi-plugin-users-permissions/services/Providers.js
|
packages/strapi-plugin-users-permissions/services/Providers.js
|
||||||
@ -203,7 +201,7 @@ packages/strapi-plugin-users-permissions/admin/src/translations/en.json
|
|||||||
|
|
||||||
We will go step by step.
|
We will go step by step.
|
||||||
|
|
||||||
### Configure your Provider request
|
### Configure your Provider Request
|
||||||
First, we need to configure our new provider onto `Provider.js` file.
|
First, we need to configure our new provider onto `Provider.js` file.
|
||||||
|
|
||||||
Jump onto the `getProfile` function, you will see the list of currently available providers in the form of a `switch...case`.
|
Jump onto the `getProfile` function, you will see the list of currently available providers in the form of a `switch...case`.
|
||||||
@ -212,9 +210,10 @@ As you can see, `getProfile` take three params:
|
|||||||
|
|
||||||
1. provider :: The name of the used provider as a string.
|
1. provider :: The name of the used provider as a string.
|
||||||
2. query :: The query is the result of the provider callback.
|
2. query :: The query is the result of the provider callback.
|
||||||
3. callback :: The callback function who will continue the internal strapi login logic.
|
3. callback :: The callback function who will continue the internal Strapi login logic.
|
||||||
|
|
||||||
Let's take the `discord` one as an example since it's not the easier, it should cover most of the case you may encounter trying to implement your own provider.
|
Let's take the `discord` one as an example since it's not the easier, it should cover most of the case you
|
||||||
|
may encounter trying to implement your own provider.
|
||||||
|
|
||||||
#### Configure your oauth generic information
|
#### Configure your oauth generic information
|
||||||
|
|
||||||
@ -239,9 +238,11 @@ Let's take the `discord` one as an example since it's not the easier, it should
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
So here, you can see that we use a module called `Purest`. This module gives us with a generic way to interact with the REST API.
|
So here, you can see that we use a module called `Purest`. This module gives us with a generic way to interact
|
||||||
|
with the REST API.
|
||||||
|
|
||||||
To understand each value usage, and the templating syntax, I invite you to read the [Official Purest Documentation](https://github.com/simov/purest/tree/2.x)
|
To understand each value usage, and the templating syntax, I invite you to read the [Official Purest Documentation](https://github.com/simov/purest/tree/2.x)
|
||||||
|
|
||||||
@ -265,17 +266,21 @@ You may also want to take a look onto the numerous already made configurations [
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here is the next part of our switch. Now that we have properly configured our provider, we want to use it to retrieve user information.
|
Here is the next part of our switch. Now that we have properly configured our provider, we want to use it to retrieve
|
||||||
|
user information.
|
||||||
|
|
||||||
Here you see the real power of `purest`, you can simply make a get request on the desired URL, using the `access_token` from the `query` parameter to authenticate.
|
Here you see the real power of `purest`, you can simply make a get request on the desired URL, using the `access_token`
|
||||||
|
from the `query` parameter to authenticate.
|
||||||
|
|
||||||
That way, you should be able to retrieve the user info you need.
|
That way, you should be able to retrieve the user info you need.
|
||||||
|
|
||||||
Now, you can simply call the `callback` function with the username and email of your user. That way, strapi will be able to retrieve your user from the database and log you in.
|
Now, you can simply call the `callback` function with the username and email of your user. That way, strapi will be able
|
||||||
|
to retrieve your user from the database and log you in.
|
||||||
|
|
||||||
#### Configure the new provider model onto database
|
#### Configure the new provider model onto database
|
||||||
|
|
||||||
Now, we need to configure our 'model' for our new provider. That way, our settings can be stored in the database, and managed from the admin panel.
|
Now, we need to configure our 'model' for our new provider. That way, our settings can be stored in the database, and
|
||||||
|
managed from the admin panel.
|
||||||
|
|
||||||
Into: `packages/strapi-plugin-users-permissions/config/functions/bootstrap.js`
|
Into: `packages/strapi-plugin-users-permissions/config/functions/bootstrap.js`
|
||||||
|
|
||||||
@ -296,9 +301,8 @@ For our discord provider it will look like:
|
|||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You have already done the hard part, now, we simply need to make our new provider available from the front
|
||||||
You have already done the hard part, now, we simply need to make our new provider available from the front side of our application. So let's do it!
|
side of our application. So let's do it!
|
||||||
|
|
||||||
|
|
||||||
<!-- #### Tests -->
|
<!-- #### Tests -->
|
||||||
<!-- TODO Add documentation about how to configure unit test for the new provider -->
|
<!-- TODO Add documentation about how to configure unit test for the new provider -->
|
||||||
@ -323,7 +327,6 @@ These two change will set up the popup message who appear on the UI when we will
|
|||||||
|
|
||||||
That's it, now you should be able to use your new provider.
|
That's it, now you should be able to use your new provider.
|
||||||
|
|
||||||
|
|
||||||
## Email templates
|
## Email templates
|
||||||
|
|
||||||
[See the documentation on GitHub](https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/docs/email-templates.md)
|
[See the documentation on GitHub](https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/docs/email-templates.md)
|
||||||
|
@ -29,11 +29,11 @@ Easily filter results according to fields values.
|
|||||||
|
|
||||||
Find users having `John` as first name.
|
Find users having `John` as first name.
|
||||||
|
|
||||||
`GET /user?firstName=John`
|
`GET /users?firstName=John`
|
||||||
|
|
||||||
Find products having a price equal or greater than `3`.
|
Find products having a price equal or greater than `3`.
|
||||||
|
|
||||||
`GET /product?price_gte=3`
|
`GET /products?price_gte=3`
|
||||||
|
|
||||||
### Sort
|
### Sort
|
||||||
|
|
||||||
@ -43,8 +43,8 @@ Sort according to a specific field.
|
|||||||
|
|
||||||
Sort users by email.
|
Sort users by email.
|
||||||
|
|
||||||
- ASC: `GET /user?_sort=email:asc`
|
- ASC: `GET /users?_sort=email:asc`
|
||||||
- DESC: `GET /user?_sort=email:desc`
|
- DESC: `GET /users?_sort=email:desc`
|
||||||
|
|
||||||
### Limit
|
### Limit
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ Limit the size of the returned results.
|
|||||||
|
|
||||||
Limit the result length to 30.
|
Limit the result length to 30.
|
||||||
|
|
||||||
`GET /user?_limit=30`
|
`GET /users?_limit=30`
|
||||||
|
|
||||||
### Start
|
### Start
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ Skip a specific number of entries (especially useful for pagination).
|
|||||||
|
|
||||||
Get the second page of results.
|
Get the second page of results.
|
||||||
|
|
||||||
`GET /user?_start=10&_limit=10`
|
`GET /users?_start=10&_limit=10`
|
||||||
|
|
||||||
## Programmatic usage
|
## Programmatic usage
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ The global policies can be associated to any routes in your project.
|
|||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/car",
|
"path": "/cars",
|
||||||
"handler": "Car.find",
|
"handler": "Car.find",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [
|
"policies": [
|
||||||
@ -66,7 +66,7 @@ Plugins can add and expose policies into your app. For example, the plugin `Auth
|
|||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/car",
|
"path": "/cars",
|
||||||
"handler": "Car.find",
|
"handler": "Car.find",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [
|
"policies": [
|
||||||
@ -102,7 +102,7 @@ module.exports = async (ctx, next) => {
|
|||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/car",
|
"path": "/cars",
|
||||||
"handler": "Car.find",
|
"handler": "Car.find",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [
|
"policies": [
|
||||||
|
@ -12,17 +12,17 @@ You have to edit the `routes.json` file in one of your APIs folders (`./api/**/c
|
|||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/product",
|
"path": "/products",
|
||||||
"handler": "Product.find",
|
"handler": "Product.find",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": ["POST", "PUT"],
|
"method": ["POST", "PUT"],
|
||||||
"path": "/product/:id",
|
"path": "/products/:id",
|
||||||
"handler": "Product.createOrUpdate",
|
"handler": "Product.createOrUpdate",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/product/:id/buy",
|
"path": "/products/:id/buy",
|
||||||
"handler": "Product.buy",
|
"handler": "Product.buy",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": ["isAuthenticated", "hasCreditCard"]
|
"policies": ["isAuthenticated", "hasCreditCard"]
|
||||||
@ -33,7 +33,7 @@ You have to edit the `routes.json` file in one of your APIs folders (`./api/**/c
|
|||||||
```
|
```
|
||||||
|
|
||||||
- `method` (string): Method or array of methods to hit the route (ex: `GET`, `POST`, `PUT`, `HEAD`, `DELETE`, `PATCH`)
|
- `method` (string): Method or array of methods to hit the route (ex: `GET`, `POST`, `PUT`, `HEAD`, `DELETE`, `PATCH`)
|
||||||
- `path` (string): URL starting with `/` (ex: `/product`)
|
- `path` (string): URL starting with `/` (ex: `/products`)
|
||||||
- `handler` (string): Action to executed when the route is hit following this syntax `<Controller>.<action>`
|
- `handler` (string): Action to executed when the route is hit following this syntax `<Controller>.<action>`
|
||||||
- `config`
|
- `config`
|
||||||
- `policies` (array): Array of policies names or path ([see more](../guides/policies.md))
|
- `policies` (array): Array of policies names or path ([see more](../guides/policies.md))
|
||||||
@ -48,12 +48,12 @@ The router used by Strapi allows you to create dynamic routes where you can use
|
|||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/product/:category/:id",
|
"path": "/products/:category/:id",
|
||||||
"handler": "Product.findOneByCategory",
|
"handler": "Product.findOneByCategory",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/product/:region(\\d{2}|\\d{3})/:id", // Only match when the first parameter contains 2 or 3 digits.
|
"path": "/products/:region(\\d{2}|\\d{3})/:id", // Only match when the first parameter contains 2 or 3 digits.
|
||||||
"handler": "Product.findOneByRegion",
|
"handler": "Product.findOneByRegion",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -21,42 +21,42 @@ module.exports = scope => {
|
|||||||
const routes = {
|
const routes = {
|
||||||
routes: [{
|
routes: [{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/' + scope.humanizeId,
|
path: '/' + scope.idPluralized,
|
||||||
handler: scope.globalID + '.find',
|
handler: scope.globalID + '.find',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/' + scope.humanizeId + '/count',
|
path: '/' + scope.idPluralized + '/count',
|
||||||
handler: scope.globalID + '.count',
|
handler: scope.globalID + '.count',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/' + scope.humanizeId + '/:' + tokenID,
|
path: '/' + scope.idPluralized + '/:' + tokenID,
|
||||||
handler: scope.globalID + '.findOne',
|
handler: scope.globalID + '.findOne',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path: '/' + scope.humanizeId,
|
path: '/' + scope.idPluralized,
|
||||||
handler: scope.globalID + '.create',
|
handler: scope.globalID + '.create',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
path: '/' + scope.humanizeId + '/:' + tokenID,
|
path: '/' + scope.idPluralized + '/:' + tokenID,
|
||||||
handler: scope.globalID + '.update',
|
handler: scope.globalID + '.update',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: '/' + scope.humanizeId + '/:' + tokenID,
|
path: '/' + scope.idPluralized + '/:' + tokenID,
|
||||||
handler: scope.globalID + '.destroy',
|
handler: scope.globalID + '.destroy',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
@ -67,21 +67,21 @@ module.exports = scope => {
|
|||||||
if (scope.args.tpl && scope.args.tpl !== 'mongoose') {
|
if (scope.args.tpl && scope.args.tpl !== 'mongoose') {
|
||||||
routes.routes.push({
|
routes.routes.push({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
path: '/' + scope.humanizeId + '/:' + tokenID + '/relationships/:relation',
|
path: '/' + scope.idPluralized + '/:' + tokenID + '/relationships/:relation',
|
||||||
handler: scope.globalID + '.createRelation',
|
handler: scope.globalID + '.createRelation',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
path: '/' + scope.humanizeId + '/:' + tokenID + '/relationships/:relation',
|
path: '/' + scope.idPluralized + '/:' + tokenID + '/relationships/:relation',
|
||||||
handler: scope.globalID + '.updateRelation',
|
handler: scope.globalID + '.updateRelation',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
path: '/' + scope.humanizeId + '/:' + tokenID + '/relationships/:relation',
|
path: '/' + scope.idPluralized + '/:' + tokenID + '/relationships/:relation',
|
||||||
handler: scope.globalID + '.destroyRelation',
|
handler: scope.globalID + '.destroyRelation',
|
||||||
config: {
|
config: {
|
||||||
policies: []
|
policies: []
|
||||||
|
@ -9,5 +9,8 @@
|
|||||||
},
|
},
|
||||||
"cron": {
|
"cron": {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"autoOpen": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,8 @@
|
|||||||
},
|
},
|
||||||
"cron": {
|
"cron": {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"autoOpen": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,8 @@
|
|||||||
},
|
},
|
||||||
"cron": {
|
"cron": {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"autoOpen": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,6 +461,11 @@ module.exports = function(strapi) {
|
|||||||
const connection = strapi.config.connections[definition.connection];
|
const connection = strapi.config.connections[definition.connection];
|
||||||
let columns = Object.keys(attributes).filter(attribute => ['string', 'text'].includes(attributes[attribute].type));
|
let columns = Object.keys(attributes).filter(attribute => ['string', 'text'].includes(attributes[attribute].type));
|
||||||
|
|
||||||
|
if (!columns) {
|
||||||
|
// No text columns founds, exit from creating Fulltext Index
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (connection.settings.client) {
|
switch (connection.settings.client) {
|
||||||
case 'pg': {
|
case 'pg': {
|
||||||
// Enable extension to allow GIN indexes.
|
// Enable extension to allow GIN indexes.
|
||||||
|
@ -456,7 +456,6 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
|||||||
const hashArray = split(this.props.hash, ('::'));
|
const hashArray = split(this.props.hash, ('::'));
|
||||||
const valueToReplace = includes(this.props.hash, '#create') ? '#create' : '#edit';
|
const valueToReplace = includes(this.props.hash, '#create') ? '#create' : '#edit';
|
||||||
const contentTypeName = replace(hashArray[0], valueToReplace, '');
|
const contentTypeName = replace(hashArray[0], valueToReplace, '');
|
||||||
|
|
||||||
let cbSuccess;
|
let cbSuccess;
|
||||||
let dataSucces = null;
|
let dataSucces = null;
|
||||||
let cbFail;
|
let cbFail;
|
||||||
@ -466,7 +465,7 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
|||||||
// Check if the user is editing the attribute
|
// Check if the user is editing the attribute
|
||||||
const isAttribute = includes(hashArray[1], 'attribute');
|
const isAttribute = includes(hashArray[1], 'attribute');
|
||||||
cbSuccess = isAttribute ? () => this.editTempContentTypeAttribute(redirectToChoose) : this.createContentType;
|
cbSuccess = isAttribute ? () => this.editTempContentTypeAttribute(redirectToChoose) : this.createContentType;
|
||||||
dataSucces = isAttribute ? null : this.props.modifiedDataEdit;
|
dataSucces = isAttribute ? null : this.getModelWithCamelCaseName(this.props.modifiedDataEdit);
|
||||||
cbFail = isAttribute ? () => this.editContentTypeAttribute(redirectToChoose) : this.contentTypeEdit;
|
cbFail = isAttribute ? () => this.editContentTypeAttribute(redirectToChoose) : this.contentTypeEdit;
|
||||||
return this.testContentType(contentTypeName, cbSuccess, dataSucces, cbFail);
|
return this.testContentType(contentTypeName, cbSuccess, dataSucces, cbFail);
|
||||||
}
|
}
|
||||||
@ -476,11 +475,24 @@ export class Form extends React.Component { // eslint-disable-line react/prefer-
|
|||||||
return this.testContentType(contentTypeName, cbSuccess, dataSucces, cbFail);
|
return this.testContentType(contentTypeName, cbSuccess, dataSucces, cbFail);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
return this.createContentType(this.props.modifiedData);
|
return this.createContentType(
|
||||||
|
this.getModelWithCamelCaseName(this.props.modifiedData)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getModelWithCamelCaseName = (model = {}) => {
|
||||||
|
if (isEmpty(model) || isEmpty(model.name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...model,
|
||||||
|
name: camelCase(model.name),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
initComponent = (props, condition) => {
|
initComponent = (props, condition) => {
|
||||||
if (!isEmpty(props.hash)) {
|
if (!isEmpty(props.hash)) {
|
||||||
this.setState({ showModal: true });
|
this.setState({ showModal: true });
|
||||||
|
@ -30,7 +30,7 @@ module.exports = {
|
|||||||
|
|
||||||
let options = ctx.request.body;
|
let options = ctx.request.body;
|
||||||
|
|
||||||
await strapi.plugins.email.services.send(options, config);
|
await strapi.plugins.email.services.email.send(options, config);
|
||||||
|
|
||||||
// Send 200 `ok`
|
// Send 200 `ok`
|
||||||
ctx.send({});
|
ctx.send({});
|
||||||
|
@ -113,14 +113,16 @@ button {
|
|||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flexed {
|
.flexed,
|
||||||
|
.label {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1;
|
||||||
width: 15rem;
|
width: 15rem;
|
||||||
height: 5.2rem;
|
height: 5.2rem;
|
||||||
line-height: 5.2rem;
|
|
||||||
margin-left: 5rem;
|
margin-left: 5rem;
|
||||||
color: #333740;
|
color: #333740;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
@ -211,10 +211,9 @@
|
|||||||
"prefix": ""
|
"prefix": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/user",
|
"path": "/users",
|
||||||
"handler": "User.find",
|
"handler": "User.find",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [],
|
"policies": [],
|
||||||
@ -223,7 +222,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/user/me",
|
"path": "/users/me",
|
||||||
"handler": "User.me",
|
"handler": "User.me",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [],
|
"policies": [],
|
||||||
@ -232,7 +231,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/user/:_id",
|
"path": "/users/:_id",
|
||||||
"handler": "User.findOne",
|
"handler": "User.findOne",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [],
|
"policies": [],
|
||||||
@ -241,7 +240,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"path": "/user",
|
"path": "/users",
|
||||||
"handler": "User.create",
|
"handler": "User.create",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [],
|
"policies": [],
|
||||||
@ -250,7 +249,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "PUT",
|
"method": "PUT",
|
||||||
"path": "/user/:_id",
|
"path": "/users/:_id",
|
||||||
"handler": "User.update",
|
"handler": "User.update",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [],
|
"policies": [],
|
||||||
@ -259,7 +258,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"method": "DELETE",
|
"method": "DELETE",
|
||||||
"path": "/user/:_id",
|
"path": "/users/:_id",
|
||||||
"handler": "User.destroy",
|
"handler": "User.destroy",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": [],
|
"policies": [],
|
||||||
|
@ -12,7 +12,7 @@ const _ = require('lodash');
|
|||||||
|
|
||||||
// Following this discussion https://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric this function is the best implem to determine if a value is a valid number candidate
|
// Following this discussion https://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric this function is the best implem to determine if a value is a valid number candidate
|
||||||
const isNumeric = (value) => {
|
const isNumeric = (value) => {
|
||||||
return !isNaN(parseFloat(value)) && isFinite(value);
|
return !_.isObject(value) && !isNaN(parseFloat(value)) && isFinite(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* eslint-disable prefer-template */
|
/* eslint-disable prefer-template */
|
||||||
|
@ -382,6 +382,31 @@ const enableHookNestedDependencies = function (name, flattenHooksConfig, force =
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow dynamic config values through
|
||||||
|
* the native ES6 template string function.
|
||||||
|
*/
|
||||||
|
const regex = /\$\{[^()]*\}/g;
|
||||||
|
const excludeConfigPaths = ['info.scripts'];
|
||||||
|
const templateConfigurations = function (obj, configPath = '') {
|
||||||
|
// Allow values which looks like such as
|
||||||
|
// an ES6 literal string without parenthesis inside (aka function call).
|
||||||
|
// Exclude config with conflicting syntax (e.g. npm scripts).
|
||||||
|
return Object.keys(obj).reduce((acc, key) => {
|
||||||
|
if (isPlainObject(obj[key]) && !isString(obj[key])) {
|
||||||
|
acc[key] = templateConfigurations(obj[key], `${configPath}.${key}`);
|
||||||
|
} else if (isString(obj[key])
|
||||||
|
&& !excludeConfigPaths.includes(configPath.substr(1))
|
||||||
|
&& obj[key].match(regex) !== null) {
|
||||||
|
acc[key] = eval('`' + obj[key] + '`'); // eslint-disable-line prefer-template
|
||||||
|
} else {
|
||||||
|
acc[key] = obj[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
const isAdminInDevMode = function () {
|
const isAdminInDevMode = function () {
|
||||||
try {
|
try {
|
||||||
fs.accessSync(path.resolve(this.config.appPath, 'admin', 'admin', 'build', 'index.html'), fs.constants.R_OK | fs.constants.W_OK);
|
fs.accessSync(path.resolve(this.config.appPath, 'admin', 'admin', 'build', 'index.html'), fs.constants.R_OK | fs.constants.W_OK);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user