Skip to content

Commit

Permalink
#12 Update the Custom field dialog to better generate internal reference
Browse files Browse the repository at this point in the history
  • Loading branch information
nadouani committed Jun 26, 2017
1 parent 0f83fb3 commit 3ca7691
Show file tree
Hide file tree
Showing 16 changed files with 99 additions and 42 deletions.
1 change: 1 addition & 0 deletions thehive-backend/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ DELETE /api/list/:itemId org.elastic4play.controllers.D
PATCH /api/list/:itemId org.elastic4play.controllers.DBListCtrl.updateItem(itemId)
POST /api/list/:listName org.elastic4play.controllers.DBListCtrl.addItem(listName)
GET /api/list/:listName org.elastic4play.controllers.DBListCtrl.listItems(listName)
POST /api/list/:listName/_exists org.elastic4play.controllers.DBListCtrl.itemExists(listName)


GET /api/user/current controllers.UserCtrl.currentUser()
Expand Down
1 change: 1 addition & 0 deletions ui/.jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"updatableLink": false,
"setTimeout": false,
"_": false,
"s": false,
"CryptoJS": false,
"c3": false,
"saveSvgAsPng": false,
Expand Down
1 change: 1 addition & 0 deletions ui/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
<script src="bower_components/angular-ui-sortable/sortable.js"></script>
<script src="bower_components/js-base64/base64.js"></script>
<script src="bower_components/angular-scroll/angular-scroll.js"></script>
<script src="bower_components/underscore.string/dist/underscore.string.js"></script>
<!-- endbower -->

<script type="text/javascript" src="bower_components/ace-builds/src-min-noconflict/ace.js"></script>
Expand Down
6 changes: 3 additions & 3 deletions ui/app/scripts/controllers/admin/AdminCaseTemplatesCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,10 @@
};

$scope.addCustomField = function(field) {
if($scope.templateCustomFields.indexOf(field.name) === -1) {
$scope.templateCustomFields.push(field.name);
if($scope.templateCustomFields.indexOf(field.reference) === -1) {
$scope.templateCustomFields.push(field.reference);
} else {
NotificationSrv.log('The custom field [' + field.label + '] has already been added to the template', 'warning');
NotificationSrv.log('The custom field [' + field.name + '] has already been added to the template', 'warning');
}
};

Expand Down
56 changes: 48 additions & 8 deletions ui/app/scripts/controllers/admin/AdminCustomFieldDialogCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
angular.module('theHiveControllers').controller('AdminCustomFieldDialogCtrl',
function($scope, $uibModalInstance, ListSrv, NotificationSrv, customField) {
var self = this;
self.reference = {
types: ['string', 'number', 'boolean', 'date']
self.config = {
types: ['string', 'number', 'boolean', 'date'],
referencePattern: '^[a-zA-Z]{1}[a-zA-Z0-9_-]*'
};

self.customField = customField;
Expand Down Expand Up @@ -36,8 +37,12 @@
return values;
};

self.saveField = function() {
var postData = _.pick(self.customField, 'name', 'title', 'label', 'description', 'type');
self.saveField = function(form) {
if (!form.$valid) {
return;
}

var postData = _.pick(self.customField, 'name', 'reference', 'description', 'type');
postData.options = buildOptionsCollection(self.customField.options);

if(self.customField.id) {
Expand All @@ -47,17 +52,52 @@
onSuccess,
onFailure);
} else {
ListSrv.save(
ListSrv.exists(
{'listId': 'custom_fields'},
{'value': JSON.stringify(postData)},
onSuccess,
onFailure);
{
key: 'reference',
value: postData.reference
},
function(response) {
if(response.data) {
ListSrv.save(
{'listId': 'custom_fields'},
{'value': JSON.stringify(postData)},
onSuccess,
onFailure);
} else {
// TODO handle field validation
form.reference.$setValidity('unique', false);
form.reference.$setDirty();
NotificationSrv.error('AdminCustomFieldDialogCtrl', 'There is already a custom field with the specified reference: ' + postData.reference);
}
},
onFailure
)
}
};

self.clearUniqueReferenceError = function(form) {
form.reference.$setValidity('unique', true);
form.reference.$setPristine();
}

self.cancel = function() {
$uibModalInstance.dismiss();
}

self.onNamechanged = function(form) {
if(!self.customField.name) {
return;
}

var reference = s.trim(s.classify(self.customField.name));
reference = reference.charAt(0).toLowerCase() + reference.slice(1);

self.customField.reference = reference;

self.clearUniqueReferenceError(form);
};

});
})();
4 changes: 0 additions & 4 deletions ui/app/scripts/controllers/admin/AdminCustomFieldsCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@
'listId': 'custom_fields'
}, {}, function(response) {

// self.customFields = _.values(response).filter(_.isString).map(function(item) {
// return JSON.parse(item);
// });

self.customFields = _.map(response.toJSON(), function(value, key) {
var obj = JSON.parse(value);
obj.id = key;
Expand Down
14 changes: 7 additions & 7 deletions ui/app/scripts/controllers/case/CaseDetailsCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
}

$scope.getCustomFieldName = function(fieldDef) {
return 'customFields.' + fieldDef.name + '.' + fieldDef.type;
return 'customFields.' + fieldDef.reference + '.' + fieldDef.type;
};

$scope.addCustomField = function(customField) {
Expand All @@ -111,14 +111,14 @@
modalInstance.result.then(function() {
var temp = $scope.caze.customFields || {};

temp[customField.name] = {};
temp[customField.name][customField.type] = null;
temp[customField.name].order = _.keys(temp).length;
var customFieldValue = {};
customFieldValue[customField.type] = null;
customFieldValue.order = _.keys(temp).length + 1;

$scope.caze.customFields = temp;

$scope.updateField('customFields.', $scope.caze.customFields);
$scope.updateField('customFields.' + customField.reference, customFieldValue);
$scope.updateCustomFieldsList();

$scope.caze.customFields[customField.reference] = customFieldValue;
});
};

Expand Down
4 changes: 2 additions & 2 deletions ui/app/scripts/services/CustomFieldsCacheSrv.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
return JSON.parse(item);
});

_.each(data, function(m){
cache[m.name] = m;
_.each(data, function(field){
cache[field.reference] = field;
});

deferred.resolve(cache);
Expand Down
6 changes: 5 additions & 1 deletion ui/app/scripts/services/ListSrv.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
},
update: {
url: './api/list/:itemId',
method: 'PATCH',
method: 'PATCH'
},
exists: {
url: './api/list/:listId/_exists',
method: 'POST',
}
});
});
Expand Down
4 changes: 2 additions & 2 deletions ui/app/views/partials/admin/case-templates.html
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ <h4 class="vpad10 text-primary">
</a>
<ul class="dropdown-menu" uib-dropdown-menu>
<li ng-repeat="(key, value) in fields">
<a ng-click="addCustomField(value)">{{value.label}}</a>
<a ng-click="addCustomField(value)">{{value.name}}</a>
</li>
</ul>
</span>
Expand All @@ -218,7 +218,7 @@ <h4 class="vpad10 text-primary">
<a href ng-click="isCollapsed=!isCollapsed">
<i class="fa" ng-class="{'fa-caret-down': isCollapsed, 'fa-caret-up': !isCollapsed}"></i>
</a>
<span class="hpad5">{{fields[m].label}}</span>
<span class="hpad5">{{fields[m].name}}</span>
<span class="pull-right">
<a class="text-danger" href ng-click="removeCustomField(m)">
<i class="fa fa-times"></i>&nbsp;Delete</a>
Expand Down
28 changes: 20 additions & 8 deletions ui/app/views/partials/admin/custom-field-dialog.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<form class="form-horizontal" name="fieldsForm" ng-submit="$vm.saveField()" novalidate>
<form class="form-horizontal" name="fieldsForm" ng-submit="$vm.saveField(fieldsForm)" novalidate>
<div class="modal-header bg-primary">
<h3 class="modal-title">{{$vm.customField.id ? 'Update' : 'Add'}} custom field</h3>
</div>
Expand All @@ -10,18 +10,30 @@ <h3 class="modal-title">{{$vm.customField.id ? 'Update' : 'Add'}} custom field</
<i class="fa fa-asterisk text-danger"></i>
</label>
<div class="col-sm-10">
<input class="form-control" name="name" ng-model="$vm.customField.name" placeholder="Ex: cvss, threatActor, businessRisk" required type="text">
<input class="form-control" name="name"
placeholder="Field's title, Ex: CVSS, Threat actor, Business risk"
ng-model="$vm.customField.name"
ng-keyup="$vm.onNamechanged(fieldsForm)"
required type="text">
<p class="help-block" ng-show="fieldsForm.name.$invalid && !fieldsForm.name.$pristine">This field is required.</p>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : fieldsForm.label.$invalid && !fieldsForm.label.$pristine }">

<div class="form-group" ng-class="{ 'has-error' : fieldsForm.reference.$invalid && fieldsForm.reference.$dirty }">
<label class="col-sm-2 control-label">
Label
Reference
<i class="fa fa-asterisk text-danger"></i>
</label>
<div class="col-sm-10">
<input class="form-control" name="label" ng-model="$vm.customField.label" placeholder="Ex: CVSS, Threat actor, Business risk" required type="text">
<p class="help-block" ng-show="fieldsForm.label.$invalid && !fieldsForm.label.$pristine">This field is required.</p>
<input class="form-control" name="reference" type="text"
placeholder="Internal reference, Ex: cvss, threatActor, businessRisk"
ng-model="$vm.customField.reference"
ng-keyup="$vm.clearUniqueReferenceError(fieldsForm)"
ng-pattern="$vm.config.referencePattern"
required>
<p class="help-block" ng-show="fieldsForm.reference.$error.unique">There is already a field with this reference. It should be unique.</p>
<p class="help-block" ng-show="fieldsForm.reference.$error.required && fieldsForm.reference.$dirty">This field is required.</p>
<p class="help-block" ng-show="fieldsForm.reference.$error.pattern && fieldsForm.reference.$dirty">This field is should satisfy the following pattern: {{$vm.config.referencePattern}}</p>
</div>
</div>

Expand All @@ -42,13 +54,13 @@ <h3 class="modal-title">{{$vm.customField.id ? 'Update' : 'Add'}} custom field</
</label>
<div class="col-sm-10">
<select class="form-control" name="type" ng-model="$vm.customField.type"
ng-options="fieldType for fieldType in $vm.reference.types"
ng-options="fieldType for fieldType in $vm.config.types"
placeholder="Field's type" required></select>
<p class="help-block" ng-show="fieldsForm.type.$invalid && !fieldsForm.type.$pristine">This field is required.</p>
</div>
</div>

<div class="form-group">
<div class="form-group" ng-show="$vm.customField.type === 'string' || $vm.customField.type === 'number'">
<label class="col-sm-2 control-label">
Possible values
</label>
Expand Down
4 changes: 2 additions & 2 deletions ui/app/views/partials/admin/custom-fields.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ <h3 class="box-title">Case custom fields ({{$vm.customFields.length}})</h3>
<tr>
<th width="80">Type</th>
<th width="250">Name</th>
<th width="250">Label</th>
<th width="250">Internal Reference</th>
<th>Description</th>
<th width="200">Options</th>
<th width="80" class="text-center">Actions</th>
Expand All @@ -28,7 +28,7 @@ <h3 class="box-title">Case custom fields ({{$vm.customFields.length}})</h3>
<span class="label label-default">{{field.type | uppercase}}</span>
</td>
<td><a href ng-click="$vm.showFieldDialog(field)">{{field.name}}</a></td>
<td>{{field.label}}</td>
<td>{{field.reference}}</td>
<td>{{field.description || 'N/A'}}</td>
<td ng-if="field.options.length === 0">
<em>None</em>
Expand Down
2 changes: 1 addition & 1 deletion ui/app/views/partials/case/case.add.field.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ <h3 class="modal-title">Add custom field to Case #{{caze.caseId}}</h3>
</div>
<div class="modal-body">
<div class="vpad20">
You are about to add the <strong uib-tooltip="{{data.description}}">{{data.label}}</strong> custom field to the case <strong>#{{caze.caseId}}: {{caze.title}}</strong>
You are about to add the <strong uib-tooltip="{{data.description}}">{{data.name}}</strong> custom field to the case <strong>#{{caze.caseId}}: {{caze.title}}</strong>
<br/>
<br/>
Are you sure you want to continue ?
Expand Down
6 changes: 3 additions & 3 deletions ui/app/views/partials/case/details/custom.fields.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ <h4 class="vpad10 text-primary">
</a>
<ul class="dropdown-menu" uib-dropdown-menu>
<li ng-repeat="(key, value) in allCustomFields">
<a ng-click="addCustomField(value)">{{value.label}}</a>
<a ng-click="addCustomField(value)">{{value.name}}</a>
</li>
</ul>
</span>
Expand All @@ -19,8 +19,8 @@ <h4 class="vpad10 text-primary">

<dl class="dl-horizontal clear"
ng-repeat="k in orderedFields"
ng-init="fieldDef = customFieldsCache[k]; customFieldValue=caze.customFields[fieldDef.name][fieldDef.type];">
<dt class="pull-left" uib-tooltip="{{fieldDef.description}}">{{fieldDef.label}}</dt>
ng-init="fieldDef = customFieldsCache[k]; customFieldValue=caze.customFields[fieldDef.reference][fieldDef.type];">
<dt class="pull-left" uib-tooltip="{{fieldDef.description}}">{{fieldDef.name}}</dt>
<dd ng-if="fieldDef.options.length > 0">
<updatable-select
options="fieldDef.options"
Expand Down
3 changes: 2 additions & 1 deletion ui/bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"angular-base64-upload": "^0.1.19",
"angular-ui-sortable": "^0.17.0",
"js-base64": "^2.1.9",
"angular-scroll": "^1.0.1"
"angular-scroll": "^1.0.1",
"underscore.string": "^3.3.4"
},
"devDependencies": {
"angular-mocks": "1.5.8"
Expand Down
1 change: 1 addition & 0 deletions ui/test/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ module.exports = function(config) {
'bower_components/angular-ui-sortable/sortable.js',
'bower_components/js-base64/base64.js',
'bower_components/angular-scroll/angular-scroll.js',
'bower_components/underscore.string/dist/underscore.string.js',
'bower_components/angular-mocks/angular-mocks.js',
// endbower
"bower_components/cryptojslib/components/core-min.js",
Expand Down

0 comments on commit 3ca7691

Please sign in to comment.