Skip to content
Permalink
Browse files

feat(dao): JS-29 - add support for "isAcknowledged" on alarms

  • Loading branch information...
RangerRick committed Mar 22, 2019
1 parent a01744a commit ff1515ab0588e2e978169f5a146e0497cbee9096
@@ -78,6 +78,7 @@
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"
},
"dependencies": {
"@types/lodash.clonedeep": "^4.5.6",
"axios": "^0.16.1",
"cli-table3": "^0.5.0",
"commander": "^2.9.0",
@@ -0,0 +1,16 @@

import {Clause} from './Clause';
import {Filter} from './Filter';
import {NestedRestriction} from './NestedRestriction';
import {Restriction} from './Restriction';

/**
* A visitor for filters.
* @module FilterVisitor
*/
export interface IFilterVisitor {
onFilter?: (filter: Filter) => void;
onClause?: (clause: Clause) => void;
onRestriction?: (restriction: Restriction) => void;
onNestedRestriction?: (restriction: NestedRestriction) => void;
}
@@ -1,10 +1,11 @@
import {IFilterProcessor} from '../api/IFilterProcessor';
import {IHasHTTP} from '../api/IHasHTTP';
import {IOnmsHTTP} from '../api/IOnmsHTTP';
import {OnmsError} from '../api/OnmsError';

import {Filter} from '../api/Filter';
import {IFilterVisitor} from '../api/IFilterVisitor';
import {NestedRestriction} from '../api/NestedRestriction';
import {OnmsHTTPOptions} from '../api/OnmsHTTPOptions';
import {Restriction} from '../api/Restriction';
import {SearchProperty} from '../api/SearchProperty';
import {SearchPropertyType} from '../api/SearchPropertyType';

@@ -25,6 +26,7 @@ const moment = require('moment');
// tslint:disable-next-line
import {Moment} from 'moment';
import {IValueProvider} from './IValueProvider';
import { Clause } from '../api/Clause';

/**
* An abstract data access layer API, meant to (somewhat) mirror the DAO interfaces
@@ -166,6 +168,35 @@ export abstract class AbstractDAO<K, T> extends BaseDAO implements IValueProvide
return data;
}

protected visitClause(clause: Clause, visitor: IFilterVisitor) {
const self = this;
if (visitor.onClause) { visitor.onClause(clause); }
const restriction = clause.restriction;
if (restriction instanceof Restriction) {
if (visitor.onRestriction) { visitor.onRestriction(restriction); }
} else if (restriction instanceof NestedRestriction) {
if (visitor.onNestedRestriction) { visitor.onNestedRestriction(restriction); }
restriction.clauses.forEach((c) => {
self.visitClause(c, visitor);
});
} else {
log.warn('Restriction is of an unknown type: ' + JSON.stringify(restriction), catDao);
}
}

/**
* Iterate over a Filter object and its children.
* @param filter the filter to visit
* @param visitor the class to invoke while visiting the filter
*/
protected visitFilter(filter: Filter, visitor: IFilterVisitor) {
const self = this;
if (visitor.onFilter) { visitor.onFilter(filter); }
filter.clauses.forEach((clause) => {
self.visitClause(clause, visitor);
});
}

/**
* Create an [[OnmsHTTPOptions]] object for DAO calls given an optional filter.
* @param filter - the filter to use
@@ -1,13 +1,15 @@
import {AbstractDAO} from './AbstractDAO';
import {EventDAO} from './EventDAO';

import {Comparators} from '../api/Comparator';
import {Filter} from '../api/Filter';
import {IHasHTTP} from '../api/IHasHTTP';
import {IHash} from '../internal/IHash';
import {IOnmsHTTP} from '../api/IOnmsHTTP';
import {OnmsError} from '../api/OnmsError';
import {OnmsHTTPOptions} from '../api/OnmsHTTPOptions';
import {OnmsResult} from '../api/OnmsResult';
import {Restriction} from '../api/Restriction';
import {SearchProperty} from '../api/SearchProperty';

import {OnmsAlarm} from '../model/OnmsAlarm';
@@ -21,6 +23,7 @@ import {OnmsMemo} from '../model/OnmsMemo';

import {log, catDao} from '../api/Log';
import {Category} from 'typescript-logging';
import { IFilterVisitor } from '../api/IFilterVisitor';

/** @hidden */
const cat = new Category('alarms', catDao);
@@ -438,6 +441,22 @@ export class AlarmDAO extends AbstractDAO<number, OnmsAlarm> {
* @hidden
*/
protected async getOptions(filter?: Filter): Promise<OnmsHTTPOptions> {
if (filter) {
this.visitFilter(filter, {
onRestriction: (restriction: Restriction) => {
if (restriction.attribute === 'isAcknowledged') {
let value = String(restriction.value).toLowerCase() === 'true';
restriction.attribute = 'alarmAckTime';
if (restriction.comparator.label === Comparators.NE.label) {
value = !value;
}
restriction.comparator = value ? Comparators.NOTNULL : Comparators.NULL;
restriction.value = undefined;
}
},
});
}

return super.getOptions(filter).then((options) => {
// always use application/json for v2 calls
if (this.getApiVersion() === 2) {
@@ -116,6 +116,11 @@ export class OnmsAlarm implements IHasUrlValue {
/** link to the alarm details page on the source instance */
public detailsPage: string;

/** whether the alarm has been acknowledged */
public get isAcknowledged() {
return this.ackTime !== undefined && this.ackTime !== null;
}

/** whether the alarm is a situation */
public get isSituation() {
return this.relatedAlarms && this.relatedAlarms.length > 0;
@@ -44,6 +44,44 @@ describe('AlarmDAO with v1 API', () => {
done();
});
});
it('AlarmDAO.getOptions()', (done) => {
(dao as any).getOptions().then((opts) => {
expect(opts).toMatchObject({});
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged=true)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'true'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters.alarmAckTime).toEqual('notnull');
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged=false)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'false'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters.alarmAckTime).toEqual('null');
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged!=true)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'true'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters.alarmAckTime).toEqual('null');
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged!=false)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'false'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters.alarmAckTime).toEqual('notnull');
done();
});
});
it('AlarmDAO.get(404725)', () => {
return dao.get(404725).then((alarm) => {
expect(alarm.id).toEqual(404725);
@@ -58,6 +96,44 @@ describe('AlarmDAO with v1 API', () => {
expect(alarms.length).toEqual(1);
});
});
it('AlarmDAO.find(isAcknowledged=true)', () => {
const filter = new Filter();
filter.withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'true'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).toBeDefined();
expect(alarms[0].ackTime.valueOf()).toEqual(1495806508530);
expect(alarms[0].ackUser).toEqual('ranger');
});
});
it('AlarmDAO.find(isAcknowledged=false)', () => {
const filter = new Filter();
filter.withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'false'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).not.toBeDefined();
expect(alarms[0].ackUser).not.toBeDefined();
});
});
it('AlarmDAO.find(isAcknowledged!=true)', () => {
const filter = new Filter();
filter.withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'true'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).not.toBeDefined();
expect(alarms[0].ackUser).not.toBeDefined();
});
});
it('AlarmDAO.find(isAcknowledged!=false)', () => {
const filter = new Filter();
filter.withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'false'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).toBeDefined();
expect(alarms[0].ackTime.valueOf()).toEqual(1495806508530);
expect(alarms[0].ackUser).toEqual('ranger');
});
});
it('AlarmDAO.searchProperties() should reject', () => {
return expect(dao.searchProperties()).rejects.toBeDefined();
});
@@ -162,6 +238,44 @@ describe('AlarmDAO with v2 API', () => {
done();
});
});
it('AlarmDAO.getOptions()', (done) => {
(dao as any).getOptions().then((opts) => {
expect(opts).toMatchObject({});
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged=true)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'true'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters._s).toEqual('alarmAckTime!=\u0000');
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged=false)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'false'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters._s).toEqual('alarmAckTime==\u0000');
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged!=true)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'true'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters._s).toEqual('alarmAckTime==\u0000');
done();
});
});
it('AlarmDAO.getOptions(isAcknowledged!=false)', (done) => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'false'));
(dao as any).getOptions(filter).then((opts) => {
expect(opts.parameters).toBeDefined();
expect(opts.parameters._s).toEqual('alarmAckTime!=\u0000');
done();
});
});
it('AlarmDAO.get(6806)', () => {
return dao.get(6806).then((alarm) => {
expect(alarm.id).toEqual(6806);
@@ -181,6 +295,43 @@ describe('AlarmDAO with v2 API', () => {
expect(alarms[0].id).toEqual(6806);
});
});
it('AlarmDAO.find(isAcknowledged=true)', () => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'true'));
return dao.find(filter).then((alarms) => {
console.log('alarms=', JSON.stringify(alarms, undefined, 2));
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).toBeDefined();
expect(alarms[0].ackTime.valueOf()).toEqual(1495806508530);
expect(alarms[0].ackUser).toEqual('ranger');
});
});
/*
it('AlarmDAO.find(isAcknowledged=false)', () => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.EQ, 'false'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).not.toBeDefined();
expect(alarms[0].ackUser).not.toBeDefined();
});
});
it('AlarmDAO.find(isAcknowledged!=true)', () => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'true'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).not.toBeDefined();
expect(alarms[0].ackUser).not.toBeDefined();
});
});
it('AlarmDAO.find(isAcknowledged!=false)', () => {
const filter = new Filter().withOrRestriction(new Restriction('isAcknowledged', Comparators.NE, 'false'));
return dao.find(filter).then((alarms) => {
expect(alarms.length).toEqual(1);
expect(alarms[0].ackTime).toBeDefined();
expect(alarms[0].ackTime.valueOf()).toEqual(1495806508530);
expect(alarms[0].ackUser).toEqual('ranger');
});
});
*/
it('AlarmDAO.find(uei=should-not-exist)', () => {
const filter = new Filter();
filter.withOrRestriction(new Restriction('alarm.uei', Comparators.EQ, 'should-not-exist'));
@@ -5,6 +5,8 @@ declare const Promise, require;
// tslint:disable-next-line
const URI = require('urijs');

import clonedeep from 'lodash.clonedeep';

import {AbstractHTTP} from '../../src/rest/AbstractHTTP';

import {OnmsHTTPOptions} from '../../src/api/OnmsHTTPOptions';
@@ -30,6 +32,23 @@ export class MockHTTP19 extends AbstractHTTP {
result.type = 'application/json';
return Promise.resolve(result);
}
case 'rest/alarms?limit=1000&alarmAckTime=notnull': {
const ret = clonedeep(require('./19.1.0/get/rest/alarms/id.eq.404725.json'));
ret.alarm[0].ackTime = 1495806508530;
ret.alarm[0].ackUser = 'ranger';
const result = OnmsResult.ok(ret);
result.type = 'application/json';
return Promise.resolve(result);
}
case 'rest/alarms?limit=1000&alarmAckTime=null': {
const ret = clonedeep(require('./19.1.0/get/rest/alarms/id.eq.404725.json'));
delete ret.alarm[0].ackId;
delete ret.alarm[0].ackTime;
delete ret.alarm[0].ackUser;
const result = OnmsResult.ok(ret);
result.type = 'application/json';
return Promise.resolve(result);
}
case 'rest/alarms?limit=1000&comparator=eq&id=404725': {
const result = OnmsResult.ok(require('./19.1.0/get/rest/alarms/id.eq.404725.json'));
result.type = 'application/json';
@@ -67,7 +86,7 @@ export class MockHTTP19 extends AbstractHTTP {
}
}

throw new Error('Not yet implemented: GET ' + urlObj.toString());
throw new Error('19: Not yet implemented: GET ' + urlObj.toString());
}

public put(url: string, options?: OnmsHTTPOptions) {
@@ -119,7 +138,7 @@ export class MockHTTP19 extends AbstractHTTP {
}
}

throw new Error('Not yet implemented: PUT ' + urlObj.toString());
throw new Error('19: Not yet implemented: PUT ' + urlObj.toString());
}

public post(url: string, options?: OnmsHTTPOptions) {
@@ -138,11 +157,11 @@ export class MockHTTP19 extends AbstractHTTP {
*/
}

throw new Error('Not yet implemented: POST ' + urlObj.toString());
throw new Error('19: Not yet implemented: POST ' + urlObj.toString());
}

public httpDelete(url: string, options?: OnmsHTTPOptions): Promise<OnmsResult<any>> {
const urlObj = new URI(url);
throw new Error('Not yet implemented: DELETE ' + urlObj.toString());
throw new Error('19: Not yet implemented: DELETE ' + urlObj.toString());
}
}

0 comments on commit ff1515a

Please sign in to comment.
You can’t perform that action at this time.