Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Igors assignment #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
const clientIdProperty = 'clientId';
const cc = DataStudioApp.createCommunityConnector();

const isAdminUser = () => {
return true;
};

const resetAuth = () =>
PropertiesService.getUserProperties().deleteProperty(clientIdProperty);
Expand All @@ -7,9 +12,7 @@ const isAuthValid = () =>
!!PropertiesService.getUserProperties().getProperty(clientIdProperty);

const getAuthType = () => {
const cc = DataStudioApp.createCommunityConnector();

return cc.newAuthTypeResponse().setAuthType(cc.AuthType.USER_TOKEN).build();
return cc.newAuthTypeResponse().setAuthType(cc.AuthType.NONE).build();
};

interface SetCredentialsInput {
Expand Down
13 changes: 5 additions & 8 deletions src/getConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const getConfig = () => {
const cc = DataStudioApp.createCommunityConnector();

const config = cc.getConfig();

// Add name input
Expand All @@ -9,30 +8,28 @@ const getConfig = () => {
.setId('name')
.setName('Name')
.setHelpText('Your name for registering with the API')
.setAllowOverride(true);
.setAllowOverride(false);

// Add email input
config
.newTextInput()
.setId('email')
.setName('Email')
.setHelpText('Your email for registering with the API')
.setAllowOverride(true);
.setAllowOverride(false);

// Add an input for specifying a maximum number of posts to retrieve
config
.newSelectMultiple()
.newSelectSingle()
.setId('postLimit')
.setName('Post limit')
.setHelpText(
'Maximum number of posts that will be fetched from the API'
)
.addOption(config.newOptionBuilder().setValue('10').setLabel('10'))
.addOption(config.newOptionBuilder().setValue('100').setLabel('100'))
.addOption(config.newOptionBuilder().setValue('1000').setLabel('1000'))
.addOption(
config.newOptionBuilder().setValue('10000').setLabel('10000')
)
.setAllowOverride(true);
.setAllowOverride(false);

return config.build();
};
103 changes: 102 additions & 1 deletion src/getData.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,104 @@
const cc = DataStudioApp.createCommunityConnector();

const getData = (request: unknown) => {
// TODO: Implement data fetching
let fields = cc.getFields();
const fieldIds = request.fields.map((field) => field.name);
const { postLimit = null } = request.configParams;

fieldIds.forEach((fieldId) => {
fields = _getField(fields, fieldId);
});

const requestOptions = {
muteHttpExceptions: true,
method: 'get',
};

const slToken = _getSlToken(request);
const httpResponse = UrlFetchApp.fetch(
`https://api.supermetrics.com/assignment/posts?sl_token=${slToken}`,
requestOptions
);
const statusCode = httpResponse.getResponseCode();

if (statusCode !== 200) {
Logger.log('An exception occurred accessing the posts API:');
Logger.log(statusCode);
Logger.log(httpResponse.getAllHeaders());
Logger.log(httpResponse.getContentText());
_sendUserError(
`The API replied with an unsuccessful status code of ${statusCode}`
);

return;
}

const { data = {} } = JSON.parse(httpResponse.getContentText()) || {};

const posts = data.posts || [];
const filteredPosts = postLimit ? posts.slice(0, postLimit) : posts;
const normalizedPosts = filteredPosts.map((post) => ({
values: fieldIds.map((fieldId) => _getDataField(post, fieldId)),
}));

const result = {
schema: fields.build(),
rows: normalizedPosts,
filtersApplied: false,
};

Logger.log('getData finished with: ');
Logger.log(result);

return result;
};

const _getSlToken = (request) => {
const { name, email } = request.configParams;
const requestOptions = {
muteHttpExceptions: true,
method: 'post',
payload: {
client_id: 'ju16a6m81mhid5ue1z3v2g0uh',
email: email,
name: name,
},
};

const httpResponse = UrlFetchApp.fetch(
'https://api.supermetrics.com/assignment/register',
requestOptions
);
const statusCode = httpResponse.getResponseCode();

if (statusCode !== 200) {
Logger.log('An exception occurred accessing the register API:');
Logger.log(statusCode);
Logger.log(httpResponse.getAllHeaders());
Logger.log(httpResponse.getContentText());
_sendUserError(
`The API replied with an unsuccessful status code of ${statusCode}`
);

return;
}

const { data = {} } = JSON.parse(httpResponse.getContentText()) || {};

return data.sl_token;
};

const _sendUserError = (message) => {
cc.newUserError().setText(message).throwException();
};

const _getDataField = (post, fieldId) => {
switch (fieldId) {
case 'userName':
return post.from_name;
case 'postLength':
return (post.message || '').length;
default:
throw new Error(`Invalid fieldId: ${fieldId}`);
}
};
64 changes: 33 additions & 31 deletions src/getSchema.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
const getSchema = () => {
const cc = DataStudioApp.createCommunityConnector();
const cc = DataStudioApp.createCommunityConnector();
const types = cc.FieldType;
const aggregationType = cc.AggregationType;

const fields = cc.getFields();
const _getField = (fields, fieldId) => {
switch (fieldId) {
case 'userName':
fields
.newDimension()
.setId('userName')
.setName('User name')
.setDescription('Name of user who made the post')
.setType(types.TEXT);
break;
case 'postLength':
fields
.newMetric()
.setId('postLength')
.setName('Post length')
.setDescription('Number of characters in the post')
.setType(types.NUMBER)
.setAggregation(aggregationType.AUTO);
break;
default:
throw new Error(`Invalid fieldId: ${fieldId}`);
}

[
{
id: 'userName',
name: 'User name',
description: 'Name of user who made the post',
type: cc.FieldType.TEXT,
metOrDim: 'dim',
},
{
id: 'postLength',
name: 'Post length',
description: 'Number of characters in the post',
type: cc.FieldType.NUMBER,
metOrDim: 'met',
},
].forEach((field) => {
const newField =
field.metOrDim === 'dim'
? fields.newDimension()
: fields.newMetric();
return fields;
};

const getSchema = (request) => {
let fields = cc.getFields();

newField
.setId(field.id)
.setName(field.name)
.setDescription(field.description)
.setType(field.type);
['userName', 'postLength'].forEach((fieldId) => {
fields = _getField(fields, fieldId);
});

fields.setDefaultDimension('userName');
fields.setDefaultMetric('postLength');

return {
schema: fields.build(),
};
return { schema: fields.build() };
};