Skip to content

Commit 3ca7691

Browse files
committed
#12 Update the Custom field dialog to better generate internal reference
1 parent 0f83fb3 commit 3ca7691

16 files changed

+99
-42
lines changed

thehive-backend/conf/routes

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ DELETE /api/list/:itemId org.elastic4play.controllers.D
7979
PATCH /api/list/:itemId org.elastic4play.controllers.DBListCtrl.updateItem(itemId)
8080
POST /api/list/:listName org.elastic4play.controllers.DBListCtrl.addItem(listName)
8181
GET /api/list/:listName org.elastic4play.controllers.DBListCtrl.listItems(listName)
82+
POST /api/list/:listName/_exists org.elastic4play.controllers.DBListCtrl.itemExists(listName)
8283

8384

8485
GET /api/user/current controllers.UserCtrl.currentUser()

ui/.jshintrc

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"updatableLink": false,
2424
"setTimeout": false,
2525
"_": false,
26+
"s": false,
2627
"CryptoJS": false,
2728
"c3": false,
2829
"saveSvgAsPng": false,

ui/app/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
<script src="bower_components/angular-ui-sortable/sortable.js"></script>
108108
<script src="bower_components/js-base64/base64.js"></script>
109109
<script src="bower_components/angular-scroll/angular-scroll.js"></script>
110+
<script src="bower_components/underscore.string/dist/underscore.string.js"></script>
110111
<!-- endbower -->
111112

112113
<script type="text/javascript" src="bower_components/ace-builds/src-min-noconflict/ace.js"></script>

ui/app/scripts/controllers/admin/AdminCaseTemplatesCtrl.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,10 @@
163163
};
164164

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

ui/app/scripts/controllers/admin/AdminCustomFieldDialogCtrl.js

+48-8
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
angular.module('theHiveControllers').controller('AdminCustomFieldDialogCtrl',
55
function($scope, $uibModalInstance, ListSrv, NotificationSrv, customField) {
66
var self = this;
7-
self.reference = {
8-
types: ['string', 'number', 'boolean', 'date']
7+
self.config = {
8+
types: ['string', 'number', 'boolean', 'date'],
9+
referencePattern: '^[a-zA-Z]{1}[a-zA-Z0-9_-]*'
910
};
1011

1112
self.customField = customField;
@@ -36,8 +37,12 @@
3637
return values;
3738
};
3839

39-
self.saveField = function() {
40-
var postData = _.pick(self.customField, 'name', 'title', 'label', 'description', 'type');
40+
self.saveField = function(form) {
41+
if (!form.$valid) {
42+
return;
43+
}
44+
45+
var postData = _.pick(self.customField, 'name', 'reference', 'description', 'type');
4146
postData.options = buildOptionsCollection(self.customField.options);
4247

4348
if(self.customField.id) {
@@ -47,17 +52,52 @@
4752
onSuccess,
4853
onFailure);
4954
} else {
50-
ListSrv.save(
55+
ListSrv.exists(
5156
{'listId': 'custom_fields'},
52-
{'value': JSON.stringify(postData)},
53-
onSuccess,
54-
onFailure);
57+
{
58+
key: 'reference',
59+
value: postData.reference
60+
},
61+
function(response) {
62+
if(response.data) {
63+
ListSrv.save(
64+
{'listId': 'custom_fields'},
65+
{'value': JSON.stringify(postData)},
66+
onSuccess,
67+
onFailure);
68+
} else {
69+
// TODO handle field validation
70+
form.reference.$setValidity('unique', false);
71+
form.reference.$setDirty();
72+
NotificationSrv.error('AdminCustomFieldDialogCtrl', 'There is already a custom field with the specified reference: ' + postData.reference);
73+
}
74+
},
75+
onFailure
76+
)
5577
}
5678
};
5779

80+
self.clearUniqueReferenceError = function(form) {
81+
form.reference.$setValidity('unique', true);
82+
form.reference.$setPristine();
83+
}
84+
5885
self.cancel = function() {
5986
$uibModalInstance.dismiss();
6087
}
6188

89+
self.onNamechanged = function(form) {
90+
if(!self.customField.name) {
91+
return;
92+
}
93+
94+
var reference = s.trim(s.classify(self.customField.name));
95+
reference = reference.charAt(0).toLowerCase() + reference.slice(1);
96+
97+
self.customField.reference = reference;
98+
99+
self.clearUniqueReferenceError(form);
100+
};
101+
62102
});
63103
})();

ui/app/scripts/controllers/admin/AdminCustomFieldsCtrl.js

-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@
2424
'listId': 'custom_fields'
2525
}, {}, function(response) {
2626

27-
// self.customFields = _.values(response).filter(_.isString).map(function(item) {
28-
// return JSON.parse(item);
29-
// });
30-
3127
self.customFields = _.map(response.toJSON(), function(value, key) {
3228
var obj = JSON.parse(value);
3329
obj.id = key;

ui/app/scripts/controllers/case/CaseDetailsCtrl.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
}
9393

9494
$scope.getCustomFieldName = function(fieldDef) {
95-
return 'customFields.' + fieldDef.name + '.' + fieldDef.type;
95+
return 'customFields.' + fieldDef.reference + '.' + fieldDef.type;
9696
};
9797

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

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

118-
$scope.caze.customFields = temp;
119-
120-
$scope.updateField('customFields.', $scope.caze.customFields);
118+
$scope.updateField('customFields.' + customField.reference, customFieldValue);
121119
$scope.updateCustomFieldsList();
120+
121+
$scope.caze.customFields[customField.reference] = customFieldValue;
122122
});
123123
};
124124

ui/app/scripts/services/CustomFieldsCacheSrv.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
return JSON.parse(item);
3333
});
3434

35-
_.each(data, function(m){
36-
cache[m.name] = m;
35+
_.each(data, function(field){
36+
cache[field.reference] = field;
3737
});
3838

3939
deferred.resolve(cache);

ui/app/scripts/services/ListSrv.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
},
1212
update: {
1313
url: './api/list/:itemId',
14-
method: 'PATCH',
14+
method: 'PATCH'
15+
},
16+
exists: {
17+
url: './api/list/:listId/_exists',
18+
method: 'POST',
1519
}
1620
});
1721
});

ui/app/views/partials/admin/case-templates.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ <h4 class="vpad10 text-primary">
203203
</a>
204204
<ul class="dropdown-menu" uib-dropdown-menu>
205205
<li ng-repeat="(key, value) in fields">
206-
<a ng-click="addCustomField(value)">{{value.label}}</a>
206+
<a ng-click="addCustomField(value)">{{value.name}}</a>
207207
</li>
208208
</ul>
209209
</span>
@@ -218,7 +218,7 @@ <h4 class="vpad10 text-primary">
218218
<a href ng-click="isCollapsed=!isCollapsed">
219219
<i class="fa" ng-class="{'fa-caret-down': isCollapsed, 'fa-caret-up': !isCollapsed}"></i>
220220
</a>
221-
<span class="hpad5">{{fields[m].label}}</span>
221+
<span class="hpad5">{{fields[m].name}}</span>
222222
<span class="pull-right">
223223
<a class="text-danger" href ng-click="removeCustomField(m)">
224224
<i class="fa fa-times"></i>&nbsp;Delete</a>

ui/app/views/partials/admin/custom-field-dialog.html

+20-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<form class="form-horizontal" name="fieldsForm" ng-submit="$vm.saveField()" novalidate>
1+
<form class="form-horizontal" name="fieldsForm" ng-submit="$vm.saveField(fieldsForm)" novalidate>
22
<div class="modal-header bg-primary">
33
<h3 class="modal-title">{{$vm.customField.id ? 'Update' : 'Add'}} custom field</h3>
44
</div>
@@ -10,18 +10,30 @@ <h3 class="modal-title">{{$vm.customField.id ? 'Update' : 'Add'}} custom field</
1010
<i class="fa fa-asterisk text-danger"></i>
1111
</label>
1212
<div class="col-sm-10">
13-
<input class="form-control" name="name" ng-model="$vm.customField.name" placeholder="Ex: cvss, threatActor, businessRisk" required type="text">
13+
<input class="form-control" name="name"
14+
placeholder="Field's title, Ex: CVSS, Threat actor, Business risk"
15+
ng-model="$vm.customField.name"
16+
ng-keyup="$vm.onNamechanged(fieldsForm)"
17+
required type="text">
1418
<p class="help-block" ng-show="fieldsForm.name.$invalid && !fieldsForm.name.$pristine">This field is required.</p>
1519
</div>
1620
</div>
17-
<div class="form-group" ng-class="{ 'has-error' : fieldsForm.label.$invalid && !fieldsForm.label.$pristine }">
21+
22+
<div class="form-group" ng-class="{ 'has-error' : fieldsForm.reference.$invalid && fieldsForm.reference.$dirty }">
1823
<label class="col-sm-2 control-label">
19-
Label
24+
Reference
2025
<i class="fa fa-asterisk text-danger"></i>
2126
</label>
2227
<div class="col-sm-10">
23-
<input class="form-control" name="label" ng-model="$vm.customField.label" placeholder="Ex: CVSS, Threat actor, Business risk" required type="text">
24-
<p class="help-block" ng-show="fieldsForm.label.$invalid && !fieldsForm.label.$pristine">This field is required.</p>
28+
<input class="form-control" name="reference" type="text"
29+
placeholder="Internal reference, Ex: cvss, threatActor, businessRisk"
30+
ng-model="$vm.customField.reference"
31+
ng-keyup="$vm.clearUniqueReferenceError(fieldsForm)"
32+
ng-pattern="$vm.config.referencePattern"
33+
required>
34+
<p class="help-block" ng-show="fieldsForm.reference.$error.unique">There is already a field with this reference. It should be unique.</p>
35+
<p class="help-block" ng-show="fieldsForm.reference.$error.required && fieldsForm.reference.$dirty">This field is required.</p>
36+
<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>
2537
</div>
2638
</div>
2739

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

51-
<div class="form-group">
63+
<div class="form-group" ng-show="$vm.customField.type === 'string' || $vm.customField.type === 'number'">
5264
<label class="col-sm-2 control-label">
5365
Possible values
5466
</label>

ui/app/views/partials/admin/custom-fields.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h3 class="box-title">Case custom fields ({{$vm.customFields.length}})</h3>
1616
<tr>
1717
<th width="80">Type</th>
1818
<th width="250">Name</th>
19-
<th width="250">Label</th>
19+
<th width="250">Internal Reference</th>
2020
<th>Description</th>
2121
<th width="200">Options</th>
2222
<th width="80" class="text-center">Actions</th>
@@ -28,7 +28,7 @@ <h3 class="box-title">Case custom fields ({{$vm.customFields.length}})</h3>
2828
<span class="label label-default">{{field.type | uppercase}}</span>
2929
</td>
3030
<td><a href ng-click="$vm.showFieldDialog(field)">{{field.name}}</a></td>
31-
<td>{{field.label}}</td>
31+
<td>{{field.reference}}</td>
3232
<td>{{field.description || 'N/A'}}</td>
3333
<td ng-if="field.options.length === 0">
3434
<em>None</em>

ui/app/views/partials/case/case.add.field.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ <h3 class="modal-title">Add custom field to Case #{{caze.caseId}}</h3>
33
</div>
44
<div class="modal-body">
55
<div class="vpad20">
6-
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>
6+
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>
77
<br/>
88
<br/>
99
Are you sure you want to continue ?

ui/app/views/partials/case/details/custom.fields.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ <h4 class="vpad10 text-primary">
77
</a>
88
<ul class="dropdown-menu" uib-dropdown-menu>
99
<li ng-repeat="(key, value) in allCustomFields">
10-
<a ng-click="addCustomField(value)">{{value.label}}</a>
10+
<a ng-click="addCustomField(value)">{{value.name}}</a>
1111
</li>
1212
</ul>
1313
</span>
@@ -19,8 +19,8 @@ <h4 class="vpad10 text-primary">
1919

2020
<dl class="dl-horizontal clear"
2121
ng-repeat="k in orderedFields"
22-
ng-init="fieldDef = customFieldsCache[k]; customFieldValue=caze.customFields[fieldDef.name][fieldDef.type];">
23-
<dt class="pull-left" uib-tooltip="{{fieldDef.description}}">{{fieldDef.label}}</dt>
22+
ng-init="fieldDef = customFieldsCache[k]; customFieldValue=caze.customFields[fieldDef.reference][fieldDef.type];">
23+
<dt class="pull-left" uib-tooltip="{{fieldDef.description}}">{{fieldDef.name}}</dt>
2424
<dd ng-if="fieldDef.options.length > 0">
2525
<updatable-select
2626
options="fieldDef.options"

ui/bower.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
"angular-base64-upload": "^0.1.19",
4949
"angular-ui-sortable": "^0.17.0",
5050
"js-base64": "^2.1.9",
51-
"angular-scroll": "^1.0.1"
51+
"angular-scroll": "^1.0.1",
52+
"underscore.string": "^3.3.4"
5253
},
5354
"devDependencies": {
5455
"angular-mocks": "1.5.8"

ui/test/karma.conf.js

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ module.exports = function(config) {
6969
'bower_components/angular-ui-sortable/sortable.js',
7070
'bower_components/js-base64/base64.js',
7171
'bower_components/angular-scroll/angular-scroll.js',
72+
'bower_components/underscore.string/dist/underscore.string.js',
7273
'bower_components/angular-mocks/angular-mocks.js',
7374
// endbower
7475
"bower_components/cryptojslib/components/core-min.js",

0 commit comments

Comments
 (0)