Skip to content

Commit

Permalink
Upgrade and fix preview-link code sample for Python to enable create …
Browse files Browse the repository at this point in the history
…3P resources
  • Loading branch information
pierrick committed Jan 19, 2024
1 parent aad3428 commit 25d386a
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 195 deletions.
10 changes: 7 additions & 3 deletions node/3p-resources/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2023 Google LLC
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -50,7 +50,7 @@ exports.createLinkPreview = (req, res) => {
*/
function caseLinkPreview(url) {

// Parses the URL to identify the case ID.
// Parses the URL to identify the case details.
const segments = url.split('/');
const caseDetails = JSON.parse(decodeURIComponent(segments[segments.length - 1]));

Expand Down Expand Up @@ -120,8 +120,10 @@ function peopleLinkPreview() {
};
}

// [END add_ons_people_preview_link]
// [END add_ons_preview_link]

// [START add_ons_3p_resources]
// [START add_ons_3p_resources_create_case_card]

/**
* Responds to any HTTP request related to 3P resource creations.
Expand All @@ -138,6 +140,8 @@ exports.create3pResources = (req, res) => {
}
};

// [START add_ons_3p_resources_create_case_card]

/**
* Produces a support case creation form.
*
Expand Down
82 changes: 82 additions & 0 deletions python/3p-resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Third-Party Resources

The solution is made of two Cloud Functions, one for the two link preview triggers and
one for the third-party resource create action trigger.
To learn about writing Cloud Functions,
see the documentation: https://cloud.google.com/functions/docs/writing.

For more information on preview link with Smart Chips, please read the
[guide](https://developers.google.com/apps-script/add-ons/editors/gsao/preview-links).

For more information on creating third-party resources from the @ menu, please read the
[guide](https://developers.devsite.corp.google.com/workspace/add-ons/guides/create-insert-resource-smart-chip).

## Create and deploy the Cloud Functions

### Turn on the Cloud Functions, Cloud Build, and the Add-ons API

```sh
gcloud services enable cloudfunctions cloudbuild.googleapis.com gsuiteaddons.googleapis.com
```

### Deploy the functions

```sh
gcloud functions deploy create_link_preview --runtime python312 --trigger-http --source ./create_link_preview
gcloud functions deploy create_3p_resources --runtime python312 --trigger-http --source ./create_3p_resources
```

### Set the URL of the create3pResources function

```sh
gcloud functions describe create_3p_resources
```

Run the following command after having replaced `$URL` with the deployed
function URL retrieved previously to set the environment variable `URL`.

```sh
gcloud functions deploy create_3p_resources --update-env-vars URL=$URL
```

## Create an add-on deployment

### Find the service account email for the add-on

```sh
gcloud workspace-add-ons get-authorization
```

### Grant the service account the ``cloudfunctions.invoker`` role

```sh
gcloud functions add-iam-policy-binding create_link_preview \
--role roles/cloudfunctions.invoker \
--member serviceAccount:SERVICE_ACCOUNT_EMAIL
gcloud functions add-iam-policy-binding create_3p_resources \
--role roles/cloudfunctions.invoker \
--member serviceAccount:SERVICE_ACCOUNT_EMAIL
```

### Set the URLs of the deployed functions

```sh
gcloud functions describe create_link_preview
gcloud functions describe create_3p_resources
```

Replace `$URL1` in deployment.json with the first deployed function URL
and replace `$URL2` in deployment.json with the second deployed function URL.

### Create the deployment

```sh
gcloud workspace-add-ons deployments create manageSupportCases \
--deployment-file=deployment.json
```

## Install the add-on

```sh
gcloud workspace-add-ons deployments install manageSupportCases
```
38 changes: 38 additions & 0 deletions python/3p-resources/create_3p_resources/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License")
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# [START add_ons_3p_resources]

from typing import Any, Mapping
from urllib.parse import urlparse

import flask
import functions_framework


@functions_framework.http
def create_3p_resources(req: flask.Request):
"""Responds to any HTTP request related to 3P resource creations.
Args:
req: HTTP request context.
Returns:
The response object.
"""
event = req.get_json(silent=True)
if event["docs"]["matchedUrl"]["url"]:
return create_card(event["docs"]["matchedUrl"]["url"])




# [END add_ons_3p_resources]
2 changes: 2 additions & 0 deletions python/3p-resources/create_3p_resources/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Flask>=2.2.2
functions-framework>=3.5.0
130 changes: 130 additions & 0 deletions python/3p-resources/create_link_preview/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License")
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# [START add_ons_preview_link]

from typing import Any, Mapping
from urllib.parse import urlparse, unquote

import flask
import functions_framework
import json


@functions_framework.http
def create_link_preview(req: flask.Request):
"""Responds to any HTTP request related to link previews.
Args:
req: HTTP request context.
Returns:
The response object.
"""
event = req.get_json(silent=True)
if event["docs"]["matchedUrl"]["url"]:
url = event["docs"]["matchedUrl"]["url"]
parsed_url = urlparse(url)
if parsed_url.hostname == "example.com":
if parsed_url.path.startswith("/support/cases/"):
return case_link_preview(url)

if parsed_url.path.startswith("/people/"):
return people_link_preview()

return {}


# [START add_ons_case_preview_link]


def case_link_preview(url):
"""A support case link preview.
Args:
url: The case link.
Returns:
A case link preview card.
"""

# 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.
return {
"action": {
"linkPreview": {
"title": f'Case {case_details["name"]}',
"previewCard": {
"header": {
"title": f'Case {case_details["name"]}'
},
"sections": [{
"widgets": [{
"textParagraph": {
"text": case_details["description"]
}
}]
}],
}
}
}
}


# [END add_ons_case_preview_link]
# [START add_ons_people_preview_link]


def people_link_preview():
"""An employee profile link preview.
Returns:
A people link preview card.
"""

# Builds a preview card with an employee's name, title, email, and profile photo.
# Returns the card. Uses the text from the card's header for the title of the smart chip.
return {
"action": {
"linkPreview": {
"title": "Rosario Cruz",
"previewCard": {
"header": {
"title": "Rosario Cruz"
},
"sections": [{
"widgets": [
{
"image": {
"imageUrl": "https://developers.google.com/workspace/add-ons/images/employee-profile.png"
}
},
{
"decoratedText": {
"startIcon": {
"knownIcon": "EMAIL"
},
"text": "[email protected]",
"bottomLabel": "Case Manager",
}
},
]
}],
}
}
}
}


# [END add_ons_people_preview_link]
# [END add_ons_preview_link]
2 changes: 2 additions & 0 deletions python/3p-resources/create_link_preview/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Flask>=2.2.2
functions-framework>=3.5.0
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
{
"oauthScopes": [
"https://www.googleapis.com/auth/workspace.linkpreview"
"https://www.googleapis.com/auth/workspace.linkpreview",
"https://www.googleapis.com/auth/workspace.linkcreate"
],
"addOns": {
"common": {
"name": "Preview support cases",
"logoUrl": "https://developers.google.com/workspace/add-ons/images/link-icon.png",
"name": "Manage support cases",
"logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png",
"layoutProperties": {
"primaryColor": "#dd4b39"
}
},
"docs": {
"linkPreviewTriggers": [
{
"runFunction": "$URL",
"runFunction": "$URL1",
"patterns": [
{
"hostPattern": "example.com",
Expand All @@ -34,7 +35,7 @@
"logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
},
{
"runFunction": "$URL",
"runFunction": "$URL1",
"patterns": [
{
"hostPattern": "example.com",
Expand All @@ -47,6 +48,17 @@
},
"logoUrl": "https://developers.google.com/workspace/add-ons/images/person-icon.png"
}
],
"createActionTriggers": [
{
"id": "createCase",
"labelText": "Create support case",
"localizedLabelText": {
"es": "Crear caso de soporte"
},
"runFunction": "$URL2",
"logoUrl": "https://developers.google.com/workspace/add-ons/images/support-icon.png"
}
]
}
}
Expand Down
Loading

0 comments on commit 25d386a

Please sign in to comment.