• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ringcentral / google-forms-notification-add-in / 3824228323

pending completion
3824228323

Pull #38

github

GitHub
Merge fcfcbd0d9 into e4d5c816a
Pull Request #38: chore(deps): bump json5 and babel-loader

223 of 239 branches covered (93.31%)

Branch coverage included in aggregate %.

641 of 652 relevant lines covered (98.31%)

14.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.13
/src/server/lib/GoogleClient.js
1
const axios = require('axios');
5✔
2
const querystring = require('querystring');
5✔
3
const constants = require('./constants');
5✔
4

5
class GoogleClient {
6
  constructor({ token }) {
7
    this._token = token;
39✔
8
    this._apiServer = 'https://forms.googleapis.com';
39✔
9
  }
10

11
  setToken(token) {
12
    this._token = token;
×
13
  }
14

15
  static authorizationUrl() {
16
    const scopes = process.env.GOOGLE_AUTH_SCOPES.split(process.env.GOOGLE_AUTH_SCOPES_SEPARATOR);
1✔
17
    const query = querystring.stringify({
1✔
18
      scope: scopes.join(' '),
19
      access_type: 'offline',
20
      response_type: 'code',
21
      redirect_uri: `${process.env.APP_SERVER}${constants.route.forThirdParty.AUTH_CALLBACK}`,
22
      client_id: process.env.GOOGLE_CLIENT_ID,
23
    });
24
    return `${process.env.GOOGLE_AUTHORIZATION_URI}?${query}`;
1✔
25
  }
26

27
  static async getToken(callbackUri) {
28
    const url = new URL(callbackUri);
10✔
29
    if (url.searchParams.get('error')) {
10✔
30
      const error = new Error('authError');
1✔
31
      error.details = url.searchParams.get('error');
1✔
32
      throw error;
1✔
33
    }
34
    const code = url.searchParams.get('code');
9✔
35
    if (!code) {
9✔
36
      throw new Error('noCode');
1✔
37
    }
38
    const scope = url.searchParams.get('scope');
8✔
39
    if (
8✔
40
      !scope ||
21✔
41
      scope.indexOf('forms.responses.readonly') === -1 ||
42
      scope.indexOf('forms.body.readonly') === -1
43
    ) {
44
      throw new Error('invalidScope');
3✔
45
    }
46
    const response = await axios.post(
5✔
47
      process.env.GOOGLE_ACCESS_TOKEN_URI,
48
      querystring.stringify({
49
        code,
50
        client_id: process.env.GOOGLE_CLIENT_ID,
51
        client_secret: process.env.GOOGLE_CLIENT_SECRET,
52
        redirect_uri: `${process.env.APP_SERVER}${constants.route.forThirdParty.AUTH_CALLBACK}`,
53
        grant_type: 'authorization_code',
54
      }),
55
      {
56
        headers: {
57
          'Content-type': 'application/x-www-form-urlencoded'
58
        },
59
      },
60
    );
61
    return response.data;
4✔
62
  }
63

64
  static async refreshToken(token) {
65
    const response = await axios.post(
21✔
66
      process.env.GOOGLE_ACCESS_TOKEN_URI,
67
      querystring.stringify({
68
        refresh_token: token,
69
        client_id: process.env.GOOGLE_CLIENT_ID,
70
        client_secret: process.env.GOOGLE_CLIENT_SECRET,
71
        grant_type: 'refresh_token',
72
      }),
73
      {
74
        headers: {
75
          'Content-type': 'application/x-www-form-urlencoded'
76
        },
77
      },
78
    );
79
    return response.data;
7✔
80
  }
81

82
  revokeToken(refreshToken) {
83
    const token = refreshToken || this._token;
6!
84
    return axios({
6✔
85
      url: `https://oauth2.googleapis.com/revoke?token=${token}`,
86
      method: 'POST',
87
      headers: {
88
        'Content-type': 'application/x-www-form-urlencoded'
89
      },
90
    });
91
  }
92

93
  async getForm(id) {
94
    const response = await this.requestWithToken(`${this._apiServer}/v1/forms/${id}`, 'GET');
12✔
95
    return response.data;
10✔
96
  }
97

98
  async getUserInfo() {
99
    const apiServer = 'https://www.googleapis.com';
3✔
100
    const response = await this.requestWithToken(`${apiServer}/oauth2/v3/userinfo`, 'GET');
3✔
101
    return response.data;
3✔
102
  }
103

104
  async getFormResponses(formId, fromTime = null) {
×
105
    let url = `${this._apiServer}/v1/forms/${formId}/responses`;
8✔
106
    if (fromTime) {
8!
107
      const time = new Date(fromTime);
×
108
      url = `${url}?filter=timestamp > ${time.toISOString()}`;
×
109
    }
110
    const response = await this.requestWithToken(url, 'GET');
8✔
111
    return response.data.responses;
8✔
112
  }
113

114
  async getFormResponse(formId, responseId) {
115
    const response = await this.requestWithToken(`${this._apiServer}/v1/forms/${formId}/responses/${responseId}`, 'GET');
×
116
    return response.data;
×
117
  }
118

119
  async createWatch(formId) {
120
    const response = await this.requestWithToken(
6✔
121
      `${this._apiServer}/v1/forms/${formId}/watches`,
122
      'POST',
123
      {
124
        watch: {
125
          target: {
126
            topic: {
127
              topicName: process.env.GOOGLE_PUBSUB_TOPIC_NAME
128
            }
129
          },
130
          eventType: 'RESPONSES'
131
        }
132
      }
133
    );
134
    return response.data;
5✔
135
  }
136

137
  async renewWatch(formId, watchId) {
138
    const response = await this.requestWithToken(
6✔
139
      `${this._apiServer}/v1/forms/${formId}/watches/${watchId}:renew`,
140
      'POST',
141
    );
142
    return response.data;
6✔
143
  }
144

145
  async deleteWatch(formId, watchId) {
146
    const response = await this.requestWithToken(
7✔
147
      `${this._apiServer}/v1/forms/${formId}/watches/${watchId}`,
148
      'DELETE',
149
    );
150
    return response.data;
6✔
151
  }
152

153
  async getWatches(formId) {
154
    const response = await this.requestWithToken(
×
155
      `${this._apiServer}/v1/forms/${formId}/watches`,
156
      'GET',
157
    );
158
    return response.data;
×
159
  }
160

161
  requestWithToken(url, method, data) {
162
    return axios({
42✔
163
      url,
164
      method,
165
      data,
166
      headers: {
167
        Authorization: `Bearer ${this._token}`,
168
      }
169
    });
170
  }
171
}
172

173
exports.GoogleClient = GoogleClient;
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc