Skip to content

Commit

Permalink
Merge pull request #54 from friggframework/bf/ironclad-credential-ent…
Browse files Browse the repository at this point in the history
…ity-bug

Bf/ironclad credential entity bug
  • Loading branch information
sheehantoufiq authored Oct 13, 2022
2 parents 1b49587 + 7884a58 commit 0795148
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 84 deletions.
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

0 comments on commit 0795148

Please sign in to comment.