@@ -2,8 +2,10 @@ import * as serloAuth from '@serlo/authorization'
2
2
import { instanceToScope , Scope } from '@serlo/authorization'
3
3
import { createHash } from 'crypto'
4
4
import { array as A , either as E , function as F , option as O } from 'fp-ts'
5
+ import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
5
6
import * as t from 'io-ts'
6
7
import * as R from 'ramda'
8
+ import { URL } from 'url'
7
9
8
10
import { resolveUnrevisedEntityIds } from '../abstract-entity/resolvers'
9
11
import { UuidResolver } from '../abstract-uuid/resolvers'
@@ -25,7 +27,6 @@ import {
25
27
generateRole ,
26
28
isGlobalRole ,
27
29
} from '~/internals/graphql'
28
- import { CellValues , MajorDimension } from '~/model'
29
30
import { EntityDecoder , UserDecoder } from '~/model/decoder'
30
31
import {
31
32
getPermissionsForRole ,
@@ -37,6 +38,11 @@ import { createThreadResolvers } from '~/schema/thread/utils'
37
38
import { createUuidResolvers } from '~/schema/uuid/abstract-uuid/utils'
38
39
import { Instance , Resolvers } from '~/types'
39
40
41
+ enum MajorDimension {
42
+ Rows = 'ROWS' ,
43
+ Columns = 'COLUMNS' ,
44
+ }
45
+
40
46
export const ActiveUserIdsResolver = createCachedResolver <
41
47
Record < string , never > ,
42
48
number [ ]
@@ -200,12 +206,12 @@ export const resolvers: Resolvers = {
200
206
User : {
201
207
...createUuidResolvers ( ) ,
202
208
...createThreadResolvers ( ) ,
203
- async motivation ( user , _args , context ) {
209
+ async motivation ( user , _args , _context ) {
210
+ const spreadsheetId = process . env . GOOGLE_SPREADSHEET_API_MOTIVATION
211
+ const range = 'Formularantworten!B:D'
212
+
204
213
return F . pipe (
205
- await context . dataSources . model . googleSpreadsheetApi . getValues ( {
206
- spreadsheetId : process . env . GOOGLE_SPREADSHEET_API_MOTIVATION ,
207
- range : 'Formularantworten!B:D' ,
208
- } ) ,
214
+ await getSpreadsheetValues ( { spreadsheetId, range } ) ,
209
215
E . mapLeft ( addContext ( { location : 'motivationSpreadsheet' } ) ) ,
210
216
E . getOrElse ( consumeErrorEvent ( [ ] as string [ ] [ ] ) ) ,
211
217
A . findLast (
@@ -622,11 +628,14 @@ async function fetchActivityByType(
622
628
return result
623
629
}
624
630
625
- async function activeDonorIDs ( context : Context ) {
631
+ async function activeDonorIDs ( _context : Context ) {
632
+ const spreadsheetId = process . env . GOOGLE_SPREADSHEET_API_ACTIVE_DONORS
633
+ const range = 'Tabellenblatt1!A:A'
634
+
626
635
return F . pipe (
627
- await context . dataSources . model . googleSpreadsheetApi . getValues ( {
628
- spreadsheetId : process . env . GOOGLE_SPREADSHEET_API_ACTIVE_DONORS ,
629
- range : 'Tabellenblatt1!A:A' ,
636
+ await getSpreadsheetValues ( {
637
+ spreadsheetId,
638
+ range,
630
639
majorDimension : MajorDimension . Columns ,
631
640
} ) ,
632
641
extractIDsFromFirstColumn ,
@@ -675,3 +684,50 @@ async function deleteKratosUser(
675
684
await authServices . kratos . admin . deleteIdentity ( { id : identity . id } )
676
685
}
677
686
}
687
+
688
+ type CellValues = NonEmptyArray < string [ ] >
689
+
690
+ interface GetSpreadsheetValuesArgs {
691
+ spreadsheetId : string
692
+ range : string
693
+ majorDimension ?: MajorDimension
694
+ }
695
+
696
+ async function getSpreadsheetValues (
697
+ args : GetSpreadsheetValuesArgs ,
698
+ ) : Promise < E . Either < ErrorEvent , CellValues > > {
699
+ const { spreadsheetId, range } = args
700
+ const majorDimension = args . majorDimension ?? MajorDimension . Rows
701
+ const url = new URL (
702
+ `https://sheets.googleapis.com/v4/spreadsheets/${ spreadsheetId } /values/${ range } ` ,
703
+ )
704
+ url . searchParams . append ( 'majorDimension' , majorDimension )
705
+ const apiSecret = process . env . GOOGLE_SPREADSHEET_API_SECRET
706
+ url . searchParams . append ( 'key' , apiSecret )
707
+
708
+ const specifyErrorLocation = E . mapLeft (
709
+ addContext ( {
710
+ location : 'googleSpreadSheetApi' ,
711
+ locationContext : { ...args } ,
712
+ } ) ,
713
+ )
714
+
715
+ try {
716
+ const response = await fetch ( url . toString ( ) )
717
+ const data = ( await response . json ( ) ) as { values ?: string [ ] [ ] }
718
+
719
+ if (
720
+ ! data . values ||
721
+ ! Array . isArray ( data . values ) ||
722
+ data . values . length === 0
723
+ ) {
724
+ return specifyErrorLocation (
725
+ E . left ( { error : new Error ( 'invalid response or empty range' ) } ) ,
726
+ )
727
+ }
728
+
729
+ return specifyErrorLocation ( E . right ( data . values as CellValues ) )
730
+ } catch ( error ) {
731
+ return specifyErrorLocation ( E . left ( { error : E . toError ( error ) } ) )
732
+ }
733
+ }
0 commit comments