Sånn bruker du Google Forms og Google Sheets som et CMS

- Her er en guide, så du ikke lider så mye som meg, skriver Marcus Haaland.

Et regneark hos Google Sheets kan få data fra et skjema i Google Forms, og vipps så har du allerede mye på plass for et CMS. 📸: Ole Petter Baugerød Stokke
Et regneark hos Google Sheets kan få data fra et skjema i Google Forms, og vipps så har du allerede mye på plass for et CMS. 📸: Ole Petter Baugerød Stokke Vis mer

Hvor lang tid tar det for deg å sette opp en database og et CMS? 2 minutter? 2 timer? 2 dager? Hvor lang tid tar det for deg å gå på denne lenken til Google spreadsheet og trykke på pluss-knappen? For det er så kort tid det kan ta å lage en database med et CMS. Kobler man også et Google Skjema til regnearket, har man plutselig også brukerinput.

Mitt bruk var for en applikasjon som skulle tillate

  1. Å lagre innsendte spørsmål, og
  2. Å lese ut spørsmål og markere dem som lest (les om applikasjonen HER).

Altså henholdsvis Create, Read og Update. Ideen om å bruke Google Spreadsheet som CMS kom fra å lese kode24s “Google Sheets er et sjitbra CMS” (takk for fin guide!). Det var tiltalende å lære å håndtere regneark-formatet med kode. Det er lett å opprette et regneark, og å redigere arket krever ikke kodekunnskaper.

Jeg fulgte stegene, men møtte utfordringer med biblioteket node-google-spreadsheet. Oppfordringen “Bruk heller en av de åpne bibliotekene fra Github-brukere som har lidd seg gjennom Googles egne forklaringer, og pakket alt inn i et enkelt grensesnitt for deg” måtte jeg dessverre avstå fra, da biblioteket ikke fungerte for meg.

Istedenfor benyttet jeg meg av Google sitt bibliotek, som jeg måtte lide meg masse gjennom. Så her er en guide på hvordan å ikke lide så mye som meg.

Oppsett

Start nytt node-prosjekt med default verdier med kommandoen npm init -y. Vi skal bruke noen verdier vi ønsker å holde hemmelige, så installer dotenv med npm install dotenv --save. Lag en fil .env som du legger til i .gitignore.

Installer vår integrasjon mot google ved å kjøre kommandoen npm install googleapis. Google-klienten trenger noen app-credentials den får fra en json-fil som vi straks vil hente. I .env legger vi til miljøvariabelen:

GOOGLE_APPLICATION_CREDENTIALS=./secrets.json

For å hemmeliggjøre verdiene, legg til /secrets.json i .gitignore.

Registrer servicekonto

Våre app-credentials får vi fra google-servicekontoen, som opprettes HER.

Opprett en servicekonto og legg til nøkler
Opprett en servicekonto og legg til nøkler Vis mer

Vi trenger så å opprette nøkler for kontoen. Ved opprettelse får man nøklene som en json-fil. Vi lagrer den som secrets.json og putter den i mappestrukturen. Vi bør nå ha følgende mappestruktur:

index.js
.gitignore
.env
package.json
secrets.json

Før servicekontoen kan samhandle med google sheet, må API-et aktiveres: Enable Google sheet API for servicekonto.

Opprette Google Spreadsheet

Vi trenger nå et regneark vi kan lagre verdier til og hente verdier fra. Det kan opprettes HER. spreadsheetId hentes fra Google-spreadsheet-dokumentet du oppretter, e.g.:

https://docs.google.com/spreadsheets/d/
<spreadsheetId>/edit#gid=<sheetId>.

Vi må også styre tilganger til dokumentet, som kan aksesseres ved å trykke på “Del”-knappen oppe til høyre i regnearket.

Aksesser tilgangsstyring via “Del”-knappen
Aksesser tilgangsstyring via “Del”-knappen Vis mer

Her kan vi legge til servicekonto-eposten og huke av for redigeringstilgang. Eposten finner vi i secrets.json med nøkkelen client_email. Ønsker vi å gi alle personer tilganger, kan vi endre så alle som har lenken kan redigere dokumentet. Uansett tilgangsnivå, velger vi her å skjule id-en som en miljøvariabel:

SPREADSHEET_ID:<spreadsheetId>

Vi kan nå begynne med CRUD-metodene.

CREATE med Google Form til Google Spreadsheet

I flere scenarioer kan det være nok å sende inn data med skjema, istedenfor å lage Create-logikk selv. Det kan gjøres ved å opprette skjema HER. For å bestemme destinasjon på dataene kan vi gå inn på “Svar”-fanen og trykke alternativ-ikon oppe til høyre og velge målplassering.

Velg målplassering for svar
Velg målplassering for svar Vis mer

CREATE med kode

Vi ønsker nå å lage koden for å legge inn et spørsmål på regnearket vårt. Først trenger vi å autentisere oss. Ved henting av klienten leses miljøvariabelen GOOGLE_APPLICATION_CREDENTIALS implisitt av. Vi sender med et scope som tillater klienten å lese og skrive av vår service konto sine regneark (mer om autorisasjoner kan leses om HER).

const { google } = require("googleapis");
const auth = await google.auth.getClient({
  scopes: ["https://www.googleapis.com/auth/spreadsheets"],
});

Neste steg er å opprette en forespørsel som skal utføres. Vi bruker miljøvariabelen SPREADSHEET_ID vi fikk fra regnearket vi opprettet for å definere hvilket regneark forespørselen gjelder.

Regnearket vårt har to kolonner: A: Dato, B: Spørsmål
Regnearket vårt har to kolonner: A: Dato, B: Spørsmål Vis mer

range er hvilket ark på regnearket og hvilke rader det gjelder. Arkets navn er for mitt regneark “Skjemasvar 1”. Siden vi sender inn to verdier (dato og et spørsmål), bruker vi de to kolonnene A og B. valueInputOption gir oss mulighet til å parse dataene vi sender inn. Her er det definert som at vi lar det være likt som om brukeren sendte det inn. Mer om parsing kan leses HER.

Innsendingen av dataene med resource er en munnfull. I values sender vi med en liste av én liste med verdier. Hvorfor er det slik? Vi kan sende inn flere rader av gangen, som hver har en liste av verdier (kolonner). I vårt tilfelle ønsker vi imidlertid bare å legge til én rad.

const newRow = [new Date(), question];
const sheetName = "Skjemasvar 1";
const appendRequest = {
  spreadsheetId: process.env.SPREADSHEET_ID,
  range: `${sheetName}!A:B`,
  valueInputOption: "USER_ENTERED",
  resource: {
    values: [newRow],
  },
};

Etter å ha definert en forespørsel, må vi jo sende denne forespørselen. Vi får tilgang til sheets og bruker funksjonen append for å legge til en verdi på regnearket.

const sheets = google.sheets({ version: "v4", auth });
await sheets.spreadsheets.values.append(appendRequest);

Her er komplett kode:

Funksjonen kan brukes for å legge til en ny rad med dato og spørsmål
Funksjonen kan brukes for å legge til en ny rad med dato og spørsmål Vis mer

READ

For å lese rader må vi igjen opprette en forespørsel. Denne gangen trenger vi bare å definere regneark-id-en og hvor vi leser av. Vi leser også av C, som jeg vil forklare ved UPDATE-seksjonen.

Igjen bruker vi sheets-objektet til å sende vår forespørsel, men denne gangen bruker vi get-funksjonen. Via get får vi hentet verdiene fra data.

Lesing av verdier
Lesing av verdier Vis mer

UPDATE

For å oppdatere regnearket må vi først vite hva vi skal oppdatere. Vi ønsker å publisere spørsmål som ikke har blitt publisert allerede. For å holde rede på hva som er publisert, legger vi til en kolonne “Er publisert” i regnearket. Vi har da kolonnene “Dato”, “Spørsmål” og “Er publisert”. Vi ønsker å oppdatere den tredje kolonnen ved lesing av et spørsmål.

image: Sånn bruker du Google Forms og Google Sheets som et CMS

Vi itererer da over alle kolonner frem til en rad i den tredje kolonnen er markert med “ja”.

const rowToPublishIndex = allRows.findIndex((x) => x[2] !== "ja");

Den nye verdien vi ønsker å putte inn en liste med de gamle verdiene og “ja”.

const updatedRow = [...allRows[rowToPublishIndex], "ja"];

Selv om vi finner indeksen ved en gitt verdi, må vi legge til 2. Dette er på grunn av at vi må ta hensyn til å skippe tittelen og at regneark-radene er 1-indeksert.

const skipTitleAndOneIndex = 2;
const rowToPublishSheetIndex = skipTitleAndOneIndex + rowToPublishIndex;
const updateRange = `${sheetName}!A${rowToPublishSheetIndex}:C${rowToPublishSheetIndex}`;

Vi har nå kommet frem til selve forespørselen for å oppdatere, som i og for seg er like enkel som de andre operasjonene.

const updateRequest = {
  spreadsheetId: process.env.SPREADSHEET_ID,
  range: updateRange,
  valueInputOption: "USER_ENTERED",
  resource: {
    values: [
      updatedRow,
    ],
  },
};
await sheets.spreadsheets.values.update(updateRequest);

Komplett kode:

Henter ut ikke-publisert spørsmål og markerer det som publisert
Henter ut ikke-publisert spørsmål og markerer det som publisert Vis mer

DELETE

Jeg trengte ikke sletting for min applikasjon, men for kompletthet ønsker jeg også å vise DELETE. Sletting av verdier ligner leseoperasjonen. Vi definerer en range, men benytter heller clear-funksjonen.

Sletting av verdier
Sletting av verdier Vis mer

Deployment

Ved deployment må vi inkludere miljøvariablene vi har satt. Jeg har valgt heroku for denne applikasjon. Miljøvariabler i heroku settes i “Settings”. Det er ikke rett frem å sette disse miljøvariablene, ettersom Google Credentials forventer en JSON-fil. Følg guiden HER for å sette Google Credentials. Ettersom vi har en node-applikasjon, trenger vi også en build-pakke for node-js, se HER.

Heroku gir et dashboard for dine deploys
Heroku gir et dashboard for dine deploys Vis mer

Konklusjon

Vi har nå sett på hvordan vi kan utføre CRUD-operasjoner på Google Spreadsheet. Det er lett å sette opp, og gir muligheter for ikke-kodende også å utføre handlinger på databasen.

Hva kunne du ha tenkt deg å bruke Google Spreadsheet for?