diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..6a23db85a9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: TheHive Community Support + url: https://chat.thehive-project.org/ + about: Please ask and answer questions here. + - name: TheHive Documentation + url: https://docs.thehive-project.org/ + about: Please read documentation here. diff --git a/.github/ISSUE_TEMPLATE/thehive3_bug_report.md b/.github/ISSUE_TEMPLATE/thehive3_bug_report.md index 69218ae1c4..f73685e1cc 100644 --- a/.github/ISSUE_TEMPLATE/thehive3_bug_report.md +++ b/.github/ISSUE_TEMPLATE/thehive3_bug_report.md @@ -7,20 +7,18 @@ assignees: '' --- -# EDIT THIS TITLE BEFORE POSTING. Use this template for bug reports. If you'd like to request a feature, please be as descriptive as possible and delete the template except the first section (Request Type) - ### Request Type Bug ### Work Environment -| Question | Answer -|---------------------------|-------------------- -| OS version (server) | Debian, Ubuntu, CentOS, RedHat, ... -| OS version (client) | XP, Seven, 10, Ubuntu, ... -| TheHive version / git hash | 3.x, hash of the commit -| Package Type | RPM, DEB, Docker, Binary, From source -| Browser type & version | If applicable +| Question | Answer | +| -------------------------- | ------------------------------------- | +| OS version (server) | Debian, Ubuntu, CentOS, RedHat, ... | +| OS version (client) | XP, Seven, 10, Ubuntu, ... | +| TheHive version / git hash | 3.x, hash of the commit | +| Package Type | RPM, DEB, Docker, Binary, From source | +| Browser type & version | If applicable | ### Problem Description diff --git a/.github/ISSUE_TEMPLATE/thehive4_bug_report.md b/.github/ISSUE_TEMPLATE/thehive4_bug_report.md index 4c7cbcb330..3e158e3a33 100644 --- a/.github/ISSUE_TEMPLATE/thehive4_bug_report.md +++ b/.github/ISSUE_TEMPLATE/thehive4_bug_report.md @@ -7,20 +7,18 @@ assignees: '' --- -# EDIT THIS TITLE BEFORE POSTING. Use this template for bug reports. If you'd like to request a feature, please be as descriptive as possible and delete the template except the first section (Request Type) - ### Request Type Bug ### Work Environment -| Question | Answer -|---------------------------|-------------------- -| OS version (server) | Debian, Ubuntu, CentOS, RedHat, ... -| OS version (client) | XP, Seven, 10, Ubuntu, ... -| TheHive version / git hash | 4.x, hash of the commit -| Package Type | RPM, DEB, Docker, Binary, From source -| Browser type & version | If applicable +| Question | Answer | +| -------------------------- | ------------------------------------- | +| OS version (server) | Debian, Ubuntu, CentOS, RedHat, ... | +| OS version (client) | XP, Seven, 10, Ubuntu, ... | +| TheHive version / git hash | 4.x, hash of the commit | +| Package Type | RPM, DEB, Docker, Binary, From source | +| Browser type & version | If applicable | ### Problem Description diff --git a/.github/ISSUE_TEMPLATE/thehive4_feature_request.md b/.github/ISSUE_TEMPLATE/thehive4_feature_request.md index 4bf32d9fa1..de898ed8ef 100644 --- a/.github/ISSUE_TEMPLATE/thehive4_feature_request.md +++ b/.github/ISSUE_TEMPLATE/thehive4_feature_request.md @@ -2,22 +2,13 @@ name: Feature Request for TheHive4 about: Create a feature request for TheHive 4. title: "[Bug]" -labels: "feature request", TheHive4 +labels: feature request, TheHive4 assignees: '' --- - -# EDIT THIS TITLE BEFORE POSTING. Use this template for bug reports. If you'd like to request a feature, please be as descriptive as possible and delete the template except the first section (Request Type) - ### Request Type Feature Request -### Work Environment - -| Question | Answer -|---------------------------|-------------------- -| TheHive version | 4.x - ### Feature Description Describe feature as clearly as possible. diff --git a/CHANGELOG.md b/CHANGELOG.md index 335d9618fa..80390ce52c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Change Log +## [4.1.2](https://github.com/TheHive-Project/TheHive/milestone/71) (2021-03-29) + +**Implemented enhancements:** + +- [Feature Request] Add case search by TTP [\#1893](https://github.com/TheHive-Project/TheHive/issues/1893) + +**Fixed bugs:** + +- [Bug] Slow loading of TheHive because of Tags [\#1869](https://github.com/TheHive-Project/TheHive/issues/1869) +- [Bug] After migration from 4.0.5 to 4.1.0 old tasklogs are not returned by "/api/v1/query?name=case-task-logs" query [\#1875](https://github.com/TheHive-Project/TheHive/issues/1875) +- Dashboards - custom fields [\#1877](https://github.com/TheHive-Project/TheHive/issues/1877) +- [Bug] TH 4.1.1 : Filter by "IMPORTED" does not work for alerts imported into existing cases [\#1891](https://github.com/TheHive-Project/TheHive/issues/1891) +- [Bug] Fix the S3 configuration options [\#1892](https://github.com/TheHive-Project/TheHive/issues/1892) +- [Bug] All attachments in task logs disappeared following upgrade to 4.1.1 [\#1894](https://github.com/TheHive-Project/TheHive/issues/1894) +- [Bug] Continued performance issues after upgrade to 4.1.1 [\#1896](https://github.com/TheHive-Project/TheHive/issues/1896) +- [Bug] Fix issues dashboard list [\#1901](https://github.com/TheHive-Project/TheHive/issues/1901) +- [Bug] Migration tool migrates unsupported elastic index [\#1907](https://github.com/TheHive-Project/TheHive/issues/1907) +- [Bug] Folder permissions are not correctly set in docker image [\#1908](https://github.com/TheHive-Project/TheHive/issues/1908) + ## [4.1.1](https://github.com/TheHive-Project/TheHive/milestone/70) (2021-03-23) **Implemented enhancements:** diff --git a/ScalliGraph b/ScalliGraph index e9122723b8..4aa2d6084e 160000 --- a/ScalliGraph +++ b/ScalliGraph @@ -1 +1 @@ -Subproject commit e9122723b83fd87a4c1e808fe5fbe3d5626ef2ad +Subproject commit 4aa2d6084eaca86a8dbc7e078a53a103f0d63c8c diff --git a/build.sbt b/build.sbt index 94da0fb5b8..281257f67c 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import Dependencies._ import com.typesafe.sbt.packager.Keys.bashScriptDefines import org.thp.ghcl.Milestone -val thehiveVersion = "4.1.1-1" +val thehiveVersion = "4.1.2-1" val scala212 = "2.12.13" val scala213 = "2.13.1" val supportedScalaVersions = List(scala212, scala213) diff --git a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/models/CortexSchemaDefinition.scala b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/models/CortexSchemaDefinition.scala index dbf25c51b1..8718790641 100644 --- a/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/models/CortexSchemaDefinition.scala +++ b/cortex/connector/src/main/scala/org/thp/thehive/connector/cortex/models/CortexSchemaDefinition.scala @@ -16,7 +16,7 @@ import scala.reflect.runtime.{universe => ru} class CortexSchemaDefinition @Inject() () extends Schema with UpdatableSchema { lazy val logger: Logger = Logger(getClass) - val operations: Operations = Operations("thehive-cortex") + val operations: Operations = Operations("thehive-cortex").noop lazy val reflectionClasses = new Reflections( new ConfigurationBuilder() diff --git a/docker.sbt b/docker.sbt index 60d0f5fe54..94a925c413 100644 --- a/docker.sbt +++ b/docker.sbt @@ -47,7 +47,7 @@ dockerCommands := Seq( Cmd("ADD", "--chown=thehive:thehive", "var", "/var"), Cmd("ADD", "--chown=thehive:thehive", "etc", "/etc"), ExecCmd("RUN", "chmod", "+x", "/opt/thehive/bin/thehive", "/opt/thehive/entrypoint"), - Cmd("RUN", "mkdir", "/data", "&&", "chown", "thehive:thehive", "/data"), + Cmd("RUN", "mkdir", "/data", "/opt/thp", "&&", "chown", "thehive:thehive", "/data", "/opt/thp"), Cmd("EXPOSE", "9000"), Cmd("USER", "thehive"), ExecCmd("ENTRYPOINT", "/opt/thehive/entrypoint"), diff --git a/dto/src/main/scala/org/thp/thehive/dto/v0/Log.scala b/dto/src/main/scala/org/thp/thehive/dto/v0/Log.scala index ec0b7d077a..9e691401d7 100644 --- a/dto/src/main/scala/org/thp/thehive/dto/v0/Log.scala +++ b/dto/src/main/scala/org/thp/thehive/dto/v0/Log.scala @@ -19,7 +19,8 @@ case class OutputLog( startDate: Date, attachment: Option[OutputAttachment] = None, status: String, - owner: String + owner: String, + case_task: Option[OutputTask] ) object OutputLog { diff --git a/frontend/app/scripts/controllers/dashboard/DashboardViewCtrl.js b/frontend/app/scripts/controllers/dashboard/DashboardViewCtrl.js index 64946c42c8..459a43aae6 100644 --- a/frontend/app/scripts/controllers/dashboard/DashboardViewCtrl.js +++ b/frontend/app/scripts/controllers/dashboard/DashboardViewCtrl.js @@ -1,9 +1,9 @@ -(function() { +(function () { 'use strict'; angular .module('theHiveControllers') - .controller('DashboardViewCtrl', function($scope, $q, $interval, $timeout, $uibModal, AuthenticationSrv, DashboardSrv, NotificationSrv, ModalUtilsSrv, UtilsSrv, dashboard, metadata) { + .controller('DashboardViewCtrl', function ($scope, $q, $interval, $timeout, $uibModal, AuthenticationSrv, DashboardSrv, NotificationSrv, ModalUtilsSrv, UtilsSrv, dashboard, metadata) { var self = this; this.currentUser = AuthenticationSrv.currentUser; @@ -15,13 +15,13 @@ this.autoRefresh = null; this.authRefreshRunner = null; - this.buildDashboardPeriodFilter = function(period) { + this.buildDashboardPeriodFilter = function (period) { return period === 'custom' ? DashboardSrv.buildPeriodQuery(period, 'createdAt', this.definition.customPeriod.fromDate, this.definition.customPeriod.toDate) : DashboardSrv.buildPeriodQuery(period, 'createdAt'); }; - this.loadDashboard = function(dashboard) { + this.loadDashboard = function (dashboard) { this.dashboard = dashboard; this.definition = JSON.parse(dashboard.definition) || { period: 'all', @@ -37,22 +37,22 @@ this.loadDashboard(dashboard); - $scope.$watch('$vm.autoRefresh', function(value) { - if(value === self.authRefreshRunner || self.options.editLayout === true) { + $scope.$watch('$vm.autoRefresh', function (value) { + if (value === self.authRefreshRunner || self.options.editLayout === true) { return; } - if(value === null) { + if (value === null) { $interval.cancel(self.authRefreshRunner); } else { $interval.cancel(self.authRefreshRunner); - self.authRefreshRunner = $interval(function() { + self.authRefreshRunner = $interval(function () { $scope.$broadcast('refresh-chart', self.periodFilter); }, value * 1000); } }); - this.canEditDashboard = function() { + this.canEditDashboard = function () { return (this.createdBy === this.currentUser.login) || this.dashboardStatus === 'Shared'; }; @@ -70,23 +70,23 @@ text: 'Text', multiline: 'Multi Lines' }, - editLayout: !_.find(this.definition.items, function(row) { + editLayout: !_.find(this.definition.items, function (row) { return row.items.length > 0; }) && this.canEditDashboard() }; - this.applyPeriod = function(period) { + this.applyPeriod = function (period) { this.definition.period = period; this.periodFilter = this.buildDashboardPeriodFilter(period); $scope.$broadcast('refresh-chart', this.periodFilter); }; - this.removeContainer = function(index) { + this.removeContainer = function (index) { var row = this.definition.items[index]; var promise; - if(row.items.length === 0) { + if (row.items.length === 0) { // If the container is empty, don't ask for confirmation promise = $q.resolve(); } else { @@ -96,54 +96,55 @@ }); } - promise.then(function() { + promise.then(function () { self.definition.items.splice(index, 1); }); }; - this.saveDashboard = function() { - var copy = _.pick(this.dashboard, 'title', 'description', 'status'); - copy.definition = angular.toJson(this.definition); + this.saveDashboard = function () { + var copy = { + definition: angular.toJson(this.definition) + }; DashboardSrv.update(this.dashboard.id, copy) - .then(function(/*response*/) { + .then(function (/*response*/) { self.options.editLayout = false; self.resizeCharts(); NotificationSrv.log('The dashboard has been successfully updated', 'success'); }) - .catch(function(err) { + .catch(function (err) { NotificationSrv.error('DashboardEditCtrl', err.data, err.status); }); }; - this.removeItem = function(rowIndex, colIndex) { + this.removeItem = function (rowIndex, colIndex) { ModalUtilsSrv.confirm('Remove widget', 'Are you sure you want to remove this item', { okText: 'Yes, remove it', flavor: 'danger' - }).then(function() { + }).then(function () { var row = self.definition.items[rowIndex]; row.items.splice(colIndex, 1); - $timeout(function() { + $timeout(function () { $scope.$broadcast('resize-chart-' + rowIndex); }, 0); }); }; - this.itemInserted = function(item, rows/*, rowIndex, index*/) { - if(!item.id){ + this.itemInserted = function (item, rows/*, rowIndex, index*/) { + if (!item.id) { item.id = UtilsSrv.guid(); } - for(var i=0; i < rows.length; i++) { + for (var i = 0; i < rows.length; i++) { $scope.$broadcast('resize-chart-' + i); } if (this.options.containerAllowedTypes.indexOf(item.type) !== -1 && !item.options.entity) { // The item is a widget - $timeout(function() { + $timeout(function () { $scope.$broadcast('edit-chart-' + item.id); }, 0); } @@ -151,34 +152,34 @@ return item; }; - this.itemDragStarted = function(colIndex, row) { + this.itemDragStarted = function (colIndex, row) { row.items.splice(colIndex, 1); }; - this.exportDashboard = function() { + this.exportDashboard = function () { DashboardSrv.exportDashboard(this.dashboard); }; - this.resizeCharts = function() { - $timeout(function() { - for(var i=0; i < self.definition.items.length; i++) { + this.resizeCharts = function () { + $timeout(function () { + for (var i = 0; i < self.definition.items.length; i++) { $scope.$broadcast('resize-chart-' + i); } }, 100); }; - this.enableEditMode = function() { + this.enableEditMode = function () { this.options.editLayout = true; this.resizeCharts(); }; - this.enableViewMode = function() { + this.enableViewMode = function () { DashboardSrv.get(this.dashboard.id) - .then(function(response) { + .then(function (response) { self.loadDashboard(response.data); self.options.editLayout = false; self.resizeCharts(); - }, function(err) { + }, function (err) { NotificationSrv.error('DashboardViewCtrl', err.data, err.status); }); }; diff --git a/frontend/app/scripts/controllers/dashboard/DashboardsCtrl.js b/frontend/app/scripts/controllers/dashboard/DashboardsCtrl.js index 307c17ba0b..a9f679d18c 100644 --- a/frontend/app/scripts/controllers/dashboard/DashboardsCtrl.js +++ b/frontend/app/scripts/controllers/dashboard/DashboardsCtrl.js @@ -1,28 +1,28 @@ -(function() { +(function () { 'use strict'; angular .module('theHiveControllers') - .controller('DashboardImportCtrl', function($scope, $uibModalInstance) { + .controller('DashboardImportCtrl', function ($scope, $uibModalInstance) { var self = this; this.formData = { fileContent: {} }; - $scope.$watch('vm.formData.attachment', function(file) { - if(!file) { + $scope.$watch('vm.formData.attachment', function (file) { + if (!file) { self.formData.fileContent = {}; return; } var aReader = new FileReader(); aReader.readAsText(self.formData.attachment, 'UTF-8'); aReader.onload = function (evt) { - $scope.$apply(function() { + $scope.$apply(function () { self.formData.fileContent = JSON.parse(aReader.result); }); } aReader.onerror = function (evt) { - $scope.$apply(function() { + $scope.$apply(function () { self.formData.fileContent = {}; }); } @@ -39,23 +39,26 @@ $uibModalInstance.dismiss('cancel'); }; }) - .controller('DashboardModalCtrl', function($uibModalInstance, $state, statuses, dashboard) { + .controller('DashboardModalCtrl', function ($uibModalInstance, AuthenticationSrv, $state, statuses, dashboard) { this.dashboard = dashboard; this.statuses = statuses; + this.currentUser = AuthenticationSrv.currentUser; - this.cancel = function() { + this.cancel = function () { $uibModalInstance.dismiss(); }; - this.ok = function() { + this.ok = function () { return $uibModalInstance.close(dashboard); }; }) - .controller('DashboardsCtrl', function($scope, $state, $uibModal, PaginatedQuerySrv, FilteringSrv, ModalUtilsSrv, NotificationSrv, DashboardSrv, AuthenticationSrv) { + .controller('DashboardsCtrl', function ($scope, $state, $uibModal, PaginatedQuerySrv, FilteringSrv, ModalUtilsSrv, NotificationSrv, DashboardSrv, AuthenticationSrv) { this.dashboards = []; var self = this; - this.$onInit = function() { + this.currentUser = AuthenticationSrv.currentUser; + + this.$onInit = function () { self.filtering = new FilteringSrv('dashboard', 'dashboard.list', { version: 'v0', defaults: { @@ -68,7 +71,7 @@ }); self.filtering.initContext('list') - .then(function() { + .then(function () { self.load(); $scope.$watch('$vm.list.pageSize', function (newValue) { @@ -77,7 +80,7 @@ }); } - this.load = function() { + this.load = function () { self.list = new PaginatedQuerySrv({ name: 'dashboard-list', @@ -88,10 +91,10 @@ pageSize: self.filtering.context.pageSize, filter: this.filtering.buildQuery(), operations: [ - {'_name': 'listDashboard'} + { '_name': 'listDashboard' } ], - onFailure: function(err) { - if(err && err.status === 400) { + onFailure: function (err) { + if (err && err.status === 400) { self.filtering.resetContext(); self.load(); } @@ -99,24 +102,24 @@ }); }; - this.openDashboardModal = function(dashboard) { + this.openDashboardModal = function (dashboard) { return $uibModal.open({ templateUrl: 'views/partials/dashboard/create.dialog.html', controller: 'DashboardModalCtrl', controllerAs: '$vm', size: 'lg', resolve: { - statuses: function() { + statuses: function () { return ['Private', 'Shared']; }, - dashboard: function() { + dashboard: function () { return dashboard; } } }); }; - this.addDashboard = function() { + this.addDashboard = function () { var modalInstance = this.openDashboardModal({ title: null, description: null, @@ -125,79 +128,87 @@ }); modalInstance.result - .then(function(dashboard) { + .then(function (dashboard) { return DashboardSrv.create(dashboard); }) - .then(function(response) { - $state.go('app.dashboards-view', {id: response.data.id}); + .then(function (response) { + $state.go('app.dashboards-view', { id: response.data.id }); NotificationSrv.log('The dashboard has been successfully created', 'success'); }) - .catch(function(err) { + .catch(function (err) { if (err && err.status) { NotificationSrv.error('DashboardsCtrl', err.data, err.status); } }); }; - this.duplicateDashboard = function(dashboard) { + this.duplicateDashboard = function (dashboard) { var copy = _.pick(dashboard, 'title', 'description', 'status', 'definition'); copy.title = 'Copy of ' + copy.title; this.openDashboardModal(copy) - .result.then(function(dashboard) { + .result.then(function (dashboard) { return DashboardSrv.create(dashboard); }) - .then(function(response) { - $state.go('app.dashboards-view', {id: response.data.id}); + .then(function (response) { + $state.go('app.dashboards-view', { id: response.data.id }); NotificationSrv.log('The dashboard has been successfully created', 'success'); }) - .catch(function(err) { + .catch(function (err) { if (err && err.status) { NotificationSrv.error('DashboardsCtrl', err.data, err.status); } }); }; - this.editDashboard = function(dashboard) { + this.editDashboard = function (dashboard) { var copy = _.extend({}, dashboard); - this.openDashboardModal(copy).result.then(function(dashboard) { - return DashboardSrv.update(dashboard.id, _.omit(dashboard, 'id')); - }) - .then(function(response) { - self.load() + this.openDashboardModal(copy).result + .then(function (dashboard) { - NotificationSrv.log('The dashboard has been successfully updated', 'success'); - }) - .catch(function(err) { - if (err && err.status) { - NotificationSrv.error('DashboardsCtrl', err.data, err.status); - } - }); + if (dashboard.createdBy === self.currentUser.login) { + return DashboardSrv.update(dashboard.id, _.omit(dashboard, 'id', 'definition')); + } else { + return DashboardSrv.update(dashboard.id, _.omit(dashboard, 'id', 'status', 'definition')); + } + + + }) + .then(function (response) { + self.load() + + NotificationSrv.log('The dashboard has been successfully updated', 'success'); + }) + .catch(function (err) { + if (err && err.status) { + NotificationSrv.error('DashboardsCtrl', err.data, err.status); + } + }); }; - this.deleteDashboard = function(id) { + this.deleteDashboard = function (id) { ModalUtilsSrv.confirm('Remove dashboard', 'Are you sure you want to remove this dashboard', { okText: 'Yes, remove it', flavor: 'danger' }) - .then(function() { + .then(function () { return DashboardSrv.remove(id); }) - .then(function(response) { + .then(function (response) { self.load(); NotificationSrv.log('The dashboard has been successfully removed', 'success'); }); }; - this.exportDashboard = function(dashboard) { + this.exportDashboard = function (dashboard) { DashboardSrv.exportDashboard(dashboard); } - this.importDashboard = function() { + this.importDashboard = function () { var modalInstance = $uibModal.open({ animation: true, templateUrl: 'views/partials/dashboard/import.dialog.html', @@ -206,19 +217,19 @@ size: 'lg' }); - modalInstance.result.then(function(dashboard) { + modalInstance.result.then(function (dashboard) { return DashboardSrv.create(dashboard); }) - .then(function(response) { - $state.go('app.dashboards-view', {id: response.data.id}); + .then(function (response) { + $state.go('app.dashboards-view', { id: response.data.id }); - NotificationSrv.log('The dashboard has been successfully imported', 'success'); - }) - .catch(function(err) { - if (err && err.status) { - NotificationSrv.error('DashboardsCtrl', err.data, err.status); - } - }); + NotificationSrv.log('The dashboard has been successfully imported', 'success'); + }) + .catch(function (err) { + if (err && err.status) { + NotificationSrv.error('DashboardsCtrl', err.data, err.status); + } + }); } // Filtering @@ -249,28 +260,28 @@ this.search(); }; - this.filterBy = function(field, value) { + this.filterBy = function (field, value) { self.filtering.clearFilters() - .then(function(){ + .then(function () { self.addFilterValue(field, value); }); }; - this.sortBy = function(sort) { + this.sortBy = function (sort) { self.list.sort = sort; self.list.update(); self.filtering.setSort(sort); }; - this.sortByField = function(field) { + this.sortByField = function (field) { var context = this.filtering.context; var currentSort = Array.isArray(context.sort) ? context.sort[0] : context.sort; var sort = null; - if(currentSort.substr(1) !== field) { + if (currentSort.substr(1) !== field) { sort = ['+' + field]; } else { - sort = [(currentSort === '+' + field) ? '-'+field : '+'+field]; + sort = [(currentSort === '+' + field) ? '-' + field : '+' + field]; } self.list.sort = sort; diff --git a/frontend/app/scripts/directives/tag-item.js b/frontend/app/scripts/directives/tag-item.js index 0d060ec5c0..20edaca32f 100644 --- a/frontend/app/scripts/directives/tag-item.js +++ b/frontend/app/scripts/directives/tag-item.js @@ -1,6 +1,6 @@ -(function() { +(function () { 'use strict'; - angular.module('theHiveDirectives').directive('tagItem', function(TaxonomyCacheSrv) { + angular.module('theHiveDirectives').directive('tagItem', function (TaxonomyCacheSrv, TagSrv) { return { restrict: 'E', replace: true, @@ -9,15 +9,16 @@ colour: '=' }, templateUrl: 'views/directives/tag-item.html', - link: function(scope/*, element, attrs*/) { - if(!scope.value) { + link: function (scope/*, element, attrs*/) { + if (!scope.value) { return; } - if(_.isString(scope.value)) { + if (_.isString(scope.value)) { scope.tag = scope.value; scope.bgColor = scope.colour || TaxonomyCacheSrv.getColour(scope.value) || TaxonomyCacheSrv.getColour('_freetags_:' + scope.value) || + TagSrv.tagsDefaultColour || '#000000'; } else { scope.tag = _.without([ @@ -26,22 +27,25 @@ scope.value.predicate, scope.value.value ? ("=\"" + scope.value.value + "\"") : null ], null).join(''); - scope.bgColor = scope.value.colour || scope.colour || '#000000'; + scope.bgColor = scope.value.colour || + scope.colour || + TagSrv.tagsDefaultColour || + '#000000'; } - scope.$watch('colour', function(value) { - if(!value) { + scope.$watch('colour', function (value) { + if (!value) { return; } scope.bgColor = value; }); - scope.$watch('value', function(value) { - if(!value) { + scope.$watch('value', function (value) { + if (!value) { return; } - if(_.isString(value)) { + if (_.isString(value)) { scope.tag = value; } else { scope.tag = _.without([ diff --git a/frontend/app/scripts/services/api/DashboardSrv.js b/frontend/app/scripts/services/api/DashboardSrv.js index ba5394b896..4e96544320 100644 --- a/frontend/app/scripts/services/api/DashboardSrv.js +++ b/frontend/app/scripts/services/api/DashboardSrv.js @@ -1,6 +1,6 @@ -(function() { +(function () { 'use strict'; - angular.module('theHiveServices').service('DashboardSrv', function(QueryBuilderSrv, localStorageService, $q, AuthenticationSrv, $http) { + angular.module('theHiveServices').service('DashboardSrv', function (QueryBuilderSrv, localStorageService, $q, AuthenticationSrv, $http) { var baseUrl = './api/dashboard'; var self = this; @@ -141,43 +141,43 @@ } ]; - this.skipFields = function(fields, types) { - return _.filter(fields, function(item) { + this.skipFields = function (fields, types) { + return _.filter(fields, function (item) { return types.indexOf(item.type) === -1; }); }; - this.pickFields = function(fields, types) { - return _.filter(fields, function(item) { + this.pickFields = function (fields, types) { + return _.filter(fields, function (item) { return types.indexOf(item.type) !== -1; }); }; - this.fieldsForAggregation = function(fields, agg) { - if(agg === 'count') { + this.fieldsForAggregation = function (fields, agg) { + if (agg === 'count') { return []; - } else if(agg === 'sum' || agg === 'avg') { - return self.pickFields(fields, ['number']); + } else if (agg === 'sum' || agg === 'avg') { + return self.pickFields(fields, ['number', 'integer', 'float']); } else { return fields; } }; this.renderers = { - severity: function() {} + severity: function () { } }; - this.create = function(dashboard) { + this.create = function (dashboard) { return $http.post(baseUrl, dashboard); }; - this.update = function(id, dashboard) { + this.update = function (id, dashboard) { var db = _.pick(dashboard, 'id', 'title', 'description', 'status', 'definition'); return $http.patch(baseUrl + '/' + id, db); }; - this.list = function() { + this.list = function () { return $http.post(baseUrl + '/_search', { range: 'all', sort: ['-status', '-updatedAt', '-createdAt'], @@ -194,28 +194,28 @@ }); }; - this.get = function(id) { + this.get = function (id) { return $http.get(baseUrl + '/' + id); }; - this.remove = function(id) { + this.remove = function (id) { return $http.delete(baseUrl + '/' + id); }; - this._objectifyBy = function(collection, field) { + this._objectifyBy = function (collection, field) { var obj = {}; - _.each(collection, function(item) { + _.each(collection, function (item) { obj[item[field]] = item; }); return obj; }; - this.getMetadata = function(version) { + this.getMetadata = function (version) { var defer = $q.defer(); - if(!version) { + if (!version) { version = 'v0'; } @@ -224,13 +224,13 @@ } else { $http .get('./api/' + version + '/describe/_all') - .then(function(response) { + .then(function (response) { var data = response.data; var metadata = { entities: _.keys(data).sort() }; - _.each(metadata.entities, function(entity) { + _.each(metadata.entities, function (entity) { metadata[entity] = _.omit(data[entity], 'attributes'); metadata[entity].attributes = self._objectifyBy(data[entity].attributes, 'name'); metadata[entity].attributeKeys = _.keys(metadata[entity].attributes).sort(); @@ -240,7 +240,7 @@ defer.resolve(metadata); }) - .catch(function(err) { + .catch(function (err) { defer.reject(err); }); } @@ -248,7 +248,7 @@ return defer.promise; }; - this.hasMinimalConfiguration = function(component) { + this.hasMinimalConfiguration = function (component) { switch (component.type) { case 'multiline': case 'text': @@ -258,22 +258,22 @@ } }; - this.buildFiltersQuery = function(fields, filters) { + this.buildFiltersQuery = function (fields, filters) { return QueryBuilderSrv.buildFiltersQuery(fields, filters); }; - this.buildChartQuery = function(filter, query) { - var criteria = _.filter(_.without([filter, query], null, undefined, '', '*'), function(c){return !_.isEmpty(c);}); + this.buildChartQuery = function (filter, query) { + var criteria = _.filter(_.without([filter, query], null, undefined, '', '*'), function (c) { return !_.isEmpty(c); }); - if(criteria.length === 0) { + if (criteria.length === 0) { return {}; } else { return criteria.length === 1 ? criteria[0] : { _and: criteria }; } }; - this.buildPeriodQuery = function(period, field, start, end) { - if(!period && !start && !end) { + this.buildPeriodQuery = function (period, field, start, end) { + if (!period && !start && !end) { return null; } @@ -287,7 +287,7 @@ from = moment(today).subtract(30, 'days'); } else if (period === 'last3Months') { from = moment(today).subtract(3, 'months'); - } else if(period === 'custom') { + } else if (period === 'custom') { from = start && start !== null ? moment(start).valueOf() : null; to = end && end !== null ? moment(end).hours(23).minutes(59).seconds(59).milliseconds(999).valueOf() : null; @@ -311,7 +311,7 @@ }; }; - this.exportDashboard = function(dashboard) { + this.exportDashboard = function (dashboard) { var fileName = dashboard.title.replace(/\s/gi, '_') + '.json'; var content = _.omit(dashboard, '_type', diff --git a/frontend/app/scripts/services/api/TagSrv.js b/frontend/app/scripts/services/api/TagSrv.js index 83a6057a21..ff9914a730 100644 --- a/frontend/app/scripts/services/api/TagSrv.js +++ b/frontend/app/scripts/services/api/TagSrv.js @@ -1,47 +1,59 @@ -(function() { +(function () { 'use strict'; angular.module('theHiveServices') - .service('TagSrv', function(QuerySrv, $q, $http) { + .service('TagSrv', function (QuerySrv, $q, VersionSrv, $http) { - this.getFreeTags = function() { + var self = this; + + this.tagsDefaultColour = '#000000'; + + this.getFreeTags = function () { var defer = $q.defer(); - var operations = [ - { _name: 'listTag'}, - { _name: 'freetags'}, - ] + VersionSrv.get() + .then(function (appConfig) { + var defaultColour = appConfig.config.freeTagDefaultColour; - QuerySrv.query('v1', operations, { - params: { - name: 'list-tags' - } - }).then(function(response) { - defer.resolve(response.data); - }); + self.tagsDefaultColour = defaultColour; + + return QuerySrv.query('v1', [ + { _name: 'listTag' }, + { _name: 'freetags' }, + { _name: 'filter', _not: { colour: defaultColour } } + ], { + params: { + name: 'list-tags' + } + }) + }) + + .then(function (response) { + defer.resolve(response.data); + }); return defer.promise; }; - this.updateTag = function(id, patch) { + this.updateTag = function (id, patch) { return $http.patch('./api/v1/tag/' + id, patch); } - this.removeTag = function(id) { + this.removeTag = function (id) { return $http.delete('./api/v1/tag/' + id); } - this.autoComplete = function(term) { + this.autoComplete = function (term) { var defer = $q.defer(); var operations = [ - { _name: 'tagAutoComplete', freeTag: term, limit: 20} + { _name: 'tagAutoComplete', freeTag: term, limit: 20 } ] QuerySrv.call('v1', operations, { name: 'tags-auto-complete' - }).then(function(response) { - defer.resolve(_.map(response, function(tag) { - return {text: tag}; + }).then(function (response) { + defer.resolve(_.map(response, function (tag) { + return { text: tag }; })); }); diff --git a/frontend/app/scripts/services/api/TaxonomyCacheSrv.js b/frontend/app/scripts/services/api/TaxonomyCacheSrv.js index 9a72d87700..cfae25df92 100644 --- a/frontend/app/scripts/services/api/TaxonomyCacheSrv.js +++ b/frontend/app/scripts/services/api/TaxonomyCacheSrv.js @@ -1,17 +1,17 @@ -(function() { +(function () { 'use strict'; angular.module('theHiveServices') - .service('TaxonomyCacheSrv', function($http, $q, $filter, $uibModal, TagSrv, QuerySrv) { + .service('TaxonomyCacheSrv', function ($http, $q, $filter, $uibModal, VersionSrv, TagSrv, QuerySrv) { var self = this; this.cache = null; this.tagsCache = null; - this.list = function() { + this.list = function () { return QuerySrv.call('v1', [ { _name: 'listTaxonomy' } ], { - name:'list-taxonomies' + name: 'list-taxonomies' }, { name: 'filter', _field: 'enabled', @@ -19,50 +19,50 @@ }); }; - this.clearCache = function() { + this.clearCache = function () { self.cache = null; self.tagsCache = null; }; - this.getCache = function(name) { + this.getCache = function (name) { return self.cache[name]; }; - this.getColour = function(tag) { + this.getColour = function (tag) { return self.tagsCache[tag]; }; - this.cacheTagColors = function(tags) { + this.cacheTagColors = function (tags) { var fn = $filter('tagValue'); - _.each(tags, function(tag) { + _.each(tags, function (tag) { var name = fn(tag); - if(!_.isEmpty(name)) { - self.tagsCache[name] = tag.colour; + if (!_.isEmpty(name)) { + self.tagsCache[name] = tag.colour; } }); }; - this.all = function(reload) { + this.all = function (reload) { var deferred = $q.defer(); if (self.cache === null || reload === true) { self.list() - .then(function(response) { + .then(function (response) { self.cache = {}; self.tagsCache = {}; - _.each(response, function(taxonomy) { + _.each(response, function (taxonomy) { self.cache[taxonomy.namespace] = taxonomy; self.cacheTagColors(taxonomy.tags); }); }) - .then(function() { + .then(function () { return TagSrv.getFreeTags(); }) - .then(function(freeTags) { + .then(function (freeTags) { self.cacheTagColors(freeTags); deferred.resolve(self.cache); @@ -74,7 +74,7 @@ return deferred.promise; }; - self.openTagLibrary = function() { + self.openTagLibrary = function () { var defer = $q.defer(); var modalInstance = $uibModal.open({ @@ -84,18 +84,18 @@ templateUrl: 'views/partials/misc/taxonomy-selection.modal.html', size: 'lg', resolve: { - taxonomies: function() { + taxonomies: function () { return self.all(); } } }); modalInstance.result - .then(function(selectedTags) { + .then(function (selectedTags) { var filterFn = $filter('tagValue'), tags = []; - _.each(selectedTags, function(tag) { + _.each(selectedTags, function (tag) { tags.push({ text: filterFn(tag) }); @@ -104,7 +104,7 @@ //$scope.tags = $scope.tags.concat(tags); defer.resolve(tags); }) - .catch(function(err) { + .catch(function (err) { if (err && !_.isString(err)) { NotificationSrv.error('Tag selection', err.data, err.status); } diff --git a/frontend/app/views/directives/dashboard/counter/series.html b/frontend/app/views/directives/dashboard/counter/series.html index 4ce488e140..bbb3722365 100644 --- a/frontend/app/views/directives/dashboard/counter/series.html +++ b/frontend/app/views/directives/dashboard/counter/series.html @@ -11,15 +11,14 @@
Click on a tag to unselect it
@@ -32,9 +32,11 @@