generated from vaadin/addon-template
/
FeedbackSheet.java
129 lines (110 loc) · 4.56 KB
/
FeedbackSheet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package com.example.application.data;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.sheets.v4.Sheets;
import com.google.api.services.sheets.v4.SheetsScopes;
import com.google.api.services.sheets.v4.model.ValueRange;
import com.google.auth.oauth2.ServiceAccountCredentials;
/* Class to store feedack into a Google Sheet.
*
* This needs a Google Service Account to be set up first and give 'editor'
* permissions to that account in the specified sheet.
*
*
*/
public class FeedbackSheet {
private static final String APPLICATION_NAME = "NPS Feedback App";
private static final List<String> AUTH_SCOPES = List.of(SheetsScopes.SPREADSHEETS);
private static final String RANGE = "Sheet1";
private static final GsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
private String credentialsFilePath;
private ServiceAccountCredentials loadedCredentials;
private Sheets loadedService;
private String sheetId;
public FeedbackSheet(String sheetId, String credentialsFilePath) {
this.sheetId = sheetId;
this.credentialsFilePath = credentialsFilePath;
}
/**
* Append a user score to the spreadsheet.
* <p>
* Adds a new row in the first sheet in a Google Spreadsheet
* with timestamp userId and given NPS score.
*
* <code>2023-06-26 11:09:44,1687640813, 10</code>
*
* @param anonymousUserId Unique but anonymous I
* @param score NPS score
*/
public void append(String product, String anonymousUserId, int score) {
executor.submit(() -> {
try {
List<List<Object>> values = Arrays.asList(
Arrays.asList(LocalDateTime.now().toString(), product, anonymousUserId, score));
ValueRange newEntry = new ValueRange().setValues(values);
Sheets service = getSheetsService();
service.spreadsheets().values()
.append(this.sheetId, RANGE, newEntry)
.setValueInputOption("USER_ENTERED")
.setAccessToken(getCredentials().getAccessToken().getTokenValue())
.execute();
} catch (Exception e) {
throw new RuntimeException("Failed to append Google Sheet", e);
}
});
}
/**
* Initialize and get Google Sheets service.
*
* @return Sheets service to perform operations.
* @throws IOException
* @throws GeneralSecurityException
*/
public Sheets getSheetsService() throws IOException, GeneralSecurityException {
if (this.loadedService == null) {
NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
this.loadedService = new Sheets.Builder(httpTransport, JSON_FACTORY, request -> {
})
.setApplicationName(APPLICATION_NAME)
.build();
}
return this.loadedService;
}
/**
* Load and create new ServiceAccountCredential instance.
* <p>
* Once successfully loaded, calling this will return the same credential
* instance.
*
* @return An authorized Credential object.
* @throws IOException If the credentials.json file cannot be found.
*/
protected ServiceAccountCredentials getCredentials() throws IOException {
if (this.loadedCredentials != null) {
if (this.loadedCredentials.getAccessToken().getExpirationTime().before(new Date())) {
this.loadedCredentials.refresh();
}
return this.loadedCredentials;
}
try (InputStream in = new FileInputStream(credentialsFilePath)) {
this.loadedCredentials = (ServiceAccountCredentials) ServiceAccountCredentials
.fromStream(new FileInputStream(credentialsFilePath))
.createScoped(AUTH_SCOPES);
this.loadedCredentials.refresh();
return this.loadedCredentials;
}
}
}