Skip to content

Commit

Permalink
Implemented 3P resources creation function for Python
Browse files Browse the repository at this point in the history
  • Loading branch information
pierrick committed Jan 19, 2024
1 parent 25d386a commit a88606d
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 6 deletions.
2 changes: 1 addition & 1 deletion apps-script/3p-resources/3p-resources.gs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ function validateFormInputs(caseDetails) {
if (caseDetails.priority === undefined) {
errors.priority = 'You must provide a priority';
}
if (caseDetails.impact && caseDetails.priority === 'P2' || caseDetails.impact && caseDetails.priority === 'P3') {
if (caseDetails.impact && !(['P0', 'P1']).includes(caseDetails.priority)) {
errors.impact = 'If an issue blocks a critical customer operation, priority must be P0 or P1';
}

Expand Down
2 changes: 1 addition & 1 deletion node/3p-resources/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ function validateFormInputs(caseDetails) {
if (caseDetails.priority === undefined) {
errors.priority = 'You must provide a priority';
}
if (caseDetails.impact && caseDetails.priority === 'P2' || caseDetails.impact && caseDetails.priority === 'P3') {
if (caseDetails.impact && !(['P0', 'P1']).includes(caseDetails.priority)) {
errors.impact = 'If an issue blocks a critical customer operation, priority must be P0 or P1';
}

Expand Down
231 changes: 229 additions & 2 deletions python/3p-resources/create_3p_resources/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
from typing import Any, Mapping
from urllib.parse import urlparse

import os
import json
import flask
import functions_framework

Expand All @@ -29,10 +31,235 @@ def create_3p_resources(req: flask.Request):
The response object.
"""
event = req.get_json(silent=True)
if event["docs"]["matchedUrl"]["url"]:
return create_card(event["docs"]["matchedUrl"]["url"])
parameters = event["commonEventObject"]["parameters"] if "parameters" in event["commonEventObject"] else None
if parameters is not None and parameters["submitCaseCreationForm"]:
return submit_case_creation_form(event)
else:
return create_case_input_card(event)


# [START add_ons_3p_resources_create_case_card]


def create_case_input_card(event, errors = {}, isUpdate = False):
"""A support case link preview.
Args:
event: The event object.
errors: An optional dict of per-field error messages.
isUpdate: Whether to return the form as an updateCard navigation.
Returns:
A card or an action reponse.
"""
card_header1 = {
"title": "Create a support case"
}

card_section1_text_input1 = {
"textInput": {
"name": "name",
"label": "Name"
}
}

card_section1_text_input2 = {
"textInput": {
"name": "description",
"label": "Description",
"type": "MULTIPLE_LINE"
}
}

card_section1_selection_input1 = {
"selectionInput": {
"name": "priority",
"label": "Priority",
"type": "DROPDOWN",
"items": [{
"text": "P0",
"value": "P0"
}, {
"text": "P1",
"value": "P1"
}, {
"text": "P2",
"value": "P2"
}, {
"text": "P3",
"value": "P3"
}]
}
}

card_section1_selection_input2 = {
"selectionInput": {
"name": "impact",
"label": "Impact",
"items": [{
"text": "Blocks a critical customer operation",
"value": "Blocks a critical customer operation"
}]
}
}

card_section1_button_list1_button1_action1 = {
"function": os.environ["URL"],
"parameters": [
{
"key": "submitCaseCreationForm",
"value": True
}
],
"persistValues": True
}

card_section1_button_list1_button1 = {
"text": "Create",
"onClick": {
"action": card_section1_button_list1_button1_action1
}
}

card_section1_button_list1 = {
"buttonList": {
"buttons": [card_section1_button_list1_button1]
}
}

# Builds the creation form and adds error text for invalid inputs.
card_section1 = []
if "name" in errors:
card_section1.append(create_error_text_paragraph(errors["name"]))
card_section1.append(card_section1_text_input1)
if "description" in errors:
card_section1.append(create_error_text_paragraph(errors["description"]))
card_section1.append(card_section1_text_input2)
if "priority" in errors:
card_section1.append(create_error_text_paragraph(errors["priority"]))
card_section1.append(card_section1_selection_input1)
if "impact" in errors:
card_section1.append(create_error_text_paragraph(errors["impact"]))

card_section1.append(card_section1_selection_input2)
card_section1.append(card_section1_button_list1)

card = {
"header": card_header1,
"sections": [{
"widgets": card_section1
}]
}

if isUpdate:
return {
"renderActions": {
"action": {
"navigations": [{
"updateCard": card
}]
}
}
}
else:
return {
"action": {
"navigations": [{
"pushCard": card
}]
}
}


# [END add_ons_3p_resources_create_case_card]
# [START add_ons_3p_resources_submit_create_case]


def submit_case_creation_form(event):
"""Called when the creation form is submitted.
If form input is valid, returns a render action that inserts a new link
into the document. If invalid, returns an updateCard navigation that
re-renders the creation form with error messages.
Args:
event: The event object.
Returns:
A card or an action reponse.
"""
formInputs = event["commonEventObject"]["formInputs"] if "formInputs" in event["commonEventObject"] else None
case_details = {
"name": None,
"description": None,
"priority": None,
"impact": None,
}
if formInputs is not None:
case_details["name"] = formInputs["name"]["stringInputs"]["value"][0] if "name" in formInputs else None
case_details["description"] = formInputs["description"]["stringInputs"]["value"][0] if "description" in formInputs else None
case_details["priority"] = formInputs["priority"]["stringInputs"]["value"][0] if "priority" in formInputs else None
case_details["impact"] = formInputs["impact"]["stringInputs"]["value"][0] if "impact" in formInputs else None

errors = validate_form_inputs(case_details)
if len(errors) > 0:
return create_case_input_card(event, errors, True) # Update mode
else:
title = f'Case {case_details["name"]}'
url = "https://example.com/support/cases/" + json.dumps(case_details, separators=(',', ':'))
return create_link_render_action(title, url)

# [END add_ons_3p_resources_submit_create_case]
# [START add_ons_3p_resources_validate_inputs]

def validate_form_inputs(case_details):
"""Validates form inputs for case creation.
Args:
case_details: The values of each form input submitted by the user.
Returns:
A dict from field name to error message. An empty object represents a valid form submission.
"""
errors = {}
if case_details["name"] is None:
errors["name"] = "You must provide a name"
if case_details["description"] is None:
errors["description"] = "You must provide a description"
if case_details["priority"] is None:
errors["priority"] = "You must provide a priority"
if case_details["impact"] is not None and case_details["priority"] not in ['P0', 'P1']:
errors["impact"] = "If an issue blocks a critical customer operation, priority must be P0 or P1"
return errors

def create_error_text_paragraph(error_message):
"""Returns a text paragraph with red text indicating a form field validation error.
Args:
error_essage: A description of the invalid input.
Returns:
A text paragraph.
"""
return {
"textParagraph": {
"text": '<font color=\"#BA0300\"><b>Error:</b> ' + error_message + '</font>'
}
}

# [END add_ons_3p_resources_validate_inputs]
# [START add_ons_3p_resources_link_render_action]

def create_link_render_action(title, url):
"""Returns a render action that inserts a link into the document.
Args:
title: The title of the link to insert.
url: The URL of the link to insert.
Returns:
A render action.
"""
return {
"renderActions": {
"action": {
"links": [{
"title": title,
"url": url
}]
}
}
}

# [END add_ons_3p_resources_link_render_action]
# [END add_ons_3p_resources]
3 changes: 1 addition & 2 deletions python/3p-resources/create_link_preview/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
from typing import Any, Mapping
from urllib.parse import urlparse, unquote

import json
import flask
import functions_framework
import json


@functions_framework.http
Expand Down Expand Up @@ -57,7 +57,6 @@ def case_link_preview(url):
# Parses the URL to identify the case details.
segments = url.split("/")
case_details = json.loads(unquote(segments[len(segments) - 1]));
print(case_details)

# Returns the card.
# Uses the text from the card's header for the title of the smart chip.
Expand Down

0 comments on commit a88606d

Please sign in to comment.