التحقّق من صحة متغيّر إدخال

يوضّح هذا الدليل كيفية التحقّق من صحة متغيّر إدخال.

عند تحديد متغيّر إدخال، من أفضل الممارسات التحقّق من أنّ المستخدم يدخل قيمة مناسبة. على سبيل المثال، إذا طلبت من المستخدم إدخال رقم، سيؤدي التحقّق من إدخاله 1 بدلاً من a إلى التأكّد من أنّ خطوتك تعمل بدون أخطاء.

هناك طريقتان للتحقّق من صحة متغيّر إدخال:

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

التحقّق من صحة البيانات من جهة العميل

تتوفّر طريقتان لتنفيذ عملية التحقّق من الصحة من جهة العميل:

  • لإجراء عمليات التحقّق الأساسية، مثل التأكّد من أنّ إحدى الأدوات تحتوي على عدد أقل من عدد معيّن من الأحرف أو أنّها تحتوي على الرمز @، استدعِ الفئة Validation من خدمة "البطاقات" في إضافة Google Workspace.
  • لإجراء عملية تحقّق قوية، مثل مقارنة قيم عناصر واجهة المستخدم بقيم عناصر واجهة مستخدم أخرى، يمكنك إضافة عملية التحقّق باستخدام "لغة التعبير العادي" (CEL) إلى عناصر واجهة المستخدم التالية المتوافقة مع البطاقات باستخدام CardService.

استدعاء الفئة Validation

يتحقّق المثال التالي من أنّ أداة TextInput تحتوي على 10 أحرف أو أقل:

برمجة التطبيقات

const validation = CardService.newValidation().setCharacterLimit('10').setInputType(
    CardService.InputType.TEXT);

للحصول على خيارات تحقّق إضافية، استخدِم التحقّق من صحة CEL.

التحقّق من صحة CEL

توفّر عملية التحقّق من صحة Common Expression Language (CEL) عمليات تحقّق فورية من الإدخالات بدون تأخير عملية التحقّق من صحة البيانات من جهة الخادم، وذلك من خلال نقل عمليات التحقّق من قيم الإدخالات التي لا تعتمد على البحث عن البيانات من خدمات أخرى إلى جهة العميل.

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

يتضمّن إنشاء عملية التحقّق الكاملة من صحة CEL المكوّنات التالية:

  • ExpressionData في البطاقة: يحتوي على منطق التحقّق من الصحة المحدّد ومنطق تشغيل الأداة عندما يتم استيفاء أحد الشروط المحدّدة.

    • Id: معرّف فريد لـ ExpressionData ضمن البطاقة الحالية.
    • Expression: سلسلة CEL التي تحدّد منطق التحقّق (مثلاً، "value1 == value2").
    • Conditions: قائمة بالشروط التي تتضمّن مجموعة من نتائج التحقّق المحدّدة مسبقًا (SUCCESS أو FAILURE). ترتبط الشروط بجانب الأداة EventAction من خلال Triggers باستخدام actionRuleId مشترَك.
    • على مستوى البطاقة EventAction: يتم تفعيل عمليات التحقّق من صحة بيانات CEL في البطاقة وربط الحقل ExpressionData بأدوات نتائج البحث من خلال مشغّلات ما بعد الحدث.
      • actionRuleId: المعرّف الفريد لهذا EventAction.
      • ExpressionDataAction: اضبط القيمة على START_EXPRESSION_EVALUATION للإشارة إلى أنّ هذا الإجراء يبدأ تقييم CEL.
      • Trigger: يربط Conditions بـ EventActions من جهة الأداة استنادًا إلى actionRuleId.
  • EventAction على مستوى الأداة: تتحكّم في سلوك أداة النتائج عند استيفاء شرط النجاح أو الفشل. يمكن أن يكون عنصر واجهة المستخدم الخاص بالنتائج، على سبيل المثال، TextParagraph يحتوي على رسالة خطأ لا تظهر إلا عند فشل عملية التحقّق.

    • actionRuleId: تطابق actionRuleId في Trigger على جانب البطاقة.
    • CommonWidgetAction: تحدّد الإجراءات التي لا تتضمّن تقييمات، مثل تعديل مستوى ظهور التطبيق المصغّر.
      • UpdateVisibilityAction: إجراء يعدّل حالة ظهور أداة (VISIBLE أو HIDDEN).

يوضّح المثال التالي كيفية تنفيذ عملية التحقّق من صحة CEL للتأكّد مما إذا كان إدخالان نصيان متساويين. تظهر رسالة خطأ إذا لم يكونا متساويين.

  • عند استيفاء failCondition (عدم تساوي المدخلات)، يتم ضبط أداة رسالة الخطأ على VISIBLE وتظهر.
    الشكل 1: عند استيفاء failCondition (عدم تساوي القيم المُدخَلة)، يتم ضبط أداة رسالة الخطأ على VISIBLE وتظهر.
  • عند استيفاء شرط النجاح (تكون المدخلات متساوية)، يتم ضبط أداة رسالة الخطأ على HIDDEN ولا تظهر.
    الشكل 2: عند استيفاء successCondition (تكون المدخلات متساوية)، يتم ضبط أداة رسالة الخطأ على HIDDEN ولا تظهر.

في ما يلي مثال على رمز التطبيق وملف بيان JSON:

برمجة التطبيقات

function onConfig() {

  // Create a Card
  let card = CardService.newCardBuilder();

  const textInput_1 = CardService.newTextInput()
    .setTitle("Input number 1")
    .setFieldName("value1"); // FieldName's value must match a corresponding ID defined in the inputs[] array in the manifest file.
  const textInput_2 = CardService.newTextInput()
    .setTitle("Input number 2")
    .setFieldName("value2"); // FieldName's value must match a corresponding ID defined in the inputs[] array in the manifest file.
  let sections = CardService.newCardSection()
    .setHeader("Two number equals")
    .addWidget(textInput_1)
    .addWidget(textInput_2);

  // CEL Validation

  // Define Conditions
  const condition_success = CardService.newCondition()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID")
    .setExpressionDataCondition(
      CardService.newExpressionDataCondition()
      .setConditionType(
        CardService.ExpressionDataConditionType.EXPRESSION_EVALUATION_SUCCESS));
  const condition_fail = CardService.newCondition()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID")
    .setExpressionDataCondition(
      CardService.newExpressionDataCondition()
      .setConditionType(
        CardService.ExpressionDataConditionType.EXPRESSION_EVALUATION_FAILURE));

  // Define Card-side EventAction
  const expressionDataAction = CardService.newExpressionDataAction()
    .setActionType(
      CardService.ExpressionDataActionType.START_EXPRESSION_EVALUATION);
  // Define Triggers for each Condition respectively
  const trigger_success = CardService.newTrigger()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID");
  const trigger_failure = CardService.newTrigger()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID");

  const eventAction = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_EVALUATION_RULE_ID")
    .setExpressionDataAction(expressionDataAction)
    .addPostEventTrigger(trigger_success)
    .addPostEventTrigger(trigger_failure);

  // Define ExpressionData for the current Card
  const expressionData = CardService.newExpressionData()
    .setId("expData_id")
    .setExpression("value1 == value2") // CEL expression
    .addCondition(condition_success)
    .addCondition(condition_fail)
    .addEventAction(eventAction);
  card = card.addExpressionData(expressionData);

  // Create Widget-side EventActions and a widget to display error message
  const widgetEventActionFail = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_FAILURE_RULE_ID")
    .setCommonWidgetAction(
      CardService.newCommonWidgetAction()
      .setUpdateVisibilityAction(
        CardService.newUpdateVisibilityAction()
        .setVisibility(
          CardService.Visibility.VISIBLE)));
  const widgetEventActionSuccess = CardService.newEventAction()
    .setActionRuleId("CEL_TEXTINPUT_SUCCESS_RULE_ID")
    .setCommonWidgetAction(
      CardService.newCommonWidgetAction()
      .setUpdateVisibilityAction(
        CardService.newUpdateVisibilityAction()
        .setVisibility(
          CardService.Visibility.HIDDEN)));
  const errorWidget = CardService.newTextParagraph()
    .setText("The first and second value must match.")
    .setVisibility(CardService.Visibility.HIDDEN) // Initially hidden
    .addEventAction(widgetEventActionFail)
    .addEventAction(widgetEventActionSuccess);
  sections = sections.addWidget(errorWidget);

  card = card.addSection(sections);
  // Build and return the Card
  return card.build();
}

ملف البيان بتنسيق JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "CEL validation example",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/calculator_search/v1/web-24dp/logo_calculator_search_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "CEL Demo",
          "description": "Demonstrates CEL Validation",
          "workflowAction": {
            "inputs": [
              {
                "id": "value1",
                "description": "The first number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              },
              {
                "id": "value2",
                "description": "The second number",
                "cardinality": "SINGLE",
                "dataType": {
                  "basicType": "INTEGER"
                }
              }
            ],
            "onConfigFunction": "onConfig",
            "onExecuteFunction": "onExecute"
          }
        }
      ]
    }
  }
}

أدوات وعمليات التحقّق من صحة CEL المتوافقة

أدوات البطاقات التي تتوافق مع التحقّق من صحة CEL

تتيح التطبيقات المصغّرة التالية التحقّق من صحة تعبيرات CEL:

  • TextInput
  • SelectionInput
  • DateTimePicker

عمليات التحقّق من صحة CEL المتوافقة

  • العمليات الحسابية
    • +: تضيف رقمَين من int64 أو uint64 أو double.
    • -: تطرح هذه الدالة رقمَين من النوع int64 أو uint64 أو double.
    • *: تضرب هذه الدالة رقمَين من النوع int64 أو uint64 أو double.
    • /: تقسم عددَين من النوع int64 أو uint64 أو double (القسمة الصحيحة).
    • %: تحسب هذه الدالة باقي القسمة بين عددَين من النوع int64 أو uint64.
    • -: تنفي رقم int64 أو uint64.
  • العمليات المنطقية:
    • &&: تنفّذ عملية AND منطقية على قيمتَين منطقيتَين.
    • ||: تنفّذ عملية OR منطقية على قيمتَين منطقيتَين.
    • !: تنفّذ عملية NOT منطقية على قيمة منطقية.
  • عمليات المقارنة:
    • ==: تتحقّق هذه الدالة ممّا إذا كانت قيمتان متساويتَين. يتيح استخدام الأرقام والقوائم.
    • !=: تتحقّق مما إذا كانت قيمتان غير متساويتين. يتيح استخدام الأرقام والقوائم.
    • <: تتحقّق هذه الدالة ممّا إذا كان الرقم الأول int64 أو uint64 أو double أصغر من الرقم الثاني.
    • <=: تتحقّق مما إذا كان الرقم الأول int64 أو uint64 أو double أصغر من الرقم الثاني أو يساويه.
    • >: تتحقّق هذه الدالة ممّا إذا كان الرقم الأول int64 أو uint64 أو double أكبر من الرقم الثاني.
    • >=: تتحقّق مما إذا كان الرقم الأول int64 أو uint64 أو double أكبر من الرقم الثاني أو يساويه.
  • عمليات القوائم:
    • in: تتحقّق مما إذا كانت قيمة معيّنة متوفّرة في قائمة. يتيح استخدام الأرقام والسلاسل والقوائم المتداخلة.
    • size: تعرض عدد العناصر في قائمة. تتيح استخدام الأرقام والقوائم المتداخلة.

سيناريوهات التحقّق غير المتاحة من شهادة CEL

  • أحجام الوسيطات غير صحيحة للعمليات الثنائية: تتطلّب العمليات الثنائية (مثل add_int64، يساوي) وسيطتَين بالضبط. سيؤدي تقديم عدد مختلف من الوسيطات إلى ظهور خطأ.
  • أحجام وسيطات غير صحيحة للعمليات الأحادية: تتطلّب العمليات الأحادية (مثل negate_int64) وسيطة واحدة بالضبط. سيؤدي تقديم عدد مختلف من الوسيطات إلى ظهور خطأ.
  • الأنواع غير المتوافقة في العمليات العددية: تقبل العمليات الثنائية والأحادية العددية وسيطات الأرقام فقط. سيؤدي توفير أنواع أخرى (مثل القيمة المنطقية) إلى ظهور خطأ.

التحقّق على صعيد الخادم

باستخدام عملية التأكّد من صحة البيانات من جهة الخادم، يمكنك تنفيذ منطق من جهة الخادم من خلال تحديد onSaveFunction() في رمز خطوتك. عندما ينتقل المستخدم بعيدًا عن بطاقة إعداد الخطوة، يتم تشغيل onSaveFunction() ويتيح لك التحقّق من إدخال المستخدم.

إذا كان إدخال المستخدم صالحًا، ارجع إلى saveWorkflowAction.

إذا كانت بيانات المستخدم غير صالحة، عليك عرض بطاقة إعدادات تعرض رسالة خطأ للمستخدم توضّح له كيفية حلّ المشكلة.

بما أنّ عملية التأكّد من صحة البيانات من جهة الخادم غير متزامنة، قد لا يعرف المستخدم بشأن خطأ الإدخال إلى أن ينشر التدفق.

يجب أن يتطابق id لكل إدخال تم التحقّق من صحته في ملف البيان مع name لأداة بطاقة في الرمز.

يتحقّق المثال التالي من أنّ إدخال نص المستخدم يتضمّن علامة "@":

ملف البيان

يحدّد مقتطف ملف البيان onSaveFunction() باسم "onSave":

JSON

{
  "timeZone": "America/Los_Angeles",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "Server-side validation example",
      "logoUrl": "https://www.gstatic.com/images/branding/productlogos/calculator_search/v1/web-24dp/logo_calculator_search_color_1x_web_24dp.png",
      "useLocaleFromApp": true
    },
    "flows": {
      "workflowElements": [
        {
          "id": "actionElement",
          "state": "ACTIVE",
          "name": "Calculate",
          "description": "Asks the user for an email address",
          "workflowAction": {
            "inputs": [
              {
                "id": "email",
                "description": "email address",
                "cardinality": "SINGLE",
                "required": true,
                "dataType": {
                  "basicType": "STRING"
                }
              }
            ],
            "onConfigFunction": "onConfigCalculate",
            "onExecuteFunction": "onExecuteCalculate",
            "onSaveFunction": "onSave"
          }
        }
      ]
    }
  }
}

رمز التطبيق

يتضمّن رمز الخطوة دالة باسم onSave(). تتحقّق هذه السمة من أنّ السلسلة التي أدخلها المستخدم تتضمّن الرمز @. وفي حال تضمّنها له، يتم حفظ خطوة المسار. إذا لم يكن الأمر كذلك، سيعرض بطاقة إعدادات تتضمّن رسالة خطأ توضّح كيفية حلّ المشكلة.

برمجة التطبيقات

/**
 * Validates user input asynchronously when the user
 * navigates away from a step's configuration card.
*/
function onSave(event) {

  // "email" matches the input ID specified in the manifest file.
  var email = event.workflow.actionInvocation.inputs["email"];

  // Validate that the email address contains an "@" sign:
  if(email.includes("@")) {

  // If successfully validated, save and proceed.
    return {
      "hostAppAction" : {
        "workflowAction" : {
          "saveWorkflowAction" : {}
        }
      }
    };

  // If the input is invalid, return a card with an error message
  } else {

var card = {
    "sections": [
      {
        "header": "Collect Email",
        "widgets": [
          {
            "textInput": {
              "name": "email",
              "label": "email address",
              "hostAppDataSource" : {
                "workflowDataSource" : {
                  "includeVariables" : true
                }
              }
            }
          },
          {
            "textParagraph": {
              "text": "<b>Error:</b> Email addresses must include the '@' sign.",
              "maxLines": 1
            }
          }
        ]
      }
    ]
  };
  return pushCard(card);
  }
}