Skip to content

Commit

Permalink
reworked UI for token credential
Browse files Browse the repository at this point in the history
  • Loading branch information
cgrayson committed Mar 15, 2024
1 parent cd0228f commit c2c9179
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 36 deletions.
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
outbound: {
authenticated_json: require('./lib/authjson'),
token_authenticated: require('./lib/authjson'),
json: require('./lib/json')
},
ui: require('./lib/ui')
Expand Down
2 changes: 1 addition & 1 deletion lib/authjson.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const validate = (vars) => {
if (baseValidation) {
return baseValidation;
}
if (!vars.credential_id) return 'credential ID is required';
if (!vars.credential_id || vars.credential?.type !== 'token') return 'ID of token credential is required';
if (!vars.authentication_url) return 'authentication URL is required';
};

Expand Down
88 changes: 65 additions & 23 deletions lib/ui/public/app/auth/Auth.vue
Original file line number Diff line number Diff line change
@@ -1,49 +1,91 @@
<template>
<div>
<header>
Basic Authentication
</header>
<header>Authentication</header>
<section>
<p>A username and password combo for standard HTTP authentication.
<form>
<p v-if="!originalType">What type of authentication should be used?</p>
<ul>
<li>
<label>Username</label>
<input type="text" v-model="credential.username">
<li v-if="!originalType">
<label>
<input type="radio" v-model="credential.type" value="none" id="none"> <b>None</b> - The server doesn't require any authentication
</label>
</li>
<li>
<label>Password</label>
<input type="text" v-model="credential.password">
<li v-if="originalType === 'user' || !originalType">
<label>
<input type="radio" v-model="credential.type" value="user" id="user"> <b>Username &amp; Password</b> - The server requires a username and password ("Basic" authentication)
</label>
<section v-if="credential.type === 'user'">
<ul>
<li>
<label>Username</label>
<input type="text" v-model="credential.username">
</li>
<li>
<label>Password</label>
<input type="text" v-model="credential.password">
</li>
</ul>
</section>
</li>
<li v-if="originalType === 'token' || !originalType">
<label>
<input type="radio" v-model="credential.type" value="token" id="token"> <b>Bearer Token</b> - The server uses token-based authentication
</label>
<section v-if="credential.type === 'token'">
<ul>
<li>
<label>Token</label>
<input type="text" v-model="credential.token">
</li>
</ul>
</section>
</li>
</ul>
</form>
</section>
<footer>
<button v-on:click="$store.dispatch('cancel')">Cancel</button>
<button v-on:click="next" class="primary">{{ (credential.username && credential.password) ? 'Continue' : 'Skip' }}</button>
</footer>
<Navigation :onNext="next" :disableNext="(credential.type === 'token' && !credential.token) || (credential.type === 'user' && (!credential.username || !credential.password))" />
</div>
</template>

<script>
import { Navigation } from '@activeprospect/integration-components';
export default {
data() {
// this isn't a "real" credential, which wouldn't have `type: none` or both password & token
const credentialTemplate = {
username: '',
password: '',
token: '',
package: 'leadconduit-json',
type: 'none'
};
const existingCredential = this.$store.getters.getCredential;
return {
credential: this.$store.getters.getCredential || {
username: '',
password: '',
package: 'leadconduit-json',
type: 'user'
}
originalType: existingCredential?.type, // used to keep user from changing type when editing
credential: existingCredential || credentialTemplate,
};
},
methods: {
next() {
if (this.credential.username && this.credential.password) {
return this.$store.dispatch('createCredential', this.credential);
if (this.credential.type === 'user') {
delete this.credential.token;
this.$store.dispatch('saveCredential', this.credential);
} else if (this.credential.type === 'token') {
delete this.credential.username;
delete this.credential.password;
this.$store.dispatch('saveCredential', this.credential);
}
this.$store.state.ui.create({ 'redirect': 'config'});
},
},
components: { Navigation }
};
</script>

<style>
label {
font-weight: normal !important;
}
input[type=text] {
width: 50%
}
</style>
10 changes: 5 additions & 5 deletions lib/ui/public/app/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const initStore = (config, ui) => new Vuex.Store({
Vue.set(state, 'parsedFields', fields);
},
setJson (state, json) {
Vue.set(state, 'rawJson', json)
Vue.set(state, 'rawJson', json);
},
setResponseOpts (state, { outcomePath, outcomeTerm, reasonPath }) {
Vue.set(state, 'outcomePath', outcomePath);
Expand All @@ -33,15 +33,15 @@ const initStore = (config, ui) => new Vuex.Store({
}
},
getters: {
getCredential: (state, getters) => {
getCredential: () => {
return config.credential;
}
},
actions: {
cancel (context) {
context.state.ui.cancel();
},
createCredential(context, credential) {
saveCredential(context, credential) {
if (!credential.id) credential.id = new ObjectID().toHexString();
context.state.ui.create({ credential });
},
Expand All @@ -58,7 +58,7 @@ const initStore = (config, ui) => new Vuex.Store({
id: config.entity.id
},
integration: {
module_id: config.integration,
module_id: config.credential?.type === 'token' ? 'leadconduit-json.outbound.token_authenticated' : 'leadconduit-json.outbound.json',
mappings: [{
property: 'credential_id',
value: (config.credential) ? config.credential.id : undefined
Expand All @@ -74,7 +74,7 @@ const initStore = (config, ui) => new Vuex.Store({
}, {
property: 'reason_path',
value: context.state.reasonPath
}].filter((mapping) => { return mapping.value })
}].filter((mapping) => { return mapping.value; })
}
}]
};
Expand Down
1 change: 0 additions & 1 deletion lib/ui/public/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<!DOCTYPE html>
<head>
<title>Leadconduit Integration</title>
<link href="/lc-client.css" rel="stylesheet">
</head>
<body class="rich-integration-ui">
<div id="app"></div>
Expand Down
9 changes: 6 additions & 3 deletions test/authjson-spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { assert } = require('chai');
const { requestVariables, validate } = require('../lib/authjson');

describe('Authenticated JSON', function () {
describe('Token Authenticated', function () {

describe('Request variables', function () {
it('makes credential_id required', function () {
Expand All @@ -18,7 +18,10 @@ describe('Authenticated JSON', function () {
vars = {
url: 'https://example.com/deliver',
credential_id: 'abc123',
authentication_url: 'https://example.com/authenticate'
authentication_url: 'https://example.com/authenticate',
credential: {
type: 'token'
}
};
});

Expand All @@ -33,7 +36,7 @@ describe('Authenticated JSON', function () {

it('fails when missing credential ID', function () {
delete vars.credential_id;
assert.equal(validate(vars), 'credential ID is required');
assert.equal(validate(vars), 'ID of token credential is required');
});

it('fails when missing auth URL', function () {
Expand Down
3 changes: 1 addition & 2 deletions test/json-spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Generated by CoffeeScript 1.10.0
(function() {
var assert, integration, types;

Expand Down Expand Up @@ -217,7 +216,7 @@
return assert.equal(integration.validate({
url: 'http://foo.com',
method: 'HEAD'
}), 'Unsupported HTTP method - use POST, PUT, DELETE');
}), 'Unsupported HTTP method - use POST, PUT, DELETE, PATCH');
});
it('should require valid search outcome', function() {
return assert.equal(integration.validate({
Expand Down

0 comments on commit c2c9179

Please sign in to comment.