MakerLabs ACM
functions/

Documentation

See functions/ Documentation

Classes

class  Exception
 
class  GoogleCloudFunctionsRequest
 Request class which consumes body stream and provides buffered body. More...
 
class  GoogleCloudFunctionsResponse
 Response class which wraps standard HTTP response. More...
 
class  HttpResponseException
 Custom Exception class which has an optional statusCode and uri to indicate details of a failed HTTP request. More...
 

Global Functions

void google_apps_script_proxy_http (GoogleCloudFunctionsRequest request, GoogleCloudFunctionsResponse response) async
 Firebase Function HTTPS handler. More...
 
Future< void > permissions_check_http (GoogleCloudFunctionsRequest request, GoogleCloudFunctionsResponse response) async
 HTTPS handler to query Google Spreadsheet for ACM.User which matches ACM.Activity flatbuffer supplied in request payload. More...
 
Future append_activity_to_spreadsheet (SheetsApi sheets, String spreadsheetId, String sheetName, ACM.Activity activity, ACM.User user)
 Use Google Sheets API to append a new Activity row from provided Activity and User. More...
 
Uint8List datatable_to_user (Map datatable)
 Convert DataTable from result of Users query to ACM.User flatbuffer. More...
 
String extract_access_token (auth_header)
 Parse HTTP Authorization header to extract an OAuth access token. More...
 
Future< String > fetch_sheet_columns (String authority, String path, String sheetName, String accessToken)
 Fetch IDs/labels of Google Spreadsheet columns for specified sheet. More...
 
String generate_permissions_check_query (Map usersColumnsDatatable, List< List< String >> selectColumnLabels, String tagId)
 Generate a query to return all permissions (and optional additional columns) for a specific user by Tag ID. More...
 
FutureReference push_activity_to_firebase (Reference activityRef, ACM.Activity activity)
 Append Activity details to Firebase to provided Database Reference. More...
 
Future< void > push_latest_user_to_firebase (Reference latestUserRef, ACM.User user)
 Write User details to Firebase at provided Database Reference. More...
 
SheetsApi spreadsheet_client (String accessToken, [http.NodeClient baseClient])
 Create a Google SheetsApi handle using a provided OAuth access token. More...
 
String toColumnName (int colNum)
 Get column letter from column index. More...
 
int toColumnNum (String colName)
 Get column number from column letter. More...
 
bool isYesLike (String s)
 Check whether a given string represents "yes" ("☑", "t", "y", etc) More...
 
bool isNoLike (String s)
 Check whether a given string represents "no" ("☐", "f", "n", etc) More...
 
String nthColumnLabel (Map datatable, int i)
 Get the label string of the Nth column from a DataTable. More...
 
String labelToColumnId (Map datatable, String prefix, String label)
 Get the column letter for a specific label (with optional prefix) More...
 
void main ()
 Establish Dart -> JS module exports. More...
 

Global Variables

 HttpStatus
 
const String ACM_FILE_IDENTIFIER = "ACM."
 

/permissions_check AWS Lambda HTTPS handler imports

const express = require("express")
 Express server to run Google Cloud Function handler. More...
 
const serverless = require("serverless-http")
 Express middleware to wrap (req,res) handlers as an AWS Lambda handler. More...
 
const bodyParser = require("body-parser")
 Express middleware to provide the full request body in a req.body field. More...
 
const index = require("./build/node/index.dart.js")
 (req,res)-style Dart handlers More...
 
const app = express()
 Setup Express server to run (req,res)-style Dart handlers. More...
 
app use (bodyParser.raw())
 Provide request body as raw binary Buffer. More...
 

/permissions_check AWS Lambda HTTPS handler exports

Re-export the Express server wrapped as an AWS Lambda-compatible handler

exports permissions_check
 Export /permissions_check AWS Lambda handler, much lower-latency than Google/Firebase Functions leading to faster tag scanning response times. More...
 
exports google_apps_script_proxy
 Export /google_apps_script_proxy AWS Lambda handler. More...
 

/google_apps_script_proxy Firebase Functions handler imports

const functions = require("firebase-functions")
 Firebase Functions SDK. More...
 
const index = require("./build/node/index.dart.js")
 Dart <-> JS Interop generated entrypoint. More...
 

/google_apps_script_proxy Firebase Functions handler exports

exports google_apps_script_proxy
 Export /google_apps_script_proxy Firebase Functions handler. More...
 

/permissions_check constants

final String SPREADSHEET_QUERY_AUTHORITY = "docs.google.com"
 
const String SPREADSHEET_USERS_SHEET_NAME = "Users"
 Sheet used for permissions check query. More...
 
const String SPREADSHEET_ACTIVITY_SHEET_NAME = "Activity"
 Sheet used for Activity row append. More...
 

/permissions_check global variables

These global values will persist across function invocations.

String USER_COLUMNS_DATATABLE
 
FirebaseAdmin FIREBASE_admin
 
App FIREBASE_app
 
Database FIREBASE_database
 

Files

file  config.production.yml
 Environment variables / settings for /permissions_check production environment.
 
file  config.test.yml
 Environment variables / settings for /permissions_check test environment.
 
file  build.yaml
 Configure Dart 2.x build_runner including files and Dart2JS options.
 
file  package.json
 Runnable targets: pub, watch, build, deploy, serve, Serverless, Express, and Firebase dependencies.
 
file  google_apps_script_proxy_http.dart
 HTTPS handler for /google_apps_script_proxy.
 
file  google_cloud_functions.dart
 Wrapper classes for Node interop HTTP Request/Response objects for Google/Firebase Functions.
 
file  permissions_check_http.dart
 HTTPS handler to query Google Spreadsheet for ACM.User which matches ACM.Activity flatbuffer supplied in request payload.
 
file  append_activity_to_spreadsheet.dart
 Use Google Sheets API to append a new Activity row from provided Activity and User.
 
file  datatable_to_user.dart
 Convert DataTable from result of Users query to ACM.User flatbuffer.
 
file  extract_access_token.dart
 Parse HTTP Authorization header to extract an OAuth access token.
 
file  fetch_sheet_columns.dart
 Fetch IDs/labels of Google Spreadsheet columns for specified sheet.
 
file  generate_permissions_check_query.dart
 Generate a query to return all permissions (and optional additional columns) for a specific user by Tag ID.
 
file  http_response_exception.dart
 Custom Exception class which has an optional statusCode and uri to indicate details of a failed HTTP request.
 
file  push_activity_to_firebase.dart
 Append Activity details to Firebase to provided Database Reference.
 
file  push_latest_user_to_firebase.dart
 Write User details to Firebase at provided Database Reference.
 
file  spreadsheet_client.dart
 Provide an (authenticated) Google Sheets REST API client.
 
file  spreadsheet_helpers.dart
 Utility functions for spreadsheet columns<->index, string helpers, and Google Visualization DataTable parsing.
 
file  index.dart
 Main entrypoint for HTTP handlers, Dart -> JS interop.
 
file  pubspec.yaml
 Configure Dart metadata and package dependencies.
 
file  serverless.yml
 Configure Serverless framework for /permissions_check on AWS Lambda.
 

Global Functions

◆ append_activity_to_spreadsheet()

Future append_activity_to_spreadsheet ( SheetsApi  sheets,
String  spreadsheetId,
String  sheetName,
ACM.Activity  activity,
ACM.User  user 
)

Use Google Sheets API to append a new Activity row from provided Activity and User.

Parameters
sheetsGoogle Sheets API Handle
spreadsheetIdGoogle Sheets Spreadsheet ID
sheetNameName of sheet to append to (e.g. Activity)
activityACM.Activity flatbuffer
userACM.User flatbuffer (used for MakerLabs ID and Maker Status)
Returns
Future that completes when row insertion is done.

◆ datatable_to_user()

Uint8List datatable_to_user ( Map  datatable)

Convert DataTable from result of Users query to ACM.User flatbuffer.

Parameters
datatableGoogle Visualization DataTable
Returns
ACM.User flatbuffer bytes

Expect query result columns in a hard-coded order as follows:

  1. name
  2. email
  3. makerlabs_id
  4. maker_status
  5. alerts
  6. tagId
Here is the call graph for this function:

◆ extract_access_token()

String extract_access_token ( auth_header  )

Parse HTTP Authorization header to extract an OAuth access token.

Parameters
auth_headerHTTP Authorization header in format "Authorization: Bearer {token}"`
Returns
OAuth access token string
Exceptions
HttpResponseExceptionif header is missing or invalid

◆ fetch_sheet_columns()

Future<String> fetch_sheet_columns ( String  authority,
String  path,
String  sheetName,
String  accessToken 
)

Fetch IDs/labels of Google Spreadsheet columns for specified sheet.

Parameters
authorityHost portion of Google Visualization Query URL (e.g. "docs.google.com")
pathPath portion of Google Visualization Query URL (e.g. "/spreadsheets/d/{spreadsheetId}/gviz/tq")
sheetNameName of sheet to query (e.g. Users)
accessTokenGoogle OAuth token to use for query
Returns
Future that completes when query result DataTable JSON has been parsed

◆ generate_permissions_check_query()

String generate_permissions_check_query ( Map  usersColumnsDatatable,
List< List< String >>  selectColumnLabels,
String  tagId 
)

Generate a query to return all permissions (and optional additional columns) for a specific user by Tag ID.

Parameters
usersColumnsDatatableGoogle Visualization query result DataTable
selectColumnLabels(optional) Additional section headers/labels to select
tagIdTag ID of desired user
Returns
String of query in Google Visualization SQL

Steps:

  1. Validate datatable
  2. Search for label that starts with "Permissions", count how many columns precede it (non-permissions columns) and follow it (permissions columns only).
  3. Add provided selectedColumnLabels labels to the select portion of the query
  4. Add permissions column labels to the select portion of the query
  5. Find column ID for Tag ID column and add it to the select portion of the query
  6. Execute permissions check query
Here is the call graph for this function:

◆ google_apps_script_proxy_http()

void google_apps_script_proxy_http ( GoogleCloudFunctionsRequest  request,
GoogleCloudFunctionsResponse  response 
)

Firebase Function HTTPS handler.

Parameters
requestHTTP request
responseHTTP response

Steps:

  • (Check for external ping to keep function "warm", exit 200 immediately)
  • (Check for CORS preflight check, exit 200 immediately)
  1. Extract OAuth access_token from received request headers, use it for Google API requests
  2. Strip /google_apps_script_proxy from received URL path
  3. Create upstream URL path as https://script.google.com/{path}
  4. Send the request, copy upstream response headers to the proxied response
  5. Return the body of the upstream response as the body of the proxied response
  • (In case of failure, return response with exception text. Use the error code from the upstream response if available, otherwise use 500.)

◆ isNoLike()

bool isNoLike ( String  s)

Check whether a given string represents "no" ("☐", "f", "n", etc)

Parameters
sCandidate input string
Returns
True if the input represents "no".

◆ isYesLike()

bool isYesLike ( String  s)

Check whether a given string represents "yes" ("☑", "t", "y", etc)

Parameters
sCandidate input string
Returns
True if the input represents "yes".

◆ labelToColumnId()

String labelToColumnId ( Map  datatable,
String  prefix,
String  label 
)

Get the column letter for a specific label (with optional prefix)

Parameters
datatableGoogle Visualization DataTable
prefixPrefix string to strip from field before matching
labelLabel string to match
Returns
Column letter for a matching column, or null.

◆ main()

void main ( )

Establish Dart -> JS module exports.

Here is the call graph for this function:

◆ nthColumnLabel()

String nthColumnLabel ( Map  datatable,
int  i 
)

Get the label string of the Nth column from a DataTable.

Parameters
datatableGoogle Visualization DataTable
iIndex of desired column, 0-based
Returns
Full label of matching column, or null.

◆ permissions_check_http()

Future<void> permissions_check_http ( GoogleCloudFunctionsRequest  request,
GoogleCloudFunctionsResponse  response 
)

HTTPS handler to query Google Spreadsheet for ACM.User which matches ACM.Activity flatbuffer supplied in request payload.

Parameters
GoogleCloudFunctionsRequestrequest
GoogleCloudFunctionsResponseresponse
Returns
Future which is fulfilled when all child subrequests are complete and ACM.User payload is ready

Steps:

  • (Check for external ping to keep function "warm", exit 200 immediately)
  1. Extract OAuth access_token from received request headers, use it for Google API requests
  2. Parse request body as ACM.Activity flatbuffer
  3. Prepare Firebase Database connection: latestUserRef, activityRef
  4. Check for cached User sheet columns, fetch them if not present
  5. Generate permissions check query in Google Visualization SQL format
  6. Send the query, set "X-DataSource-Auth" header to force JSON format
  7. Check for valid query response
  8. Extract User details from query results
  9. Push matching User details to Firebase
  10. Return matching ACM.User flatbuffer (including permissions info) in response
  11. Append Activity to Google Spreadsheet
  • (In case of failure, return response with exception text. Use the error code from the upstream response if available, otherwise use 500.)
Here is the call graph for this function:

◆ push_activity_to_firebase()

FutureReference push_activity_to_firebase ( Reference  activityRef,
ACM.Activity  activity 
)

Append Activity details to Firebase to provided Database Reference.

Parameters
activityRefFirebase Database Reference (e.g. readers/{machineId}/activity)
activityACM.Activity flatbuffer
Returns
Future that completes when write to Firebase Database is done.

◆ push_latest_user_to_firebase()

Future<void> push_latest_user_to_firebase ( Reference  latestUserRef,
ACM.User  user 
)

Write User details to Firebase at provided Database Reference.

Parameters
latestUserRefFirebase Database Reference (e.g. readers/{machineId}/latestUser)
userACM.User flatbuffer
Returns
Future that completes when write to Firebase Database is done.

◆ spreadsheet_client()

SheetsApi spreadsheet_client ( String  accessToken)

Create a Google SheetsApi handle using a provided OAuth access token.

Parameters
accessTokenOAuth access token
baseClient(optional) Existing http.NodeClient HTTP client to use
Returns
SheetsApi handle
  1. Generate credentials from existing token, guessing at best-case expiry time (1 hour)
  2. Create a base HTTP client which will be used for Google API requests
  3. Wrap base client with OAuth2-token-aware version from googleapis_auth
  4. Extract the latest Sheets API from the generated APIs

◆ toColumnName()

String toColumnName ( int  colNum)

Get column letter from column index.

Parameters
colNumColumn index, 0-based
Returns
Column letter

http://cwestblog.com/2013/09/05/javascript-snippet-convert-number-to-column-name/

◆ toColumnNum()

int toColumnNum ( String  colName)

Get column number from column letter.

Parameters
colNameColumn letter
Returns
Column index, 0-based

http://cwestblog.com/2013/09/05/javascript-snippet-convert-number-to-column-name/

◆ use()

app use ( bodyParser.  raw())

Provide request body as raw binary Buffer.

Global Variables

◆ ACM_FILE_IDENTIFIER

const String ACM_FILE_IDENTIFIER = "ACM."

◆ app

const app = express()

Setup Express server to run (req,res)-style Dart handlers.

◆ bodyParser

const bodyParser = require("body-parser")

Express middleware to provide the full request body in a req.body field.

◆ express

const express = require("express")

Express server to run Google Cloud Function handler.

◆ FIREBASE_admin

FirebaseAdmin FIREBASE_admin

◆ FIREBASE_app

App FIREBASE_app

◆ FIREBASE_database

Database FIREBASE_database

◆ functions

const functions = require("firebase-functions")

Firebase Functions SDK.

◆ google_apps_script_proxy [1/2]

exports google_apps_script_proxy

Export /google_apps_script_proxy Firebase Functions handler.

◆ google_apps_script_proxy [2/2]

exports google_apps_script_proxy

Export /google_apps_script_proxy AWS Lambda handler.

Deprecated:
Use Firebase Functions handler instead, no need to move this to AWS for performance reasons.

◆ HttpStatus

HttpStatus

◆ index [1/2]

const index = require("./build/node/index.dart.js")

Dart <-> JS Interop generated entrypoint.

◆ index [2/2]

const index = require("./build/node/index.dart.js")

(req,res)-style Dart handlers

◆ permissions_check

exports permissions_check

Export /permissions_check AWS Lambda handler, much lower-latency than Google/Firebase Functions leading to faster tag scanning response times.

◆ serverless

const serverless = require("serverless-http")

Express middleware to wrap (req,res) handlers as an AWS Lambda handler.

◆ SPREADSHEET_ACTIVITY_SHEET_NAME

const String SPREADSHEET_ACTIVITY_SHEET_NAME = "Activity"

Sheet used for Activity row append.

◆ SPREADSHEET_QUERY_AUTHORITY

final String SPREADSHEET_QUERY_AUTHORITY = "docs.google.com"

◆ SPREADSHEET_USERS_SHEET_NAME

const String SPREADSHEET_USERS_SHEET_NAME = "Users"

Sheet used for permissions check query.

◆ USER_COLUMNS_DATATABLE

String USER_COLUMNS_DATATABLE