Merge branch 'master' into fix/forgot-password-url

This commit is contained in:
Alexandre BODIN 2019-10-15 12:17:00 +02:00 committed by GitHub
commit c69e3fd042
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1506 additions and 3033 deletions

View File

@ -100,35 +100,41 @@ module.exports = {
},
{
collapsable: true,
title: '💡 Guides',
title: '💡 Concepts',
children: [
'/3.0.0-beta.x/concepts/file-structure',
'/3.0.0-beta.x/concepts/configurations',
'/3.0.0-beta.x/concepts/requests-responses',
'/3.0.0-beta.x/concepts/customization',
'/3.0.0-beta.x/concepts/routing',
'/3.0.0-beta.x/concepts/controllers',
'/3.0.0-beta.x/concepts/models',
'/3.0.0-beta.x/concepts/services',
'/3.0.0-beta.x/concepts/queries',
'/3.0.0-beta.x/concepts/parameters',
'/3.0.0-beta.x/concepts/policies',
'/3.0.0-beta.x/concepts/public-assets',
'/3.0.0-beta.x/concepts/hooks',
'/3.0.0-beta.x/concepts/middlewares',
'/3.0.0-beta.x/concepts/logging',
'/3.0.0-beta.x/concepts/plugins',
],
},
{
collapsable: true,
title: '📚 Guides',
children: [
'/3.0.0-beta.x/concepts/concepts',
'/3.0.0-beta.x/configurations/configurations',
'/3.0.0-beta.x/guides/controllers',
'/3.0.0-beta.x/guides/databases',
'/3.0.0-beta.x/guides/deployment',
'/3.0.0-beta.x/guides/parameters',
'/3.0.0-beta.x/guides/i18n',
'/3.0.0-beta.x/guides/models',
'/3.0.0-beta.x/guides/policies',
'/3.0.0-beta.x/guides/public-assets',
'/3.0.0-beta.x/guides/requests',
'/3.0.0-beta.x/guides/responses',
'/3.0.0-beta.x/guides/routing',
'/3.0.0-beta.x/guides/services',
'/3.0.0-beta.x/guides/queries',
'/3.0.0-beta.x/guides/webhooks',
],
},
{
collapsable: true,
title: '⚙️️ Advanced',
title: '⚙️️ Admin panel',
children: [
'/3.0.0-beta.x/advanced/customize-admin',
'/3.0.0-beta.x/advanced/hooks',
'/3.0.0-beta.x/advanced/logging',
'/3.0.0-beta.x/advanced/middlewares',
'/3.0.0-beta.x/advanced/usage-information',
'/3.0.0-beta.x/admin-panel/customization',
'/3.0.0-beta.x/admin-panel/deploy',
],
},
{
@ -162,7 +168,10 @@ module.exports = {
{
collapsable: true,
title: '🏗 Global strapi',
children: ['/3.0.0-beta.x/global-strapi/reference'],
children: [
'/3.0.0-beta.x/global-strapi/api-reference',
'/3.0.0-beta.x/global-strapi/usage-information',
],
},
{
collapsable: false,

View File

@ -1,10 +1,4 @@
# Admin panel
One of Strapi's main feature is its fully extendable and customizable admin panel. This section explains how the admin panel section is structured and how to customize it.
See the [Contributing Guide](https://github.com/strapi/strapi/blob/master/CONTRIBUTING.md) for information on how to contribute to Strapi's admin interface.
## Customization
# Customization
The administration panel can be customized according to your needs, so you can make it reflects your identity.
@ -12,7 +6,7 @@ The administration panel can be customized according to your needs, so you can m
To apply your changes you need to [rebuild](#build) your admin panel
:::
### Change access URL
## Change access URL
By default, the administration panel is exposed via [http://localhost:1337/admin](http://localhost:1337/admin). However, for security reasons, you can easily update this path.
@ -33,9 +27,7 @@ By default, the administration panel is exposed via [http://localhost:1337/admin
The panel will be available through [http://localhost:1337/dashboard](http://localhost:1337/dashboard) with the configurations above.
---
### Development mode
## Development mode
To enable the front-end development mode you need to start your application using the `--watch-admin` flag.
@ -46,7 +38,7 @@ strapi develop --watch-admin
With this option you can do the following:
#### Customize the `strapi-admin` package
### Customize the `strapi-admin` package
All files added in `my-app/admin/src/` will either be replaced or added
@ -116,7 +108,7 @@ export { languages, translationMessages };
With this modification only English and French will be available in your admin
:::
#### Customize a plugin
### Customize a plugin
Similarly to the back-end override system any file added in `my-app/extensions/<plugin-name>/admin/` will be copied and used instead of the original one (use with care).
@ -146,8 +138,6 @@ const WysiwygWithErrors = props => <MyNewWYSIWYG {...props} />;
export default WysiwygWithErrors;
```
---
### Styles
The AdminUI package source can be easily found in `./node_modules/strapi-admin/src/`.
@ -162,8 +152,6 @@ To apply your changes you need to rebuild your admin panel
npm run build
```
---
### Logo
To change the top-left displayed admin panel's logo, add your custom image at `./admin/src/assets/images/logo-strapi.png`.
@ -245,100 +233,3 @@ NODE_ENV=production strapi build
::::
This will replace the folder's content located at `./build`. Visit [http://localhost:1337/admin](http://localhost:1337/admin) to make sure your updates have been taken into account.
---
## Deployment
The administration is nothing more than a React front-end application calling an API. The front-end and the back-end are independent and can be deployed on different servers which brings us to different scenarios:
1. Deploy the entire project on the same server.
2. Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
Let's dive into the build configurations for each case.
#### Deploy the entire project on the same server.
You don't need to touch anything in your configuration file. This is the default behavior and the build configurations will be automatically set. The server will start on the defined port and the administration panel will be accessible through `http://yourdomain.com:1337/dashboard`.
You might want to change the path to access to the administration panel. Here the required configurations to change the path:
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"cron": {
"enabled": false
},
"admin": {
"path": "/dashboard" // We change the path to access to the admin (highly recommended for security reasons).
}
}
```
**You have to rebuild the administration panel to make this work.** [Build instructions](#build).
#### Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
It's very common to deploy the front-end and the back-end on different servers. Here the required configurations to handle this case:
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"cron": {
"enabled": false
},
"admin": {
"path": "/", // Note: The administration will be accessible from the root of the domain (ex: http//yourfrontend.com/)
"build": {
"backend": "http://yourbackend.com"
}
}
}
```
The administration URL will be `http://yourfrontend.com` and every request from the panel will hit the backend at `http://yourbackend.com`.
#### Deploy the administration panel and the plugins on another server than the API
In this case, we suppose that you decided to put your administration panel on a different server than the API.
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"cron": {
"enabled": false
},
"admin": {
"path": "/dashboard",
"build": {
"backend": "http://yourbackend.com"
}
}
}
```
The administration URL will be `http://yourfrontend.com/dashboard` and every request from the panel will hit the backend at `http://yourbackend.com`.
The generated `index.html` will look like this:
**Path —** `./build/index.html`.
```html
<html lang="en">
<head></head>
<body>
<div id="app"></div>
<script type="text/javascript" src="/dashboard/runtime~main.js"></script>
<script type="text/javascript" src="/dashboard/main.chunk.js"></script>
</body>
</html>
```

View File

@ -0,0 +1,94 @@
# Deployment
The administration is nothing more than a React front-end application calling an API. The front-end and the back-end are independent and can be deployed on different servers which brings us to different scenarios:
1. Deploy the entire project on the same server.
2. Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
Let's dive into the build configurations for each case.
## Deploy the entire project on the same server.
You don't need to touch anything in your configuration file. This is the default behavior and the build configurations will be automatically set. The server will start on the defined port and the administration panel will be accessible through `http://yourdomain.com:1337/dashboard`.
You might want to change the path to access to the administration panel. Here the required configurations to change the path:
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"cron": {
"enabled": false
},
"admin": {
"path": "/dashboard" // We change the path to access to the admin (highly recommended for security reasons).
}
}
```
**You have to rebuild the administration panel to make this work.** [Build instructions](#build).
## Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
It's very common to deploy the front-end and the back-end on different servers. Here the required configurations to handle this case:
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"cron": {
"enabled": false
},
"admin": {
"path": "/", // Note: The administration will be accessible from the root of the domain (ex: http//yourfrontend.com/)
"build": {
"backend": "http://yourbackend.com"
}
}
}
```
The administration URL will be `http://yourfrontend.com` and every request from the panel will hit the backend at `http://yourbackend.com`.
## Deploy the administration panel and the plugins on another server than the API
In this case, we suppose that you decided to put your administration panel on a different server than the API.
**Path —** `./config/environment/**/server.json`.
```js
{
"host": "localhost",
"port": 1337,
"cron": {
"enabled": false
},
"admin": {
"path": "/dashboard",
"build": {
"backend": "http://yourbackend.com"
}
}
}
```
The administration URL will be `http://yourfrontend.com/dashboard` and every request from the panel will hit the backend at `http://yourbackend.com`.
The generated `index.html` will look like this:
**Path —** `./build/index.html`.
```html
<html lang="en">
<head></head>
<body>
<div id="app"></div>
<script type="text/javascript" src="/dashboard/runtime~main.js"></script>
<script type="text/javascript" src="/dashboard/main.chunk.js"></script>
</body>
</html>
```

View File

@ -1,352 +0,0 @@
# Concepts
- Table of contents
- [Files structure](#files-structure)
- [Controllers](#controllers)
- [Parameters](#parameters)
- [Models](#models)
- [Attributes](#attributes)
- [Relations](#relations)
- [Many-to-many](#many-to-many)
- [One-to-many](#one-to-many)
- [One-to-one](#one-to-one)
- [One-way](#one-way)
- [Lifecycle callbacks](#lifecycle-callbacks)
- [Internationalization](#internationalization-and-localization)
- [Plugin](#plugin)
- [Extensions](#extensions)
- [Policies](#policies)
- [Global policies](#global-policies)
- [Scoped policies](#scoped-policies)
- [Plugin policies](#plugin-policies)
- [Public assets](#public-assets)
- [Requests](#requests)
- [Responses](#responses)
- [Routing](#routing)
- [Services](#services)
- [Queries](#queries)
---
## Files structure
By default, your project's structure will look like this:
- `/api`: contains the business logic of your project split in sub-folder per API.
- `**`
- `/config`: contains the API's configurations ([`routes`](#routing), [`policies`](#policies), etc).
- [`/controllers`](#controllers): contains the API's custom controllers.
- [`/models`](#models): contains the API's models.
- [`/services`](#services): contains the API's custom services.
- `/node_modules`: contains the npm's packages used by the project.
- [`/config`](../configurations/configurations.md)
- [`/environments`](../configurations/configurations.md#environments): contains the project's configurations per environment.
- `/**`
- `/development`
- [`custom.json`](../configurations/configurations.md#custom): contains the custom configurations for this environment.
- [`database.json`](../configurations/configurations.md#database): contains the database connections for this environment.
- [`request.json`](../configurations/configurations.md#request): contains the request settings for this environment.
- [`response.json`](../configurations/configurations.md#response): contains the response settings for this environment.
- [`server.json`](../configurations/configurations.md#server): contains the server settings for this environment.
- `/production`
- `/staging`
- [`/functions`](../configurations/configurations.html#functions): contains lifecycle or generic functions of the project.
- [`/locales`](../configurations/configurations.html#locales): contains the translation files used by the built-in i18n feature.
- [`application.json`](../configurations/configurations.html#application): contains the general configurations of the project.
- [`custom.json`](../configurations/configurations.html#custom): contains the custom configurations of the project.
- [`hook.json`](../configurations/configurations.html#hook): contains the hook settings of the project.
- [`language.json`](../configurations/configurations.html#language): contains the language settings of the project.
- [`middleware.json`](../configurations/configurations.html#middleware): contains the middleware settings of the project.
- [`/hooks`](../advanced/hooks.html): contains the custom hooks of the project.
- [`/middlewares`](../advanced/middlewares.html): contains the custom middlewares of the project.
- [`/admin`](../advanced/customize-admin.md): contains your admin customization files.
- [`/extensions`](#extensions): contains the files to extend installed plugins.
- [`/plugins`](#plugin): contains your local plugins.
- [`/public`](#public-assets): contains the file accessible to the outside world.
- `/build`: contains your admin panel UI build.
- `/.cache`: contains files used to build your admin panel.
::: note
Inside the `/config` folder, every folder will be parsed and injected into the global object `strapi.config`. Let's say, you added a folder named `credentials` with two files `stripe.json` and `paypal.json` into it. The content of these files will be accessible through `strapi.config.credentials.stripe` and `strapi.config.credentials.paypal`.
:::
---
## Controllers
Controllers are JavaScript files which contain a set of methods called **actions** reached by the client according to the requested route. It means that every time a client requests the route, the action performs the business logic coded and sends back the response. They represent the _C_ in the _MVC_ pattern. In most cases, the controllers will contain the bulk of a project's business logic.
```js
module.exports = {
// GET /hello
index: async ctx => {
ctx.send('Hello World!');
},
};
```
In this example, any time a web browser is pointed to the `/hello` URL on your app, the page will display the text: `Hello World!`.
### Where are the controllers defined?
The controllers are defined in each `./api/**/controllers/` folders. Every JavaScript file put in these folders will be loaded as a controller. They are also available through the `strapi.controllers` and `strapi.api.**.controllers` global variables. By convention, controllers' names should be Pascal-cased, so that every word in the file (include the first one) is capitalized `User.js`, `LegalEntity.js`.
::: note
Please refer to the [controllers' guide](../guides/controllers.md) for more information.
:::
---
## Parameters
Parameters 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`).
::: note
Please refer to the [parameters' guide](../content-api/parameters.md) for more information.
:::
---
## Models
Models are a representation of the database's structure and lifecycle. They are split into two separate files. A JavaScript file that contains the lifecycle callbacks, and a JSON one that represents the data stored in the database and their format. The models also allow you to define the relationships between them.
**Path —** `./api/user/models/User.js`.
```js
module.exports = {
// Before saving a value.
// Fired before an `insert` or `update` query.
beforeSave: next => {
// Use `this` to get your current object
next();
},
// After saving a value.
// Fired after an `insert` or `update` query.
afterSave: (doc, next) => {
next();
},
// ... and more
};
```
**Path —** `./api/user/models/User.settings.json`.
```json
{
"connection": "default",
"info": {
"name": "user",
"description": "This represents the User Model"
},
"attributes": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
}
}
}
```
In this example, there is a `User` model which contains two attributes `firstname` and `lastname`.
### Where are the models defined?
The models are defined in each `./api/**/models/` folder. Every JavaScript or JSON file in these folders will be loaded as a model. They are also available through the `strapi.models` and `strapi.api.**.models` global variables. Usable everywhere in the project, they contain the ORM model object that they are refer to. By convention, models' names should be written in lowercase.
### Attributes
A model must contain a list of attributes, and each of these attributes must have a type.
::: note
Please refer to the [models' guide for more information about the attributes](../guides/models.md#define-the-attributes).
:::
### Relations
#### Many-to-many
Many-to-many associations allow to link an entry to many entries.
::: note
Please refer to the [many-to-many guide](../guides/models.md#many-to-many)
:::
#### One-to-many
One-way relationships are useful to link an entry to another.
::: note
Please refer to the [one-to-many guide](../guides/models.md#one-to-many)
:::
#### One-to-one
One-way relationships are useful to link an entry to another.
::: note
Please refer to the [one-to-one guide](../guides/models.md#one-to-one).
:::
#### One-way
One-way relationships are useful to link an entry to another. However, only one of the models can be queried with its populated items.
::: note
Please refer to the [one-way guide](../guides/models.md#one-way).
:::
### Lifecycle callbacks
Lifecycle callbacks are functions triggered at specific moments of the queries.
::: note
Please refer to the [lifecycle callbacks guide](../guides/models.md#lifecycle-callbacks).
:::
---
## Internationalization and localization
Internationalization and localization (i18n) allows to adapt the project to different languages and serve the right content to the users. This feature is deeply integrated into the Strapi's core. It will detect the user language preference (locale) and translate the requested content using the translation files.
::: note
Please refer to the [internationalization's guide](../guides/i18n.md).
:::
---
## Plugin
A plugin is like a small independent sub-application. It has its own business logic with dedicated models, controllers, services, middlewares or hooks. It can also have it's own UI integrated in the admin panel.
::: note
Please refer to the [plugins documentation](../plugin-development/quick-start.md) for more information.
:::
---
## Extensions
In strapi you can install plugins in your `node_modules`. This allows for easy updates and respect best practices. To customize those installed plugins you can work in the `/extensions` directory. It contains all the plugins' customizable files.
Certain plugins will create files in these folders so you can then modify them. You can also create certain files manually to add some custom configuration for example.
Depending on the plugins you will find extension documentation directly in the plugin's documentation.
Extensions folder structure:
- `extensions/`
- `**`: Plugin Id
- `config`: You can extend a plugin's configuration by add a settings.json file with your custom configuration
- `models`: Contains the plugin's models that you have overwritten (e.g: When you add a relation to the User model)
- `controllers`: You can extend the plugin's controllers by create controllers with the same names and override certain methods
- `services`: You can extend the plugin's services by create services with the same names and override certain methods
---
## Policies
Policies are functions which have the ability to execute specific logic on each request before it reaches the controller's action. They are mostly used for securing business logic easily.
Each route of the project can be associated to an array of policies. For example, you can create a policy named `isAdmin`, which obviously checks that the request is sent by an admin user, and use it for critical routes.
Policies can be:
- `global`: so they can be used within the entire project.
- `scoped`: used by single API or plugin.
### Where are the policies defined?
The API and plugins policies (scoped) are defined in each `./api/**/config/policies/` folders and plugins. They are respectively exposed through `strapi.api.**.config.policies` and `strapi.plugins.**.config.policies`. The global policies are defined at `./config/policies/` and accessible via `strapi.config.policies`.
::: note
Please refer to the [policy guide](../guides/policies.md)
:::
### Global policies
Global policies are reusable through the entire app.
::: note
Please refer to the [global policy guide](../guides/policies.md#global-policies)
:::
### Scoped policies
A policy defined in an API or plugin is usable only from this API or plugin. You don't need any prefix to use it.
::: note
Please refer to the [scoped policy guide](../guides/policies.md#scoped-policies).
:::
### Plugin policies
Plugin policies are usable from any app API.
::: note
Please refer to the [plugin policy guide](../guides/policies.md#plugins).
:::
## Public Assets
Public assets are static files such as images, video, css, etc that you want to make accessible to the outside world. Every new project includes by default, a folder named `./public`.
::: note
Please refer to the [public configuration](../configurations/configurations.md#Application) for more information.
:::
---
## Requests
The context object (`ctx`) contains all the request's related information.
::: note
Please refer to the [requests guide](../guides/requests.md) for more information.
:::
---
## Responses
The context object (`ctx`) contains a list of values and functions useful to manage server responses.
::: note
Please refer to the [responses guide](../guides/responses.md) for more information.
:::
---
## Routing
`./api/**/config/routes.json` files define all available routes for the clients.
::: note
Please refer to the [routing guide](../guides/routing.md) for more information.
:::
---
## Services
Services are a set of reusable functions. They are particularly useful to respect the DRY (dont repeat yourself) programming concept and to simplify [controllers](#controllers) logic.
::: note
Please refer to the [services guide](../guides/services.md) for more information.
:::
---
## Queries
Queries are a way to implement database agnostic queries in strapi's core or plugins.
::: note
Please refer to the [queries guide](../guides/queries.md) for more information.
:::
---

View File

@ -2,6 +2,10 @@
The main configurations of the project are located in the `./config` directory. Additional configs can be added in the `./api/**/config` folder of each API and plugin by creating JavaScript or JSON files.
::: note
Inside the `/config` folder, every folder will be parsed and injected into the global object `strapi.config`. Let's say, you added a folder named `credentials` with two files `stripe.json` and `paypal.json` into it. The content of these files will be accessible through `strapi.config.credentials.stripe` and `strapi.config.credentials.paypal`.
:::
## Application
Contains the main configurations relative to your project.
@ -45,30 +49,12 @@ Add custom configurations to the project. The content of this file is available
These configurations are accessible through `strapi.config.backendURL` and `strapi.config.mainColor`.
## Language
As described in the [i18n documentation](../guides/i18n.md), Strapi includes an internationalization system. This is especially useful to translate API messages (errors, etc.).
**Path —** `./config/language.json`.
```json
{
"enabled": true,
"defaultLocale": "en_us",
"modes": ["query", "subdomain", "cookie", "header", "url", "tld"],
"cookieName": "locale"
}
```
- `enabled` (boolean): Enable or disable i18n. Default value: `true`.
- `defaultLocale` (string): Default locale used by the application. Default value: `en_us`.
- `modes` (array): Methods used to detect client language. Default value: `["query", "subdomain", "cookie", "header", "url", "tld"]`.
- `cookieName` (string): Name of the cookie used to store the locale name. Default value: `locale`.
## Functions
The `./config/functions/` folder contains a set of JavaScript files in order to add dynamic and logic based configurations.
All functions that are expose in this folder or in your `./config` folder are accessible via `strapi.config.functions['fileName']();`
### Bootstrap
**Path —** `./config/functions/bootstrap.js`.
@ -147,13 +133,17 @@ module.exports = {
};
```
### Bookshelf, Mongoose
### Database ORM customization
**Path —** `./config/functions/bookshelf.js`.
**Path —** `./config/functions/mongoose.js`.
- **Path —** `./config/functions/bookshelf.js`.
- **Path —** `./config/functions/mongoose.js`.
When present, they are loaded to let you customize your database connection instance, for example for adding some plugin, customizing parameters, etc.
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Mongoose" id="mongoose"
As an example, for using the `mongoose-simple-random` plugin for MongoDB, you can register it like this:
**Path —** `./config/functions/mongoose.js`.
@ -168,6 +158,10 @@ module.exports = (mongoose, connection) => {
};
```
:::
::: tab "Bookshelf" id="bookshelf"
Another example would be using the `bookshelf-uuid` plugin for MySQL, you can register it like this:
**Path —** `./config/functions/bookshelf.js`.
@ -180,26 +174,10 @@ module.exports = (bookshelf, connection) => {
};
```
## Locales
The `locales` directory contains the translations of your API.
Each JSON file located in the folder must have the name of its corresponding translation (eg. `en_US.json`, `fr_FR.json`, etc.). Each line defines a translation key and its corresponding value.
#### Example
**Path —** `./config/locales/en_US.json`.
```js
{
"welcome": "Welcome"
}
```
::: note
Take a look at the [internationalization's guide](../guides/i18n.md) for more details.
:::
::::
## Environments
Most of the application's configurations are defined by environment. It means that you can specify settings for each environment (`development`, `production`, `test`, etc.).
@ -212,22 +190,26 @@ You can access the config of the current environment through `strapi.config.curr
**Path —** `./config/environments/**/database.json`.
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Bookshelf" id="bookshelf"
- `defaultConnection` (string): Connection by default for models which are not related to a specific `connection`. Default value: `default`.
- `connections` List of all available connections.
- `default`
- `connector` (string): Connector used by the current connection. Default value: `strapi-hook-mongoose`.
- `connector` (string): Connector used by the current connection. Will be `strapi-hook-bookshelf`.
- `settings` Useful for external session stores such as Redis.
- `client` (string): Database client to create the connection. Default value: `mongo`.
- `client` (string): Database client to create the connection. `sqlite` or `postgres` or `mysql`.
- `host` (string): Database host name. Default value: `localhost`.
- `port` (integer): Database port. Default value: `27017`.
- `database` (string): Database name. Default value: `development`.
- `port` (integer): Database port.
- `database` (string): Database name.
- `username` (string): Username used to establish the connection.
- `password` (string): Password used to establish the connection.
- `options` (object): List of additional options used by the connector.
- `timezone` (string): Set the default behavior for local time (used only for a SQL database). Default value: `utc`.
- `schema` (string): Set the default database schema. (used only for Postgres DB)
- `timezone` (string): Set the default behavior for local time. Default value: `utc`.
- `schema` (string): Set the default database schema. **Used only for Postgres DB**
- `ssl` (boolean): For ssl database connection.
- `options` Options used for database connection.
- `ssl` (boolean): For ssl database connection.
- `debug` (boolean): Show database exchanges and errors.
- `autoMigration` (boolean): To disable auto tables/columns creation for SQL database.
- `pool` Options used for database connection pooling. For more information look at [Knex's pool config documentation](https://knexjs.org/#Installation-pooling).
@ -239,46 +221,70 @@ You can access the config of the current environment through `strapi.config.curr
- `reapIntervalMillis` (integer): How often to check for idle connections in milliseconds. Default value: `1000` (1 second).
- `createRetryIntervalMillis` (integer): How long to idle after a failed create before trying again in milliseconds. Default value: `200`.
:::
::: tab "Mongoose" id="mongoose"
- `defaultConnection` (string): Connection by default for models which are not related to a specific `connection`. Default value: `default`.
- `connections` List of all available connections.
- `default`
- `connector` (string): Connector used by the current connection. Will be `strapi-hook-mongoose`.
- `settings` Useful for external session stores such as Redis.
- `client` (string): Database client to create the connection. Will be `mongo`.
- `host` (string): Database host name. Default value: `localhost`.
- `port` (integer): Database port. Default value: `27017`.
- `database` (string): Database name.
- `username` (string): Username used to establish the connection.
- `password` (string): Password used to establish the connection.
- `options` Options used for database connection.
- `ssl` (boolean): For ssl database connection.
- `debug` (boolean): Show database exchanges and errors.
- `authenticationDatabase` (string): Connect with authentication.
:::
::::
#### Example
**Path —** `./config/environments/**/database.json`.
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Postgres" id="postgres"
```json
{
"defaultConnection": "default",
"connections": {
"default": {
"connector": "strapi-hook-mongoose",
"settings": {
"client": "mongo",
"host": "localhost",
"port": 27017,
"database": "development",
"username": "fooUsername",
"password": "fooPwd"
},
"options": {
"authenticationDatabase": "",
"ssl": true,
"minimize": true
}
},
"postgres": {
"connector": "strapi-hook-bookshelf",
"settings": {
"client": "postgres",
"host": "localhost",
"port": 5432,
"username": "${process.env.USERNAME}",
"password": "${process.env.PWD}",
"password": "${process.env.PASSWORD}",
"database": "strapi",
"schema": "public"
},
"options": {
"debug": true
}
},
"mysql": {
}
}
}
```
:::
::: tab "MySQL" id="mysql"
```json
{
"defaultConnection": "default",
"connections": {
"default": {
"connector": "strapi-hook-bookshelf",
"settings": {
"client": "mysql",
@ -286,10 +292,22 @@ You can access the config of the current environment through `strapi.config.curr
"port": 5432,
"username": "strapi",
"password": "root",
"database": ""
"database": "strapi"
},
"options": {}
},
}
}
}
```
:::
::: tab "SQLite" id="sqlite"
```json
{
"defaultConnection": "default",
"connections": {
"sqlite": {
"connector": "strapi-hook-bookshelf",
"settings": {
@ -304,6 +322,37 @@ You can access the config of the current environment through `strapi.config.curr
}
```
:::
::: tab "Mongo" id="mongo"
```json
{
"defaultConnection": "default",
"connections": {
"default": {
"connector": "strapi-hook-mongoose",
"settings": {
"client": "mongo",
"host": "localhost",
"port": 27017,
"database": "strapi",
"username": "",
"password": ""
},
"options": {
"authenticationDatabase": "",
"ssl": true
}
}
}
}
```
:::
::::
::: note
Please refer to the [dynamic configurations section](#dynamic-configurations) to use global environment variable to configure the databases.
:::
@ -461,7 +510,7 @@ In any JSON configurations files in your project, you can inject dynamic values
You can't execute functions inside the curly braces. Only strings are allowed.
:::
## Database configuration
## Configuration in database
Configuration files are not multi server friendly. So we created a data store for config you will want to update in production.

View File

@ -1,6 +1,23 @@
# Controllers
See the [controllers' concepts](../concepts/concepts.md#controllers) for a simple overview.
## Concept
Controllers are JavaScript files which contain a set of methods called **actions** reached by the client according to the requested route. It means that every time a client requests the route, the action performs the business logic coded and sends back the response. They represent the _C_ in the _MVC_ pattern. In most cases, the controllers will contain the bulk of a project's business logic.
```js
module.exports = {
// GET /hello
index: async ctx => {
ctx.send('Hello World!');
},
};
```
In this example, any time a web browser is pointed to the `/hello` URL on your app, the page will display the text: `Hello World!`.
### Where are the controllers defined?
The controllers are defined in each `./api/**/controllers/` folders. Every JavaScript file put in these folders will be loaded as a controller. They are also available through the `strapi.controllers` and `strapi.api.**.controllers` global variables. By convention, controllers' names should be Pascal-cased, so that every word in the file (include the first one) is capitalized `User.js`, `LegalEntity.js`.
## Core controllers
@ -26,6 +43,10 @@ const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
- `parseMultipartData`: This function parses strapi's formData format.
- `sanitizeEntity`: This function removes all private fields from the model and its relations.
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "find" id="find"
#### `find`
```js
@ -49,6 +70,10 @@ module.exports = {
};
```
:::
::: tab "findOne" id="findone"
#### `findOne`
```js
@ -66,6 +91,10 @@ module.exports = {
};
```
:::
::: tab "count" id="count"
#### `count`
```js
@ -85,6 +114,10 @@ module.exports = {
};
```
:::
::: tab "create" id="create"
#### `create`
```js
@ -108,6 +141,10 @@ module.exports = {
};
```
:::
::: tab "update" id="update"
#### `update`
```js
@ -132,6 +169,10 @@ module.exports = {
};
```
:::
::: tab "delete" id="delete"
#### `delete`
```js
@ -149,6 +190,10 @@ module.exports = {
};
```
:::
::::
## Custom controllers
You can also create custom controllers to build your own business logic and API endpoints.
@ -163,7 +208,7 @@ There are two ways to create a controller:
### Adding Endpoints
Each controllers action must be an `async` function.
Every action receives a `context` (`ctx`) object as first parameter containing the [request context](../guides/requests.md) and the [response context](../guides/responses.md).
Every action receives a `context` (`ctx`) object as first parameter containing the [request context](./requests-responses.md) and the [response context](./requests-responses.md).
::: note
Every action must be referenced by a route.

View File

@ -0,0 +1,29 @@
# Customization
## Plugin extensions
In strapi you can install plugins in your `node_modules`. This allows for easy updates and respect best practices. To customize those installed plugins you can work in the `/extensions` directory. It contains all the plugins' customizable files.
Some plugins will create files in these folders so you can then modify them. You can also create certain files manually to add some custom configuration for example.
Extensions folder structure:
- `extensions/`
- `**`: Plugin Id
- `admin`: You can extend a plugin's admin by creating a file with the same name, doing so will override the original one.
- `config`: You can extend a plugin's configuration by adding a settings.json file with your custom configuration
- `models`: Contains the plugin's models that you have overwritten (e.g: When you add a relation to the User model)
- `controllers`: You can extend the plugin's controllers by creating controllers with the same names and override certain methods
- `services`: You can extend the plugin's services by creating services with the same names and override certain methods
## Admin extension
The admin panel is a `node_module` that is similar to a plugin but the slight difference that it encapsulate all the installed plugin of your application.
To extend this package you will have to create an `admin` folder at the root of your application.
In this folder you will be able to override admin flies and functions.
::: note
For more details, visit the [admin panel constomization](../admin-panel/customization.md) documentation.
:::

View File

@ -0,0 +1,37 @@
# Files structure
By default, your project's structure will look like this:
- `/api`: contains the business logic of your project split in sub-folder per API.
- `**`
- `/config`: contains the API's configurations ([`routes`](./routing.md), [`policies`](./policies.md), etc).
- [`/controllers`](./controllers.md): contains the API's custom controllers.
- [`/models`](./models.md): contains the API's models.
- [`/services`](./services.md): contains the API's custom services.
- `/node_modules`: contains the npm's packages used by the project.
- [`/config`](./configurations.md)
- [`/environments`](./configurations.md#environments): contains the project's configurations per environment.
- `/**`
- `/development`
- [`custom.json`](./configurations.md#custom): contains the custom configurations for this environment.
- [`database.json`](./configurations.md#database): contains the database connections for this environment.
- [`request.json`](./configurations.md#request): contains the request settings for this environment.
- [`response.json`](./configurations.md#response): contains the response settings for this environment.
- [`server.json`](./configurations.md#server): contains the server settings for this environment.
- `/production`
- `/staging`
- [`/functions`](./configurations.md#functions): contains lifecycle or generic functions of the project.
- [`bootstrap.js`](./configurations.md#bootstrap): contains the code executed at the application start.
- [`cron.js`](./configurations.md#cron-tasks): contains the cron tasks.
- [`application.json`](./configurations.md#application): contains the general configurations of the project.
- [`custom.json`](./configurations.md#custom): contains the custom configurations of the project.
- [`hook.json`](./configurations.md#hook): contains the hook settings of the project.
- [`middleware.json`](./configurations.md#middleware): contains the middleware settings of the project.
- [`/hooks`](./hooks.md): contains the custom hooks of the project.
- [`/middlewares`](./middlewares.md): contains the custom middlewares of the project.
- [`/admin`](../admin-panel/customization.md): contains your admin customization files.
- [`/extensions`](./customization.md): contains the files to extend installed plugins.
- [`/plugins`](./plugins.md): contains your local plugins.
- [`/public`](./public-assets.md): contains the file accessible to the outside world.
- `/build`: contains your admin panel UI build.
- `/.cache`: contains files used to build your admin panel.

View File

@ -1,6 +1,55 @@
# Models
See the [models' concepts](../concepts/concepts.md#models) for details.
## Concept
Models are a representation of the database's structure and lifecycle. They are split into two separate files. A JavaScript file that contains the lifecycle callbacks, and a JSON one that represents the data stored in the database and their format. The models also allow you to define the relationships between them.
**Path —** `./api/user/models/User.js`.
```js
module.exports = {
// Before saving a value.
// Fired before an `insert` or `update` query.
beforeSave: next => {
// Use `this` to get your current object
next();
},
// After saving a value.
// Fired after an `insert` or `update` query.
afterSave: (doc, next) => {
next();
},
// ... and more
};
```
**Path —** `./api/user/models/User.settings.json`.
```json
{
"connection": "default",
"info": {
"name": "user",
"description": "This represents the User Model"
},
"attributes": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
}
}
}
```
In this example, there is a `User` model which contains two attributes `firstname` and `lastname`.
### Where are the models defined?
The models are defined in each `./api/**/models/` folder. Every JavaScript or JSON file in these folders will be loaded as a model. They are also available through the `strapi.models` and `strapi.api.**.models` global variables. Usable everywhere in the project, they contain the ORM model object that they are refer to. By convention, models' names should be written in lowercase.
## How to create a model?
@ -19,7 +68,32 @@ This will create two files located at `./api/user/models`:
when you create a new API using the CLI (`strapi generate:api <name>`), a model is automatically created.
:::
## Model Information
## Model settings
Additional settings can be set on models:
- `connection` (string) - Connection's name which must be used. Default value: `default`.
- `collectionName` (string) - Collection's name (or table's name) in which the data should be stored.
- `globalId` (string) -Global variable name for this model (case-sensitive).
**Path —** `User.settings.json`.
```json
{
"connection": "mongo",
"collectionName": "Users_v1",
"globalId": "Users",
"attributes": {}
}
```
In this example, the model `User` will be accessible through the `Users` global variable. The data will be stored in the `Users_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
::: note
The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.
:::
## Model information
The info key on the model-json states information about the model. This information is used in the admin interface, when showing the model.
@ -27,6 +101,17 @@ The info key on the model-json states information about the model. This informat
- `description`: The description of the model.
- `mainField`: Determines which model-attribute is shown when displaying the model.
**Path —** `User.settings.json`.
```json
{
"info": {
"name": "user",
"description": ""
}
}
```
## Model options
The options key on the model-json states.
@ -34,7 +119,17 @@ The options key on the model-json states.
- `idAttribute`: This tells the model which attribute to expect as the unique identifier for each database row (typically an auto-incrementing primary key named 'id'). _Only valid for strapi-hook-bookshelf_
- `idAttributeType`: Data type of `idAttribute`, accepted list of value below. _Only valid for strapi-hook-bookshelf_
- `timestamps`: This tells the model which attributes to use for timestamps. Accepts either `boolean` or `Array` of strings where first element is create date and second element is update date. Default value when set to `true` for Bookshelf is `["created_at", "updated_at"]` and for MongoDB is `["createdAt", "updatedAt"]`.
- `uuid` : Boolean to enable UUID support on MySQL, you will need to set the `idAttributeType` to `uuid` as well and install the `bookshelf-uuid` package. To load the package you can see [this example](../configurations/configurations.md#bookshelf-mongoose).
- `uuid` : Boolean to enable UUID support on MySQL, you will need to set the `idAttributeType` to `uuid` as well and install the `bookshelf-uuid` package. To load the package you can see [this example](./configurations.md#bookshelf-mongoose).
**Path —** `User.settings.json`.
```json
{
"options": {
"timestamps": true
}
}
```
## Define the attributes
@ -122,11 +217,15 @@ To improve the Developer eXperience when developing or using the administration
## Relations
Refer to the [relations concept](../concepts/concepts.md#relations) for more information about relations type.
Relations let your create links (relations) between your Content Types.
### One-way
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
Refer to the [one-way concept](../concepts/concepts.md#one-way) for information.
::: tab "One-Way" id="one-way"
### One-Way
One-way relationships are useful to link an entry to another. However, only one of the models can be queried with its populated items.
#### Example
@ -173,9 +272,13 @@ xhr.send(
);
```
### One-to-one
:::
Refer to the [one-to-one concept](../concepts/concepts.md#one-to-one) for information.
::: tab "One-to-One" id="one-to-one"
### One-to-One
One-to-One relationships are usefull when you have one entity that could be linked to only one other entity. And vis versa.
#### Example
@ -250,9 +353,13 @@ xhr.send(
);
```
### One-to-many
:::
Refer to the [one-to-many concept](../concepts/concepts.md#one-to-many) for more information.
::: tab "One-to-Many" id="one-to-many"
### One-to-Many
One-to-Many relationships are usefull when an entry can be liked to multiple entries of an other Content Type. And an entry of the other Content Type can be linked to only one entry.
#### Example
@ -337,9 +444,13 @@ xhr.send(
);
```
### Many-to-many
:::
Refer to the [many-to-many concept](../concepts/concepts.md#many-to-many).
::: tab "Many-to-Many" id="many-to-many"
### Many-to-Many
One-to-Many relationships are usefull when an entry can be liked to multiple entries of an other Content Type. And an entry of the other Content Type can be linked to many entries.
#### Example
@ -359,9 +470,8 @@ A `product` can be related to many `categories`, so a `category` can have many `
}
```
::: note
**NOTE**:
(NoSQL databases only) The `dominant` key defines which table/collection should store the array that defines the relationship. Because there are no join tables in NoSQL, this key is required for NoSQL databases (ex: MongoDB).
:::
**Path —** `./api/category/models/Category.settings.json`.
@ -420,19 +530,20 @@ xhr.send(
);
```
:::
::: tab "Polymorphic" id="polymorphic"
### Polymorphic
The polymorphic relationships are the solution when you don't know which kind of model will be associated to your entry. A common use case is an `Image` model that can be associated to many others kind of models (Article, Product, User, etc).
Refer to the [upload plugin](../plugins/upload.md) polymorphic implementation for more information.
#### Single vs Many
Let's stay with our `Image` model which might belongs to **a single `Article` or `Product` entry**.
::: note
**NOTE**:
In other words, it means that an `Image` entry can be associated to one entry. This entry can be a `Article` or `Product` entry.
:::
**Path —** `./api/image/models/Image.settings.json`.
@ -449,9 +560,8 @@ In other words, it means that an `Image` entry can be associated to one entry. T
Also, our `Image` model which might belongs to **many `Article` or `Product` entries**.
::: note
**NOTE**:
In other words, it means that an `Article` entry can relate to the same image as a `Product` entry.
:::
**Path —** `./api/image/models/Image.settings.json`.
@ -663,9 +773,8 @@ CREATE TABLE `image` (
)
```
::: note
**NOTE**:
If you've overridden the default table name given by Strapi by using the `collectionName` attribute. Use the value set in the `collectionName` to name the table.
:::
The second table will allow us to associate one or many others entries to the `Image` model. The name of the table is the same as the previous one with the suffix `_morph`.
@ -694,42 +803,84 @@ CREATE TABLE `image_morph` (
| 2 | 4738 | 58 | article | avatar |
| 3 | 1738 | 71 | article | avatar |
:::
::::
## Lifecycle callbacks
Refer to the [lifecycle callbacks concepts](../concepts/concepts.md#lifecycle-callbacks) for information.
::: warning
The life cycle functions are based on the ORM life cycle and not on the strapi request.
We are currently woking on it to make it easier to use and understand.
Please check [this issue](https://github.com/strapi/strapi/issues/1443) on GitHub.
:::
The following events are available by default:
Callbacks on `save`:
Callbacks on:
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "save" id="save"
`save`
- beforeSave
- afterSave
Callbacks on `fetch`:
:::
::: tab "fetch" id="fetch"
`fetch`
- beforeFetch
- afterFetch
Callbacks on `fetchAll`:
::: tab "fetchAll" id="fetchall"
`fetchAll`
- beforeFetchAll
- afterFetchAll
Callbacks on `create`:
:::
::: tab "create" id="create"
`create`
- beforeCreate
- afterCreate
Callbacks on `update`:
:::
::: tab "update" id="update"
`update`
- beforeUpdate
- afterUpdate
Callbacks on `destroy`:
:::
::: tab "destroy" id="destroy"
destroy`
- beforeDestroy
- afterDestroy
:::
::::
### Example
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Mongoose" id="mongoose"
#### Mongoose
The entry is available through the `model` parameter
@ -753,6 +904,10 @@ module.exports = {
};
```
:::
::: tab "Bookshelf" id="bookshelf"
#### Bookshelf
Each of these functions receives a three parameters `model`, `attrs` and `options`. You have to return a Promise.
@ -776,27 +931,6 @@ module.exports = {
};
```
## Settings
Additional settings can be set on models:
- `connection` (string) - Connection's name which must be used. Default value: `default`.
- `collectionName` (string) - Collection's name (or table's name) in which the data should be stored.
- `globalId` (string) -Global variable name for this model (case-sensitive).
**Path —** `User.settings.json`.
```json
{
"connection": "mongo",
"collectionName": "Users_v1",
"globalId": "Users",
"attributes": {}
}
```
In this example, the model `User` will be accessible through the `Users` global variable. The data will be stored in the `Users_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
::: note
The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.
:::
:::::

View File

@ -1,12 +1,12 @@
# Prameters
## Programmatic usage
## Concept
You can use `strapi-utils` to parse the query params to Strapi's standards filters programmatically if you need it.
### Extracting requests filters
## Extracting requests filters
To transform the query params to Strapi's standard filters a request, you can use the `convertRestQueryParams` function from [strapi-utils](../global-strapi/reference.md#strapiutils).
To transform the query params to Strapi's standard filters a request, you can use the `convertRestQueryParams` function from [strapi-utils](../global-strapi/api-reference.md#strapiutils).
```js
const { convertRestQueryParams } = require('strapi-utils');
@ -32,7 +32,7 @@ module.exports = {
};
```
### Querying data
## Querying data
We added a new API to query data base on the new filters API.
@ -53,15 +53,15 @@ module.exports = {
};
```
#### SQL databases (strapi-hook-bookshelf)
### SQL databases (strapi-hook-bookshelf)
If you are using a SQL database, calling `buildQuery` will return a [`Bookshelf Query`](https://bookshelfjs.org/api.html) on which you can call other functions (e.g `count`)
#### Mongo database
### Mongo database
If you are using a mongo database calling `buildQuery` returns either a [`Mongoose Query`](https://mongoosejs.com/docs/api.html#Query) or a custom query when used with deep filtering.
##### Custom Query
#### Custom Query
When using the deep filtering feature with mongo, we build an aggregation query to avoid too many round-trips with the mongo DB.
Doing that means we don't get a Mongoose object as a response but instead a plain JS Object. This brings a some issues like no virtual fields available and no Mongoose lifecycles.

View File

@ -0,0 +1,7 @@
# Plugins
A plugin is like a small independent sub-application. It has its own business logic with dedicated models, controllers, services, middlewares or hooks. It can also have it's own UI integrated in the admin panel.
::: note
Please refer to the [plugins documentation](../plugin-development/quick-start.md) for more information.
:::

View File

@ -1,6 +1,30 @@
# Policies
See the [policies' concepts](../concepts/concepts.md#policies) for details.
## Concept
Policies are functions which have the ability to execute specific logic on each request before it reaches the controller's action. They are mostly used for securing business logic easily.
Each route of the project can be associated to an array of policies. For example, you can create a policy named `isAdmin`, which obviously checks that the request is sent by an admin user, and use it for critical routes.
Policies can be:
- `global`: so they can be used within the entire project.
- `scoped`: used by single API or plugin.
### Where are the policies defined?
The API and plugins policies (scoped) are defined in each `./api/**/config/policies/` folders and plugins. They are respectively exposed through `strapi.api.**.config.policies` and `strapi.plugins.**.config.policies`. The global policies are defined at `./config/policies/` and accessible via `strapi.config.policies`.
### Global policies
Global policies are reusable through the entire app.
### Scoped policies
A policy defined in an API or plugin is usable only from this API or plugin. You don't need any prefix to use it.
### Plugin policies
Plugin policies are usable from any app API.
## How to create a policy?
@ -30,17 +54,15 @@ You can access to any controllers, services or models thanks to the global varia
## Usage
To apply policies to a route, you need to associate an array of policies to it. As explained in the [policies' concepts](../concepts/concepts.md#policies), there are two kinds of policies: global or scoped.
To apply policies to a route, you need to associate an array of policies to it. There are two kinds of policies: global or scoped.
### Global policies
Refer to the [concept](../concepts/concepts.md#policies) for details.
The global policies can be associated to any routes in your project.
**Path —** `./api/restaurant/routes.json`.
```js
```json
{
"routes": [
{
@ -48,9 +70,7 @@ The global policies can be associated to any routes in your project.
"path": "/restaurants",
"handler": "Restaurant.find",
"config": {
"policies": [
"global.isAuthenticated"
]
"policies": ["global.isAuthenticated"]
}
}
]
@ -65,11 +85,11 @@ You can put as much policy you want in this array. However be careful about the
### Plugins policies
Plugins can add and expose policies into your app. For example, the plugin `Auth` (COMING SOON) comes with several useful policies to ensure that the user is well authenticated or has the rights to perform an action.
Plugins can add and expose policies into your app. For example, the plugin **Users & Permissions** comes with useful policies to ensure that the user is well authenticated or has the rights to perform an action.
**Path —** `./api/restaurant/config/routes.json`.
```js
```json
{
"routes": [
{
@ -77,9 +97,7 @@ Plugins can add and expose policies into your app. For example, the plugin `Auth
"path": "/restaurants",
"handler": "Restaurant.find",
"config": {
"policies": [
"plugins.users-permissions.isAuthenticated"
]
"policies": ["plugins.users-permissions.isAuthenticated"]
}
}
]
@ -107,7 +125,7 @@ module.exports = async (ctx, next) => {
**Path —** `./api/restaurant/config/routes.json`.
```js
```json
{
"routes": [
{
@ -115,9 +133,7 @@ module.exports = async (ctx, next) => {
"path": "/restaurants",
"handler": "Restaurant.find",
"config": {
"policies": [
"isAdmin"
]
"policies": ["isAdmin"]
}
}
]

View File

@ -1,6 +1,6 @@
# Public Assets
See the [public assets concepts](../concepts/concepts.md#public-assets) for details.
Public assets are static files such as images, video, css, etc that you want to make accessible to the outside world. Every new project includes by default, a folder named `./public`.
Because an API may need to serve static assets, every new Strapi project includes by default, a folder named `/public`. Any file located in this directory is accessible if the request's path doesn't match any other defined route and if it matches a public file name.
@ -16,4 +16,4 @@ An image named `company-logo.png` in `./public/` is accessible through `/company
The dotfiles are not exposed. It means that every files with the names start by `.` such as `.htaccess` or `.gitignore` are not served.
:::
Refer to the [public assets configurations](../configurations/configurations.md#Application) for more information.
Refer to the [public assets configurations](./configurations.md#Application) for more information.

View File

@ -8,38 +8,9 @@ These queries handle for you specific Strapi features like `groups`, `filters` a
## API Reference
### `findOne`
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
This method returns the first entry matching some basic params.
You can also pass a populate option to specify which relations you want to be populated.
#### Examples
**Find one by id**:
```js
strapi.query('restaurant').findOne({ id: 1 });
```
**Find one by name**:
```js
strapi.query('restaurant').findOne({ name: 'restaurant name' });
```
**Find one by name and creation_date**:
```js
strapi
.query('restaurant')
.findOne({ name: 'restaurant name', date: '2019-01-01T00:00:00Z' });
```
**Find one by id and populate a relation**
```js
strapi.query('restaurant').findOne({ id: 1 }, ['category', 'category.name']);
```
::: tab "find" id="find"
### `find`
@ -76,6 +47,47 @@ strapi
.find({ id_nin: [1], _start: 10 }, ['category', 'category.name']);
```
:::
::: tab "findOne" id="findone"
### `findOne`
This method returns the first entry matching some basic params.
You can also pass a populate option to specify which relations you want to be populated.
#### Examples
**Find one by id**:
```js
strapi.query('restaurant').findOne({ id: 1 });
```
**Find one by name**:
```js
strapi.query('restaurant').findOne({ name: 'restaurant name' });
```
**Find one by name and creation_date**:
```js
strapi
.query('restaurant')
.findOne({ name: 'restaurant name', date: '2019-01-01T00:00:00Z' });
```
**Find one by id and populate a relation**
```js
strapi.query('restaurant').findOne({ id: 1 }, ['category', 'category.name']);
```
:::
::: tab "create" id="create"
### `create`
Creates an entry in the database and returns the entry.
@ -105,6 +117,10 @@ strapi.query('restaurant').create({
});
```
:::
::: tab "update" id="update"
### `update`
Updates an entry in the database and returns the entry.
@ -180,6 +196,10 @@ strapi.query('restaurant').update(
);
```
:::
::: tab "delete" id="delete"
### `delete`
Deletes and entry and return its value before deletion.
@ -199,6 +219,10 @@ strapi.query('restaurant').delete({ id: 1 });
strapi.query('restaurant').delete({ district: '_18th' });
```
:::
::: tab "count" id="count"
### `count`
Returns the count of entries matching Strapi filters.
@ -223,6 +247,10 @@ strapi.query('restaurant').count({ name_contains: 'food' });
strapi.query('restaurant').count({ date_lt: '2019-08-01T00:00:00Z' });
```
:::
::: tab "search" id="search"
### `search`
Returns entries based on a search on all fields allowing it. (this feature will return all entries on sqlite).
@ -245,6 +273,10 @@ strapi
.search({ _q: 'my search query', _limit: 100, _sort: 'date:desc' });
```
:::
::: tab "countSearch" id="countsearch"
### `countSearch`
Returns the total count of entries based on a search. (this feature will return all entries on sqlite).
@ -255,6 +287,10 @@ Returns the total count of entries based on a search. (this feature will return
strapi.query('restaurant').countSearch({ _q: 'my search query' });
```
:::
::::
## Custom Queries
When you want to customize your services or create new ones you will have to build your queries with the underlying ORM models.
@ -267,6 +303,10 @@ strapi.query(modelName, plugin).model;
Then you can run any queries available on the model. You should refer to the specific ORM documentation for more details:
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "Bookshelf" id="bookshelf"
### Bookshelf
Documentation: [https://bookshelfjs.org/](https://bookshelfjs.org/)
@ -284,6 +324,10 @@ const result = await strapi
const fields = result.toJSON();
```
:::
::: tab "Mongoose" id="mongoose"
### Mongoose
Documentation: [https://mongoosejs.com/](https://mongoosejs.com/)
@ -297,3 +341,7 @@ const result = strapi.query('restaurant').model.find({
const fields = result.toObject();
```
:::
::::

View File

@ -0,0 +1,13 @@
# Requests and responses
## Request
The context object (`ctx`) contains all the requests related information. They are accessible through `ctx.request`, from [controllers](controllers.md) and [policies](policies.md).
For more information, please refer to the [Koa request documentation](http://koajs.com/#request).
## Responses
The context object (`ctx`) contains a list of values and functions useful to manage server responses. They are accessible through `ctx.response`, from [controllers](controllers.md) and [policies](policies.md).
For more information, please refer to the [Koa response documentation](http://koajs.com/#response).

View File

@ -1,6 +1,10 @@
# Routing
See the [routing's concept](../concepts/concepts.md#routing) for details.
## Concept
`./api/**/config/routes.json` files define all available endpoints for the clients.
By default Strapi generate endpoints for all your Content Type. More information in the [Content API](../content-api/api-endpoints.md) documentation.
## How to create a route?
@ -14,12 +18,18 @@ You have to edit the `routes.json` file in one of your APIs folders (`./api/**/c
{
"method": "GET",
"path": "/restaurants",
"handler": "Restaurant.find"
"handler": "Restaurant.find",
"config": {
"policies": []
}
},
{
"method": ["POST", "PUT"],
"path": "/restaurants/:id",
"handler": "Restaurant.createOrUpdate"
"handler": "Restaurant.createOrUpdate",
"config": {
"policies": []
}
},
{
"method": "POST",
@ -37,7 +47,7 @@ You have to edit the `routes.json` file in one of your APIs folders (`./api/**/c
- `path` (string): URL starting with `/` (ex: `/restaurants`)
- `handler` (string): Action to executed when the route is hit following this syntax `<Controller>.<action>`
- `config`
- `policies` (array): Array of policies names or path ([see more](../guides/policies.md))
- `policies` (array): Array of policies names or path ([see more](./policies.md))
- `prefix` (string): Set a prefix to this route. Also, it will be loaded into the main router (useful feature for plugin)
## Dynamic parameters
@ -50,12 +60,18 @@ The router used by Strapi allows you to create dynamic routes where you can use
{
"method": "GET",
"path": "/restaurants/:category/:id",
"handler": "Restaurant.findOneByCategory"
"handler": "Restaurant.findOneByCategory",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/restaurants/:region(\\d{2}|\\d{3})/:id", // Only match when the first parameter contains 2 or 3 digits.
"handler": "Restaurant.findOneByRegion"
"handler": "Restaurant.findOneByRegion",
"config": {
"policies": []
}
}
]
}
@ -71,7 +87,10 @@ By default, the main route of the server `/` is pointed to the `/public/index.ht
{
"method": "GET",
"path": "/",
"handler": "Controller.name"
"handler": "Controller.name",
"config": {
"policies": []
}
}
]
}

View File

@ -1,6 +1,8 @@
# Services
See the [services concept](../concepts/concepts.md#services) for an overview.
## Concept
Services are a set of reusable functions. They are particularly useful to respect the DRY (dont repeat yourself) programming concept and to simplify [controllers](./controllers.md) logic.
## Core services
@ -17,6 +19,10 @@ You can read about `strapi.query` calls [here](./queries.md)
In the following example your controller, service and model is named `restaurant`
:::
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
::: tab "find" id="find"
#### `find`
```js
@ -32,6 +38,10 @@ module.exports = {
};
```
:::
::: tab "findOne" id="findone"
#### `findOne`
```js
@ -48,6 +58,10 @@ module.exports = {
};
```
:::
::: tab "count" id="count"
#### `count`
```js
@ -64,6 +78,10 @@ module.exports = {
};
```
:::
::: tab "create" id="create"
#### `create`
```js
@ -88,6 +106,10 @@ module.exports = {
};
```
:::
::: tab "update" id="update"
#### `update`
```js
@ -112,6 +134,10 @@ module.exports = {
};
```
:::
::: tab "delete" id="delete"
#### `delete`
```js
@ -128,6 +154,10 @@ module.exports = {
};
```
:::
::: tab "search" id="search"
#### `search`
```js
@ -144,6 +174,10 @@ module.exports = {
};
```
:::
::: tab "countSearch" id="countsearch"
#### `countSearch`
```js
@ -159,6 +193,10 @@ module.exports = {
};
```
:::
::::
## Custom services
You can also create custom services to build your own business logic.

View File

@ -71,7 +71,7 @@ This feature doesn't allow you to filter nested models, e.g `Find users and only
To achieve this, there are two options:
- Either build a custom route or modify your services
- Use [GraphQL](../guides/graphql.md#query-api)
- Use [GraphQL](../plugins/graphql.md#query-api)
:::
::: warning

View File

@ -1,4 +1,4 @@
# Reference
# API reference
- strapi
- [.admin](#strapi-admin)
@ -73,7 +73,7 @@ Returns an object of plugins available within the project. Each plugin object co
## strapi.query
This utility function allows to bind models with query functions specific to each ORM (e.g: `mongoose` or `bookshelf`).
For more details, see the [Queries section](../guides/queries.md).
For more details, see the [Queries section](../concepts/queries.md).
## strapi.reload

View File

@ -1,68 +0,0 @@
# Internationalization
See the [internationalization' concepts](../concepts/concepts.md#internationalization-and-localization) for details.
Because an API may need to send different data based on the language of the user, Strapi provides a built-in strategy to handle the internationalization (i18n).
## Usage
The `i18n` method that will allow you to retrieve the right string based on the language is accessible through the request's context.
There are many strategies to define the language that the server should use to return the correct translation. It can be based on the `locale` query parameter, the `cookie` or the `Accept-Language` header.
- Query: Add the `locale` parameter in the URL `GET /hello/John?locale=en_US`.
- Cookie: Set the `locale` field in the cookie `locale=en\-US;`.
- Header: Set the `Accept-Language` header with the value `en_US`.
::: note
Please refer to the [language configuration](../configurations/configurations.md#language)
:::
### Example
Let's say we want to say `Hello John` in english and `Bonjour Tom` in french. We need to use the built-in `i18n` feature and replace the string based on the received name.
**Path —** `./api/hello/config/routes.json`.
```json
{
"routes": [
{
"method": "GET",
"path": "/hello/:name",
"handler": "Hello.sayHello"
}
]
}
```
**Path —** `./api/hello/controllers/Hello.js`.
```js
module.exports = {
// GET /hello/:name
sayHello: async ctx => {
ctx.send(ctx.i18n.__('Hello %s', ctx.params.name));
},
};
```
You need to define the english and french translation for this key.
**Path —** `./config/locales/en_US.json`.
```json
{
"Hello %s": "Hello %s"
}
```
**Path —** `./config/locales/fr_FR.json`.
```json
{
"Hello %s": "Bonjour %s"
}
```
That's all! The request `GET /hello/John?locale=en_US` will return `Hello John` and `GET /hello/Tom?locale=fr_FR` will return `Bonjour Tom`

View File

@ -1,394 +0,0 @@
# Request
See the [requests concepts](../concepts/concepts.md#requests) for details.
The context object (`ctx`) contains all the requests related information. They are accessible through `ctx.request`, from [controllers](controllers.md) and [policies](policies.md).
## API Reference
For more information, please refer to the [Koa request documentation](http://koajs.com/#request).
### request.header
Request header object.
### request.header=
Set request header object.
### request.headers
Request header object. Alias as `request.header`.
### request.headers=
Set request header object. Alias as `request.header=`.
### request.method
Request method.
### request.method=
Set request method, useful for implementing middleware
such as `methodOverride()`.
### request.length
Return request Content-Length as a number when present, or `undefined`.
### request.url
Get request URL.
### request.url=
Set request URL, useful for url rewrites.
### request.originalUrl
Get request original URL.
### request.origin
Get origin of URL, include `protocol` and `host`.
```js
ctx.request.origin;
// => http://example.com
```
### request.href
Get full request URL, include `protocol`, `host` and `url`.
```js
ctx.request.href;
// => http://example.com/foo/bar?q=1
```
### request.path
Get request pathname.
### request.path=
Set request pathname and retain query-string when present.
### request.querystring
Get raw query string void of `?`.
### request.querystring=
Set raw query string.
### request.search
Get raw query string with the `?`.
### request.search=
Set raw query string.
### request.host
Get host (hostname:port) when present. Supports `X-Forwarded-Host`
when `app.proxy` is **true**, otherwise `Host` is used.
### request.hostname
Get hostname when present. Supports `X-Forwarded-Host`
when `app.proxy` is **true**, otherwise `Host` is used.
If host is IPv6, Koa delegates parsing to
[WHATWG URL API](https://nodejs.org/dist/latest-v8.x/docs/api/url.html#url_the_whatwg_url_api),
_Note_ This may impact performance.
### request.URL
Get WHATWG parsed URL object.
### request.type
Get request `Content-Type` void of parameters such as "charset".
```js
const ct = ctx.request.type;
// => "image/png"
```
### request.charset
Get request charset when present, or `undefined`:
```js
ctx.request.charset;
// => "utf-8"
```
### request.query
Get parsed query-string, returning an empty object when no
query-string is present. Note that this getter does _not_
support nested parsing.
For example "color=blue&size=small":
```js
{
color: 'blue',
size: 'small'
}
```
### request.query=
Set query-string to the given object. Note that this
setter does _not_ support nested objects.
```js
ctx.query = { next: '/login' };
```
### request.fresh
Check if a request cache is "fresh", aka the contents have not changed. This
method is for cache negotiation between `If-None-Match` / `ETag`, and `If-Modified-Since` and `Last-Modified`. It should be referenced after setting one or more of these response headers.
```js
// freshness check requires status 20x or 304
ctx.status = 200;
ctx.set('ETag', '123');
// cache is ok
if (ctx.fresh) {
ctx.status = 304;
return;
}
// cache is stale
// fetch new data
ctx.body = await db.find('something');
```
### request.stale
Inverse of `request.fresh`.
### request.protocol
Return request protocol, "https" or "http". Supports `X-Forwarded-Proto`
when `app.proxy` is **true**.
### request.secure
Shorthand for `ctx.protocol == "https"` to check if a request was
issued via TLS.
### request.ip
Request remote address. Supports `X-Forwarded-For` when `app.proxy`
is **true**.
### request.ips
When `X-Forwarded-For` is present and `app.proxy` is enabled an array
of these ips is returned, ordered from upstream -> downstream. When disabled
an empty array is returned.
### request.subdomains
Return subdomains as an array.
Subdomains are the dot-separated parts of the host before the main domain of
the app. By default, the domain of the app is assumed to be the last two
parts of the host. This can be changed by setting `app.subdomainOffset`.
For example, if the domain is "tobi.ferrets.example.com":
If `app.subdomainOffset` is not set, `ctx.subdomains` is `["ferrets", "tobi"]`.
If `app.subdomainOffset` is 3, `ctx.subdomains` is `["tobi"]`.
### request.is(types...)
Check if the incoming request contains the "Content-Type"
header field, and it contains any of the five mime `type`s.
If there is no request body, `null` is returned.
If there is no content type, or the match fails `false` is returned.
Otherwise, it returns the matching content-type.
```js
// With Content-Type: text/html; charset=utf-8
ctx.is('html'); // => 'html'
ctx.is('text/html'); // => 'text/html'
ctx.is('text/*', 'text/html'); // => 'text/html'
// When Content-Type is application/json
ctx.is('json', 'urlencoded'); // => 'json'
ctx.is('application/json'); // => 'application/json'
ctx.is('html', 'application/*'); // => 'application/json'
ctx.is('html'); // => false
```
For example if you want to ensure that
only images are sent to a given route:
```js
if (ctx.is('image/*')) {
// process
} else {
ctx.throw(415, 'images only!');
}
```
### Content Negotiation
Koa's `request` object includes helpful content negotiation utilities powered by [accepts](http://github.com/expressjs/accepts) and [negotiator](https://github.com/federomero/negotiator). These utilities are:
- `request.accepts(types)`
- `request.acceptsEncodings(types)`
- `request.acceptsCharsets(charsets)`
- `request.acceptsLanguages(langs)`
If no types are supplied, **all** acceptable types are returned.
If multiple types are supplied, the best match will be returned. If no matches are found, a `false` is returned, and you should send a `406 "Not Acceptable"` response to the client.
In the case of missing accept headers where any type is acceptable, the first type will be returned. Thus, the order of types you supply is important.
### request.accepts(types)
Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `false`. The `type` value may be one or more mime type string
such as "application/json", the extension name
such as "json", or an array `["json", "html", "text/plain"]`.
```js
// Accept: text/html
ctx.accepts('html');
// => "html"
// Accept: text/*, application/json
ctx.accepts('html');
// => "html"
ctx.accepts('text/html');
// => "text/html"
ctx.accepts('json', 'text');
// => "json"
ctx.accepts('application/json');
// => "application/json"
// Accept: text/*, application/json
ctx.accepts('image/png');
ctx.accepts('png');
// => false
// Accept: text/*;q=.5, application/json
ctx.accepts(['html', 'json']);
ctx.accepts('html', 'json');
// => "json"
// No Accept header
ctx.accepts('html', 'json');
// => "html"
ctx.accepts('json', 'html');
// => "json"
```
You may call `ctx.accepts()` as many times as you like,
or use a switch:
```js
switch (ctx.accepts('json', 'html', 'text')) {
case 'json':
break;
case 'html':
break;
case 'text':
break;
default:
ctx.throw(406, 'json, html, or text only');
}
```
### request.acceptsEncodings(encodings)
Check if `encodings` are acceptable, returning the best match when true, otherwise `false`. Note that you should include `identity` as one of the encodings!
```js
// Accept-Encoding: gzip
ctx.acceptsEncodings('gzip', 'deflate', 'identity');
// => "gzip"
ctx.acceptsEncodings(['gzip', 'deflate', 'identity']);
// => "gzip"
```
When no arguments are given all accepted encodings
are returned as an array:
```js
// Accept-Encoding: gzip, deflate
ctx.acceptsEncodings();
// => ["gzip", "deflate", "identity"]
```
Note that the `identity` encoding (which means no encoding) could be unacceptable if the client explicitly sends `identity;q=0`. Although this is an edge case, you should still handle the case where this method returns `false`.
### request.acceptsCharsets(charsets)
Check if `charsets` are acceptable, returning
the best match when true, otherwise `false`.
```js
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets('utf-8', 'utf-7');
// => "utf-8"
ctx.acceptsCharsets(['utf-7', 'utf-8']);
// => "utf-8"
```
When no arguments are given all accepted charsets
are returned as an array:
```js
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets();
// => ["utf-8", "utf-7", "iso-8859-1"]
```
### request.acceptsLanguages(langs)
Check if `langs` are acceptable, returning
the best match when true, otherwise `false`.
```js
// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages('es', 'en');
// => "es"
ctx.acceptsLanguages(['en', 'es']);
// => "es"
```
When no arguments are given all accepted languages
are returned as an array:
```js
// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages();
// => ["es", "pt", "en"]
```
### request.idempotent
Check if the request is idempotent.
### request.socket
Return the request socket.
### request.get(field)
Return request header.

File diff suppressed because it is too large Load Diff

View File

@ -1,127 +0,0 @@
# Filters
See the [filters' concepts](../concepts/concepts.md#filters) for details.
::: note
by default, the filters can only be used from `find` endpoints generated by the Content Type Builder and the [CLI](../cli/CLI.md). If you need to implement a filters system somewhere else, read the [programmatic usage](#programmatic-usage) section.
:::
## Available operators
The available operators are separated in four different categories:
- [Filters](#filters)
- [Sort](#sort)
- [Limit](#limit)
- [Start](#start)
### Filters
Easily filter results according to fields values.
- `=`: Equals
- `_ne`: Not equals
- `_lt`: Lower than
- `_gt`: Greater than
- `_lte`: Lower than or equal to
- `_gte`: Greater than or equal to
- `_contains`: Contains
- `_containss`: Contains case sensitive
- `_in`: Matches any value in the array of values
- `_nin`: Doesn't match any value in the array of values
- `_null`: Equals null/Not equals null
#### Examples
Find users having `John` as first name.
`GET /user?firstName=John`
Find products having a price equal or greater than `3`.
`GET /product?price_gte=3`
### Sort
Sort according to a specific field.
#### Example
Sort users by email.
- ASC: `GET /user?_sort=email:asc`
- DESC: `GET /user?_sort=email:desc`
### Limit
Limit the size of the returned results.
#### Example
Limit the result length to 30.
`GET /user?_limit=30`
### Start
Skip a specific number of entries (especially useful for pagination).
#### Example
Get the second page of results.
`GET /user?_start=10&_limit=10`
## Programmatic usage
Requests system can be implemented in custom code sections.
### Extracting requests filters
To extract the filters from an JavaScript object or a request, you need to call the [`strapi.utils.models.convertParams` helper](../api-reference/reference.md#strapiutils).
::: note
The returned objects is formatted according to the ORM used by the model.
:::
#### Example
**Path —** `./api/user/controllers/User.js`.
```js
// Define a list of params.
const params = {
_limit: 20,
_sort: 'email',
};
// Convert params.
const formattedParams = strapi.utils.models.convertParams('user', params); // { limit: 20, sort: 'email' }
```
### Query usage
#### Example
**Path —** `./api/user/controllers/User.js`.
```js
module.exports = {
find: async (ctx) => {
// Convert params.
const formattedParams = strapi.utils.models.convertParams('user', ctx.request.query);
// Get the list of users according to the request query.
const filteredUsers = await User
.find()
.where(formattedParams.where)
.sort(formattedParams.sort)
.skip(formattedParams.start)
.limit(formattedParams.limit);
// Finally, send the results to the client.
ctx.body = filteredUsers;
};
};
```

View File

@ -383,6 +383,26 @@ Add the language translation in `packages/strapi-plugin-users-permissions/admin/
These two change will set up the popup message that appears in the UI. That's it, now you should be able to use your new provider.
## Email templates
## Templating emails
[See the documentation on GitHub](https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/docs/email-templates.md)
By default, this plugin comes with only one template (reset password) for the moment. More templates will come later. The templates use Lodash' template() method to populate the variables.
You can update these template in the **Email Templates** tab in the admin panel.
### Reset Password
- `USER` (object)
- `username`
- `email`
- ...and every other fields that you added manually in the model.
- `TOKEN` corresponds to the token generated to be able to reset the password.
- `URL` is the link where the user will be redirected after clicking on it in the email.
### Email address confirmation
- `USER` (object)
- `username`
- `email`
- ...and every other fields that you added manually in the model.
- `CODE` corresponds to the CODE generated to be able confirm the user email.
- `URL` is the Strapi backend URL that confirm the code (by default `/auth/email-confirmation`).

View File

@ -2,6 +2,7 @@
"Analytics": "Analytics",
"Content Manager": "Inhalts-Manager",
"Content Type Builder": "Inhaltstyp-Manager",
"Documentation": "Dokumentation",
"Email": "E-Mail",
"Files Upload": "Dateien hochladen",
"HomePage.notification.newsLetter.success": "Newsletter erfolgreich abonniert",

View File

@ -2,6 +2,7 @@
"Analytics": "Analytics",
"Content Manager": "Content Manager",
"Content Type Builder": "Content Type Builder",
"Documentation": "Documentation",
"Email": "Email",
"Files Upload": "Files Upload",
"HomePage.notification.newsLetter.success": "Successfully subscribed to the newsletter",

View File

@ -2,6 +2,7 @@
"Analytics": "Аналитика",
"Content Manager": "Редактор контента",
"Content Type Builder": "Типы Контента",
"Documentation": "Документация",
"Email": "Email",
"Files Upload": "Загрузка файлов",
"HomePage.notification.newsLetter.success": "Успешная подписка на рассылку новостей",

View File

@ -81,6 +81,7 @@
"video-react": "^0.13.2",
"webpack": "^4.40.1",
"webpackbar": "^3.2.0",
"webpack-dev-server": "^3.4.1",
"yup": "^0.27.0"
},
"author": {
@ -104,7 +105,6 @@
"devDependencies": {
"chokidar": "^3.1.1",
"webpack": "^4.40.1",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.4.1"
"webpack-cli": "^3.3.2"
}
}

View File

@ -1,5 +1,14 @@
/* eslint-disable prefer-template */
export default (location, n) => {
const half = location.split(n + '=')[1];
return half !== undefined ? decodeURIComponent(half.split('&')[0]) : null;
if (half !== undefined) {
try {
return decodeURIComponent(half.split('&')[0]);
} catch (e) {
return null;
}
}
return null;
};

View File

@ -56,7 +56,7 @@ module.exports = function(strapi) {
password,
database,
srv,
useUnifiedTopology
useUnifiedTopology,
} = connection.settings;
const uriOptions = uri ? url.parse(uri, true).query : {};
@ -93,9 +93,9 @@ module.exports = function(strapi) {
* https://github.com/Automattic/mongoose/issues/6881 */
await instance.connect(
uri ||
`mongodb${isSrv ? '+srv' : ''}://${username}:${password}@${host}${
!isSrv ? ':' + port : ''
}/`,
`mongodb${isSrv ? '+srv' : ''}://${username}:${encodeURIComponent(
password
)}@${host}${!isSrv ? ':' + port : ''}/`,
connectOptions
);
} catch (error) {

View File

@ -4,5 +4,6 @@
"shadowCRUD": true,
"playgroundAlways": false,
"depthLimit": 7,
"amountLimit": 100
"amountLimit": 100,
"shareEnabled": false
}

View File

@ -92,6 +92,7 @@ module.exports = strapi => {
) {
serverParams.playground = {
endpoint: strapi.plugins.graphql.config.endpoint,
shareEnabled: strapi.plugins.graphql.config.shareEnabled
};
serverParams.introspection = true;

View File

@ -30,7 +30,7 @@
"EditPage.notification.policies.error": "Beim Abruf von policies ist ein Fehler aufgetreten",
"EditPage.notification.role.error": "Beim Abruf der Rolle ist ein Fehler aufgetreten",
"EditPage.submit": "Speichern",
"Email.template.email_confirmation": "Betsätigung der E-Mail Adresse",
"Email.template.email_confirmation": "Bestätigung der E-Mail Adresse",
"Email.template.reset_password": "Passwort zurücksetzen",
"Email.template.success_register": "Anmeldung erfolgreich",
"Email.template.validation_email": "Validierung der E-Mail-Adresse",

View File

@ -15,11 +15,13 @@ module.exports = async () => {
const jwtSecret = uuid();
_.set(strapi.plugins['users-permissions'], 'config.jwtSecret', jwtSecret);
strapi.reload.isWatching = false;
await strapi.fs.writePluginFile(
'users-permissions',
'config/jwt.json',
JSON.stringify({ jwtSecret }, null, 2)
);
strapi.reload.isWatching = true;
}
const pluginStore = strapi.store({

1389
yarn.lock

File diff suppressed because it is too large Load Diff