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

Bf/ironclad credential entity bug #54

Merged
merged 22 commits into from
Oct 13, 2022
Merged
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
17 changes: 17 additions & 0 deletions api-module-library/ironclad/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# v0.0.4 (Wed Oct 12 2022)

#### 🐛 Bug Fix

- Bug fixes and updates for Manager
- Switched from credential model object to mongoose queries for Credential
- Switched from credential model object to mongoose queries from Entity
- Updated logic behind findOrCreateCredential and findOrCreateEntity
- Added Authfield for Ironclad Api Key
- Fixed deathorize bug

#### Authors: 1

- Sheehan Khan([@sheehantoufiq](https://github.com/sheehantoufiq))

---

# v0.0.3 (Tue Oct 11 2022)

#### 🐛 Bug Fix
Expand Down
2 changes: 1 addition & 1 deletion api-module-library/ironclad/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

This is the API Module for ironclad that allows the [Frigg](https://friggframework.org) code to talk to the ironclad API.

Read more on the [Frigg documentation site](https://docs.friggframework.org/api-modules/list/ironclad
Read more on the [Frigg documentation site](https://docs.friggframework.org/api-modules/list/ironclad
47 changes: 20 additions & 27 deletions api-module-library/ironclad/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ class Api extends ApiKeyRequester {
webhooks: '/public/api/v1/webhooks',
webhookByID: (webhookId) => `/public/api/v1/webhooks/${webhookId}`,
workflows: '/public/api/v1/workflows',
workflowsByID: (workflowId) => `/public/api/v1/workflows/${workflowId}`,
workflowsByID: (workflowId) =>
`/public/api/v1/workflows/${workflowId}`,
workflowSchemas: '/public/api/v1/workflow-schemas',
workflowSchemaByID: (schemaId) => `/public/api/v1/workflow-schemas/${schemaId}`
workflowSchemaByID: (schemaId) =>
`/public/api/v1/workflow-schemas/${schemaId}`,
};
}

Expand Down Expand Up @@ -43,8 +45,8 @@ class Api extends ApiKeyRequester {
},
body: {
events,
targetURL
}
targetURL,
},
};
const response = await this._post(options);
return response;
Expand All @@ -56,8 +58,8 @@ class Api extends ApiKeyRequester {
headers: {
'content-type': 'application/json',
},
body: {}
}
body: {},
};

if (events.length > 0) {
options.body.events = events;
Expand All @@ -69,28 +71,19 @@ class Api extends ApiKeyRequester {

const response = await this._patch(options);
return response;

}
async deleteWebhook(webhookId) {
const options = {
url: this.baseUrl + this.URLs.webhookByID(webhookId)
}
url: this.baseUrl + this.URLs.webhookByID(webhookId),
};
const response = await this._delete(options);
return response;
}

async listAllWorkflows() {
const options = {
url: this.baseUrl + this.URLs.workflows
}
const response = await this._get(options);
return response;
}

async retrieveWorkflow(id) {
const options = {
url: this.baseUrl + this.URLs.workflowsByID(id)
}
url: this.baseUrl + this.URLs.workflows,
};
const response = await this._get(options);
return response;
}
Expand All @@ -99,36 +92,36 @@ class Api extends ApiKeyRequester {
const options = {
url: this.baseUrl + this.URLs.workflows,
headers: {
'content-type': 'application/json'
'content-type': 'application/json',
},
body
}
body,
};
const response = await this._post(options);
return response;
}

async listAllWorkflowSchemas(params) {
const options = {
url: this.baseUrl + this.URLs.workflowSchemas,
query: params
}
query: params,
};
const response = await this._get(options);
return response;
}

async retrieveWorkflowSchema(params, id) {
const options = {
url: this.baseUrl + this.URLs.workflowSchemaByID(id),
query: params
}
query: params,
};
const response = await this._get(options);
return response;
}

async listAllWorkflowApprovals(id) {
const options = {
url: this.baseUrl + this.URLs.workflowsByID(id) + '/approvals',
}
};
const response = await this._get(options);
return response;
}
Expand Down
21 changes: 21 additions & 0 deletions api-module-library/ironclad/authFields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const AuthFields = {
jsonSchema: {
type: 'object',
required: ['apiKey'],
properties: {
apiKey: {
type: 'string',
title: 'Access Token',
},
},
},
uiSchema: {
apiKey: {
'ui:help':
'Generate access tokens in Ironclad by clicking [YOUR_NAME] > Company Settings > API > Access Tokens. Must have admin privalages.',
'ui:placeholder': 'Your Ironclad Access Token...',
},
},
};

module.exports = AuthFields;
10 changes: 5 additions & 5 deletions api-module-library/ironclad/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ const ModuleManager = require('./manager');
const Config = require('./defaultConfig');

module.exports = {
Api,
Credential,
Entity,
ModuleManager,
Config,
Api,
Credential,
Entity,
ModuleManager,
Config,
};
107 changes: 72 additions & 35 deletions api-module-library/ironclad/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ const _ = require('lodash');
const { Api } = require('./api');
const { Entity } = require('./models/entity');
const { Credential } = require('./models/credential');
const { get } = require('@friggframework/assertions');
const {
ModuleManager,
ModuleConstants,
} = require('@friggframework/module-plugin');
const AuthFields = require('./authFields');
const Config = require('./defaultConfig.json');

class Manager extends ModuleManager {
static Entity = Entity;

static Credential = Credential;

constructor(params) {
Expand All @@ -24,29 +25,21 @@ class Manager extends ModuleManager {
static async getInstance(params) {
const instance = new this(params);

let ironcladParams;
let managerParams = { delegate: instance };

if (params.entityId) {
instance.entity = await instance.entityMO.get(params.entityId);
if (instance.entity.credential) {
instance.credential = await instance.credentialMO.get(
instance.entity.credential
);
ironcladParams = {
apiKey: instance.credential.apiKey,
};
}
instance.entity = await Entity.findById(params.entityId);
instance.credential = await Credential.findById(
instance.entity.credential
);
managerParams.apiKey = instance.credential.apiKey;
} else if (params.credentialId) {
instance.credential = await instance.credentialMO.get(
instance.credential = await Credential.findById(
params.credentialId
);
ironcladParams = {
apiKey: instance.credential.apiKey,
};
}
if (ironcladParams) {
instance.api = await new Api(ironcladParams);
managerParams.apiKey = instance.credential.apiKey;
}
instance.api = await new Api(managerParams);

return instance;
}
Expand All @@ -55,41 +48,85 @@ class Manager extends ModuleManager {
return {
url: null,
type: ModuleConstants.authType.apiKey,
data: {
jsonSchema: AuthFields.jsonSchema,
uiSchema: AuthFields.uiSchema,
},
};
}

async processAuthorizationCallback(params) {
const apiKey = get(params.data, 'apiKey');
const apiKey = get(params.data, 'apiKey', null);
this.api = new Api({ apiKey });

const credentials = await this.credentialMO.list({ user: this.userId });
await this.findOrCreateCredential({
apiKey,
});
await this.findOrCreateEntity({
apiKey,
});
return {
credential_id: this.credential.id,
entity_id: this.entity.id,
type: Manager.getName(),
};
}

if (credentials.length > 1) {
throw new Error('User has multiple credentials???');
}
async findOrCreateCredential(params) {
const apiKey = get(params.data, 'apiKey', null);

const credential = await this.credentialMO.upsert({ user: this.userId }, {
const search = await Entity.find({
user: this.userId,
api_key: apiKey,
})
apiKey,
});

if (search.length === 0) {
const createObj = {
user: this.userId,
apiKey,
};
this.credential = await Credential.create(createObj);
} else if (search.length === 1) {
this.credential = search[0];
} else {
debug(
'Multiple credentials found with the same Client ID:',
apiKey
);
}
}

const entity = await this.entityMO.getByUserId(this.userId);
async findOrCreateEntity(params) {
const apiKey = get(params.data, 'apiKey', null);
const name = get(params, 'name', null);

return {
credential_id: credential.id,
entity_id: entity.id,
type: Manager.getName(),
};
const search = await Entity.find({
user: this.userId,
externalId: apiKey,
});
if (search.length === 0) {
const createObj = {
credential: this.credential.id,
user: this.userId,
name,
externalId: apiKey,
};
this.entity = await Entity.create(createObj);
} else if (search.length === 1) {
this.entity = search[0];
} else {
debug('Multiple entities found with the same external ID:', apiKey);
this.throwException('');
}
}

async deauthorize() {
// wipe api connection
this.api = new Api();

// delete credentials from the database
const entity = await this.entityMO.getByUserId(this.userId);
const entity = await Entity.find({ user: this.userId });
if (entity.credential) {
await this.credentialMO.delete(entity.credential);
await Credential.deleteOne({ _id: entity.credential });
entity.credential = undefined;
await entity.save();
}
Expand Down
2 changes: 1 addition & 1 deletion api-module-library/ironclad/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@friggframework/api-module-ironclad",
"version": "0.0.3",
"version": "0.0.4",
"prettier": "@friggframework/prettier-config",
"description": "",
"main": "index.js",
Expand Down
Loading