Merge branch 'master' into discordProvider

This commit is contained in:
Jim LAURIE 2018-07-31 16:18:04 +02:00 committed by GitHub
commit f559bcc82c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 471 additions and 60 deletions

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="8px" height="8px" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
<title>Icon grab</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Pages" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Content-Manager---Settings-view---Single" transform="translate(-335.000000, -698.000000)" fill="#B3B5B9">
<g id="Container" transform="translate(261.000000, 84.000000)">
<g id="Forms" transform="translate(3.000000, 77.000000)">
<g id="Settings">
<g id="Attributes" transform="translate(4.000000, 456.000000)">
<g id="Order-attributes" transform="translate(0.000000, 23.000000)">
<g id="Link" transform="translate(0.000000, 19.000000)">
<g id="Icon-grab" transform="translate(67.000000, 39.000000)">
<rect id="Rectangle-4" x="0" y="0" width="2" height="2"></rect>
<rect id="Rectangle-4" x="3" y="0" width="2" height="2"></rect>
<rect id="Rectangle-4" x="6" y="0" width="2" height="2"></rect>
<rect id="Rectangle-4" x="0" y="3" width="2" height="2"></rect>
<rect id="Rectangle-4" x="3" y="3" width="2" height="2"></rect>
<rect id="Rectangle-4" x="6" y="3" width="2" height="2"></rect>
<rect id="Rectangle-4" x="0" y="6" width="2" height="2"></rect>
<rect id="Rectangle-4" x="3" y="6" width="2" height="2"></rect>
<rect id="Rectangle-4" x="6" y="6" width="2" height="2"></rect>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
<title>Icon remove</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Pages" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Content-Manager---List-view" transform="translate(-279.000000, -165.000000)">
<g id="Container" transform="translate(234.000000, 0.000000)">
<g id="Add-filters" transform="translate(0.000000, 60.000000)">
<g id="Icon-remove" transform="translate(45.000000, 105.000000)">
<rect id="Rectangle-12" stroke="#E3E9F3" x="0.5" y="0.5" width="19" height="19" rx="9.5"></rect>
<path d="M6,10 L14,10" id="Line-4" stroke="#007EFF" stroke-width="2" stroke-linecap="round"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -5,7 +5,6 @@
*/
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { get, map } from 'lodash';
@ -26,9 +25,6 @@ const filterRelationsUpload = (data) => Object.keys(data).reduce((acc, current)
function EditRelations(props) {
return (
<div className={styles.editFormRelations}>
<FormattedMessage id="content-manager.EditRelations.title">
{(message) => <h3>{message}</h3>}
</FormattedMessage>
{map(filterRelationsUpload(props.schema.relations), (relation, key) => {
if (relation.nature.toLowerCase().includes('morph') && relation[key]) return '';
@ -43,6 +39,7 @@ function EditRelations(props) {
schema={props.schema}
setRecordAttribute={props.changeData}
location={props.location}
onRedirect={props.onRedirect}
/>
);
})}
@ -59,6 +56,7 @@ EditRelations.propTypes = {
changeData: PropTypes.func.isRequired,
currentModelName: PropTypes.string.isRequired,
location: PropTypes.object.isRequired,
onRedirect: PropTypes.func.isRequired,
record: PropTypes.object,
schema: PropTypes.object,
};

View File

@ -1,13 +1,3 @@
.editFormRelations { /* stylelint-disable */
h3{
height: 41px;
margin: 0 -25px 14px;
padding: 0 25px;
background: #F3F3F3;
line-height: 41px;
border-radius: 2px 2px 0 0;
letter-spacing: 0.03rem;
font-size: 1.3rem;
font-weight: bold;
}
padding: 19px 0 20px;
}

View File

@ -6,15 +6,46 @@
import React from 'react';
import Select from 'react-select';
import { SortableContainer, SortableElement, arrayMove } from 'react-sortable-hoc';
import PropTypes from 'prop-types';
import 'react-select/dist/react-select.css';
import { cloneDeep, isArray, isNull, isUndefined, get, findIndex, includes } from 'lodash';
// Utils.
import request from 'utils/request';
import templateObject from 'utils/templateObject';
// CSS.
import 'react-select/dist/react-select.css';
// Icons.
import IconRemove from '../../assets/images/icon_remove.svg';
import styles from './styles.scss';
const SortableItem = SortableElement(({idx, onRemove, item, onClick}) => {
return (
<li className={styles.sortableListItem}>
<div>
<div className={styles.dragHandle}><span></span></div>
<span className="sortable-item--value" onClick={() => onClick(item)}>{item.label}</span>
</div>
<div className={styles.sortableListItemActions}>
<img src={IconRemove} alt="Remove Icon" onClick={() => onRemove(idx)} />
</div>
</li>
);
});
const SortableList = SortableContainer(({items, onRemove, onClick}) => {
return (
<ul className={styles.sortableList}>
{items.map((item, index) => (
<SortableItem key={`item-${index}`} index={index} idx={index} item={item} onRemove={onRemove} onClick={onClick} />
))}
</ul>
);
});
class SelectMany extends React.Component {
// eslint-disable-line react/prefer-stateless-function
constructor(props) {
@ -92,13 +123,12 @@ class SelectMany extends React.Component {
};
handleChange = value => {
const filteredValue = value.filter(
(data, index) => findIndex(value, o => o.value.id === data.value.id) === index
);
const values = get(this.props.record, this.props.relation.alias) || [];
const target = {
name: `record.${this.props.relation.alias}`,
type: 'select',
value: filteredValue,
value: [...values, value],
};
this.props.setRecordAttribute({ target });
@ -121,6 +151,35 @@ class SelectMany extends React.Component {
}
}
handleSortEnd = ({oldIndex, newIndex}) => {
const values = get(this.props.record, this.props.relation.alias);
const target = {
name: `record.${this.props.relation.alias}`,
type: 'select',
value: arrayMove(values, oldIndex, newIndex),
};
this.props.setRecordAttribute({ target });
};
handleRemove = (index) => {
const values = get(this.props.record, this.props.relation.alias);
const target = {
name: `record.${this.props.relation.alias}`,
type: 'select',
value: values.filter( (item, idx) => idx !== index),
};
this.props.setRecordAttribute({ target });
}
// Redirect to the edit page
handleClick = (item = {}) => {
this.props.onRedirect({
model: this.props.relation.collection || this.props.relation.model,
id: item.value.id || item.value._id,
source: this.props.relation.plugin,
});
}
render() {
const description = this.props.relation.description ? (
<p>{this.props.relation.description}</p>
@ -128,7 +187,7 @@ class SelectMany extends React.Component {
''
);
const value = get(this.props.record, this.props.relation.alias);
const value = get(this.props.record, this.props.relation.alias) || [];
/* eslint-disable jsx-a11y/label-has-for */
return (
<div className={`form-group ${styles.selectMany}`}>
@ -140,10 +199,9 @@ class SelectMany extends React.Component {
id={this.props.relation.alias}
isLoading={this.state.isLoading}
onMenuScrollToBottom={this.handleBottomScroll}
onInputChange={this.handleInputChange}
onSelectResetsInput={false}
multi
value={
/>
<SortableList
items={
isNull(value) || isUndefined(value) || value.size === 0
? null
: value.map(item => {
@ -159,6 +217,10 @@ class SelectMany extends React.Component {
}
})
}
onSortEnd={this.handleSortEnd}
onRemove={this.handleRemove}
distance={1}
onClick={this.handleClick}
/>
</div>
);
@ -167,6 +229,7 @@ class SelectMany extends React.Component {
}
SelectMany.propTypes = {
onRedirect: PropTypes.func.isRequired,
record: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]).isRequired,
relation: PropTypes.object.isRequired,
setRecordAttribute: PropTypes.func.isRequired,

View File

@ -7,7 +7,7 @@
}
label + div{
margin: 5px 0 26px;
margin: 3px 0 26px;
&:focus{
outline: none;
@ -25,3 +25,116 @@
}
}
}
.sortableList {
margin-top: -21px;
padding-left: 0 !important;
list-style: none !important;
}
.sortableListItem {
display: flex;
flex-wrap: nowrap;
align-content: center;
justify-content: space-between;
height: 27px;
&:hover{
cursor: pointer;
}
&:active{
.dragHandle{
cursor: pointer;
> span {
background: #AED4FB;
}
}
}
.dragHandle{
outline: none;
text-decoration: none;
margin-top: -1px;
> span {
vertical-align: middle;
position: relative;
display: inline-block;
width: 6px;
height: 1px;
padding: 0px !important;
background: #B3B5B9;
overflow: visible !important;
transition: background .25s ease-out;
&:before, &:after{
content: '';
display: inline-block;
width: 6px;
height: 1px;
background: inherit;
}
&:before{
position: absolute;
top: -2px;
left: 0;
}
&:after{
position: absolute;
bottom: -2px;
left: 0;
}
}
}
> div {
span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
&:first-of-type{
display: flex;
align-items: center;
transition: color .25s ease-out;
&:hover{
.dragHandle{
> span {
background: #007EFF;
}
}
color: #007EFF;
}
span {
&:last-of-type{
padding-left: 10px;
}
}
}
&:last-of-type{
display: inline-block;
height: 100%;
line-height: 27px;
text-align: right;
padding-right: 0px;
img{
display: inline-block;
height: 14px;
}
}
}
}

View File

@ -72,7 +72,10 @@ export function initModelProps(modelName, isCreating, source, attributes) {
const record = Object.keys(attributes).reduce((acc, current) => {
if (attributes[current].default) {
acc[current] = attributes[current].default;
} else if (attributes[current].type === 'json') {
acc[current] = {};
}
return acc;
}, {});

View File

@ -33,6 +33,7 @@ import injectSaga from 'utils/injectSaga';
import getQueryParameters from 'utils/getQueryParameters';
import { bindLayout } from 'utils/bindLayout';
import inputValidations from 'utils/inputsValidations';
import { generateRedirectURI } from 'containers/ListPage/utils';
import { checkFormValidity } from 'utils/formValidations';
@ -57,35 +58,15 @@ export class EditPage extends React.Component {
state = { showWarning: false };
componentDidMount() {
this.props.initModelProps(this.getModelName(), this.isCreating(), this.getSource(), this.getModelAttributes());
if (!this.isCreating()) {
const mainField = get(this.getModel(), 'info.mainField') || this.getModel().primaryKey;
this.props.getData(this.props.match.params.id, this.getSource(), mainField);
} else {
this.props.getLayout(this.getSource());
}
// Get all relations made with the upload plugin
const fileRelations = Object.keys(get(this.getSchema(), 'relations', {})).reduce((acc, current) => {
const association = get(this.getSchema(), ['relations', current], {});
if (association.plugin === 'upload' && association[association.type] === 'file') {
const relation = {
name: current,
multiple: association.nature === 'manyToManyMorph',
};
acc.push(relation);
}
return acc;
}, []);
// Update the reducer so we can use it to create the appropriate FormData in the saga
this.props.setFileRelations(fileRelations);
this.initComponent(this.props);
}
componentDidUpdate(prevProps) {
if (prevProps.location.pathname !== this.props.location.pathname) {
this.props.resetProps();
this.initComponent(this.props);
}
if (prevProps.editPage.submitSuccess !== this.props.editPage.submitSuccess) {
if (!isEmpty(this.props.location.search) && includes(this.props.location.search, '?redirectUrl')) {
const redirectUrl = this.props.location.search.split('?redirectUrl=')[1];
@ -168,6 +149,38 @@ export class EditPage extends React.Component {
*/
getSource = () => getQueryParameters(this.props.location.search, 'source');
/**
* Initialize component
*/
initComponent = (props) => {
this.props.initModelProps(this.getModelName(), this.isCreating(), this.getSource(), this.getModelAttributes());
if (!this.isCreating()) {
const mainField = get(this.getModel(), 'info.mainField') || this.getModel().primaryKey;
this.props.getData(props.match.params.id, this.getSource(), mainField);
} else {
this.props.getLayout(this.getSource());
}
// Get all relations made with the upload plugin
const fileRelations = Object.keys(get(this.getSchema(), 'relations', {})).reduce((acc, current) => {
const association = get(this.getSchema(), ['relations', current], {});
if (association.plugin === 'upload' && association[association.type] === 'file') {
const relation = {
name: current,
multiple: association.nature === 'manyToManyMorph',
};
acc.push(relation);
}
return acc;
}, []);
// Update the reducer so we can use it to create the appropriate FormData in the saga
this.props.setFileRelations(fileRelations);
}
handleBlur = ({ target }) => {
const defaultValue = get(this.getModelAttribute(target.name), 'default');
@ -212,6 +225,15 @@ export class EditPage extends React.Component {
this.props.changeData({ target });
}
handleRedirect = ({ model, id, source = 'content-manager'}) => {
const pathname = `${this.props.match.path.replace(':slug', model).replace(':id', id)}`;
this.props.history.push({
pathname,
search: `?source=${source}&redirectURI=${generateRedirectURI({ model, search: `?source=${source}` })}`,
});
}
handleSubmit = (e) => {
e.preventDefault();
const formErrors = checkFormValidity(this.generateFormFromRecord(), this.props.editPage.formValidations);
@ -330,6 +352,7 @@ export class EditPage extends React.Component {
changeData={this.props.changeData}
record={editPage.record}
schema={this.getSchema()}
onRedirect={this.handleRedirect}
/>
)}
</div>

View File

@ -87,9 +87,10 @@ export function* submit() {
// Show button loader
yield put(setLoader());
const recordCleaned = Object.keys(record).reduce((acc, current) => {
const attrType = source !== 'content-manager' ? get(schema, ['plugins', source, currentModelName, 'fields', current, 'type'], null) : get(schema, [currentModelName, 'fields', current, 'type'], null);
const attrType = source !== 'content-manager' ? get(schema, ['models', 'plugins', source, currentModelName, 'fields', current, 'type'], null) : get(schema, ['models', currentModelName, 'fields', current, 'type'], null);
const cleanedData = attrType === 'json' ? record[current] : cleanData(record[current], 'value', 'id');
if (isString(cleanedData) || isNumber(cleanedData)) {
acc.append(current, cleanedData);
} else if (findIndex(fileRelations, ['name', current]) !== -1) {
@ -114,6 +115,11 @@ export function* submit() {
return acc;
}, new FormData());
// Helper to visualize FormData
// for(var pair of recordCleaned.entries()) {
// console.log(pair[0]+ ', '+ pair[1]);
// }
const id = isCreating ? '' : record.id || record._id;
const params = { source };
// Change the request helper default headers so we can pass a FormData

View File

@ -62,6 +62,7 @@ import {
generateFiltersFromSearch,
generateSearchFromFilters,
generateSearchFromParams,
generateRedirectURI,
} from './utils';
import styles from './styles.scss';
@ -177,9 +178,7 @@ export class ListPage extends React.Component {
* Generate the redirect URI when editing an entry
* @type {String}
*/
generateRedirectURI = () => (
`?redirectUrl=/plugins/content-manager/${this.getCurrentModelName().toLowerCase()}${this.generateSearch()}`
);
generateRedirectURI = generateRedirectURI.bind(this);
generateSearch = () => {
const {

View File

@ -50,8 +50,17 @@ const generateSearchFromParams = params =>
return acc;
}, '');
/**
* Generate the redirect URI when editing an entry
* @type {String}
*/
const generateRedirectURI = function ({ model, search } = {}) {
return `?redirectUrl=/plugins/content-manager/${(model || this.getCurrentModelName()).toLowerCase()}${(search || this.generateSearch())}`;
};
export {
generateFiltersFromSearch,
generateSearchFromFilters,
generateSearchFromParams,
generateRedirectURI,
};

View File

@ -27,6 +27,7 @@
"react-dnd": "^5.0.0",
"react-dnd-html5-backend": "^5.0.1",
"react-select": "^1.2.1",
"react-sortable-hoc": "^0.8.3",
"showdown": "^1.8.6",
"strapi-helper-plugin": "3.0.0-alpha.13.0.1"
},

View File

@ -1 +1,144 @@
{}
{
"Auth.form.button.register-success" : "Invia di nuovo",
"Auth.form.button.forgot-password.success" : "Invia di nuovo",
"Auth.form.button.forgot-password" : "Invia Email",
"Auth.form.button.reset-password" : "Cambia password",
"Auth.form.button.login" : "Accedi",
"Auth.form.button.register" : "Inizia adesso",
"Auth.form.error.noAdminAccess" : "Non puoi accedere al pannello di amministrazione.",
"Auth.form.forgot-password.email.label" : "Inserisci la tua email",
"Auth.form.forgot-password.email.label.success" : "Email inviata correttamente",
"Auth.form.forgot-password.email.placeholder" : "mysuperemail@gmail.com",
"Auth.header.register.description" : "Per terminare l'installazione e mettere in sicurezza la tua applicazione è necessario creare il primo utente (root admin) inserendo le informazioni necessarie di seguito riportate",
"Auth.form.header.login" : "strapi",
"Auth.form.header.forgot-password" : "strapi",
"Auth.form.header.register" : "Benvenuto!",
"Auth.form.header.register-success" : "strapi",
"Auth.form.login.password.label" : "Password",
"Auth.form.login.rememberMe.label" : "Ricordati di me",
"Auth.form.login.username.label" : "Username",
"Auth.form.login.username.placeholder" : "John Doe",
"Auth.form.register.email.label" : "Email",
"Auth.form.register.email.placeholder" : "johndoe@gmail.com",
"Auth.form.register.username.label" : "Username",
"Auth.form.register.username.placeholder" : "John Doe",
"Auth.form.register.password.label" : "Password",
"Auth.form.register.confirmPassword.label" : "Password di conferma",
"Auth.form.register.news.label" : "Tienimi aggiornato su nuove funzionalità e futuri miglioramenti",
"Auth.form.register-success.email.label" : "Email inviata con successo a",
"Auth.form.register-success.email.placeholder" : "mysuperemail@gmail.com",
"Auth.form.error.email.provide" : "Per favore fornisci il tuo username o la tua password",
"Auth.form.error.email.invalid" : "Questa email non è valida.",
"Auth.form.error.password.provide" : "Per favore fornisci la tua password",
"Auth.form.error.invalid" : "Identificatore o password non valida.",
"Auth.form.error.password.local" : "Questo utente non ha mai impostato una password locale, accedi gentilmente tramite il provider usato durante la creazione dell'account",
"Auth.form.error.password.format" : "La tua password non può contenere il simbolo $ per più di tre volte.",
"Auth.form.error.user.not-exist" : "Questa email non esiste.",
"Auth.form.error.code.provide" : "Codice fornito non corretto.",
"Auth.form.error.password.matching" : "La password non corrisponde.",
"Auth.form.error.params.provide" : "I parametri forniti non sono corretti.",
"Auth.form.error.username.taken" : "Username in uso",
"Auth.form.error.email.taken" : "Email in uso",
"Auth.link.forgot-password" : "Password dimenticata?",
"Auth.link.ready" : "Sei pronto per accedere?",
"BoundRoute.title" : "Percorso vincolato a",
"components.Input.error.password.noMatch" : "La password non corrisponde",
"Controller.input.label" : "{label}",
"Controller.selectAll" : "Seleziona tutto",
"EditForm.inputSelect.label.role" : "Ruolo di default per gli utenti autenticati",
"EditForm.inputSelect.description.role" : "Questa operazione associerà i nuovi utenti autenticati al ruolo selezionato.",
"EditForm.inputSelect.subscriptions.label" : "Gestisci le sottoscrizioni di quota",
"EditForm.inputSelect.subscriptions.description" : "Limita il numero di sottoscrizioni per IP per ora.",
"EditForm.inputSelect.durations.label" : "Durata",
"EditForm.inputSelect.durations.description" : "Numero di ore in cui l'utente non può registrarsi",
"EditForm.inputToggle.label.email" : "Un account per indirizzo email",
"EditForm.inputToggle.label.sign-up" : "Abilita iscrizioni",
"EditForm.inputToggle.description.email" : "Non consentire all'utente di creare account multipli usando lo stesso indirizzo email con fornitori di autenticazione diversi.",
"EditForm.inputToggle.description.sign-up" : "Quando disabilitata (OFF), il processo di registrazione è proibito. Nessuno può iscriversi indipendentemente dal fornitore utilizzato.",
"EditPage.cancel" : "Cancella",
"EditPage.submit" : "Salva",
"EditPage.form.roles" : "Dettagli del ruolo",
"EditPage.form.roles.label.description" : "Descrizione",
"EditPage.form.roles.label.name" : "Nome",
"EditPage.form.roles.label.users" : "Utente associato con questo ruolo ({number})",
"EditPage.form.roles.name.error" : "Questo valore è obbligatorio",
"EditPage.header.title" : "{name}",
"EditPage.header.title.create" : "Crea un nuovo ruolo",
"EditPage.header.description" : "{description}",
"EditPage.header.description.create" : "Crea",
"EditPage.notification.permissions.error" : "Si è verificato un errore durante il recupero dei permessi",
"EditPage.notification.policies.error" : "Si è verificato un errore durante il recupero delle policy",
"EditPage.notification.role.error" : "Si è verificato un errore durante il recupero del ruolo",
"eaderNav.link.advancedSettings" : "Impostazioni avanzate",
"HeaderNav.link.emailTemplates" : "Template delle Email",
"HeaderNav.link.providers" : "Providers",
"HeaderNav.link.roles" : "Ruoli e permessi",
"HomePage.header.title" : "Ruoli e permessi",
"HomePage.header.description" : "Definisci i ruoli e i permessi per i tuoi utenti.",
"InputSearch.placeholder" : "Cerca un utente",
"List.button.roles" : "Aggiungi un ruolo",
"List.button.providers" : "Aggiungi un nuovo Provider",
"List.title.emailTemplates.singular" : "{number} template per le email disponibile",
"List.title.emailTemplates.plural" : "{number} template per le email disponibili",
"List.title.providers.disabled.singular" : "{number} disabilitato",
"List.title.providers.disabled.plural" : "{number} sono disabilitati",
"List.title.providers.enabled.singular" : "{number} provider è abilitato e",
"List.title.providers.enabled.plural" : "{number} providers sono disponibili e",
"List.title.roles.singular" : "{number} ruolo disponibile",
"List.title.roles.plural" : "{number} ruoli disponibili",
"notification.error.delete" : "Si è verificato un errore mentre si stava cercando di eliminare l'elemento",
"notification.error.fetch" : "Si è verificato un errore mentre si stava cercando di recuperare i dati",
"notification.error.fetchUser" : "Si è verificato un errore mentre si stava cercando di recuperare gli utenti",
"notification.info.emailSent" : "Email inviata",
"notification.success.delete" : "L'elemento è stato eliminato",
"notification.success.submit" : "Impostazioni aggiornate",
"plugin.description.short" : "Proteggi le tue API con un processo completo di autenticazione basato su JWT",
"plugin.description.long" : "Proteggi le tue API con un processo completo di autenticazione basato su JWT. Questo plugin è implementato con una strategia ACL che ti consente di gestire i permessi tra i gruppi di utenti.",
"Plugin.permissions.application.description" : "Definire tutte le azioni consentite per il tuo progetto.",
"Plugin.permissions.plugins.description" : "Definire tutte le azioni consentite per il plugin {name}.",
"Plugins.header.title" : "Permessi",
"Plugins.header.description" : "Solo le azioni guidate da un percorso sono elencate sotto.",
"Policies.InputSelect.empty" : "Nessuno",
"Policies.InputSelect.label" : "Consenti di eseguire questa azione per:",
"Policies.header.hint" : "Seleziona le azioni dell'applicazione o del plugin e clicca sull'icona cog per mostrare il percorso corrispondente",
"Policies.header.title" : "Impostazioni avanzate",
"Email.template.validation_email" : "Validazione dell'indirizzo Email",
"Email.template.reset_password" : "Reset password",
"Email.template.success_register" : "Registrazione avvenuta",
"Auth.advanced.allow_register" : "Registrazione consentita",
"PopUpForm.button.cancel" : "Cancella",
"PopUpForm.button.save" : "Salva",
"PopUpForm.header.add.providers" : "Aggiungi nuovo Provider",
"PopUpForm.header.edit.email-templates" : "Modifica il template delle Email",
"PopUpForm.header.edit.providers" : "Modifica {provider} Provider",
"PopUpForm.inputSelect.providers.label" : "Scegli il provider",
"PopUpForm.Email.options.from.name.label" : "Nome del mittente",
"PopUpForm.Email.options.from.email.label" : "Email del mittente",
"PopUpForm.Email.options.response_email.label" : "Email di risposta",
"PopUpForm.Email.options.object.label" : "Soggetto",
"PopUpForm.Email.options.message.label" : "Messaggio",
"PopUpForm.Email.validation_email.options.object.placeholder" : "Conferma gentilmente il tuo indirizzo email per %APP_NAME%",
"PopUpForm.Email.reset_password.options.object.placeholder" : "Conferma gentilmente il tuo indirizzo email per %APP_NAME%",
"PopUpForm.Email.success_register.options.object.placeholder" : "Conferma gentilmente il tuo indirizzo email per %APP_NAME%",
"PopUpForm.Email.validation_email.options.message.placeholder" : "Clicca su questo link per validare il tuo account",
"PopUpForm.Email.reset_password.options.message.placeholder" : "Clicca su questo link per validare il tuo account",
"PopUpForm.Email.success_register.options.message.placeholder" : "Clicca su questo link per validare il tuo account",
"PopUpForm.Email.options.from.email.placeholder" : "johndoe@gmail.com",
"PopUpForm.Email.options.response_email.placeholder" : "johndoe@gmail.com",
"PopUpForm.Email.options.from.name.placeholder" : "John Doe",
"PopUpForm.Providers.enabled.label" : "Abilita",
"PopUpForm.Providers.enabled.description" : "Se disabilitato, gli utenti non potranno usare questo provider.",
"opUpForm.Providers.key.label" : "Client ID",
"PopUpForm.Providers.key.placeholder" : "TEXT",
"PopUpForm.Providers.secret.label" : "Client Secret",
"PopUpForm.Providers.secret.placeholder" : "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label" : "L'URL di redirect per la tua app di front-end",
"PopUpForm.Providers.facebook.providerConfig.redirectURL" : "L'URL di redirect per aggiungere la tua configurazione dell'applicazione Facebook",
"PopUpForm.Providers.google.providerConfig.redirectURL" : "L'URL di redirect per aggiungere la tua configurazione dell'applicazione Google",
"PopUpForm.Providers.github.providerConfig.redirectURL" : "L'URL di redirect per aggiungere la tua configurazione dell'applicazione Github",
"PopUpForm.Providers.linkedin2.providerConfig.redirectURL" : "L'URL di redirect per aggiungere la tua configurazione dell'applicazione Linkdin",
"PopUpForm.Providers.twitter.providerConfig.redirectURL" : "L'URL di redirect per aggiungere la tua configurazione dell'applicazione Twitter",
"PopUpForm.Providers.callback.placeholder" : "TEXT",
"PopUpForm.Email.email_templates.inputDescription" : "Se non sai bene come usare le variabili, {link}",
"PopUpForm.Email.link.documentation" : "controlla la documentazione"
}

View File

@ -14,6 +14,14 @@ module.exports = strapi => {
},
initialize: function(cb) {
console.log();
_.forEach(strapi.admin.config.routes, value => {
if (_.get(value.config, 'policies')) {
value.config.policies.unshift('plugins.users-permissions.permissions');
}
});
_.forEach(strapi.config.routes, value => {
if (_.get(value.config, 'policies')) {
value.config.policies.unshift('plugins.users-permissions.permissions');

View File

@ -40,4 +40,4 @@
"configurable": false
}
}
}
}

View File

@ -116,7 +116,9 @@ module.exports = {
}, {}));
const appControllers = Object.keys(strapi.api || {}).reduce((acc, key) => {
acc.controllers[key] = generateActions(strapi.api[key].controllers[key]);
Object.keys(strapi.api[key].controllers).forEach((controller) => {
acc.controllers[controller] = generateActions(strapi.api[key].controllers[controller]);
});
return acc;
}, { controllers: {} });
@ -203,7 +205,7 @@ module.exports = {
const databasePermissions = await strapi.query('permission', 'users-permissions').find();
const actions = databasePermissions
.map(permission => `${permission.type}.${permission.controller}.${permission.action}`);
// Aggregate first level actions.
const appActions = Object.keys(strapi.api || {}).reduce((acc, api) => {