Aller au contenu principal

Permettre aux visiteurs d’enregistrer des modifications

Objectif​

Permettre à une personne sur votre portail de soumettre une demande, en modifier une ou en supprimer une — et pas seulement de lire.

Avant de commencer​

  • Un portail dont Qui peut l’ouvrir est réglé sur Personnes qui se connectent. L’écriture est refusée sur un portail que tout le monde peut ouvrir : il n’y aurait personne à qui attribuer la modification. Voir Demander aux visiteurs de se connecter.
  • Une API personnalisée pour chaque action autorisée. Une API qui lit n’est pas une API qui écrit, et la plateforme ne la traitera pas comme les deux à la fois.

Étapes​

  1. Écrivez la Custom API. Pour créer, donnez-lui le verbe POST ; pour modifier, PATCH ; pour supprimer, DELETE. Écrivez-lui un schéma de requête : c’est la première chose entre un visiteur et une colonne qu’il ne doit pas renseigner. Sans lui, le corps d’un visiteur ne peut porter que les champs que votre script lit avec getInput, et tout le reste est refusé.
  2. Ouvrez votre solution, choisissez Portails, puis ouvrez le portail.
  3. Sous Ce qu’il peut lire, appuyez sur Ajouter un élément à lire et choisissez :
    • la table que votre écran nomme dans createRecord / updateRecord / deleteRecord,
    • l’opération — Créer un enregistrement, Modifier un enregistrement ou Supprimer un enregistrement,
    • l’API qui y répond.
  4. Appuyez sur Enregistrer.

Chacune des cinq actions qu’un écran peut effectuer a besoin de sa propre ligne. Un portail qui peut lister des demandes ne peut pas en créer tant que vous n’avez pas ajouté aussi la ligne Création — ce sont deux contrats distincts, et la page ne peut nommer que la table.

Ce que fait votre écran​

Rien de nouveau. Les mêmes actions que celles que vous dessineriez pour une application à l’intérieur de la plateforme :

createRecord("par_request", {
par_name: getState("subject"),
par_detail: getState("detail")
}, "saved");

Sur un portail, cela devient un appel à l’API que vous avez autorisée pour par_request / Création. Le dessin est inchangé — c’est tout l’intérêt de publier une même application à deux endroits.

Ce que l’API doit faire​

Décider qui a le droit de faire cela, et renseigner ce que le visiteur ne doit pas renseigner.

var me = portalEmail();
if (me == '') {
throwValidationError('Sign in before raising a request.');
} else {
var subject = getInput('par_name');
if (subject == '') {
throwValidationError('Please give your request a subject.');
} else {
// **The visitor does not get to say who raised it.** Whatever the page sent for this column
// is ignored; the address comes off their signed-in session.
var id = createRecord('par_request', {
par_name: subject,
par_detail: getInput('par_detail'),
par_raised_by_email: me,
par_status: 'New'
});
setOutput('record', getRecord('par_request', id));
}
}

Tenir un visiteur à l’écart des colonnes qu’il ne doit pas renseigner​

Le portail transmet le corps exactement tel que la page l’a envoyé, et il ne peut pas faire autrement : les champs qu’un visiteur peut renseigner sont une question qui porte sur votre table, et seul votre contrat connaît la réponse.

Deux éléments y répondent, et il vous faut les deux.

Votre schéma de requête, qui refuse un champ que vous n’avez jamais promis. Définissez "additionalProperties": false et ne listez que ce qu’un visiteur peut envoyer :

{
"type": "object",
"additionalProperties": false,
"required": ["par_name"],
"properties": {
"par_name": { "type": "string", "minLength": 1, "maxLength": 200 }
}
}

Un corps contenant par_raised_by_email est désormais refusé avant même l’exécution de votre script.

La lecture de chaque champ par son nom, comme le fait le script ci-dessus. getInput('par_name') prend ce que vous avez demandé et rien d’autre.

Ne transmettez jamais le corps en entier

Un script qui remet le corps entier à createRecord permet à un visiteur de renseigner n’importe quelle colonne dont il devine le nom — y compris celle qui indique à qui appartient l’enregistrement. Le schéma rend cela difficile ; la lecture par nom le rend impossible.

Ce que voit le visiteur en cas d’échec​

  • Un refus que vous avez écrit — throwValidationError('Please give your request a subject.') — apparaît à côté du bouton sur lequel il a appuyé.
  • Tout le reste affiche un message général « l’enregistrement n’a pas pu être effectué », et la vraie raison est consignée dans le journal de l’hôte du portail.

Cette séparation est délibérée : votre phrase le concerne et il peut agir en conséquence, alors qu’une erreur interne n’a ni l’une ni l’autre de ces qualités.

Vos messages de validation sont lus par des inconnus

Comme le premier type de message est affiché, rédigez ces phrases pour le public. Ne nommez ni colonne, ni table, ni règle interne — « Veuillez donner un objet à votre demande » plutôt que « par_name failed constraint NOT NULL ».

Ce que la plateforme ne vérifie pas​

Si un visiteur peut relire ce qu’il vient d’écrire. Si votre API de création stocke un enregistrement que votre API de requête filtre, l’enregistrement existe et la liste ne l’affiche pas. Rien ne vous avertit : les deux scripts sont des contrats distincts, et la plateforme ne remet pas en cause une paire que vous avez écrite volontairement.

Si un écran enregistre quelque chose puis affiche une liste vide, c’est généralement cela — comparez le filtre de votre API de lecture avec ce que votre API d’écriture a stocké.

Le désactiver​

Retirez la ligne de Ce qu’il peut lire, ou remettez Qui peut l’ouvrir sur Tout le monde. L’une ou l’autre de ces actions arrête immédiatement l’écriture par le portail. La seconde l’arrête aussi dès l’enregistrement, même si les lignes sont toujours listées — un portail ouvert sert ses lectures et aucune de ses écritures.

Voir aussi​