إنتقل إلى المحتوى الرئيسي

دع الزوّار يحفظون التغييرات

الهدف​

دع أحدًا على بوابتك يرفع طلبًا أو يغيّره أو يحذفه — لا أن يقرأ فحسب.

قبل أن تبدأ​

  • بوابة من يمكنه فتحها فيها مضبوط على من يسجّل الدخول. الكتابة مرفوضة في بوابة يفتحها أي أحد: فلا أحد يُنسب إليه التغيير. انظر اطلب من الزوّار تسجيل الدخول.
  • واجهة Custom API لكل ما يجوز لهم فعله. فالتي تقرأ ليست التي تكتب، والمنصّة لا تعاملها كليهما.

الخطوات​

  1. اكتب الواجهة المخصّصة. للإنشاء اجعل فعلها POST؛ وللتغيير PATCH؛ وللحذف DELETE. اكتب لها مخطط طلب: إنه أول ما يقف بين الزائر وعمود لا ينبغي له ضبطه. من دونه لا يحمل جسم طلب الزائر إلا الحقول التي يقرؤها نصّك بـgetInput، ويُرفض كل ما سواها.
  2. افتح حلّك، واختر البوابات، ثم افتح البوابة.
  3. تحت ما الذي تقرؤه، اضغط أضف شيئًا للقراءة واختر:
    • الجدول الذي تسمّيه شاشتك في createRecord / updateRecord / deleteRecord،
    • العملية — إنشاء سجل أو تغيير سجل أو حذف سجل،
    • الواجهة التي تجيب.
  4. اضغط حفظ.

كل واحد من الخمسة التي تستطيع الشاشة فعلها يحتاج سطره الخاص. فبوابة تستطيع سرد الطلبات لا تستطيع إنشاء واحد حتى تضيف سطر الإنشاء أيضًا — فهما عقدان منفصلان، والصفحة لا تملك إلا تسمية الجدول.

ماذا تفعل شاشتك​

لا شيء جديد. الإجراءات نفسها التي كنت سترسمها لتطبيق داخل المنصّة:

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

وعلى البوابة يصير ذلك نداءً للواجهة التي سمحت بها لـ par_request / الإنشاء. الرسم لم يتغيّر — وهذا كل مقصد نشر تطبيق واحد في موضعين.

ماذا يجب أن تفعل الواجهة​

أن تقرّر من يُسمح له، وأن تملأ هي ما لا يجوز للزائر تحديده.

var me = portalEmail();
if (me == '') {
throwValidationError('سجّل الدخول قبل رفع طلب.');
} else {
var subject = getInput('par_name');
if (subject == '') {
throwValidationError('من فضلك أعطِ طلبك عنوانًا.');
} else {
// **الزائر لا يقرّر من رفعه.** ما أرسلته الصفحة لهذا العمود يُهمَل؛ والعنوان يأتي من جلسته
// المسجَّلة هو.
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));
}
}

أن تُبعد الزائر عن الأعمدة التي لا ينبغي له ضبطها​

تمرّر البوابة الجسم كما أرسلته الصفحة تمامًا، ولا تستطيع غير ذلك: فأي الحقول يجوز للزائر ضبطها سؤال عن جدولك أنت، ولا يعرف جوابه إلا عقدك.

يجيب عنه شيئان، وتريدهما معًا.

مخطّط طلبك، الذي يرفض حقلًا لم تَعِد به. اضبط "additionalProperties": false واسرد ما يجوز للزائر إرساله فقط:

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

فيُرفض الآن جسمٌ يحمل par_raised_by_email قبل أن يعمل سكربتك.

وقراءة كل حقل بالاسم، كما يفعل السكربت أعلاه. getInput('par_name') يأخذ ما طلبته لا غير.

لا تمرّر الجسم كاملًا أبدًا

السكربت الذي يسلّم الجسم كلّه إلى createRecord يتيح للزائر ضبط أي عمود يستطيع تخمين اسمه — بما في ذلك العمود الذي يقول لمن السجل. المخطّط يجعل ذلك صعبًا، والقراءة بالاسم تجعله مستحيلًا.

ماذا يرى الزائر عند الفشل​

  • رفضٌ كتبته أنت — throwValidationError('من فضلك أعطِ طلبك عنوانًا.') — يظهر بجوار الزر الذي ضغطه.
  • وأي شيء آخر يُظهر رسالة عامة «تعذّر الحفظ»، ويذهب السبب الحقيقي إلى سجل مضيف البوابة.

هذا الفصل مقصود: جملتك عنه هو ويستطيع التصرّف بناءً عليها، أما الخطأ الداخلي فليس كذلك.

رسائل التحقق عندك يقرؤها غرباء

ولأن النوع الأول يُعرض، اكتب تلك الجمل للعامة. لا تذكر عمودًا ولا جدولًا ولا قاعدة داخلية — «من فضلك أعطِ طلبك عنوانًا» بدل «par_name خالف قيد NOT NULL».

ما الذي لا تتحقق منه المنصّة​

أن يستطيع الزائر قراءة ما كتبه للتو. إن خزّنت واجهةُ الإنشاء سجلًا تُرشِّحه واجهةُ القراءة، فالسجل موجود والقائمة لا تعرضه. ولا شيء ينبّهك: فالسكربتان عقدان منفصلان، والمنصّة لا تراجع زوجًا كتبته أنت عن قصد.

فإن حفظت شاشة شيئًا ثم عرضت قائمة فارغة، فهذا هو السبب عادةً — قارن المرشِّح في واجهة القراءة بما خزّنته واجهة الكتابة.

إطفاؤه​

احذف السطر من ما الذي تقرؤه، أو أعد من يمكنه فتحها إلى الجميع. كلاهما يوقف كتابة البوابة في الحال. والثاني يوقفها منذ لحظة الحفظ وإن بقيت السطور مسرودة — فالبوابة المفتوحة تخدم قراءاتها ولا تخدم شيئًا من كتاباتها.

ذات صلة​