mirror of https://github.com/MISP/MISP
Merge branch '2.4' of https://github.com/MISP/MISP into 2.4
commit
c0aec75a09
|
@ -43,6 +43,8 @@ tools/mkdocs
|
|||
!/app/files/misp-galaxy/*
|
||||
!/app/files/misp-objects
|
||||
!/app/files/misp-objects/*
|
||||
!/app/files/misp-decaying-models
|
||||
!/app/files/misp-decaying-models/*
|
||||
/app/files/scripts/python-stix/
|
||||
/app/files/scripts/python-cybox/
|
||||
/app/files/scripts/mixbox/
|
||||
|
|
|
@ -42,4 +42,7 @@
|
|||
url = https://github.com/pear/Crypt_GPG
|
||||
[submodule "INSTALL/Console_CommandLine"]
|
||||
path = INSTALL/dependencies/Console_CommandLine
|
||||
url = https://github.com/pear/Console_CommandLine
|
||||
url = https://github.com/pear/Console_CommandLine
|
||||
[submodule "app/files/misp-decaying-models"]
|
||||
path = app/files/misp-decaying-models
|
||||
url = https://github.com/MISP/misp-decaying-models.git
|
||||
|
|
|
@ -943,8 +943,6 @@ alias composer70='composer72'
|
|||
composer72 () {
|
||||
cd $PATH_TO_MISP/app
|
||||
mkdir /var/www/.composer ; chown $WWW_USER:$WWW_USER /var/www/.composer
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
}
|
||||
|
||||
|
@ -961,8 +959,6 @@ composer73 () {
|
|||
checkFail "composer.phar checksum failed, please investigate manually. " $?
|
||||
$SUDO_WWW php composer-setup.php
|
||||
$SUDO_WWW php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
}
|
||||
|
||||
|
@ -1329,8 +1325,6 @@ installCake () {
|
|||
# Make composer cache happy
|
||||
# /!\ composer on Ubuntu when invoked with sudo -u doesn't set $HOME to /var/www but keeps it /home/misp \!/
|
||||
sudo mkdir /var/www/.composer ; sudo chown $WWW_USER:$WWW_USER /var/www/.composer
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
|
|
|
@ -1 +1 @@
|
|||
6f5260ea0b7af730f4b94007e5046f661e3c2585 INSTALL.sh
|
||||
692b4b07289064b7e0c895a11dc627c39c51f108 INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
babd4491825edd02153d7d09624f1668c452ee14279872f367c5729dd51171bc INSTALL.sh
|
||||
4c3fe46366616bd77f78fcf68f0a33cd90f9c0480dd06b0d14da1fa66f4ed2a8 INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
0cf66499a027baaf5b52aba19270a7f6e5fbc7d99df225a9049bf9c35c35f9c4316a59ef92ec544ef2f23eea416897b0 INSTALL.sh
|
||||
576574cf5390b00b2fd05ef6a2cbe6c85f5d737224776927c8f937a2465c41cbb0bf1a21e564a1715bf8cc104799c59c INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
cfc7e4b1749ad8ed2d75fd3e7d984bb48ab253559c4a37318568dfc175fad40612a05bb59d3672dc3de88b651bd18e8b959457c4ae9c72eff2c0a7418e51fce8 INSTALL.sh
|
||||
3f5e83afab583b63d83d4d71f3d5f395e058b990c1ed68aa6fee4a77a26529a5ebe6110723a4afc7e99aa451ea2fdebcc1931aafb121cadaa09225fa986f3c08 INSTALL.sh
|
||||
|
|
|
@ -711,6 +711,7 @@ CREATE TABLE IF NOT EXISTS `roles` (
|
|||
`restricted_to_site_admin` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`perm_publish_zmq` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`perm_publish_kafka` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`perm_decaying` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
|
||||
|
||||
|
@ -1262,23 +1263,23 @@ INSERT INTO `feeds` (`id`, `provider`, `name`, `url`, `distribution`, `default`,
|
|||
-- 7. Read Only - read
|
||||
--
|
||||
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
|
||||
VALUES (1, 'admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0);
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `perm_decaying`, `default_role`)
|
||||
VALUES (1, 'admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0);
|
||||
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
|
||||
VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0);
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `perm_decaying`, `default_role`)
|
||||
VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0);
|
||||
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
|
||||
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1);
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `perm_decaying`, `default_role`)
|
||||
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1);
|
||||
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
|
||||
VALUES (4, 'Publisher', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0);
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `perm_decaying`, `default_role`)
|
||||
VALUES (4, 'Publisher', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0);
|
||||
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
|
||||
VALUES (5, 'Sync user', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0);
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `perm_decaying`, `default_role`)
|
||||
VALUES (5, 'Sync user', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0);
|
||||
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
|
||||
VALUES (6, 'Read Only', NOW(), NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `perm_decaying`, `default_role`)
|
||||
VALUES (6, 'Read Only', NOW(), NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
|
|
|
@ -309,13 +309,13 @@ COPY public.regexp (id, regexp, replacement, type) FROM stdin;
|
|||
-- Data for Name: roles; Type: TABLE DATA; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COPY public.roles (id, name, created, modified, perm_add, perm_modify, perm_modify_org, perm_publish, perm_delegate, perm_sync, perm_admin, perm_audit, perm_full, perm_auth, perm_site_admin, perm_regexp_access, perm_tagger, perm_template, perm_sharing_group, perm_tag_editor, perm_sighting, perm_object_template, default_role, memory_limit, max_execution_time, restricted_to_site_admin, perm_publish_zmq, perm_publish_kafka) FROM stdin;
|
||||
1 admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t t t t t t t t t t t t t f f t t
|
||||
2 Org Admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f t t f t f f t t t t t f f f t t
|
||||
3 User 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t f f f f f f t f f f f f f t f t f f f
|
||||
4 Publisher 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f f f f t f f f f f f t f f f t t
|
||||
5 Sync user 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t f f f t f f f f t f t f f f t t
|
||||
6 Read Only 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 f f f f f f f f f t f f f f f f f f f f f f
|
||||
COPY public.roles (id, name, created, modified, perm_add, perm_modify, perm_modify_org, perm_publish, perm_delegate, perm_sync, perm_admin, perm_audit, perm_full, perm_auth, perm_site_admin, perm_regexp_access, perm_tagger, perm_template, perm_sharing_group, perm_tag_editor, perm_sighting, perm_object_template, default_role, memory_limit, max_execution_time, restricted_to_site_admin, perm_publish_zmq, perm_publish_kafka, perm_decaying) FROM stdin;
|
||||
1 admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t t t t t t t t t t t t t f f t t t
|
||||
2 Org Admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f t t f t f f t t t t t f f f t t t
|
||||
3 User 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t f f f f f f t f f f f f f t f t f f f t
|
||||
4 Publisher 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f f f f t f f f f f f t f f f t t t
|
||||
5 Sync user 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t f f f t f f f f t f t f f f t t t
|
||||
6 Read Only 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 f f f f f f f f f t f f f f f f f f f f f f f
|
||||
\.
|
||||
|
||||
|
||||
|
|
|
@ -1135,7 +1135,8 @@ CREATE TABLE public.roles (
|
|||
max_execution_time character varying(255) DEFAULT ''::character varying,
|
||||
restricted_to_site_admin boolean DEFAULT false NOT NULL,
|
||||
perm_publish_zmq boolean DEFAULT false NOT NULL,
|
||||
perm_publish_kafka boolean DEFAULT false NOT NULL
|
||||
perm_publish_kafka boolean DEFAULT false NOT NULL,
|
||||
perm_decaying boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -164,20 +164,6 @@
|
|||
group: root
|
||||
mode: 0755
|
||||
|
||||
- name: Cake-resque installation
|
||||
composer:
|
||||
command: "require"
|
||||
arguments: "kamisama/cake-resque:4.1.2"
|
||||
working_dir: "/opt/misp-server/misp/app"
|
||||
register: cakeresque_install
|
||||
|
||||
- name: Vendor configure
|
||||
composer:
|
||||
command: "config"
|
||||
arguments: "vendor-dir Vendor"
|
||||
working_dir: "/opt/misp-server/misp/app"
|
||||
when: cakeresque_install.changed
|
||||
|
||||
- name: PHP composer install
|
||||
composer:
|
||||
command: "install"
|
||||
|
|
|
@ -46,7 +46,7 @@ class AppController extends Controller
|
|||
|
||||
public $helpers = array('Utility', 'OrgImg', 'FontAwesome', 'UserName');
|
||||
|
||||
private $__queryVersion = '84';
|
||||
private $__queryVersion = '85';
|
||||
public $pyMispVersion = '2.4.114';
|
||||
public $phpmin = '7.0';
|
||||
public $phprec = '7.2';
|
||||
|
@ -453,6 +453,7 @@ class AppController extends Controller
|
|||
$this->set('isAclSighting', isset($role['perm_sighting']) ? $role['perm_sighting'] : false);
|
||||
$this->set('isAclZmq', isset($role['perm_publish_zmq']) ? $role['perm_publish_zmq'] : false);
|
||||
$this->set('isAclKafka', isset($role['perm_publish_kafka']) ? $role['perm_publish_kafka'] : false);
|
||||
$this->set('isAclDecaying', isset($role['perm_decaying']) ? $role['perm_decaying'] : false);
|
||||
$this->userRole = $role;
|
||||
if (Configure::read('MISP.log_paranoid')) {
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
|
|
|
@ -1891,7 +1891,8 @@ class AttributesController extends AppController
|
|||
'value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp',
|
||||
'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id', 'includeEventTags',
|
||||
'includeProposals', 'returnFormat', 'published', 'limit', 'page', 'requested_attributes', 'includeContext', 'headerless',
|
||||
'includeWarninglistHits', 'attackGalaxy', 'object_relation', 'includeSightings', 'includeCorrelations'
|
||||
'includeWarninglistHits', 'attackGalaxy', 'object_relation', 'includeSightings', 'includeCorrelations', 'includeDecayScore',
|
||||
'decayingModel', 'excludeDecayed', 'modelOverrides', 'includeFullModel', 'score'
|
||||
);
|
||||
$filterData = array(
|
||||
'request' => $this->request,
|
||||
|
|
|
@ -70,6 +70,28 @@ class ACLComponent extends Component
|
|||
'view' => array('*'),
|
||||
'viewPicture' => array('*'),
|
||||
),
|
||||
'decayingModel' => array(
|
||||
"update" => array(),
|
||||
"export" => array('*'),
|
||||
"import" => array('*'),
|
||||
"view" => array('*'),
|
||||
"index" => array('*'),
|
||||
"add" => array( 'OR' => array('perm_admin', 'perm_decaying')),
|
||||
"edit" => array( 'OR' => array('perm_admin', 'perm_decaying')),
|
||||
"delete" => array( 'OR' => array('perm_admin', 'perm_decaying')),
|
||||
"enable" => array( 'OR' => array('perm_admin', 'perm_decaying')),
|
||||
"disable" => array( 'OR' => array('perm_admin', 'perm_decaying')),
|
||||
"decayingTool" => array( 'OR' => array('perm_admin', 'perm_decaying')),
|
||||
"getAllDecayingModels" => array('*'),
|
||||
"decayingToolBasescore" => array('*'),
|
||||
"decayingToolSimulation" => array('*'),
|
||||
"decayingToolRestSearch" => array('*'),
|
||||
"decayingToolComputeSimulation" => array('*')
|
||||
),
|
||||
'decayingModelMapping' => array(
|
||||
"viewAssociatedTypes" => array('*'),
|
||||
"linkAttributeTypeToModel" => array( 'OR' => array('perm_admin', 'perm_decaying'))
|
||||
),
|
||||
'communities' => array(
|
||||
'index' => array(),
|
||||
'requestAccess' => array(),
|
||||
|
@ -165,7 +187,6 @@ class ACLComponent extends Component
|
|||
'xml' => array('*')
|
||||
),
|
||||
'favouriteTags' => array(
|
||||
'index' => array('*'),
|
||||
'toggle' => array('*'),
|
||||
'getToggleField' => array('*')
|
||||
),
|
||||
|
@ -514,7 +535,6 @@ class ACLComponent extends Component
|
|||
'edit' => array('*'),
|
||||
'fetchPGPKey' => array('*'),
|
||||
'histogram' => array('*'),
|
||||
'index' => array('*'),
|
||||
'initiatePasswordReset' => array('perm_admin'),
|
||||
'login' => array('*'),
|
||||
'logout' => array('*'),
|
||||
|
|
|
@ -47,7 +47,7 @@ class RestResponseComponent extends Component
|
|||
Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export).
|
||||
This API allows pagination via the page and limit parameters.",
|
||||
'mandatory' => array('returnFormat'),
|
||||
'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals'),
|
||||
'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals', 'includeDecayScore', 'includeFullModel', 'decayingModel', 'excludeDecayed', 'score'),
|
||||
'params' => array()
|
||||
)
|
||||
),
|
||||
|
@ -443,6 +443,9 @@ class RestResponseComponent extends Component
|
|||
$type = $format;
|
||||
}
|
||||
if (!$raw) {
|
||||
if (is_string($response)) {
|
||||
$response = array('message' => $response);
|
||||
}
|
||||
$response = json_encode($response, JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
||||
|
@ -725,6 +728,13 @@ class RestResponseComponent extends Component
|
|||
'autoclose' => true
|
||||
),
|
||||
),
|
||||
'decayingModel' => array(
|
||||
'input' => 'select',
|
||||
'type' => 'string',
|
||||
'operators' => array('equal', 'not_equal'),
|
||||
'unique' => true,
|
||||
'help' => 'Specify the decaying model from which the decaying score should be calculated'
|
||||
),
|
||||
'default_role' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
|
@ -825,6 +835,12 @@ class RestResponseComponent extends Component
|
|||
'values' => array(1 => 'True', 0 => 'False' ),
|
||||
'help' => __('The tag is exported when synchronising with other instances')
|
||||
),
|
||||
'excludeDecayed' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
'values' => array(1 => 'True', 0 => 'False' ),
|
||||
'help' => 'Should the decayed elements by excluded'
|
||||
),
|
||||
'excludeLocalTags' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
|
@ -904,6 +920,12 @@ class RestResponseComponent extends Component
|
|||
'values' => array(1 => 'True', 0 => 'False' ),
|
||||
'help' => __('Include matching attributes in the response')
|
||||
),
|
||||
'includeDecayScore' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
'values' => array(1 => 'True', 0 => 'False' ),
|
||||
'help' => 'Include all enabled decaying score'
|
||||
),
|
||||
'includeEvent' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
|
@ -922,6 +944,12 @@ class RestResponseComponent extends Component
|
|||
'values' => array(1 => 'True', 0 => 'False' ),
|
||||
'help' => __('Include tags of matching events in the response')
|
||||
),
|
||||
'includeFullModel' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
'values' => array(1 => 'True', 0 => 'False' ),
|
||||
'help' => 'Include all model information of matching events in the response'
|
||||
),
|
||||
'includeProposals' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
|
@ -1244,6 +1272,13 @@ class RestResponseComponent extends Component
|
|||
'operators' => array('equal'),
|
||||
'validation' => array(0 => 'role1'),
|
||||
),
|
||||
'score' => array(
|
||||
'input' => 'number',
|
||||
'type' => 'integer',
|
||||
'operators' => array('equal'),
|
||||
'validation' => array('min' => 0, 'step' => 1, 'max' => 100),
|
||||
'help' => 'An alias to override on-the-fly the threshold of the decaying model'
|
||||
),
|
||||
'searchall' => array(
|
||||
'input' => 'radio',
|
||||
'type' => 'integer',
|
||||
|
@ -1546,6 +1581,9 @@ class RestResponseComponent extends Component
|
|||
case "category":
|
||||
$this->__overwriteCategory($scope, $fieldsConstraint[$field]);
|
||||
break;
|
||||
case "decayingModel":
|
||||
$this->__overwriteDecayingModel($scope, $fieldsConstraint[$field]);
|
||||
break;
|
||||
case "distribution":
|
||||
$this->__overwriteDistribution($scope, $fieldsConstraint[$field]);
|
||||
break;
|
||||
|
@ -1614,6 +1652,17 @@ class RestResponseComponent extends Component
|
|||
$field['values'][] = array('label' => $text, 'value' => $d);
|
||||
}
|
||||
}
|
||||
private function __overwriteDecayingModel($scope, &$field) {
|
||||
$this->{$scope} = ClassRegistry::init("DecayingModel");
|
||||
$models = $this->{$scope}->find('list', array(
|
||||
'recursive' => -1,
|
||||
'fields' => array('name')
|
||||
));
|
||||
$field['values'] = array();
|
||||
foreach($models as $i => $model_name) {
|
||||
$field['values'][] = array('label' => h($model_name), 'value' => $i);
|
||||
}
|
||||
}
|
||||
private function __overwriteTags($scope, &$field) {
|
||||
$this->{$scope} = ClassRegistry::init("Tag");
|
||||
$tags = $this->{$scope}->find('list', array(
|
||||
|
|
|
@ -0,0 +1,724 @@
|
|||
<?php
|
||||
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
class DecayingModelController extends AppController
|
||||
{
|
||||
public $components = array('Security' ,'RequestHandler');
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 50,
|
||||
'order' => array(
|
||||
'DecayingModel.ID' => 'desc'
|
||||
)
|
||||
);
|
||||
|
||||
public function update($force=false)
|
||||
{
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$this->DecayingModel->update($force, $this->Auth->user());
|
||||
$message = __('Default decaying models updated');
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->saveSuccessResponse('DecayingModel', 'update', false, $this->response->type(), $message);
|
||||
} else {
|
||||
$this->Flash->success($message);
|
||||
$this->redirect(array('controller' => 'decayingModel', 'action' => 'index'));
|
||||
}
|
||||
} else {
|
||||
throw new MethodNotAllowedException(__("This method is not allowed"));
|
||||
}
|
||||
}
|
||||
|
||||
public function export($model_id)
|
||||
{
|
||||
$model = $this->DecayingModel->fetchModel($this->Auth->user(), $model_id, true);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
unset($model['DecayingModel']['id'], $model['DecayingModel']['uuid'], $model['DecayingModel']['org_id'], $model['DecayingModelMapping']);
|
||||
return $this->RestResponse->viewData($model, $this->response->type());
|
||||
}
|
||||
|
||||
public function import()
|
||||
{
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$data = $this->request->data['DecayingModel'];
|
||||
if ($data['submittedjson']['name'] != '' && $data['json'] != '') {
|
||||
throw new MethodNotAllowedException(__('Only one import field can be used'));
|
||||
}
|
||||
if ($data['submittedjson']['size'] > 0) {
|
||||
$filename = basename($data['submittedjson']['name']);
|
||||
$file_content = file_get_contents($data['submittedjson']['tmp_name']);
|
||||
if ((isset($data['submittedjson']['error']) && $data['submittedjson']['error'] == 0) ||
|
||||
(!empty($data['submittedjson']['tmp_name']) && $data['submittedjson']['tmp_name'] != '')
|
||||
) {
|
||||
if (!$file_content) {
|
||||
throw new InternalErrorException(__('PHP says file was not uploaded. Are you attacking me?'));
|
||||
}
|
||||
}
|
||||
$text = $file_content;
|
||||
} else {
|
||||
$text = $data['json'];
|
||||
}
|
||||
$json = json_decode($text, true);
|
||||
if ($json === null) {
|
||||
throw new MethodNotAllowedException(__('Error while decoding JSON'));
|
||||
}
|
||||
|
||||
unset($json['id']);
|
||||
unset($json['uuid']);
|
||||
$json['default'] = 0;
|
||||
$json['org_id'] = $this->Auth->user()['org_id'];
|
||||
|
||||
$attribute_types = array();
|
||||
if (!empty($json['attribute_types'])) {
|
||||
$attribute_types = $json['attribute_types'];
|
||||
unset($json['attribute_types']);
|
||||
}
|
||||
|
||||
if ($this->DecayingModel->save($json)) {
|
||||
$saved_model = array(
|
||||
'model_id' => $this->DecayingModel->id,
|
||||
'attribute_types' => $attribute_types
|
||||
);
|
||||
if (!empty($saved_model['attribute_types'])) {
|
||||
$result = $this->DecayingModel->DecayingModelMapping->resetMappingForModel($saved_model, $this->Auth->user());
|
||||
} else {
|
||||
$result = true;
|
||||
}
|
||||
if (!empty($result)) {
|
||||
$this->Flash->success(__('The model has been imported.'));
|
||||
} else {
|
||||
$this->Flash->error(__('The model has been imported. However importing mapping failed.'));
|
||||
}
|
||||
} else {
|
||||
$this->Flash->error(__('Error while importing model.'));
|
||||
}
|
||||
$this->redirect(array('action' => 'index'));
|
||||
}
|
||||
}
|
||||
|
||||
public function view($id)
|
||||
{
|
||||
$decaying_model = $this->DecayingModel->fetchModel($this->Auth->user(), $id, true);
|
||||
if (empty($decaying_model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$this->set('id', $id);
|
||||
$this->set('decaying_model', $decaying_model);
|
||||
$available_formulas = $this->DecayingModel->listAvailableFormulas();
|
||||
$this->set('available_formulas', $available_formulas);
|
||||
}
|
||||
|
||||
// Sets pagination condition for url parameters
|
||||
private function __setIndexFilterConditions($passedArgs)
|
||||
{
|
||||
$white_list_url_parameters = array('sort', 'direction');
|
||||
$passedArgsArray = array();
|
||||
foreach ($passedArgs as $k => $v) {
|
||||
switch ($k) {
|
||||
case 'my_models':
|
||||
$passedArgsArray[$k] = $v;
|
||||
if ($v) {
|
||||
$this->paginate['conditions']['AND'] = array('DecayingModel.org_id' => $this->Auth->user('Organisation')['id']);
|
||||
}
|
||||
break;
|
||||
case 'default_models':
|
||||
$passedArgsArray[$k] = $v;
|
||||
if ($v) {
|
||||
$this->paginate['conditions']['AND'] = array('not' => array('DecayingModel.uuid' => null));
|
||||
}
|
||||
break;
|
||||
case 'all_orgs':
|
||||
$passedArgsArray[$k] = $v;
|
||||
if ($v) {
|
||||
$this->paginate['conditions']['AND'] = array('DecayingModel.all_orgs' => $v);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (in_array($k, $white_list_url_parameters)) {
|
||||
$passedArgsArray[$k] = $v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $passedArgsArray;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$conditions = array();
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$conditions['OR'] = array(
|
||||
'org_id' => $this->Auth->user('Organisation')['id'],
|
||||
'all_orgs' => 1
|
||||
);
|
||||
$this->paginate = Set::merge($this->paginate, array(
|
||||
'conditions' => $conditions
|
||||
));
|
||||
}
|
||||
$passedArgsArray = $this->__setIndexFilterConditions($this->passedArgs);
|
||||
$this->set('passedArgsArray', $passedArgsArray);
|
||||
$this->set('decayingModels', $this->paginate());
|
||||
$available_formulas = $this->DecayingModel->listAvailableFormulas();
|
||||
$this->set('available_formulas', $available_formulas);
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->viewData($this->paginate(), $this->response->type());
|
||||
}
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
if (!isset($this->request->data['DecayingModel'])) {
|
||||
$this->request->data = array('DecayingModel' => $this->request->data);
|
||||
}
|
||||
|
||||
$this->request->data['DecayingModel']['org_id'] = $this->Auth->user()['org_id'];
|
||||
unset($this->request->data['DecayingModel']['id']);
|
||||
unset($this->request->data['DecayingModel']['uuid']);
|
||||
$this->request->data['DecayingModel']['default'] = 0;
|
||||
|
||||
if (empty($this->request->data['DecayingModel']['name'])) {
|
||||
throw new MethodNotAllowedException(__("The model must have a name"));
|
||||
}
|
||||
$this->request->data = $this->__adjustJSONData($this->request->data);
|
||||
if ($this->request->data === false) {
|
||||
return false;
|
||||
}
|
||||
$attribute_types = array();
|
||||
if (!empty($this->request->data['attribute_types'])) {
|
||||
$attribute_types = $this->request->data['attribute_types'];
|
||||
unset($this->request->data['attribute_types']);
|
||||
}
|
||||
if ($this->DecayingModel->save($this->request->data)) {
|
||||
$success_message = __('The model has been saved.');
|
||||
if (!empty($saved_model['attribute_types'])) {
|
||||
if (!$this->DecayingModel->DecayingModelMapping->resetMappingForModel($saved_model, $this->Auth->user())) {
|
||||
$success_message = __('The model has been saved. However importing mapping failed.');
|
||||
}
|
||||
}
|
||||
if ($this->request->is('ajax') || $this->_isRest()) {
|
||||
$saved = $this->DecayingModel->fetchModel($this->Auth->user(), $this->DecayingModel->id, true, array(), true);
|
||||
if (empty($saved)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $saved, 'action' => 'add');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->success($sucess_messaqge);
|
||||
$this->redirect(array('action' => 'index'));
|
||||
}
|
||||
} else {
|
||||
if ($this->request->is('ajax') || $this->_isRest()) {
|
||||
$response = array(
|
||||
'action' => 'add',
|
||||
'saved' => false,
|
||||
'errors' => array(__('The model could not be saved. Please try again.'))
|
||||
);
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->error(__('The model could not be saved. Please try again.' . $this->here));
|
||||
$this->redirect($this->here);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->set('action', 'add');
|
||||
$available_formulas = $this->DecayingModel->listAvailableFormulas();
|
||||
$formulas = array();
|
||||
foreach ($available_formulas as $formulaName => $f) {
|
||||
$formulas[$formulaName] = $formulaName;
|
||||
}
|
||||
$this->set('available_formulas', $formulas);
|
||||
}
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$decaying_model = $this->DecayingModel->fetchModel($this->Auth->user(), $id);
|
||||
if (empty($decaying_model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$enforceRestrictedEdition = $decaying_model['DecayingModel']['default'];
|
||||
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
|
||||
$this->request->data['DecayingModel']['id'] = $id;
|
||||
$fieldListToSave = array('enabled', 'all_orgs');
|
||||
if (!$enforceRestrictedEdition) {
|
||||
$fieldListToSave = array_merge($fieldListToSave, array('name', 'description', 'parameters', 'formula'));
|
||||
$this->request->data = $this->__adjustJSONData($this->request->data);
|
||||
if ($this->request->data === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$save_result = $this->DecayingModel->save($this->request->data, true, $fieldListToSave);
|
||||
if ($save_result) {
|
||||
if ($this->request->is('ajax') || $this->_isRest()) {
|
||||
$saved = $this->DecayingModel->fetchModel($this->Auth->user(), $this->DecayingModel->id, true, array(), true);
|
||||
if (empty($saved)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $saved, 'action' => 'edit');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->success(__('The model has been saved.'));
|
||||
$this->redirect(array('action' => 'index'));
|
||||
}
|
||||
} else {
|
||||
if ($this->request->is('ajax') || $this->_isRest()) {
|
||||
$saved = $this->DecayingModel->fetchModel($this->Auth->user(), $this->DecayingModel->id);
|
||||
if (empty($saved)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $saved, 'action' => 'edit', 'saved' => false);
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->error(__('The model could not be saved. Please try again.' . $this->here));
|
||||
$this->redirect($this->here);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->request->data = $decaying_model;
|
||||
$this->set('id', $id);
|
||||
$this->set('decayingModel', $decaying_model);
|
||||
$this->set('restrictEdition', $enforceRestrictedEdition);
|
||||
$this->set('action', 'edit');
|
||||
$available_formulas = $this->DecayingModel->listAvailableFormulas();
|
||||
$formulas = array();
|
||||
foreach ($available_formulas as $formulaName => $f) {
|
||||
$formulas[$formulaName] = $formulaName;
|
||||
}
|
||||
$this->set('available_formulas', $formulas);
|
||||
$this->render('add');
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust or flash the error to the user
|
||||
private function __adjustJSONData($json)
|
||||
{
|
||||
if (isset($json['DecayingModel']['parameters'])) {
|
||||
if (isset($json['DecayingModel']['parameters']['settings']) && !is_array($json['DecayingModel']['parameters']['settings'])) {
|
||||
$settings = json_decode($json['DecayingModel']['parameters']['settings'], true);
|
||||
if ($settings === null) {
|
||||
$this->Flash->error(__('Invalid JSON `Settings`.'));
|
||||
return false;
|
||||
}
|
||||
$json['DecayingModel']['parameters']['settings'] = $settings;
|
||||
}
|
||||
if (!isset($json['DecayingModel']['parameters']['lifetime'])) {
|
||||
$this->Flash->error(__('Invalid parameter `lifetime`.'));
|
||||
return false;
|
||||
}
|
||||
if (!isset($json['DecayingModel']['parameters']['decay_speed'])) {
|
||||
$this->Flash->error(__('Invalid parameter `decay_speed`.'));
|
||||
return false;
|
||||
}
|
||||
if (!isset($json['DecayingModel']['parameters']['threshold'])) {
|
||||
$this->Flash->error(__('Invalid parameter `threshold`.'));
|
||||
return false;
|
||||
}
|
||||
if (!isset($json['DecayingModel']['parameters']['default_base_score'])) {
|
||||
$this->Flash->error(__('Invalid parameter `default_base_score`.'));
|
||||
return false;
|
||||
}
|
||||
if (isset($json['DecayingModel']['parameters']['base_score_config']) && $json['DecayingModel']['parameters']['base_score_config'] != '') {
|
||||
if (!is_array($json['DecayingModel']['parameters']['base_score_config'])) {
|
||||
$encoded = json_decode($json['DecayingModel']['parameters']['base_score_config'], true);
|
||||
if ($encoded === null) {
|
||||
$this->Flash->error(__('Invalid parameter `base_score_config`.'));
|
||||
return false;
|
||||
}
|
||||
$json['DecayingModel']['parameters']['base_score_config'] = $encoded;
|
||||
}
|
||||
} else {
|
||||
$json['DecayingModel']['parameters']['base_score_config'] = new stdClass();
|
||||
}
|
||||
} else {
|
||||
$this->Flash->error(__('Missing JSON key `parameters`.'));
|
||||
return false;
|
||||
}
|
||||
$json['DecayingModel']['parameters'] = json_encode($json['DecayingModel']['parameters']);
|
||||
return $json;
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$decaying_model = $this->DecayingModel->fetchModel($this->Auth->user(), $id);
|
||||
if (empty($decaying_model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
if (
|
||||
!$this->DecayingModel->isEditableByCurrentUser($this->Auth->user(), $decaying_model) ||
|
||||
$decaying_model['DecayingModel']['default']
|
||||
) {
|
||||
throw new MethodNotAllowedException(__('You are not authorised to delete this model.'));
|
||||
}
|
||||
|
||||
if ($this->DecayingModel->delete($id, true)) {
|
||||
if ($this->request->is('ajax')) {
|
||||
$response = array('action' => 'delete', 'saved' => true);
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->success(__('Decaying Model deleted.'));
|
||||
}
|
||||
} else {
|
||||
$error_message = __('The Decaying Model could not be deleted.');
|
||||
if ($this->request->is('ajax')) {
|
||||
$response = array('action' => 'delete', 'saved' => false, 'errors' => array($error_message));
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->error($error_message);
|
||||
}
|
||||
}
|
||||
$this->redirect(array('action' => 'index'));
|
||||
}
|
||||
}
|
||||
|
||||
public function enable($id)
|
||||
{
|
||||
$decaying_model = $this->DecayingModel->fetchModel($this->Auth->user(), $id);
|
||||
if (empty($decaying_model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
if (!$this->DecayingModel->isEditableByCurrentUser($this->Auth->user(), $decaying_model)) {
|
||||
throw new MethodNotAllowedException(__('You are not authorised to enable this model.'));
|
||||
}
|
||||
|
||||
$decaying_model['DecayingModel']['enabled'] = 1;
|
||||
if ($this->DecayingModel->save($decaying_model)) {
|
||||
if ($this->request->is('ajax')) {
|
||||
$model = $this->DecayingModel->fetchModel($this->Auth->user(), $id, true, array(), true);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $model, 'action' => 'enable');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
}
|
||||
$this->Flash->success(__('Decaying Model enabled.'));
|
||||
} else {
|
||||
if ($this->request->is('ajax')) { // ajax caller expect data to be returned to update the DOM accordingly
|
||||
$model = $this->DecayingModel->fetchModel($this->Auth->user(), $id, true, array(), true);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $model, 'action' => 'enable');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} elseif ($this->_isRest()) {
|
||||
$response = array('errors' => $array(__('Error while enabling decaying model')), 'action' => 'enable');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
}
|
||||
$this->Flash->error(__('Error while enabling decaying model'));
|
||||
}
|
||||
$this->redirect($this->referer());
|
||||
} else {
|
||||
$this->set('model', $decaying_model['DecayingModel']);
|
||||
$this->render('ajax/enable_form');
|
||||
}
|
||||
}
|
||||
|
||||
public function disable($id)
|
||||
{
|
||||
$decaying_model = $this->DecayingModel->fetchModel($this->Auth->user(), $id);
|
||||
if (empty($decaying_model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
if (!$this->DecayingModel->isEditableByCurrentUser($this->Auth->user(), $decaying_model)) {
|
||||
throw new MethodNotAllowedException(__('You are not authorised to disable this model.'));
|
||||
}
|
||||
|
||||
$decaying_model['DecayingModel']['enabled'] = 0;
|
||||
if ($this->DecayingModel->save($decaying_model)) {
|
||||
if ($this->request->is('ajax')) {
|
||||
$model = $this->DecayingModel->fetchModel($this->Auth->user(), $id, true, array(), true);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $model, 'action' => 'disable');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
}
|
||||
$this->Flash->success(__('Decaying Model disabled.'));
|
||||
} else {
|
||||
if ($this->request->is('ajax')) { // ajax caller expect data to be returned to update the DOM accordingly
|
||||
$model = $this->DecayingModel->fetchModel($this->Auth->user(), $id, true, array(), true);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$response = array('data' => $model, 'action' => 'disable');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} elseif ($this->_isRest()) {
|
||||
$response = array('errors' => $array(__('Error while enabling decaying model')), 'action' => 'disable');
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
}
|
||||
$this->Flash->error(__('Error while disabling decaying model'));
|
||||
}
|
||||
$this->redirect(array('action' => 'index'));
|
||||
} else {
|
||||
$this->set('model', $decaying_model['DecayingModel']);
|
||||
$this->render('ajax/disable_form');
|
||||
}
|
||||
}
|
||||
|
||||
public function decayingTool()
|
||||
{
|
||||
$parameters = array(
|
||||
'lifetime' => array(
|
||||
'value' => 30,
|
||||
'step' => 1,
|
||||
'max' => 365,
|
||||
'greek' => '',
|
||||
'unit' => 'days',
|
||||
'name' => __('Lifetime'),
|
||||
'info' => __('Lifetime of the attribute, or time after which the score will be 0')
|
||||
),
|
||||
'decay_speed' => array(
|
||||
'value' => 0.3,
|
||||
'step' => 0.1,
|
||||
'max' => 10,
|
||||
'greek' => '',
|
||||
'name' => __('Decay speed'),
|
||||
'info' => __('Decay speed at which an indicator will loose score')
|
||||
),
|
||||
'threshold' => array(
|
||||
'value' => 30,
|
||||
'step' => 1,
|
||||
'max' => 100,
|
||||
'greek' => '',
|
||||
'name' => __('Cutoff threshold'),
|
||||
'info' => __('Cutoff value at which an indicator will be marked as decayed instead of 0')
|
||||
)
|
||||
);
|
||||
$types = $this->User->Event->Attribute->typeDefinitions;
|
||||
$this->loadModel('ObjectTemplateElement');
|
||||
$objectTypes = $this->ObjectTemplateElement->getAllAvailableTypes();
|
||||
array_walk($objectTypes, function(&$item, $key) use ($types) {
|
||||
$item["isObject"] = true;
|
||||
$isAttribute = isset($types[$key]);
|
||||
if ($isAttribute) {
|
||||
$item["isAttribute"] = true;
|
||||
$item["default_category"] = $types[$key]['default_category'];
|
||||
$item["to_ids"] = $types[$key]['to_ids'];
|
||||
} else {
|
||||
$item["default_category"] = $item["category"];
|
||||
}
|
||||
});
|
||||
$types = array_merge($types, $objectTypes);
|
||||
ksort($types);
|
||||
$savedDecayingModels = $this->DecayingModel->fetchAllAllowedModels($this->Auth->user());
|
||||
$available_formulas = $this->DecayingModel->listAvailableFormulas();
|
||||
|
||||
$this->set('available_formulas', $available_formulas);
|
||||
$this->set('parameters', $parameters);
|
||||
$this->set('types', $types);
|
||||
$this->set('savedModels', $savedDecayingModels);
|
||||
$associated_models = $this->DecayingModel->DecayingModelMapping->getAssociatedModels($this->Auth->user()); // mapping Attribute.type => Models
|
||||
$this->set('associated_models', $associated_models);
|
||||
}
|
||||
|
||||
public function getAllDecayingModels()
|
||||
{
|
||||
$filters = $this->request->query;
|
||||
$savedDecayingModels = $this->DecayingModel->fetchAllAllowedModels($this->Auth->user(), true, $filters);
|
||||
return $this->RestResponse->viewData($savedDecayingModels, $this->response->type());
|
||||
}
|
||||
|
||||
public function decayingToolBasescore()
|
||||
{
|
||||
$taxonomies = $this->DecayingModel->listTaxonomiesWithNumericalValue();
|
||||
$this->set('taxonomies', $taxonomies['taxonomies']);
|
||||
$this->set('taxonomies_not_having_numerical_value', $taxonomies['not_having_numerical_value']);
|
||||
$this->set('excluded_taxonomies', $taxonomies['excluded_taxonomies']);
|
||||
}
|
||||
|
||||
public function decayingToolSimulation($model_id)
|
||||
{
|
||||
$decaying_model = $this->DecayingModel->fetchModel($this->Auth->user(), $model_id);
|
||||
if (empty($decaying_model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
if (isset($this->request->params['named']['attribute_id'])) {
|
||||
$this->set('attribute_id', $this->request->params['named']['attribute_id']);
|
||||
}
|
||||
$this->set('user', $this->Auth->user());
|
||||
$this->set('decaying_model', $decaying_model);
|
||||
$allowed_models = $this->DecayingModel->fetchAllAllowedModels($this->Auth->user());
|
||||
$this->set('all_models', $allowed_models);
|
||||
}
|
||||
|
||||
// TODO: Consider using the export tool to perform the post treatement
|
||||
// as this does not mirror a complete restSearch (not using fetchAttribute)
|
||||
public function decayingToolRestSearch($continue = false)
|
||||
{
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$body = $this->request->data['decayingToolRestSearch']['filters'];
|
||||
$decoded_body = json_decode($body, true);
|
||||
if (is_null($decoded_body)) {
|
||||
throw new Exception(__("Error Processing Request, can't parse the body"));
|
||||
}
|
||||
$this->request->data = $decoded_body;
|
||||
$paramArray = array(
|
||||
'value' , 'type', 'category', 'org', 'tags', 'from', 'to', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp',
|
||||
'timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'event_timestamp', 'threat_level_id', 'includeEventTags',
|
||||
'includeProposals', 'returnFormat', 'published', 'limit', 'page', 'requested_attributes', 'includeContext', 'headerless',
|
||||
'includeWarninglistHits', 'attackGalaxy', 'object_relation', 'id', 'includeDecayScore', 'includeFullModel', 'decayingModel', 'excludeDecayed', 'modelOverrides',
|
||||
'score'
|
||||
);
|
||||
$filterData = array(
|
||||
'request' => $this->request,
|
||||
'named_params' => $this->params['named'],
|
||||
'paramArray' => $paramArray,
|
||||
'ordered_url_params' => compact($paramArray)
|
||||
);
|
||||
$exception = false;
|
||||
$filters = $this->_harvestParameters($filterData, $exception);
|
||||
if ($filters === false) {
|
||||
return $exception;
|
||||
}
|
||||
$filters['includeEventTags'] = 1;
|
||||
if (!isset($filters['excludeDecayed'])) {
|
||||
$filters['excludeDecayed'] = 0;
|
||||
}
|
||||
$filters['includeDecayScore'] = 1;
|
||||
if (isset($filters['id'])) { // allows searching by id
|
||||
if (Validation::uuid($filters['id'])) {
|
||||
$filters['uuid'] = $filters['id'];
|
||||
} else {
|
||||
$attributes = $this->User->Event->Attribute->fetchAttributes($this->Auth->user(), array(
|
||||
'conditions' => array('Attribute.id' => $filters['id'])
|
||||
));
|
||||
if (!empty($attributes)) {
|
||||
$filters['uuid'] = $attributes[0]['Attribute']['uuid'];
|
||||
} else {
|
||||
$filters['uuid'] = '-1'; // force no result
|
||||
}
|
||||
}
|
||||
unset($filters['id']);
|
||||
}
|
||||
unset($filterData);
|
||||
$this->Session->write('search_attributes_filters', json_encode($filters));
|
||||
} elseif ($continue === 'results') {
|
||||
$filters = $this->Session->read('search_attributes_filters');
|
||||
if (empty($filters)) {
|
||||
$filters = array();
|
||||
} else {
|
||||
$filters = json_decode($filters, true);
|
||||
}
|
||||
}
|
||||
if (isset($filters)) {
|
||||
$params = $this->User->Event->Attribute->restSearch($this->Auth->user(), 'json', $filters, true);
|
||||
if (!isset($params['conditions']['Attribute.deleted'])) {
|
||||
$params['conditions']['Attribute.deleted'] = 0;
|
||||
}
|
||||
$this->paginate = $params;
|
||||
if (empty($this->paginate['limit'])) {
|
||||
$this->paginate['limit'] = 60;
|
||||
}
|
||||
if (empty($this->paginate['page'])) {
|
||||
$this->paginate['page'] = 1;
|
||||
}
|
||||
$this->paginate['recursive'] = -1;
|
||||
$this->paginate['contain'] = array(
|
||||
'Event' => array(
|
||||
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.info', 'Event.user_id', 'Event.date'),
|
||||
'Orgc' => array('fields' => array('Orgc.id', 'Orgc.name')),
|
||||
'Org' => array('fields' => array('Org.id', 'Org.name'))
|
||||
),
|
||||
'AttributeTag' => array('Tag'),
|
||||
'Object' => array(
|
||||
'fields' => array('Object.id', 'Object.distribution', 'Object.sharing_group_id')
|
||||
)
|
||||
);
|
||||
$attributes = $this->paginate($this->User->Event->Attribute);
|
||||
|
||||
// attach sightings and massage tags
|
||||
$sightingsData = array();
|
||||
if (!empty($options['overrideLimit'])) {
|
||||
$overrideLimit = true;
|
||||
} else {
|
||||
$overrideLimit = false;
|
||||
}
|
||||
$this->loadModel('GalaxyCluster');
|
||||
$cluster_names = $this->GalaxyCluster->find('list', array('fields' => array('GalaxyCluster.tag_name'), 'group' => array('GalaxyCluster.tag_name', 'GalaxyCluster.id')));
|
||||
$this->loadModel('Sighting');
|
||||
$eventTags = array();
|
||||
foreach ($attributes as $k => $attribute) {
|
||||
$attributes[$k]['Attribute']['AttributeTag'] = $attributes[$k]['AttributeTag'];
|
||||
$attributes[$k]['Attribute'] = $this->User->Event->massageTags($attributes[$k]['Attribute'], 'Attribute');
|
||||
unset($attributes[$k]['AttributeTag']);
|
||||
foreach ($attributes[$k]['Attribute']['AttributeTag'] as $k2 => $attributeTag) {
|
||||
if (in_array($attributeTag['Tag']['name'], $cluster_names)) {
|
||||
unset($attributes[$k]['Attribute']['AttributeTag'][$k2]);
|
||||
}
|
||||
}
|
||||
$sightingsData = array_merge(
|
||||
$sightingsData,
|
||||
$this->Sighting->attachToEvent($attribute, $this->Auth->user(), $attributes[$k]['Attribute']['id'], $extraConditions = false)
|
||||
);
|
||||
if (!empty($params['includeEventTags'])) {
|
||||
$tagConditions = array('EventTag.event_id' => $attribute['Event']['id']);
|
||||
if (empty($params['includeAllTags'])) {
|
||||
$tagConditions['Tag.exportable'] = 1;
|
||||
}
|
||||
$temp = $this->User->Event->EventTag->find('all', array(
|
||||
'recursive' => -1,
|
||||
'contain' => array('Tag'),
|
||||
'conditions' => $tagConditions
|
||||
));
|
||||
foreach ($temp as $tag) {
|
||||
$attributes[$k]['Attribute']['EventTag'][] = $tag;
|
||||
}
|
||||
}
|
||||
if (empty($filters['decayingModel'])) {
|
||||
$filters['decayingModel'] = false;
|
||||
}
|
||||
$model_overrides = isset($filters['modelOverrides']) ? $filters['modelOverrides'] : array();
|
||||
if (isset($filters['score'])) {
|
||||
$model_overrides['threshold'] = intval($filters['score']);
|
||||
}
|
||||
$attributes[$k]['Attribute'] = $this->DecayingModel->attachScoresToAttribute($this->Auth->user(), $attributes[$k]['Attribute'], $filters['decayingModel'], $model_overrides);
|
||||
if ($filters['excludeDecayed']) { // filter out decayed attribute
|
||||
$decayed_flag = true;
|
||||
foreach ($attributes[$k]['Attribute']['decay_score'] as $decayResult) {
|
||||
$decayed_flag = $decayed_flag && $decayResult['decayed'];
|
||||
}
|
||||
if ($decayed_flag) {
|
||||
unset($attributes[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sightingsData = $this->User->Event->getSightingData(array('Sighting' => $sightingsData));
|
||||
$this->set('sightingsData', $sightingsData);
|
||||
$this->set('attributes', $attributes);
|
||||
$this->set('attrDescriptions', $this->User->Event->Attribute->fieldDescriptions);
|
||||
$this->set('typeDefinitions', $this->User->Event->Attribute->typeDefinitions);
|
||||
$this->set('categoryDefinitions', $this->User->Event->Attribute->categoryDefinitions);
|
||||
$this->set('shortDist', $this->User->Event->Attribute->shortDist);
|
||||
} else {
|
||||
$this->render('decayingToolRestSearchForm');
|
||||
}
|
||||
}
|
||||
|
||||
public function decayingToolComputeSimulation($model_id, $attribute_id)
|
||||
{
|
||||
if (!$this->request->is('ajax')) {
|
||||
throw new MethodNotAllowedException(__("This method is only accessible via AJAX."));
|
||||
}
|
||||
$model_overrides = array();
|
||||
if (isset($this->params['named']['modelOverride'])) {
|
||||
$model_overrides = $this->params['named']['modelOverride'];
|
||||
$model_overrides = json_decode($model_overrides, true);
|
||||
if ($model_overrides === null) {
|
||||
$model_overrides = array();
|
||||
}
|
||||
}
|
||||
if (isset($this->params['named']['score'])) {
|
||||
$model_overrides['threshold'] = intval($this->params['named']['score']);
|
||||
}
|
||||
$score_overtime = $this->DecayingModel->getScoreOvertime($this->Auth->user(), $model_id, $attribute_id, $model_overrides);
|
||||
return $this->RestResponse->viewData($score_overtime, $this->response->type());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
class DecayingModelMappingController extends AppController
|
||||
{
|
||||
public $components = array('Security' ,'RequestHandler');
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 50,
|
||||
'order' => array(
|
||||
'DecayingModel.name' => 'asc'
|
||||
)
|
||||
);
|
||||
|
||||
public function viewAssociatedTypes($model_id) {
|
||||
$associated_types = $this->DecayingModelMapping->getAssociatedTypes($this->Auth->user(), $model_id);
|
||||
return $this->RestResponse->viewData($associated_types, $this->response->type());
|
||||
}
|
||||
|
||||
|
||||
public function linkAttributeTypeToModel($model_id) {
|
||||
$model = $this->DecayingModelMapping->DecayingModel->fetchModel($this->Auth->user(), $model_id);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$this->request->data['DecayingModelMapping']['model_id'] = $model_id;
|
||||
if (!isset($this->request->data['DecayingModelMapping']['org_id'])) {
|
||||
$this->request->data['DecayingModelMapping']['org_id'] = $this->Auth->user()['org_id'];
|
||||
}
|
||||
if (empty($this->request->data['DecayingModelMapping']['attributetypes'])) {
|
||||
throw new MethodNotAllowedException(_("The model must link to at least one attribute type"));
|
||||
} else {
|
||||
$decoded = json_decode($this->request->data['DecayingModelMapping']['attributetypes'], true);
|
||||
if ($decoded === null) {
|
||||
throw new MethodNotAllowedException(_("Invalid JSON: attribute type"));
|
||||
}
|
||||
$this->request->data['DecayingModelMapping']['attribute_types'] = $decoded;
|
||||
unset($this->request->data['DecayingModelMapping']['attributetypes']);
|
||||
}
|
||||
|
||||
$response = $this->DecayingModelMapping->resetMappingForModel($this->request->data['DecayingModelMapping'], $this->Auth->user());
|
||||
return $this->RestResponse->viewData($response, $this->response->type());
|
||||
} else {
|
||||
$this->set('model_id', $model_id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -26,7 +26,7 @@ class EventsController extends AppController
|
|||
);
|
||||
|
||||
private $acceptedFilteringNamedParams = array('sort', 'direction', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'attributeFilter', 'extended', 'page',
|
||||
'searchFor', 'proposal', 'correlation', 'warning', 'deleted', 'includeRelatedTags', 'distribution', 'taggedAttributes', 'galaxyAttachedAttributes', 'objectType', 'attributeType', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'feed', 'server', 'toIDS', 'sighting'
|
||||
'searchFor', 'proposal', 'correlation', 'warning', 'deleted', 'includeRelatedTags', 'includeDecayScore', 'distribution', 'taggedAttributes', 'galaxyAttachedAttributes', 'objectType', 'attributeType', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'feed', 'server', 'toIDS', 'sighting'
|
||||
);
|
||||
|
||||
public $defaultFilteringRules = array(
|
||||
|
@ -37,6 +37,7 @@ class EventsController extends AppController
|
|||
'warning' => 0,
|
||||
'deleted' => 2,
|
||||
'includeRelatedTags' => 0,
|
||||
'includeDecayScore' => 0,
|
||||
'toIDS' => 0,
|
||||
'feed' => 0,
|
||||
'server' => 0,
|
||||
|
@ -1078,6 +1079,13 @@ class EventsController extends AppController
|
|||
}
|
||||
if (isset($filters['deleted'])) {
|
||||
$conditions['deleted'] = $filters['deleted'] == 2 ? 0 : [0, 1];
|
||||
if ($filters['deleted'] == 2) { // not-deleted only
|
||||
$conditions['deleted'] = 0;
|
||||
} elseif ($filters['deleted'] == 1) { // deleted only
|
||||
$conditions['deleted'] = 1;
|
||||
} else { // both
|
||||
$conditions['deleted'] = [0, 1];
|
||||
}
|
||||
}
|
||||
if (isset($filters['toIDS']) && $filters['toIDS'] != 0) {
|
||||
$conditions['to_ids'] = $filters['toIDS'] == 2 ? 0 : 1;
|
||||
|
@ -1099,6 +1107,12 @@ class EventsController extends AppController
|
|||
} else {
|
||||
$this->set('includeRelatedTags', 0);
|
||||
}
|
||||
if (!empty($filters['includeDecayScore'])) {
|
||||
$this->set('includeDecayScore', 1);
|
||||
$conditions['includeDecayScore'] = 1;
|
||||
} else {
|
||||
$this->set('includeDecayScore', 0);
|
||||
}
|
||||
|
||||
$results = $this->Event->fetchEvent($this->Auth->user(), $conditions);
|
||||
if (empty($results)) {
|
||||
|
@ -1213,7 +1227,7 @@ class EventsController extends AppController
|
|||
}
|
||||
$deleted = 0;
|
||||
if (isset($filters['deleted'])) {
|
||||
$deleted = $filters['deleted'] == 2 ? array(0, 1) : $filters['deleted'];
|
||||
$deleted = $filters['deleted'] == 2 ? 0 : 1;
|
||||
}
|
||||
$this->set('deleted', $deleted);
|
||||
$this->set('typeGroups', array_keys($this->Event->Attribute->typeGroupings));
|
||||
|
@ -1544,6 +1558,9 @@ class EventsController extends AppController
|
|||
if (isset($this->params['named']['includeRelatedTags']) && $this->params['named']['includeRelatedTags']) {
|
||||
$conditions['includeRelatedTags'] = 1;
|
||||
}
|
||||
if (!empty($this->params['named']['includeDecayScore'])) {
|
||||
$conditions['includeDecayScore'] = 1;
|
||||
}
|
||||
if (isset($this->params['named']['public']) && $this->params['named']['public']) {
|
||||
$conditions['distribution'] = array(3, 5);
|
||||
}
|
||||
|
@ -1619,6 +1636,7 @@ class EventsController extends AppController
|
|||
}
|
||||
$this->set('deleted', isset($this->params['named']['deleted']) ? ($this->params['named']['deleted'] == 2 ? 0 : 1) : 0);
|
||||
$this->set('includeRelatedTags', (!empty($this->params['named']['includeRelatedTags'])) ? 1 : 0);
|
||||
$this->set('includeDecayScore', (!empty($this->params['named']['includeDecayScore'])) ? 1 : 0);
|
||||
if (!$this->_isRest()) {
|
||||
if ($this->_isSiteAdmin() && $results[0]['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
|
||||
$this->Flash->info(__('You are currently logged in as a site administrator and editing an event not belonging to your organisation, which goes against the sharing model of MISP. Please only use this as a last resort and use normal user account for day to day work.'));
|
||||
|
@ -1762,11 +1780,12 @@ class EventsController extends AppController
|
|||
$advancedFilteringActive = array_diff_key($filters, array('sort'=>0, 'direction'=>0, 'focus'=>0, 'extended'=>0, 'overrideLimit'=>0, 'filterColumnsOverwrite'=>0, 'attributeFilter'=>0, 'extended' => 0, 'page' => 0));
|
||||
|
||||
if (count($advancedFilteringActive) > 0) {
|
||||
if (count(array_diff_key($advancedFilteringActive, array('deleted', 'includeRelatedTags'))) > 0) {
|
||||
if (count(array_diff_key($advancedFilteringActive, array('deleted', 'includeRelatedTags', 'includeDecayScore'))) > 0) {
|
||||
$res = true;
|
||||
} else if (
|
||||
(isset($advancedFilteringActive['deleted']) && $advancedFilteringActive['deleted'] == 2)
|
||||
|| (isset($advancedFilteringActive['includeRelatedTags']) && $advancedFilteringActive['includeRelatedTags'] == 2)
|
||||
(isset($advancedFilteringActive['deleted']) && $advancedFilteringActive['deleted'] == 2) ||
|
||||
(isset($advancedFilteringActive['includeRelatedTags']) && $advancedFilteringActive['includeRelatedTags'] == 1) ||
|
||||
(isset($advancedFilteringActive['includeDecayScore']) && $advancedFilteringActive['includeDecayScore'] == 1)
|
||||
) {
|
||||
$res = true;
|
||||
} else {
|
||||
|
|
|
@ -416,7 +416,7 @@ class LogsController extends AppController
|
|||
$this->set('actions', $actions);
|
||||
|
||||
// combobox for models
|
||||
$models = array('Attribute', 'Event', 'EventBlacklist', 'EventTag', 'MispObject', 'Organisation', 'Post', 'Regexp', 'Role', 'Server', 'ShadowAttribute', 'SharingGroup', 'Tag', 'Task', 'Taxonomy', 'Template', 'Thread', 'User', 'Whitelist');
|
||||
$models = array('Attribute', 'Event', 'EventBlacklist', 'EventTag', 'DecayingModel', 'MispObject', 'Organisation', 'Post', 'Regexp', 'Role', 'Server', 'ShadowAttribute', 'SharingGroup', 'Tag', 'Task', 'Taxonomy', 'Template', 'Thread', 'User', 'Whitelist');
|
||||
$models = array('' => 'ALL') + $this->_arrayToValuesIndexArray($models);
|
||||
$this->set('models', $models);
|
||||
$this->set('actionDefinitions', $this->{$this->defaultModel}->actionDefinitions);
|
||||
|
|
|
@ -1620,8 +1620,13 @@ class ServersController extends AppController
|
|||
{
|
||||
if ($this->request->is('post')) {
|
||||
$status = $this->Server->getCurrentGitStatus();
|
||||
$update = $this->Server->update($status);
|
||||
return new CakeResponse(array('body'=> $update, 'type' => 'txt'));
|
||||
$raw = array();
|
||||
$update = $this->Server->update($status, $raw);
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->viewData(array('results' => $raw), $this->response->type());
|
||||
} else {
|
||||
return new CakeResponse(array('body'=> $update, 'type' => 'txt'));
|
||||
}
|
||||
} else {
|
||||
$branch = $this->Server->getCurrentBranch();
|
||||
$this->set('branch', $branch);
|
||||
|
|
|
@ -314,88 +314,18 @@ class SightingsController extends AppController
|
|||
|
||||
public function listSightings($id = false, $context = 'attribute', $org_id = false)
|
||||
{
|
||||
$this->loadModel('Event');
|
||||
$rawId = $id;
|
||||
$parameters = array('id', 'context', 'org_id');
|
||||
foreach ($parameters as $parameter) {
|
||||
if ($this->request->is('post') && isset($this->request->data[$parameter])) {
|
||||
${$parameter} = $this->request->data[$parameter];
|
||||
}
|
||||
}
|
||||
$rawId = $id;
|
||||
$id = is_array($id) ? $id : $this->Sighting->explodeIdList($id);
|
||||
if ($context === 'attribute') {
|
||||
$object = $this->Event->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id, 'Attribute.deleted' => 0), 'flatten' => 1));
|
||||
} else {
|
||||
// let's set the context to event here, since we reuse the variable later on for some additional lookups.
|
||||
// Passing $context = 'org' could have interesting results otherwise...
|
||||
$context = 'event';
|
||||
$object = $this->Event->fetchEvent($this->Auth->user(), $options = array('eventid' => $id, 'metadata' => true));
|
||||
}
|
||||
if (empty($object)) {
|
||||
throw new MethodNotAllowedException('Invalid object.');
|
||||
}
|
||||
$conditions = array(
|
||||
'Sighting.' . $context . '_id' => $id
|
||||
);
|
||||
if ($org_id) {
|
||||
$this->loadModel('Organisation');
|
||||
$org_id = $this->Toolbox->findIdByUuid($this->Organisation, $org_id);
|
||||
$conditions[] = array('Sighting.org_id' => $org_id);
|
||||
}
|
||||
$sightings = $this->Sighting->find('all', array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'contain' => array('Organisation.name'),
|
||||
'order' => array('Sighting.date_sighting DESC')
|
||||
));
|
||||
if (!empty($sightings) && empty(Configure::read('Plugin.Sightings_policy')) && !$this->_isSiteAdmin()) {
|
||||
$eventOwnerOrgIdList = array();
|
||||
foreach ($sightings as $k => $sighting) {
|
||||
if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']])) {
|
||||
$temp_event = $this->Event->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('Event.id' => $sighting['Sighting']['event_id']),
|
||||
'fields' => array('Event.id', 'Event.orgc_id')
|
||||
));
|
||||
$eventOwnerOrgIdList[$temp_event['Event']['id']] = $temp_event['Event']['orgc_id'];
|
||||
}
|
||||
if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']]) || $eventOwnerOrgIdList[$sighting['Sighting']['event_id']] !== $this->Auth->user('org_id')) {
|
||||
unset($sightings[$k]);
|
||||
}
|
||||
}
|
||||
$sightings = array_values($sightings);
|
||||
} else if (!empty($sightings) && Configure::read('Plugin.Sightings_policy') == 1 && !$this->_isSiteAdmin()) {
|
||||
$eventsWithOwnSightings = array();
|
||||
foreach ($sightings as $k => $sighting) {
|
||||
if (empty($eventsWithOwnSightings[$sighting['Sighting']['event_id']])) {
|
||||
$eventsWithOwnSightings[$sighting['Sighting']['event_id']] = false;
|
||||
$sighting_temp = $this->Sighting->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'Sighting.event_id' => $sighting['Sighting']['event_id'],
|
||||
'Sighting.org_id' => $this->Auth->user('org_id')
|
||||
)
|
||||
));
|
||||
if (empty($sighting_temp)) {
|
||||
$temp_event = $this->Event->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'Event.id' => $sighting['Sighting']['event_id'],
|
||||
'Event.orgc_id' => $this->Auth->user('org_id')
|
||||
),
|
||||
'fields' => array('Event.id', 'Event.orgc_id')
|
||||
));
|
||||
$eventsWithOwnSightings[$sighting['Sighting']['event_id']] = !empty($temp_event);
|
||||
} else {
|
||||
$eventsWithOwnSightings[$sighting['Sighting']['event_id']] = true;
|
||||
}
|
||||
}
|
||||
if (!$eventsWithOwnSightings[$sighting['Sighting']['event_id']]) {
|
||||
unset($sightings[$k]);
|
||||
}
|
||||
}
|
||||
$sightings = array_values($sightings);
|
||||
}
|
||||
$sightings = $this->Sighting->listSightings($this->Auth->user(), $id, $context, $org_id);
|
||||
$this->set('org_id', $org_id);
|
||||
$this->set('rawId', $rawId);
|
||||
$this->set('context', $context);
|
||||
|
|
|
@ -75,7 +75,7 @@ class AppModel extends Model
|
|||
13 => false, 14 => false, 15 => false, 18 => false, 19 => false, 20 => false,
|
||||
21 => false, 22 => false, 23 => false, 24 => false, 25 => false, 26 => false,
|
||||
27 => false, 28 => false, 29 => false, 30 => false, 31 => false, 32 => false,
|
||||
33 => false, 34 => false, 35 => false, 36 => false
|
||||
33 => false, 34 => false, 35 => false, 36 => false, 37 => false
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
|
@ -1193,11 +1193,44 @@ class AppModel extends Model
|
|||
KEY `org_id` (`org_id`),
|
||||
KEY `type` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;";
|
||||
break;
|
||||
break;
|
||||
case 36:
|
||||
$sqlArray[] = "ALTER TABLE `event_tags` ADD `local` tinyint(1) NOT NULL DEFAULT 0;";
|
||||
$sqlArray[] = "ALTER TABLE `attribute_tags` ADD `local` tinyint(1) NOT NULL DEFAULT 0;";
|
||||
break;
|
||||
case 37:
|
||||
$sqlArray[] = "CREATE TABLE IF NOT EXISTS decaying_models (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(40) COLLATE utf8_bin DEFAULT NULL,
|
||||
`name` varchar(255) COLLATE utf8_bin NOT NULL,
|
||||
`parameters` text,
|
||||
`attribute_types` text,
|
||||
`description` text,
|
||||
`org_id` int(11),
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`all_orgs` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`ref` text COLLATE utf8_unicode_ci,
|
||||
`formula` varchar(255) COLLATE utf8_bin NOT NULL,
|
||||
`version` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',
|
||||
`default` tinyint(1) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (id),
|
||||
INDEX `uuid` (`uuid`),
|
||||
INDEX `name` (`name`),
|
||||
INDEX `org_id` (`org_id`),
|
||||
INDEX `enabled` (`enabled`),
|
||||
INDEX `all_orgs` (`all_orgs`),
|
||||
INDEX `version` (`version`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
$sqlArray[] = "CREATE TABLE IF NOT EXISTS decaying_model_mappings (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`attribute_type` varchar(255) COLLATE utf8_bin NOT NULL,
|
||||
`model_id` int(11) NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
INDEX `model_id` (`model_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
$sqlArray[] = "ALTER TABLE `roles` ADD `perm_decaying` tinyint(1) NOT NULL DEFAULT 0;";
|
||||
$sqlArray[] = "UPDATE `roles` SET `perm_decaying`=1 WHERE `perm_sighting`=1;";
|
||||
break;
|
||||
case 'fixNonEmptySharingGroupID':
|
||||
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
|
|
|
@ -2976,7 +2976,8 @@ class Attribute extends AppModel
|
|||
$params = array(
|
||||
'conditions' => $this->buildConditions($user),
|
||||
'fields' => array(),
|
||||
'recursive' => -1
|
||||
'recursive' => -1,
|
||||
'contain' => array()
|
||||
);
|
||||
if (isset($options['conditions'])) {
|
||||
$params['conditions']['AND'][] = $options['conditions'];
|
||||
|
@ -2984,10 +2985,14 @@ class Attribute extends AppModel
|
|||
if (isset($options['fields'])) {
|
||||
$params['fields'] = $options['fields'];
|
||||
}
|
||||
if (isset($options['contain'])) {
|
||||
$params['contain'] = $options['contain'];
|
||||
}
|
||||
$results = $this->find('all', array(
|
||||
'conditions' => $params['conditions'],
|
||||
'recursive' => -1,
|
||||
'fields' => $params['fields'],
|
||||
'contain' => $params['contain'],
|
||||
'sort' => false
|
||||
));
|
||||
return $results;
|
||||
|
@ -3136,6 +3141,23 @@ class Attribute extends AppModel
|
|||
if (!isset($options['includeWarninglistHits'])) {
|
||||
$options['includeWarninglistHits'] = false;
|
||||
}
|
||||
if (!isset($options['includeDecayScore'])) {
|
||||
$options['includeDecayScore'] = false;
|
||||
}
|
||||
if (!isset($options['decayingModel'])) {
|
||||
$options['decayingModel'] = false;
|
||||
}
|
||||
if (!isset($options['modelOverrides'])) {
|
||||
$options['modelOverrides'] = array();
|
||||
}
|
||||
if (isset($options['score'])) {
|
||||
$options['modelOverrides']['threshold'] = $options['score'];
|
||||
}
|
||||
if (!isset($options['excludeDecayed'])) {
|
||||
$options['excludeDecayed'] = 0;
|
||||
} else {
|
||||
$options['includeDecayScore'] = true;
|
||||
}
|
||||
if (!$user['Role']['perm_sync'] || !isset($options['deleted']) || !$options['deleted']) {
|
||||
$params['conditions']['AND']['(Attribute.deleted + 0)'] = 0;
|
||||
} else {
|
||||
|
@ -3259,6 +3281,20 @@ class Attribute extends AppModel
|
|||
$results[$key]['Attribute']['data'] = $encodedFile;
|
||||
}
|
||||
}
|
||||
if ($options['includeDecayScore']) {
|
||||
$this->DecayingModel = ClassRegistry::init('DecayingModel');
|
||||
$include_full_model = isset($options['includeFullModel']) && $options['includeFullModel'] ? 1 : 0;
|
||||
$results[$key]['Attribute'] = $this->DecayingModel->attachScoresToAttribute($user, $results[$key]['Attribute'], $options['decayingModel'], $options['modelOverrides'], $include_full_model);
|
||||
if ($options['excludeDecayed']) { // filter out decayed attribute
|
||||
$decayed_flag = true;
|
||||
foreach ($results[$key]['Attribute']['decay_score'] as $decayResult) { // remove attribute if ALL score results in a decay
|
||||
$decayed_flag = $decayed_flag && $decayResult['decayed'];
|
||||
}
|
||||
if ($decayed_flag) {
|
||||
unset($results[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($results[$key])) {
|
||||
if (!empty($options['includeGalaxy'])) {
|
||||
$massaged_attribute = $this->Event->massageTags($results[$key], 'Attribute');
|
||||
|
@ -4231,7 +4267,9 @@ class Attribute extends AppModel
|
|||
'includeWarninglistHits' => !empty($filters['includeWarninglistHits']) ? $filters['includeWarninglistHits'] : 0,
|
||||
'includeContext' => !empty($filters['includeContext']) ? $filters['includeContext'] : 0,
|
||||
'includeSightings' => !empty($filters['includeSightings']) ? $filters['includeSightings'] : 0,
|
||||
'includeCorrelations' => !empty($filters['includeCorrelations']) ? $filters['includeCorrelations'] : 0
|
||||
'includeCorrelations' => !empty($filters['includeCorrelations']) ? $filters['includeCorrelations'] : 0,
|
||||
'includeDecayScore' => !empty($filters['includeDecayScore']) ? $filters['includeDecayScore'] : 0,
|
||||
'includeFullModel' => !empty($filters['includeFullModel']) ? $filters['includeFullModel'] : 0
|
||||
);
|
||||
if (!empty($filters['attackGalaxy'])) {
|
||||
$params['attackGalaxy'] = $filters['attackGalaxy'];
|
||||
|
@ -4248,6 +4286,19 @@ class Attribute extends AppModel
|
|||
if (!empty($filters['deleted'])) {
|
||||
$params['deleted'] = $filters['deleted'];
|
||||
}
|
||||
if (!empty($filters['excludeDecayed'])) {
|
||||
$params['excludeDecayed'] = $filters['excludeDecayed'];
|
||||
$params['includeDecayScore'] = 1;
|
||||
}
|
||||
if (!empty($filters['decayingModel'])) {
|
||||
$params['decayingModel'] = $filters['decayingModel'];
|
||||
}
|
||||
if (!empty($filters['modelOverrides'])) {
|
||||
$params['modelOverrides'] = $filters['modelOverrides'];
|
||||
}
|
||||
if (!empty($filters['score'])) {
|
||||
$params['score'] = $filters['score'];
|
||||
}
|
||||
if ($paramsOnly) {
|
||||
return $params;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,609 @@
|
|||
<?php
|
||||
|
||||
App::uses('AppModel', 'Model');
|
||||
App::uses('Folder', 'Utility');
|
||||
App::uses('File', 'Utility');
|
||||
|
||||
class DecayingModel extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
|
||||
public $hasMany = array(
|
||||
'DecayingModelMapping' => array(
|
||||
'className' => 'DecayingModelMapping',
|
||||
'foreignKey' => 'model_id',
|
||||
'dependent' => true
|
||||
)
|
||||
);
|
||||
|
||||
private $__registered_model_classes = array(); // Proxy for already instantiated classes
|
||||
public $allowed_overrides = array('threshold' => 1, 'lifetime' => 1, 'decay_speed' => 1);
|
||||
|
||||
public function afterFind($results, $primary = false) {
|
||||
foreach ($results as $k => $v) {
|
||||
if (!empty($v['DecayingModel']['parameters'])) {
|
||||
$decoded = json_decode($v['DecayingModel']['parameters'], true);
|
||||
if ($decoded === null) {
|
||||
$decoded = array();
|
||||
}
|
||||
$results[$k]['DecayingModel']['parameters'] = $decoded;
|
||||
}
|
||||
if (!empty($v['DecayingModel']['attribute_types'])) {
|
||||
$decoded = json_decode($v['DecayingModel']['attribute_types'], true);
|
||||
if ($decoded === null) {
|
||||
$decoded = array();
|
||||
}
|
||||
$results[$k]['DecayingModel']['attribute_types'] = $decoded;
|
||||
} else {
|
||||
$results[$k]['DecayingModel']['attribute_types'] = array();
|
||||
}
|
||||
if (!empty($v['DecayingModel']['ref'])) {
|
||||
$decoded = json_decode($v['DecayingModel']['ref'], true);
|
||||
if ($decoded === null) {
|
||||
$decoded = array();
|
||||
}
|
||||
$results[$k]['DecayingModel']['ref'] = $decoded;
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function beforeValidate($options = array()) {
|
||||
parent::beforeValidate();
|
||||
|
||||
if (!isset($this->data['DecayingModel']['formula'])) { // default to polynomial
|
||||
$this->data['DecayingModel']['formula'] = 'polynomial';
|
||||
}
|
||||
|
||||
if ($this->data['DecayingModel']['formula'] == 'polynomial') {
|
||||
if (isset($this->data['DecayingModel']['parameters']['settings'])) { // polynomial doesn't have custom settings
|
||||
$this->data['DecayingModel']['parameters']['settings'] = '{}';
|
||||
}
|
||||
} else if (
|
||||
isset($this->data['DecayingModel']['parameters']['settings']) &&
|
||||
$this->data['DecayingModel']['parameters']['settings'] == ''
|
||||
) {
|
||||
$this->data['DecayingModel']['parameters']['settings'] = '{}';
|
||||
}
|
||||
|
||||
if (!empty($this->data['DecayingModel']['attribute_types']) && !is_array($this->data['DecayingModel']['attribute_types'])) {
|
||||
$encoded = json_decode($this->data['DecayingModel']['attribute_types'], true);
|
||||
if ($encoded === null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
isset($this->data['DecayingModel']['parameters']) &&
|
||||
!empty($this->data['DecayingModel']['parameters']) &&
|
||||
!is_array($this->data['DecayingModel']['parameters'])
|
||||
) {
|
||||
$encoded = json_decode($this->data['DecayingModel']['parameters'], true);
|
||||
if ($encoded === null) {
|
||||
return false;
|
||||
}
|
||||
$encoded = $this->__adjustParameters($encoded);
|
||||
$this->data['DecayingModel']['parameters'] = json_encode($encoded);
|
||||
return true;
|
||||
} else {
|
||||
$this->data['DecayingModel']['parameters'] = $this->__adjustParameters($this->data['DecayingModel']['parameters']);
|
||||
return $this->data['DecayingModel']['parameters'];
|
||||
}
|
||||
}
|
||||
|
||||
public function beforeSave($options = array()) {
|
||||
if (isset($this->data['DecayingModel']['parameters']) && is_array($this->data['DecayingModel']['parameters'])) {
|
||||
$this->data['DecayingModel']['parameters'] = json_encode($this->data['DecayingModel']['parameters']);
|
||||
}
|
||||
if (isset($this->data['DecayingModel']['parameters']['base_score_config']) && is_array($this->data['DecayingModel']['parameters']['base_score_config'])) {
|
||||
$this->data['DecayingModel']['parameters']['base_score_config'] = json_encode($this->data['DecayingModel']['parameters']['base_score_config']);
|
||||
}
|
||||
if (isset($this->data['DecayingModel']['parameters']['settings']) && is_array($this->data['DecayingModel']['parameters']['settings'])) {
|
||||
$this->data['DecayingModel']['parameters']['settings'] = json_encode($this->data['DecayingModel']['parameters']['settings']);
|
||||
}
|
||||
if (isset($this->data['DecayingModel']['attribute_types']) && is_array($this->data['DecayingModel']['attribute_types'])) {
|
||||
$this->data['DecayingModel']['attribute_types'] = json_encode($this->data['DecayingModel']['attribute_types']);
|
||||
}
|
||||
if (isset($this->data['DecayingModel']['ref']) && is_array($this->data['DecayingModel']['ref'])) {
|
||||
$this->data['DecayingModel']['ref'] = json_encode($this->data['DecayingModel']['ref']);
|
||||
}
|
||||
if (!isset($this->data['DecayingModel']['org_id'])) {
|
||||
$this->data['DecayingModel']['org_id'] = Configure::read('MISP.host_org_id');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* May be improved at some point.
|
||||
* For now, limit the number of digits for the parameters
|
||||
*/
|
||||
private function __adjustParameters($parameters)
|
||||
{
|
||||
foreach ($parameters as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
$this->__adjustParameters($parameters[$name]);
|
||||
} else if (is_numeric($value)) {
|
||||
$parameters[$name] = round($value, 4);
|
||||
} else if (!empty($value)) {
|
||||
$parameters[$name] = $value;
|
||||
} else {
|
||||
$parameters[$name] = 0;
|
||||
}
|
||||
}
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
private function __load_models($force = false)
|
||||
{
|
||||
$dir = new Folder(APP . 'files' . DS . 'misp-decaying-models' . DS . 'models');
|
||||
$files = $dir->find('.*\.json');
|
||||
$models = array();
|
||||
foreach ($files as $file) {
|
||||
$file = new File($dir->pwd() . DS . $file);
|
||||
$models[] = json_decode($file->read(), true);
|
||||
$file->close();
|
||||
}
|
||||
return $models;
|
||||
}
|
||||
|
||||
public function update($force=false, $user)
|
||||
{
|
||||
$new_models = $this->__load_models($force);
|
||||
if (empty($new_models)) {
|
||||
throw new NotFoundException(__('Models could not be loaded or default decaying models folder is empty'));
|
||||
}
|
||||
$temp = $this->find('all', array(
|
||||
'recursive' => -1
|
||||
));
|
||||
$existing_models = array();
|
||||
foreach ($temp as $k => $model) { // create UUID proxy
|
||||
$existing_models[$model['DecayingModel']['uuid']] = $model['DecayingModel'];
|
||||
}
|
||||
foreach ($new_models as $k => $new_model) {
|
||||
if (isset($existing_models[$new_model['uuid']])) {
|
||||
$existing_model = $existing_models[$new_model['uuid']];
|
||||
if ($force || $new_model['version'] > $existing_model['version']) {
|
||||
$new_model['id'] = $existing_model['id'];
|
||||
$this->save($new_model);
|
||||
}
|
||||
} else {
|
||||
$this->create();
|
||||
$new_model['default'] = true;
|
||||
$this->save($new_model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isEditableByCurrentUser($user, $decaying_model)
|
||||
{
|
||||
return (
|
||||
$user['Role']['perm_site_admin'] ||
|
||||
(
|
||||
$user['Role']['perm_decaying'] &&
|
||||
!$decaying_model['DecayingModel']['default'] &&
|
||||
$decaying_model['DecayingModel']['org_id'] == $user['org_id']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function attachIsEditableByCurrentUser($user, $decaying_model)
|
||||
{
|
||||
$decaying_model['DecayingModel']['isEditable'] = $this->isEditableByCurrentUser($user, $decaying_model);
|
||||
return $decaying_model;
|
||||
}
|
||||
|
||||
public function fetchAllDefaultModel($user)
|
||||
{
|
||||
$default_models = $this->fetchAllAllowedModels($user, false, array(), array('DecayingModel.default' => true));
|
||||
return $default_models;
|
||||
}
|
||||
|
||||
public function fetchAllAllowedModels($user, $full=true, $filters=array(), $additionnal_conditions=array())
|
||||
{
|
||||
$conditions = array();
|
||||
if (!$user['Role']['perm_site_admin']) {
|
||||
$conditions['OR'] = array(
|
||||
'org_id' => $user['Organisation']['id'],
|
||||
'all_orgs' => 1
|
||||
);
|
||||
}
|
||||
if (!empty($filters)) {
|
||||
if (isset($filters['my_models']) && $filters['my_models']) {
|
||||
$conditions[] = array('DecayingModel.org_id' => $user['Organisation']['id']);
|
||||
} elseif (isset($filters['default_models']) && $filters['default_models']) {
|
||||
$conditions[] = array('not' => array('DecayingModel.uuid' => null));
|
||||
}
|
||||
}
|
||||
$conditions[] = array('AND' => $additionnal_conditions);
|
||||
$decayingModels = $this->find('all', array(
|
||||
'conditions' => $conditions,
|
||||
'include' => $full ? 'DecayingModelMapping' :''
|
||||
));
|
||||
foreach ($decayingModels as $i => $decayingModel) { // includes both model default mapping and user mappings
|
||||
if ($full) {
|
||||
$decayingModels[$i]['DecayingModel']['attribute_types'] = $decayingModels[$i]['DecayingModel']['attribute_types'] + Hash::extract($decayingModels[$i]['DecayingModelMapping'], '{n}.attribute_type');
|
||||
unset($decayingModels[$i]['DecayingModelMapping']);
|
||||
$decayingModels[$i]['DecayingModel']['attribute_types'] = array_unique($decayingModels[$i]['DecayingModel']['attribute_types']);
|
||||
}
|
||||
$decayingModels[$i]['DecayingModel']['isEditable'] = $this->isEditableByCurrentUser($user, $decayingModels[$i]);
|
||||
}
|
||||
|
||||
return $decayingModels;
|
||||
}
|
||||
|
||||
public function fetchModels($user, $ids, $full=true, $conditions=array(), $attach_editable=0)
|
||||
{
|
||||
if (is_numeric($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$models = array();
|
||||
foreach ($ids as $id) {
|
||||
$model = $this->fetchModel($user, $id, $full, $conditions, $attach_editable);
|
||||
if (!empty($model)) {
|
||||
$models[] = $model;
|
||||
}
|
||||
}
|
||||
return $models;
|
||||
}
|
||||
|
||||
// Method that fetches decayingModel
|
||||
// very flexible, it's basically a replacement for find, with the addition that it restricts access based on user
|
||||
// - full attach Attribute types associated to the requested model
|
||||
public function fetchModel($user, $id, $full=true, $conditions=array(), $attach_editable=0)
|
||||
{
|
||||
$conditions['id'] = $id;
|
||||
$searchOptions = array(
|
||||
'conditions' => $conditions,
|
||||
);
|
||||
if (!$full) {
|
||||
$searchOptions['recursive'] = -1;
|
||||
}
|
||||
$decayingModel = $this->find('first', $searchOptions);
|
||||
|
||||
// if not found throw
|
||||
if (empty($decayingModel)) {
|
||||
return array();
|
||||
}
|
||||
if (
|
||||
!$user['Role']['perm_site_admin'] &&
|
||||
!( // check owner and visibility
|
||||
$user['Organisation']['id'] == $decayingModel['DecayingModel']['org_id'] ||
|
||||
$decayingModel['DecayingModel']['all_orgs']
|
||||
)
|
||||
) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ($full) {
|
||||
$decayingModel['DecayingModel']['attribute_types'] = $this->DecayingModelMapping->getAssociatedTypes($user, $decayingModel);
|
||||
}
|
||||
$decayingModel = $this->attachIsEditableByCurrentUser($user, $decayingModel);
|
||||
return $decayingModel;
|
||||
}
|
||||
|
||||
// filter out taxonomies and entries not having a numerical value
|
||||
public function listTaxonomiesWithNumericalValue()
|
||||
{
|
||||
$this->Taxonomy = ClassRegistry::init('Taxonomy');
|
||||
$this->Tag = ClassRegistry::init('Tag');
|
||||
$taxonomies = $this->Taxonomy->listTaxonomies(array('full' => true, 'enabled' => true));
|
||||
$excluded_taxonomies = array();
|
||||
$start_count = count($taxonomies);
|
||||
foreach ($taxonomies as $namespace => $taxonomy) {
|
||||
if(!empty($taxonomy['TaxonomyPredicate'])) {
|
||||
$tags = $this->Tag->getTagsForNamespace($taxonomy['namespace'], false);
|
||||
foreach($taxonomy['TaxonomyPredicate'] as $p => $predicate) {
|
||||
if(!empty($predicate['TaxonomyEntry'])) {
|
||||
foreach ($predicate['TaxonomyEntry'] as $e => $entry) {
|
||||
if (!is_numeric($entry['numerical_value'])) {
|
||||
unset($taxonomies[$namespace]['TaxonomyPredicate'][$p]['TaxonomyEntry'][$e]);
|
||||
} else {
|
||||
$tag_name = sprintf('%s:%s="%s"', $taxonomy['namespace'], $predicate['value'], $entry['value']);
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'][$p]['TaxonomyEntry'][$e]['Tag'] = $tags[strtoupper($tag_name)]['Tag'];
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'][$p]['TaxonomyEntry'][$e]['Tag']['numerical_value'] = $entry['numerical_value'];
|
||||
}
|
||||
}
|
||||
if (empty($taxonomies[$namespace]['TaxonomyPredicate'][$p]['TaxonomyEntry'])) {
|
||||
unset($taxonomies[$namespace]['TaxonomyPredicate'][$p]);
|
||||
} else {
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'][$p]['TaxonomyEntry'] = array_values($taxonomies[$namespace]['TaxonomyPredicate'][$p]['TaxonomyEntry']);
|
||||
}
|
||||
} else { // accept predicates that have a numerical value
|
||||
if (!is_numeric($predicate['numerical_value'])) {
|
||||
unset($taxonomies[$namespace]['TaxonomyPredicate'][$p]);
|
||||
} else {
|
||||
$tag_name = sprintf('%s:%s', $taxonomy['namespace'], $predicate['value']);
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'][$p]['Tag'] = $tags[strtoupper($tag_name)]['Tag'];
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'][$p]['Tag']['numerical_value'] = $predicate['numerical_value'];
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'][$p]['numerical_predicate'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (empty($taxonomies[$namespace]['TaxonomyPredicate'])) {
|
||||
$excluded_taxonomies[$namespace] = array('taxonomy' => $taxonomies[$namespace], 'reason' => __('No tags nor predicates with `numerical_value`'));
|
||||
unset($taxonomies[$namespace]);
|
||||
} else {
|
||||
$taxonomies[$namespace]['TaxonomyPredicate'] = array_values($taxonomies[$namespace]['TaxonomyPredicate']);
|
||||
}
|
||||
} else {
|
||||
unset($taxonomies[$namespace]);
|
||||
$excluded_taxonomies[$namespace] = array('taxonomy' => $taxonomies[$namespace], 'reason' => __('No predicate'));
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'taxonomies' => $taxonomies,
|
||||
'excluded_taxonomies' => $excluded_taxonomies,
|
||||
'not_having_numerical_value' => $start_count - count($taxonomies)
|
||||
);
|
||||
}
|
||||
|
||||
// Include a PHP file and return an instanciation of the formula class
|
||||
private function __include_formula_file_and_return_instance($filename='Polynomial.php')
|
||||
{
|
||||
$formula_files = $this->__listPHPFormulaFiles(); // redundant in some cases but better be safe than sorry
|
||||
$index = array_search($filename, $formula_files);
|
||||
if ($index !== false) {
|
||||
$filename_no_extension = str_replace('.php', '', $formula_files[$index]);
|
||||
$expected_classname = $filename_no_extension;
|
||||
$full_path = APP . 'Model/DecayingModelsFormulas/' . $formula_files[$index];
|
||||
if (is_file($full_path)) {
|
||||
include_once $full_path;
|
||||
try {
|
||||
$model_class = ClassRegistry::init($expected_classname);
|
||||
if ($model_class->checkLoading() === 'BONFIRE LIT') {
|
||||
return $model_class;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->Log->create();
|
||||
$this->Log->save(array(
|
||||
'org' => 'SYSTEM',
|
||||
'model' => 'DecayingModel',
|
||||
'model_id' => 0,
|
||||
'email' => 'SYSTEM',
|
||||
'action' => 'include_formula',
|
||||
'title' => sprintf('Error while trying to include file `%s`: %s', $filename, $e->getMessage()),
|
||||
'change' => ''
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function __listPHPFormulaFiles()
|
||||
{
|
||||
$dir = new Folder(APP . 'Model/DecayingModelsFormulas');
|
||||
$files = $dir->find('.*\.php', true);
|
||||
$files = array_diff($files, array('..', '.', 'Base.php'));
|
||||
return $files;
|
||||
}
|
||||
|
||||
public function listAvailableFormulas()
|
||||
{
|
||||
$formula_files = $this->__listPHPFormulaFiles();
|
||||
$available_formulas = array();
|
||||
foreach ($formula_files as $formula_file) {
|
||||
$model_class = $this->__include_formula_file_and_return_instance($formula_file);
|
||||
if ($model_class === false) {
|
||||
continue;
|
||||
}
|
||||
$available_formulas[get_class($model_class)] = array(
|
||||
'parent_class' => get_parent_class($model_class) == 'Polynomial' || get_class($model_class) == 'Polynomial' ? 'Polynomial' : get_class($model_class),
|
||||
'description' => $model_class->description
|
||||
);
|
||||
}
|
||||
return $available_formulas;
|
||||
}
|
||||
|
||||
// Get a instance of the class associated to a model
|
||||
public function getModelClass($model)
|
||||
{
|
||||
$formula_name = $model['DecayingModel']['formula'] === '' ? 'polynomial' : $model['DecayingModel']['formula'];
|
||||
$expected_filename = Inflector::humanize($formula_name) . '.php';
|
||||
if (!isset($this->__registered_model_classes[$formula_name])) {
|
||||
$model_class = $this->__include_formula_file_and_return_instance($expected_filename);
|
||||
if ($model_class === false) {
|
||||
throw new NotFoundException(sprintf(__('The class for `%s` was not found or not loaded correctly'), $formula_name));
|
||||
}
|
||||
$this->__registered_model_classes[$formula_name] = $model_class;
|
||||
}
|
||||
return $this->__registered_model_classes[$formula_name];
|
||||
}
|
||||
|
||||
// returns timestamp set to the rounded hour
|
||||
public function round_timestamp_to_hour($time, $floor=1)
|
||||
{
|
||||
if ($floor) {
|
||||
return floor((float) $time / 3600) * 3600;
|
||||
} else {
|
||||
return round((float) $time / 3600) * 3600;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns score overtime, sightings, base_score computation and other useful information
|
||||
public function getScoreOvertime($user, $model_id, $attribute_id, $model_overrides)
|
||||
{
|
||||
$this->Attribute = ClassRegistry::init('Attribute');
|
||||
$attribute = $this->Attribute->fetchAttributes($user, array(
|
||||
'conditions' => array('Attribute.id' => $attribute_id),
|
||||
'contain' => array('AttributeTag' => array('Tag')),
|
||||
'flatten' => 1
|
||||
));
|
||||
if (empty($attribute)) {
|
||||
throw new NotFoundException(__('Attribute not found'));
|
||||
} else {
|
||||
$attribute = $attribute[0];
|
||||
$tagConditions = array('EventTag.event_id' => $attribute['Attribute']['event_id']);
|
||||
$temp = $this->Attribute->Event->EventTag->find('all', array(
|
||||
'recursive' => -1,
|
||||
'contain' => array('Tag'),
|
||||
'conditions' => $tagConditions
|
||||
));
|
||||
foreach ($temp as $tag) {
|
||||
$tag['EventTag']['Tag'] = $tag['Tag'];
|
||||
unset($tag['Tag']);
|
||||
$attribute['Attribute']['EventTag'][] = $tag['EventTag'];
|
||||
}
|
||||
$attribute['Attribute']['AttributeTag'] = $attribute['AttributeTag'];
|
||||
unset($attribute['AttributeTag']);
|
||||
}
|
||||
$model = $this->fetchModel($user, $model_id, true);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
if (!empty($model_overrides)) {
|
||||
$model = $this->overrideModelParameters($model, $model_overrides);
|
||||
}
|
||||
$this->Computation = $this->getModelClass($model);
|
||||
$this->Sighting = ClassRegistry::init('Sighting');
|
||||
$sightings = $this->Sighting->listSightings($user, $attribute_id, 'attribute', false, 0, false);
|
||||
if (empty($sightings)) {
|
||||
$sightings = array(array('Sighting' => array('date_sighting' => $attribute['Attribute']['timestamp']))); // simulate a Sighting nonetheless
|
||||
}
|
||||
foreach ($sightings as $i => $sighting) {
|
||||
$sightings[$i]['Sighting']['rounded_timestamp'] = $this->round_timestamp_to_hour($sighting['Sighting']['date_sighting']);
|
||||
}
|
||||
// get start time
|
||||
$start_time = $attribute['Attribute']['timestamp'];
|
||||
$start_time = $sightings[0]['Sighting']['date_sighting'] < $start_time ? $sightings[0]['Sighting']['date_sighting'] : $start_time;
|
||||
$start_time = intval($start_time);
|
||||
$start_time = $this->round_timestamp_to_hour($start_time);
|
||||
// get end time
|
||||
$last_sighting_timestamp = $sightings[count($sightings)-1]['Sighting']['date_sighting'];
|
||||
if ($attribute['Attribute']['timestamp'] > $last_sighting_timestamp) { // The attribute was modified after the last sighting, simulate a Sighting
|
||||
$sightings[count($sightings)] = array(
|
||||
'Sighting' => array(
|
||||
'date_sighting' => $attribute['Attribute']['timestamp'],
|
||||
'type' => 0,
|
||||
'rounded_timestamp' => $this->round_timestamp_to_hour($attribute['Attribute']['timestamp'])
|
||||
)
|
||||
);
|
||||
$last_sighting_timestamp = $attribute['Attribute']['timestamp'];
|
||||
}
|
||||
$end_time = $last_sighting_timestamp + $model['DecayingModel']['parameters']['lifetime']*24*60*60;
|
||||
$end_time = $this->round_timestamp_to_hour($end_time);
|
||||
$base_score_config = $this->Computation->computeBasescore($model, $attribute['Attribute']);
|
||||
$base_score = $base_score_config['base_score'];
|
||||
|
||||
// generate time range from oldest timestamp to last decay, resolution is hours
|
||||
$score_overtime = array();
|
||||
$rounded_sightings = array();
|
||||
$sighting_index = 0;
|
||||
for ($t=$start_time; $t < $end_time; $t+=3600) {
|
||||
// fetch closest sighting to the current time
|
||||
$sighting_index = $this->getClosestSighting($sightings, $t, $sighting_index);
|
||||
$last_sighting = $sightings[$sighting_index]['Sighting']['rounded_timestamp'];
|
||||
$elapsed_time = $t - $last_sighting;
|
||||
$score_overtime[$t] = $this->Computation->computeScore($model, $attribute['Attribute'], $base_score, $elapsed_time);
|
||||
}
|
||||
$csv = 'date,value' . PHP_EOL;
|
||||
foreach ($score_overtime as $t => $v) {
|
||||
$csv .= (new DateTime())->setTimestamp($t)->format('Y-m-d H:i:s') . ',' . $v . PHP_EOL;
|
||||
}
|
||||
return array(
|
||||
'csv' => $csv,
|
||||
'sightings' => $sightings,
|
||||
'base_score_config' => $base_score_config,
|
||||
'last_sighting' => $sightings[count($sightings)-1],
|
||||
'current_score' => $this->Computation->computeCurrentScore($user, $model, $attribute['Attribute'], $base_score, $last_sighting_timestamp),
|
||||
'Model' => $model['DecayingModel']
|
||||
);
|
||||
}
|
||||
|
||||
// Get closest the Sighting for a given time
|
||||
public function getClosestSighting($sightings, $time, $offset)
|
||||
{
|
||||
if (count($sightings) <= $offset+1) {
|
||||
return $offset;
|
||||
}
|
||||
$max_time = $time + 3600;
|
||||
$next_index = $offset+1;
|
||||
$next_sighting = $sightings[$next_index]['Sighting']['date_sighting'];
|
||||
while ($next_sighting <= $max_time) {
|
||||
$next_index++;
|
||||
if ($next_index >= count($sightings)) {
|
||||
break;
|
||||
}
|
||||
$next_sighting = $sightings[$next_index]['Sighting']['date_sighting'];
|
||||
}
|
||||
return $next_index-1;
|
||||
}
|
||||
|
||||
public function overrideModelParameters($model, $model_overrides)
|
||||
{
|
||||
foreach ($model_overrides as $parameter => $value) {
|
||||
if (isset($this->allowed_overrides[$parameter])) {
|
||||
$model['DecayingModel']['parameters'][$parameter] = $value;
|
||||
}
|
||||
}
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function attachScoresToAttribute($user, $attribute, $model_id=false, $model_overrides=array(), $include_full_model=0)
|
||||
{
|
||||
$models = array();
|
||||
if ($model_id === false) { // fetch all allowed and associated models
|
||||
$associated_model_ids = $this->DecayingModelMapping->getAssociatedModels($user, $attribute['type'], true);
|
||||
$associated_model_ids = isset($associated_model_ids[$attribute['type']]) ? array_values($associated_model_ids[$attribute['type']]) : array();
|
||||
if (!empty($associated_model_ids)) {
|
||||
$models = $this->fetchModels($user, $associated_model_ids, false, array('enabled' => true));
|
||||
}
|
||||
} else {
|
||||
$models = $this->fetchModels($user, $model_id, false, array());
|
||||
}
|
||||
foreach ($models as $model) {
|
||||
if (!empty($model_overrides)) {
|
||||
$model = $this->overrideModelParameters($model, $model_overrides);
|
||||
}
|
||||
$score = $this->getScore($attribute, $model, $user);
|
||||
$decayed = $this->isDecayed($attribute, $model, $score);
|
||||
$to_attach = array(
|
||||
'score' => $score,
|
||||
'decayed' => $decayed,
|
||||
'DecayingModel' => array(
|
||||
'id' => $model['DecayingModel']['id'],
|
||||
'name' => $model['DecayingModel']['name']
|
||||
)
|
||||
);
|
||||
if ($include_full_model) {
|
||||
$to_attach['DecayingModel'] = $model['DecayingModel'];
|
||||
}
|
||||
$attribute['decay_score'][] = $to_attach;
|
||||
}
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
public function getScore($attribute, $model, $user=false)
|
||||
{
|
||||
if (is_numeric($attribute) && $user !== false) {
|
||||
$this->Attribute = ClassRegistry::init('Attribute');
|
||||
$attribute = $this->Attribute->fetchAttributes($user, array(
|
||||
'conditions' => array('Attribute.id' => $attribute),
|
||||
'contain' => array('AttributeTag' => array('Tag'))
|
||||
));
|
||||
}
|
||||
if (is_numeric($model) && $user !== false) {
|
||||
$model = $this->fetchModel($user, $model);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
}
|
||||
$this->Computation = $this->getModelClass($model);
|
||||
return $this->Computation->computeCurrentScore($user, $model, $attribute);
|
||||
}
|
||||
|
||||
public function isDecayed($attribute, $model, $score=false, $user=false)
|
||||
{
|
||||
if ($score === false) {
|
||||
$score = $this->getScore($attribute, $model, $user);
|
||||
}
|
||||
$this->Computation = $this->getModelClass($model);
|
||||
return $this->Computation->isDecayed($model, $attribute, $score);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
class DecayingModelMapping extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
|
||||
public $validate = array(
|
||||
'attribute_type' => array(
|
||||
'valueNotEmpty' => array(
|
||||
'rule' => array('valueNotEmpty'),
|
||||
),
|
||||
),
|
||||
'model_id' => array(
|
||||
'valueNotEmpty' => array(
|
||||
'rule' => array('valueNotEmpty'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'DecayingModel' => array(
|
||||
'className' => 'DecayingModel',
|
||||
'foreignKey' => 'id'
|
||||
)
|
||||
);
|
||||
|
||||
public function resetMappingForModel($new_model, $user) {
|
||||
if (empty($new_model['model_id'])) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
$this->deleteAll(array(
|
||||
'model_id' => $new_model['model_id']
|
||||
));
|
||||
|
||||
$data = array();
|
||||
foreach ($new_model['attribute_types'] as $type) {
|
||||
$to_save = array(
|
||||
'attribute_type' => $type,
|
||||
'model_id' => $new_model['model_id']
|
||||
);
|
||||
$data[] = $to_save;
|
||||
}
|
||||
|
||||
$result = $this->saveMany($data, array(
|
||||
'atomic' => true
|
||||
));
|
||||
if ($result) {
|
||||
return $new_model['attribute_types'];
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
public function getAssociatedTypes($user, $model) {
|
||||
if (is_numeric($model)) {
|
||||
$model = $this->DecayingModel->fetchModel($user, $model, false);
|
||||
if (empty($model)) {
|
||||
throw new NotFoundException(__('No Decaying Model with the provided ID exists'));
|
||||
}
|
||||
}
|
||||
$decaying_model = isset($model['DecayingModel']) ? $model['DecayingModel'] : $model;
|
||||
if ($decaying_model['default']) {
|
||||
$associated_types = $decaying_model['attribute_types'];
|
||||
} else {
|
||||
$temp = $this->find('list', array(
|
||||
'conditions' => array(
|
||||
'model_id' => $decaying_model['id']
|
||||
),
|
||||
'recursive' => -1,
|
||||
'fields' => array('attribute_type')
|
||||
));
|
||||
$associated_types = array_values($temp);
|
||||
}
|
||||
return $associated_types;
|
||||
}
|
||||
|
||||
public function getAssociatedModels($user, $attribute_type = false) {
|
||||
$conditions = array(
|
||||
'OR' => array(
|
||||
'DecayingModel.org_id' => $user['org_id'],
|
||||
'DecayingModel.all_orgs' => true
|
||||
)
|
||||
);
|
||||
if ($attribute_type !== false) {
|
||||
$conditions['attribute_type'] = $attribute_type;
|
||||
}
|
||||
$associated_models = $this->find('all', array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'fields' => array('attribute_type', 'model_id'),
|
||||
'joins' => array( // joins has to be done to enforce ACL
|
||||
array(
|
||||
'table' => 'decaying_models',
|
||||
'alias' => 'DecayingModel',
|
||||
'type' => 'INNER',
|
||||
'conditions' => array(
|
||||
'DecayingModel.id = DecayingModelMapping.model_id'
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
// Also add default models to selection
|
||||
$default_models = $this->DecayingModel->fetchAllDefaultModel($user);
|
||||
$associated_default_models = array();
|
||||
foreach ($default_models as $i => $model) {
|
||||
$intersection = array_intersect($model['DecayingModel']['attribute_types'], array($attribute_type));
|
||||
if (count($intersection) > 0) {
|
||||
$associated_default_models[$attribute_type][] = $model['DecayingModel']['id'];
|
||||
}
|
||||
}
|
||||
$associated_models = Hash::combine($associated_models, '{n}.DecayingModelMapping.model_id', '{n}.DecayingModelMapping.model_id', '{n}.DecayingModelMapping.attribute_type');
|
||||
$models = array_merge_recursive($associated_default_models, $associated_models);
|
||||
return $models;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
abstract class DecayingModelBase
|
||||
{
|
||||
public function checkLoading()
|
||||
{
|
||||
return 'BONFIRE LIT';
|
||||
}
|
||||
|
||||
// Get effective taxonomy ratio based on taxonomies attached to the attribute
|
||||
// Basically, it adapts the ratio defined in the model to fit the actual attached tags
|
||||
protected function __getRatioScore($model, $tags)
|
||||
{
|
||||
$ratioScore = array();
|
||||
$taxonomy_base_ratio = $model['DecayingModel']['parameters']['base_score_config'];
|
||||
if (empty($taxonomy_base_ratio)) {
|
||||
return array();
|
||||
}
|
||||
$total_score = 0.0;
|
||||
foreach ($tags as $tag) {
|
||||
$namespace_predicate = explode('=', $tag['Tag']['name'])[0];
|
||||
if (isset($taxonomy_base_ratio[$namespace_predicate]) && is_numeric($tag['Tag']['numerical_value'])) {
|
||||
$total_score += floatval($taxonomy_base_ratio[$namespace_predicate]);
|
||||
}
|
||||
}
|
||||
foreach ($tags as $i => $tag) {
|
||||
$namespace_predicate = explode('=', $tag['Tag']['name'])[0];
|
||||
if (isset($taxonomy_base_ratio[$namespace_predicate]) && is_numeric($tag['Tag']['numerical_value'])) {
|
||||
$ratioScore[$namespace_predicate] = floatval($taxonomy_base_ratio[$namespace_predicate]) / $total_score;
|
||||
}
|
||||
}
|
||||
return $ratioScore;
|
||||
}
|
||||
|
||||
// return attribute tag with event tag matching the namespace+predicate overridden
|
||||
protected function __getPrioritisedTag($attribute)
|
||||
{
|
||||
$tags = array();
|
||||
$overridden_tags = array();
|
||||
$temp_mapping = array();
|
||||
if (isset($attribute['EventTag'])) {
|
||||
foreach ($attribute['EventTag'] as $i => $tag) {
|
||||
$tags[] = $tag;
|
||||
$namespace_predicate = explode('=', $tag['Tag']['name'])[0];
|
||||
$temp_mapping[$namespace_predicate][] = $i;
|
||||
}
|
||||
}
|
||||
if (isset($attribute['AttributeTag'])) {
|
||||
foreach ($attribute['AttributeTag'] as $tag) {
|
||||
$namespace_predicate = explode('=', $tag['Tag']['name'])[0];
|
||||
if (!empty($temp_mapping[$namespace_predicate])) { // need to override event tag
|
||||
foreach ($temp_mapping[$namespace_predicate] as $i => $eventtag_index) {
|
||||
$overridden_tags[] = array(
|
||||
'EventTag' => $tags[$eventtag_index],
|
||||
'AttributeTag' => $tag
|
||||
);
|
||||
if ($i === 0) { // override first one
|
||||
$tags[$eventtag_index] = $tag;
|
||||
} else { // remove remaining overriden
|
||||
unset($tags[$eventtag_index]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array('tags' => array_values($tags), 'overridden' => $overridden_tags);
|
||||
}
|
||||
|
||||
public function computeBasescore($model, $attribute)
|
||||
{
|
||||
$temp = $this->__getPrioritisedTag($attribute);
|
||||
$tags = $temp['tags'];
|
||||
$overridden_tags = $temp['overridden'];
|
||||
$taxonomy_effective_ratios = $this->__getRatioScore($model, $tags);
|
||||
$default_base_score = isset($model['DecayingModel']['parameters']['default_base_score']) ? $model['DecayingModel']['parameters']['default_base_score'] : 0 ;
|
||||
$base_score = 0;
|
||||
$flag_contain_matching_taxonomy = false;
|
||||
if (!empty($taxonomy_effective_ratios)) {
|
||||
foreach ($tags as $k => $tag) {
|
||||
$taxonomy = explode('=', $tag['Tag']['name'])[0];
|
||||
if (isset($taxonomy_effective_ratios[$taxonomy])) {
|
||||
$flag_contain_matching_taxonomy = true;
|
||||
$base_score += $taxonomy_effective_ratios[$taxonomy] * $tag['Tag']['numerical_value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$flag_contain_matching_taxonomy) {
|
||||
$base_score = $default_base_score;
|
||||
}
|
||||
return array(
|
||||
'base_score' => $base_score,
|
||||
'overridden' => $overridden_tags,
|
||||
'tags' => $tags,
|
||||
'taxonomy_effective_ratios' => $taxonomy_effective_ratios,
|
||||
'default_base_score' => $default_base_score
|
||||
);
|
||||
}
|
||||
|
||||
// Compute the current score for the provided attribute according to the last sighting with the provided model
|
||||
final public function computeCurrentScore($user, $model, $attribute, $base_score = false, $last_sighting_timestamp = false)
|
||||
{
|
||||
if ($base_score === false) {
|
||||
$base_score = $this->computeBasescore($model, $attribute)['base_score'];
|
||||
}
|
||||
if ($last_sighting_timestamp === false) {
|
||||
$this->Sighting = ClassRegistry::init('Sighting');
|
||||
$all_sightings = $this->Sighting->listSightings($user, $attribute['id'], 'attribute', false, 0, true);
|
||||
if (!empty($all_sightings)) {
|
||||
$last_sighting_timestamp = $all_sightings[0]['Sighting']['date_sighting'];
|
||||
} else {
|
||||
$last_sighting_timestamp = $attribute['timestamp']; // if no sighting, take the last update time
|
||||
}
|
||||
}
|
||||
if ($attribute['timestamp'] > $last_sighting_timestamp) { // The attribute was modified after the last sighting
|
||||
$last_sighting_timestamp = $attribute['timestamp'];
|
||||
}
|
||||
$timestamp = time();
|
||||
return $this->computeScore($model, $attribute, $base_score, $timestamp - $last_sighting_timestamp);
|
||||
}
|
||||
|
||||
// Compute the score for the provided attribute according to the elapsed time with the provided model
|
||||
abstract public function computeScore($model, $attribute, $base_score, $elapsed_time);
|
||||
// Return a True if the attribute should be marked as decayed
|
||||
abstract public function isDecayed($model, $attribute, $score);
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
include_once 'Base.php';
|
||||
|
||||
class Polynomial extends DecayingModelBase
|
||||
{
|
||||
function __construct() {
|
||||
$this->description = __('The implementation of the decaying formula from the paper `An indicator scoring method for MISP platforms`.');
|
||||
}
|
||||
|
||||
public function computeScore($model, $attribute, $base_score, $elapsed_time)
|
||||
{
|
||||
if ($elapsed_time < 0) {
|
||||
return 0;
|
||||
}
|
||||
$decay_speed = $model['DecayingModel']['parameters']['decay_speed'];
|
||||
$lifetime = $model['DecayingModel']['parameters']['lifetime']*24*60*60;
|
||||
$score = $base_score * (1 - pow($elapsed_time / $lifetime, 1 / $decay_speed));
|
||||
return $score < 0 ? 0 : $score;
|
||||
}
|
||||
|
||||
public function isDecayed($model, $attribute, $score)
|
||||
{
|
||||
$threshold = $model['DecayingModel']['parameters']['threshold'];
|
||||
return $threshold > $score;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
include_once 'Polynomial.php';
|
||||
|
||||
class PolynomialExtended extends Polynomial
|
||||
{
|
||||
function __construct() {
|
||||
$this->description = __('The implementation of the decaying formula from the paper `An indicator scoring method for MISP platforms` with support of the `Retention` taxonomy which overrides the final score.');
|
||||
|
||||
// setup `retention` taxonomy
|
||||
$this->Taxonomy = ClassRegistry::init('Taxonomy');
|
||||
$retention_taxonomy_id = $this->Taxonomy->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('LOWER(Taxonomy.namespace)' => 'retention'),
|
||||
'fields' => array('id')
|
||||
));
|
||||
if (empty($retention_taxonomy_id)) {
|
||||
throw new Exception(__('`Retention` taxonomy not available'));
|
||||
} else {
|
||||
$retention_taxonomy_id = $retention_taxonomy_id['Taxonomy']['id'];
|
||||
}
|
||||
$taxonomy = $this->Taxonomy->getTaxonomy($retention_taxonomy_id, array('full' => true));
|
||||
$this->retention_taxonomy = array();
|
||||
foreach ($taxonomy['entries'] as $k => $entry) {
|
||||
$this->retention_taxonomy[$entry['tag']] = $entry['numerical_value'];
|
||||
}
|
||||
}
|
||||
|
||||
public function computeScore($model, $attribute, $base_score, $elapsed_time)
|
||||
{
|
||||
$score = parent::computeScore($model, $attribute, $base_score, $elapsed_time);
|
||||
|
||||
// handle `retention` taxonomy tags
|
||||
$temp = $this->__getPrioritisedTag($attribute);
|
||||
$tags = $temp['tags'];
|
||||
foreach ($tags as $tag) {
|
||||
$tagname = $tag['Tag']['name'];
|
||||
if (isset($this->retention_taxonomy[$tagname])) {
|
||||
$timestamp = intval($attribute['timestamp']);
|
||||
$now = time();
|
||||
$eol_time = $this->retention_taxonomy[$tagname] * 24 * 60 * 60; // `retention` taxonomy numerical_value are in seconds
|
||||
if (($now - $timestamp) > $eol_time) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $score < 0 ? 0 : $score;
|
||||
}
|
||||
|
||||
public function isDecayed($model, $attribute, $score)
|
||||
{
|
||||
return parent::isDecayed($model, $attribute, $score);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1816,7 +1816,8 @@ class Event extends AppModel
|
|||
'extended',
|
||||
'excludeGalaxy',
|
||||
'includeRelatedTags',
|
||||
'excludeLocalTags'
|
||||
'excludeLocalTags',
|
||||
'includeDecayScore'
|
||||
);
|
||||
if (!isset($options['excludeLocalTags']) && !empty($user['Role']['perm_sync']) && empty($user['Role']['perm_site_admin'])) {
|
||||
$options['excludeLocalTags'] = 1;
|
||||
|
@ -1824,6 +1825,9 @@ class Event extends AppModel
|
|||
if (!isset($options['excludeGalaxy']) || !$options['excludeGalaxy']) {
|
||||
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
|
||||
}
|
||||
if (!empty($options['includeDecayScore'])) {
|
||||
$this->DecayingModel = ClassRegistry::init('DecayingModel');
|
||||
}
|
||||
foreach ($possibleOptions as &$opt) {
|
||||
if (!isset($options[$opt])) {
|
||||
$options[$opt] = false;
|
||||
|
@ -2174,6 +2178,15 @@ class Event extends AppModel
|
|||
$event['Attribute'][$key]['data'] = $encodedFile;
|
||||
}
|
||||
}
|
||||
if (!empty($options['includeDecayScore'])) {
|
||||
if (isset($event['EventTag'])) { // include EventTags for score computation
|
||||
$event['Attribute'][$key]['EventTag'] = $event['EventTag'];
|
||||
}
|
||||
$event['Attribute'][$key] = $this->DecayingModel->attachScoresToAttribute($user, $event['Attribute'][$key]);
|
||||
if (isset($event['EventTag'])) { // remove included EventTags
|
||||
unset($event['Attribute'][$key]['EventTag']);
|
||||
}
|
||||
}
|
||||
// unset empty attribute tags that got added because the tag wasn't exportable
|
||||
if (!empty($attribute['AttributeTag'])) {
|
||||
foreach ($attribute['AttributeTag'] as $atk => $attributeTag) {
|
||||
|
|
|
@ -35,6 +35,7 @@ class Log extends AppModel
|
|||
'export',
|
||||
'file_upload',
|
||||
'galaxy',
|
||||
'include_formula',
|
||||
'login',
|
||||
'login_fail',
|
||||
'logout',
|
||||
|
|
|
@ -41,4 +41,21 @@ class ObjectTemplateElement extends AppModel
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function getAllAvailableTypes() {
|
||||
$temp = $this->find('all', array(
|
||||
'recursive' => -1,
|
||||
'fields' => array('object_relation as type', 'description AS desc', 'categories'),
|
||||
'group' => 'type'
|
||||
));
|
||||
$res = array();
|
||||
foreach ($temp as $type) {
|
||||
$res[$type['ObjectTemplateElement']['type']] = array(
|
||||
'desc' => $type['ObjectTemplateElement']['desc'],
|
||||
'category' => $type['ObjectTemplateElement']['categories']
|
||||
);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,12 @@ class Role extends AppModel
|
|||
'readonlyenabled' => false,
|
||||
'title' => 'Create or modify MISP Object templates'
|
||||
),
|
||||
'perm_decaying' => array(
|
||||
'id' => 'RolePermDecaying',
|
||||
'text' => 'Decaying Model Editor',
|
||||
'readonlyenabled' => true,
|
||||
'title' => 'Create or modify MISP Decaying Models'
|
||||
),
|
||||
// Urgently needed permission flag to avoid waking up next to a decapitated horse head sent by Enrico
|
||||
'perm_publish_zmq' => array(
|
||||
'id' => 'RolePermPublishZmq',
|
||||
|
|
|
@ -4873,6 +4873,7 @@ class Server extends AppModel
|
|||
'app/files/misp-objects',
|
||||
'app/files/noticelists',
|
||||
'app/files/warninglists',
|
||||
'app/files/misp-decaying-models',
|
||||
'cti-python-stix2'
|
||||
);
|
||||
return in_array($submodule, $accepted_submodules_names);
|
||||
|
@ -5010,7 +5011,7 @@ class Server extends AppModel
|
|||
return implode('\n', $result);
|
||||
}
|
||||
|
||||
public function update($status)
|
||||
public function update($status, &$raw = array())
|
||||
{
|
||||
$final = '';
|
||||
$workingDirectoryPrefix = 'cd $(git rev-parse --show-toplevel) && ';
|
||||
|
@ -5020,17 +5021,35 @@ class Server extends AppModel
|
|||
);
|
||||
foreach ($cleanup_commands as $cleanup_command) {
|
||||
$final .= $cleanup_command . "\n\n";
|
||||
exec($cleanup_command, $output);
|
||||
$status = false;
|
||||
exec($cleanup_command, $output, $status);
|
||||
$raw[] = array(
|
||||
'input' => $cleanup_command,
|
||||
'output' => $output,
|
||||
'status' => $status
|
||||
);
|
||||
$final .= implode("\n", $output) . "\n\n";
|
||||
}
|
||||
$command1 = $workingDirectoryPrefix . 'git pull origin ' . $status['branch'] . ' 2>&1';
|
||||
$command2 = $workingDirectoryPrefix . 'git submodule update --init --recursive 2>&1';
|
||||
$final .= $command1 . "\n\n";
|
||||
exec($command1, $output);
|
||||
$status = false;
|
||||
exec($command1, $output, $status);
|
||||
$raw[] = array(
|
||||
'input' => $command1,
|
||||
'output' => $output,
|
||||
'status' => $status
|
||||
);
|
||||
$final .= implode("\n", $output) . "\n\n=================================\n\n";
|
||||
$output = array();
|
||||
$final .= $command2 . "\n\n";
|
||||
exec($command2, $output);
|
||||
$status = false;
|
||||
exec($command2, $output, $status);
|
||||
$raw[] = array(
|
||||
'input' => $command2,
|
||||
'output' => $output,
|
||||
'status' => $status
|
||||
);
|
||||
$final .= implode("\n", $output);
|
||||
return $final;
|
||||
}
|
||||
|
|
|
@ -476,6 +476,90 @@ class Sighting extends AppModel
|
|||
return $sightingsRearranged;
|
||||
}
|
||||
|
||||
public function listSightings($user, $id, $context, $org_id = false, $sightings_type = false, $order_desc = true)
|
||||
{
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$id = is_array($id) ? $id : $this->explodeIdList($id);
|
||||
if ($context === 'attribute') {
|
||||
$object = $this->Event->Attribute->fetchAttributes($user, array('conditions' => array('Attribute.id' => $id, 'Attribute.deleted' => 0), 'flatten' => 1));
|
||||
} else {
|
||||
// let's set the context to event here, since we reuse the variable later on for some additional lookups.
|
||||
// Passing $context = 'org' could have interesting results otherwise...
|
||||
$context = 'event';
|
||||
$object = $this->Event->fetchEvent($user, $options = array('eventid' => $id, 'metadata' => true));
|
||||
}
|
||||
if (empty($object)) {
|
||||
throw new MethodNotAllowedException('Invalid object.');
|
||||
}
|
||||
$conditions = array(
|
||||
'Sighting.' . $context . '_id' => $id
|
||||
);
|
||||
if ($org_id) {
|
||||
$conditions[] = array('Sighting.org_id' => $org_id);
|
||||
}
|
||||
if ($sightings_type !== false) {
|
||||
$conditions[] = array('Sighting.type' => $sightings_type);
|
||||
}
|
||||
$sightings = $this->find('all', array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'contain' => array('Organisation.name'),
|
||||
'order' => array(sprintf('Sighting.date_sighting %s', $order_desc ? 'DESC' : ''))
|
||||
));
|
||||
if (!empty($sightings) && empty(Configure::read('Plugin.Sightings_policy')) && !$user['Role']['perm_site_admin']) {
|
||||
$eventOwnerOrgIdList = array();
|
||||
foreach ($sightings as $k => $sighting) {
|
||||
if (empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']])) {
|
||||
$temp_event = $this->Event->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('Event.id' => $sighting['Sighting']['event_id']),
|
||||
'fields' => array('Event.id', 'Event.orgc_id')
|
||||
));
|
||||
$eventOwnerOrgIdList[$temp_event['Event']['id']] = $temp_event['Event']['orgc_id'];
|
||||
}
|
||||
if (
|
||||
empty($eventOwnerOrgIdList[$sighting['Sighting']['event_id']]) ||
|
||||
($eventOwnerOrgIdList[$sighting['Sighting']['event_id']] !== $user['org_id'] && $sighting['Sighting']['org_id'] !== $user['org_id'])
|
||||
) {
|
||||
unset($sightings[$k]);
|
||||
}
|
||||
}
|
||||
$sightings = array_values($sightings);
|
||||
} else if (!empty($sightings) && Configure::read('Plugin.Sightings_policy') == 1 && !$user['Role']['perm_site_admin']) {
|
||||
$eventsWithOwnSightings = array();
|
||||
foreach ($sightings as $k => $sighting) {
|
||||
if (empty($eventsWithOwnSightings[$sighting['Sighting']['event_id']])) {
|
||||
$eventsWithOwnSightings[$sighting['Sighting']['event_id']] = false;
|
||||
$sighting_temp = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'Sighting.event_id' => $sighting['Sighting']['event_id'],
|
||||
'Sighting.org_id' => $user['org_id']
|
||||
)
|
||||
));
|
||||
if (empty($sighting_temp)) {
|
||||
$temp_event = $this->Event->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'Event.id' => $sighting['Sighting']['event_id'],
|
||||
'Event.orgc_id' => $user['org_id']
|
||||
),
|
||||
'fields' => array('Event.id', 'Event.orgc_id')
|
||||
));
|
||||
$eventsWithOwnSightings[$sighting['Sighting']['event_id']] = !empty($temp_event);
|
||||
} else {
|
||||
$eventsWithOwnSightings[$sighting['Sighting']['event_id']] = true;
|
||||
}
|
||||
}
|
||||
if (!$eventsWithOwnSightings[$sighting['Sighting']['event_id']]) {
|
||||
unset($sightings[$k]);
|
||||
}
|
||||
}
|
||||
$sightings = array_values($sightings);
|
||||
}
|
||||
return $sightings;
|
||||
}
|
||||
|
||||
public function restSearch($user, $returnFormat, $filters)
|
||||
{
|
||||
if (!isset($this->validFormats[$returnFormat][1])) {
|
||||
|
|
|
@ -478,6 +478,9 @@ class Taxonomy extends AppModel
|
|||
));
|
||||
$taxonomies = array();
|
||||
foreach ($temp as $t) {
|
||||
if (isset($options['full']) && $options['full']) {
|
||||
$t['Taxonomy']['TaxonomyPredicate'] = $t['TaxonomyPredicate'];
|
||||
}
|
||||
$taxonomies[$t['Taxonomy']['namespace']] = $t['Taxonomy'];
|
||||
}
|
||||
return $taxonomies;
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<div class="form">
|
||||
<?php echo $this->Form->create('DecayingModel');?>
|
||||
<fieldset>
|
||||
<legend><?php echo Inflector::humanize($action) . __(' Decaying Model');?></legend>
|
||||
<?php
|
||||
if (isset($restrictEdition) && $restrictEdition) {
|
||||
echo '<div class="alert alert-warning">' . __('You are editing a Default Model, only restricted edition is allowed.') . '</div>';
|
||||
echo $this->Form->input('all_orgs', array(
|
||||
'label' => __('Can other organization use this model'),
|
||||
'type' => 'checkbox',
|
||||
'checked' => isset($this->request->data['DecayingModel']['all_orgs']) ? $this->request->data['DecayingModel']['all_orgs'] : true
|
||||
));
|
||||
echo $this->Form->input('enabled', array(
|
||||
'type' => 'checkbox'
|
||||
));
|
||||
} else {
|
||||
echo $this->Form->input('name', array(
|
||||
'type' => 'text'
|
||||
));
|
||||
echo $this->Form->input('description', array(
|
||||
));
|
||||
echo $this->Form->input('formula', array(
|
||||
'value' => isset($this->request->data['DecayingModel']['formula']) ? $this->request->data['DecayingModel']['formula'] : 'Polynomial',
|
||||
'options' => $available_formulas,
|
||||
'div' => 'clear'
|
||||
));
|
||||
echo $this->Form->input('all_orgs', array(
|
||||
'label' => __('Can other organization use this model'),
|
||||
'type' => 'checkbox',
|
||||
'checked' => isset($this->request->data['DecayingModel']['all_orgs']) ? $this->request->data['DecayingModel']['all_orgs'] : true
|
||||
));
|
||||
echo $this->Form->input('enabled', array(
|
||||
'type' => 'checkbox'
|
||||
));
|
||||
echo '<div id="ContainerPolynomialSetting">';
|
||||
echo $this->Form->input('DecayingModel.parameters.lifetime', array(
|
||||
'label' => sprintf('<b>%s</b> [%s]: %s', __('Lifetime'), __('days'), __('Lifetime of the attribute, or time after which the score will be 0')),
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'title' => _('The end of life of the indicator'),
|
||||
'class' => 'form-control span6',
|
||||
'div' => 'clear',
|
||||
'value' => isset($this->request->data['DecayingModel']['parameters']['lifetime']) ? $this->request->data['DecayingModel']['parameters']['lifetime'] : ''
|
||||
));
|
||||
echo $this->Form->input('DecayingModel.parameters.decay_speed', array(
|
||||
'label' => sprintf('<b>%s</b> [%s]: %s', __('Decay speed'), __('float'), __('Decay speed at which an indicator will loose score')),
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'step' => 0.01,
|
||||
'title' => _('The decay speed of the indicator'),
|
||||
'class' => 'form-control span6',
|
||||
'div' => 'clear',
|
||||
'value' => isset($this->request->data['DecayingModel']['parameters']['decay_speed']) ? $this->request->data['DecayingModel']['parameters']['decay_speed'] : ''
|
||||
));
|
||||
echo $this->Form->input('DecayingModel.parameters.threshold', array(
|
||||
'label' => sprintf('<b>%s</b> [%s]: %s', __('Cutoff threshold'), __('float'), __('Cutoff value at which an indicator will be marked as decayed instead of 0')),
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'title' => _('The model threshold of the indicator'),
|
||||
'class' => 'form-control span6',
|
||||
'div' => 'clear',
|
||||
'value' => isset($this->request->data['DecayingModel']['parameters']['threshold']) ? $this->request->data['DecayingModel']['parameters']['threshold'] : ''
|
||||
));
|
||||
echo $this->Form->input('DecayingModel.parameters.default_base_score', array(
|
||||
'label' => sprintf('<b>%s</b> [%s]: %s', __('Default base_score'), __('float'), __('Default base_score value if no tags are attached to the indicator')),
|
||||
'type' => 'number',
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
'title' => _('The model default base_score of the indicator'),
|
||||
'class' => 'form-control span6',
|
||||
'div' => 'clear',
|
||||
'value' => isset($this->request->data['DecayingModel']['parameters']['default_base_score']) ? $this->request->data['DecayingModel']['parameters']['default_base_score'] : ''
|
||||
));
|
||||
echo '<div class="clear"></div>';
|
||||
echo '<label for="DecayingModelParametersBaseScoreConfig"><b>' . __('Base Score configuration') . '</b> [json]</label>';
|
||||
echo $this->Form->textarea('DecayingModel.parameters.base_score_config', array(
|
||||
'class' => 'form-control span6',
|
||||
'cols' => '10',
|
||||
'value' => isset($this->request->data['DecayingModel']['parameters']['base_score_config']) ? json_encode($this->request->data['DecayingModel']['parameters']['base_score_config']) : '{}'
|
||||
));
|
||||
echo '</div>';
|
||||
echo '<div id="ContainerOtherSetting">';
|
||||
echo '<div class="clear"></div>';
|
||||
echo '<label for="DecayingModelOtherSettings"><b>' . __('Model Settings') . '</b> [json]</label>';
|
||||
echo $this->Form->textarea('DecayingModel.parameters.settings', array(
|
||||
'class' => 'form-control span6',
|
||||
'cols' => '10',
|
||||
'value' => isset($this->request->data['DecayingModel']['parameters']['settings']) ? json_encode($this->request->data['DecayingModel']['parameters']['settings']) : '{}'
|
||||
));
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo $this->Form->button(Inflector::humanize($action), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => 'add'));
|
||||
?>
|
||||
<script>
|
||||
toggleOtherSetting();
|
||||
$(document).ready(function() {
|
||||
$('#DecayingModelFormula').on('input', function() {
|
||||
toggleOtherSetting();
|
||||
})
|
||||
});
|
||||
function toggleOtherSetting() {
|
||||
if ($('#DecayingModelFormula').val() === 'Polynomial') {
|
||||
$('#ContainerOtherSetting').hide();
|
||||
} else {
|
||||
$('#ContainerOtherSetting').show();
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,5 @@
|
|||
<div>
|
||||
<?php
|
||||
echo $this->Form->postLink(__('Disable model'), '/DecayingModel/disable/' . h($model['id']))
|
||||
?>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
<div>
|
||||
<?php
|
||||
echo $this->Form->postLink(__('Enable model'), '/DecayingModel/enable/' . h($model['id']))
|
||||
?>
|
||||
</div>
|
|
@ -0,0 +1,211 @@
|
|||
<div class="view">
|
||||
<h2>Decaying Of Indicator Fine Tuning Tool</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="span9 form-inline" style="border: 1px solid #ddd; border-radius: 4px; margin-bottom: 15px;">
|
||||
<div style="border-bottom: 1px solid #ddd;">
|
||||
<label class="checkbox inline">
|
||||
<input id="table_toggle_all_type" type="checkbox"></input>
|
||||
<?php echo __('Show All Types'); ?>
|
||||
</label>
|
||||
<label class="checkbox inline">
|
||||
<input id="table_toggle_objects" type="checkbox"></input>
|
||||
<?php echo __('Show MISP Objects'); ?>
|
||||
</label>
|
||||
<input id="table_type_search" class="input" type="text" placeholder="<?php echo __('Search Attribute Type'); ?>"></input>
|
||||
<button class="btn btn-primary btn-small" onclick="decayingTool.restoreSelection()"><span class="fa fa-history"></span></button>
|
||||
</div>
|
||||
<div class="AttributeTypeTableContainer">
|
||||
<table id="table_attribute_type" class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input id="checkAll" type="checkbox" title="<?php echo __('Check all'); ?>"></input></th>
|
||||
<th><?php echo __('Attribute Type'); ?></th>
|
||||
<th><?php echo __('Category'); ?></th>
|
||||
<th><?php echo __('Model ID'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="attributeTypeTableBody">
|
||||
<?php foreach ($types as $type => $info): ?>
|
||||
<?php
|
||||
$class = 'hidden ';
|
||||
if (
|
||||
isset($info['isObject']) && $info['isObject'] &&
|
||||
!(isset($info['isAttribute']) && $info['isAttribute'])
|
||||
) {
|
||||
$class .= 'isObject';
|
||||
} else if (isset($info['to_ids']) && $info['to_ids'] != 1) {
|
||||
$class .= 'isNotToIDS';
|
||||
} else {
|
||||
$class = "";
|
||||
}
|
||||
?>
|
||||
<tr class="<?php echo $class; ?>">
|
||||
<td><input type="checkbox"></input></td>
|
||||
<td class="useCursorPointer isFilteringField isAttributeTypeField">
|
||||
<?php if(isset($info['isObject']) && $info['isObject'] && !(isset($info['isAttribute']) && $info['isAttribute'])): ?>
|
||||
<it class="fa fa-cube" title="<?php echo __('Belong to a MISP Object'); ?>"></it>
|
||||
<?php endif; ?>
|
||||
<span title="<?php echo isset($info['desc']) ? h($info['desc']) : ''; ?>"><?php echo h($type); ?></span>
|
||||
<?php if(isset($info['to_ids']) && $info['to_ids'] == 1): ?>
|
||||
<it class="fa fa-flag fa-pull-right" title="<?php echo __('To IDS flag set'); ?>"></it>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="useCursorPointer isFilteringField"><?php echo is_array($info['default_category']) ? implode('</br>', h($info['default_category'])) : h($info['default_category']); ?></td>
|
||||
<td class="isFilteringField isModelIdField">
|
||||
<?php if (isset($associated_models[$type])): ?>
|
||||
<?php foreach ($associated_models[$type] as $id): ?>
|
||||
<a href="#" onclick="$('#modelId_<?php echo h($id); ?>').find('.decayingLoadBtn').click();"><?php echo h($id); ?></a>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span12">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<select id="formulaSelectPicker" style="margin: 0px;">
|
||||
<?php foreach ($available_formulas as $formula_name => $formula_data): ?>
|
||||
<option value="<?php echo h($formula_name); ?>" data-extends="<?php echo h($formula_data['parent_class']); ?>" title="<?php echo h($formula_data['description']); ?>"><?php echo h($formula_name); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<i id="formulaSelectPickerHelpText" class="fas fa-question-circle"></i>
|
||||
</div>
|
||||
<div id="containerFormulaPolynomialSetting">
|
||||
<div class="span10" style="border: 1px solid #ddd; border-radius: 4px; margin-bottom: 20px;">
|
||||
<div id="decayGraph" style="width: 100%;"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6" style="margin-bottom: 20px;">
|
||||
<?php foreach ($parameters as $param => $config): ?>
|
||||
<div class="input-prepend input-append">
|
||||
<span class="add-on param-name" data-toggle="tooltip" data-placement="left" style="min-width: 100px;" title="<?php echo isset($config['info']) ? h($config['info']) : ''?>">
|
||||
<?php echo h($config['name']) . (isset($config['greek']) ? ' <strong>' . h($config['greek']).'</strong>' : ''); ?>
|
||||
</span>
|
||||
<input id="input_<?php echo h($param); ?>" class="input-mini" type="number" min=0 step=<?php echo h($config['step']); ?> value=<?php echo h($config['value']); ?> max=<?php echo isset($config['max']) ? h($config['max']) : ''; ?> oninput="refreshGraph(this);" ></input>
|
||||
<span class="add-on"><input id="input_<?php echo h($param); ?>_range" type="range" min=0 <?php echo isset($config['max']) ? 'max=' . h($config['max']) : '' ?> step=<?php echo h($config['step']); ?> value=<?php echo h($config['value']); ?> oninput="$('#input_<?php echo h($param); ?>').val(this.value).trigger('input');"></input></span>
|
||||
<?php if (isset($config['unit'])): ?>
|
||||
<span class="add-on"><?php echo h($config['unit']); ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<input id="input_default_base_score" value=0 class="hidden"></input>
|
||||
<div class="input-append" style="margin-bottom: 0px;">
|
||||
<input id="input_base_score_config" class="hidden" value="[]"></input>
|
||||
<button class="btn btn-primary" style="border-radius: 4px 0px 0px 4px;" onclick="decayingTool.toggleBasescoreForm()">
|
||||
<span class="fa fa-tags"> <?php echo __('Adjust base score'); ?></span>
|
||||
</button>
|
||||
<span id="summary_base_score_config" class="add-on param-name">
|
||||
<span class="far fa-square"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div style="display: inline-block; margin-left: 10px;">
|
||||
<a id="button-toggle-simulation" target="_blank" class="btn btn-primary" href="" onclick="return !$(this).hasClass('disabled');">
|
||||
<span class="fa fa-chart-line"> <?php echo __('Simulate this model'); ?></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<table class="table table-striped table-bordered">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Expire after (lifetime)</td>
|
||||
<td id="infoCellExpired"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Score halved after (Half-life)</td>
|
||||
<td id="infoCellHalved"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="containerFormulaOtherSetting" class="hidden">
|
||||
<textarea id="textarea_other_settings_formulas" style="width: 430px;" rows="5" placeholder="<?php echo(__('Model\'s Settings')); ?>"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<form id="saveForm" class="form-inline">
|
||||
<input type="text" name="name" class="input" placeholder="Model name" required>
|
||||
<textarea rows="1" name="description" class="input" placeholder="Description"></textarea>
|
||||
<span id="save-model-button" class="btn btn-success" data-save-type="add" onclick="decayingTool.saveModel(this)" data-modelid="0" data-isedit="0" data-edittext="<?php echo __("Edit") ?>" data-savetext="<?php echo __("Create") ?>"><i class="fa fa-plus"> <?php echo __("Create") ?></i></span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<span class="tableRadioFilterOptionsContainer">
|
||||
<label class="radio inline">
|
||||
<input type="radio" id="tableRadioFilterAll" name="tableRadioFilterOptions" value="all" checked><?php echo __('All available models');?>
|
||||
</label>
|
||||
<label class="radio inline">
|
||||
<input type="radio" id="tableRadioFilterMy" name="tableRadioFilterOptions" value="my_models"><?php echo __('My models'); ?>
|
||||
</label>
|
||||
<label class="radio inline">
|
||||
<input type="radio" id="tableRadioFilterDefault" name="tableRadioFilterOptions" value="default_models"><?php echo __('Default models'); ?>
|
||||
</label>
|
||||
</span>
|
||||
<table id="table-model" class="table table-striped table-bordered">
|
||||
<thead id="table-model-head"></thead>
|
||||
<tbody id="table-model-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => 'decayingTool')); ?>
|
||||
<?php
|
||||
echo $this->element('genericElements/assetLoader', array(
|
||||
'css' => array('decayingTool'),
|
||||
'js' => array('d3', 'Chart.min', 'decayingTool')
|
||||
));
|
||||
?>
|
||||
|
||||
<script>
|
||||
var logged_user_org_id = <?php echo h($me['org_id']); ?>;
|
||||
$(document).ready(function() {
|
||||
$('.json-transform').each(function(i) {
|
||||
var text = $(this).text().trim();
|
||||
var parsedJson = ''
|
||||
if (text !== '') {
|
||||
parsedJson = jsonToNestedTable(text, [], ['table', 'table-condensed', 'table-bordered']);
|
||||
}
|
||||
$(this).html(parsedJson);
|
||||
});
|
||||
|
||||
$('#formulaSelectPicker').change(function() {
|
||||
toggleContainer();
|
||||
})
|
||||
|
||||
$('#formulaSelectPickerHelpText').tooltip({
|
||||
title: function() {
|
||||
return $('#formulaSelectPicker > option:selected').attr('title');
|
||||
},
|
||||
placement: 'right'
|
||||
});
|
||||
|
||||
});
|
||||
function toggleContainer() {
|
||||
var $option = $('#formulaSelectPicker').find('option:selected');
|
||||
if ($option.data('extends') == 'Polynomial') {
|
||||
$('#containerFormulaPolynomialSetting').show();
|
||||
} else {
|
||||
$('#containerFormulaPolynomialSetting').hide();
|
||||
}
|
||||
if ($('#formulaSelectPicker').val() == 'Polynomial') {
|
||||
$('#containerFormulaOtherSetting').hide();
|
||||
} else {
|
||||
$('#containerFormulaOtherSetting').show();
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,180 @@
|
|||
<div id="basescore_configurator" class="row">
|
||||
<div class="span8" class="taxonomyTableContainer">
|
||||
<input id="table_taxonomy_search" class="input" style="width: 250px; margin: 0px;" type="text" placeholder="<?php echo __('Search Taxonomy'); ?>"></input>
|
||||
<it class="fa fa-times useCursorPointer" title="<?php echo __('Clear search field'); ?>" onclick="$('#table_taxonomy_search').val('').trigger('input');"></it>
|
||||
<span style="float: right; margin-top: 6px;" class="badge badge-info"><b><?php echo h($taxonomies_not_having_numerical_value); ?></b><?php echo __(' not having numerical value'); ?></span>
|
||||
<div class="input-prepend" style="margin: 4px;">
|
||||
<span class="add-on"><?php echo __('Default basescore') ?></span>
|
||||
<input id="base_score_default_value" type="number" min=0 max=100 class="input-mini" value="0" placeholder="0"></input>
|
||||
</div>
|
||||
<table id="tableTaxonomy" class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo __('Taxonomies') ?></th>
|
||||
<th><?php echo __('Weight') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="body_taxonomies">
|
||||
<?php foreach ($taxonomies as $name => $taxonomy): ?>
|
||||
<?php if (count($taxonomy['TaxonomyPredicate']) > 1): ?>
|
||||
<tr class="bold useCursorPointer" data-namespace="<?php echo h($name); ?>" onclick="collapseNamespace(this);">
|
||||
<td colspan=2 style="background-color: #999; color: white; user-select: none;">
|
||||
<?php echo h($name); ?>
|
||||
<i class="caretIconExpand fas fa-caret-down"></i>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($taxonomy['TaxonomyPredicate'] as $p => $predicate): ?>
|
||||
<?php if (!isset($predicate['numerical_predicate']) || !$predicate['numerical_predicate']): ?>
|
||||
<tr data-namespace="<?php echo h($name); ?>">
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<?php echo h($predicate['value']) ?>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<?php foreach ($predicate['TaxonomyEntry'] as $e => $entry): ?>
|
||||
<li>
|
||||
<a style="position: relative; padding: 3px 5px;">
|
||||
<span class="tagComplete"
|
||||
style="margin-right: 35px;background-color: <?php echo h($entry['Tag']['colour']); ?>;color:<?php echo h($this->TextColour->getTextColour($entry['Tag']['colour']));?>"
|
||||
title="<?php echo sprintf('%s: %s', h($entry['expanded']), h($entry['description'])) ?>"><?php echo h($entry['Tag']['name']); ?>
|
||||
</span>
|
||||
<span class="label label-inverse numerical-value-label"><?php echo h($entry['numerical_value']) ?></span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<input id="slider_<?php echo h($name) ?>" data-taxonomyname="<?php echo sprintf('%s:%s', h($name), h($predicate['value'])); ?>" type="range" min=0 max=100 step=1 value="<?php echo isset($taxonomy['value']) ? h($taxonomy['value']) : 0 ?>" onchange="sliderChanged(this);" oninput="sliderChanged(this);"></input>
|
||||
<input type="number" min=0 max=100 step=1 value="<?php echo isset($taxonomy['value']) ? h($taxonomy['value']) : 0 ?>" class="taxonomySlider" data-taxonomyname="<?php echo sprintf('%s:%s', h($name), h($predicate['value'])); ?>" onchange="inputChanged(this);" oninput="inputChanged(this);"></input>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: // numerical_value on predicate ?>
|
||||
<tr data-namespace="<?php echo h($name); ?>">
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<?php echo h($name) ?>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<?php foreach ($taxonomies[$name]['TaxonomyPredicate'] as $p => $predicate): ?>
|
||||
<li>
|
||||
<a style="position: relative; padding: 3px 5px;">
|
||||
<span class="tagComplete"
|
||||
style="margin-right: 35px;background-color: <?php echo h($predicate['Tag']['colour']); ?>;color:<?php echo h($this->TextColour->getTextColour($predicate['Tag']['colour']));?>"
|
||||
title="<?php echo sprintf('%s: %s', h($predicate['expanded']), h($predicate['description'])) ?>"><?php echo h($predicate['Tag']['name']); ?>
|
||||
</span>
|
||||
<span class="label label-inverse numerical-value-label"><?php echo h($predicate['numerical_value']) ?></span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<input id="slider_<?php echo h($name) ?>" data-taxonomyname="<?php echo h($name); ?>" type="range" min=0 max=100 step=1 value="<?php echo isset($taxonomy['value']) ? h($taxonomy['value']) : 0 ?>" onchange="sliderChanged(this);" oninput="sliderChanged(this);"></input>
|
||||
<input type="number" min=0 max=100 step=1 value="<?php echo isset($taxonomy['value']) ? h($taxonomy['value']) : 0 ?>" class="taxonomySlider" data-taxonomyname="<?php echo h($name); ?>" onchange="inputChanged(this);" oninput="inputChanged(this);"></input>
|
||||
</td>
|
||||
</tr>
|
||||
<?php break; ?>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
<?php if (count($excluded_taxonomies) > 1): ?>
|
||||
<tr class="bold useCursorPointer" data-namespace="excluded-taxonomy" onclick="collapseNamespace(this);">
|
||||
<td colspan=2 style="background-color: #999; color: white; user-select: none;">
|
||||
<?php echo __('Excluded'); ?>
|
||||
<i class="caretIconExpand fas fa-caret-up"></i>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($excluded_taxonomies as $namespace => $taxonomy): // excluded taxonomies ?>
|
||||
<tr data-namespace="excluded-taxonomy" style="display: none;">
|
||||
<td>
|
||||
<button class="btn" disabled><?php echo h($namespace) ?></button>
|
||||
</td>
|
||||
<td style="vertical-align: middle;"><span class='label label-info'><?php echo h($taxonomy['reason']); ?></span></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="span8">
|
||||
<div style="margin-bottom: 5px;">
|
||||
<div id="treemapGraphTax"></div>
|
||||
</div>
|
||||
<div class="org-source-confidence-placeholder">
|
||||
<?php echo __('Placeholder for `Organisation source confidence`') ?>
|
||||
</div>
|
||||
<div>
|
||||
<h3><?php echo __('Example') ?><it class="fa fa-sync useCursorPointer" style="margin-left: 5px; font-size: small;" onclick="refreshExamples()"></it></h3>
|
||||
<table id="tableExamples" class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Tags</th>
|
||||
<th style="min-width: 60px;">Base score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr onclick="genHelpBaseScoreComputation(event, 0)">
|
||||
<td>
|
||||
Tag your attribute
|
||||
</td>
|
||||
<td id="basescore-example-tag-0">
|
||||
<div style="width:100%;display:inline-block;" data-original-title="" title="">
|
||||
<div id="basescore-example-customtag-container" style="float: left;display: flex;flex-flow: wrap;" data-original-title="" title="">
|
||||
<button id="basescore-example-score-addTagButton" class="btn btn-inverse noPrint" style="line-height:10px; padding: 4px 4px; margin-right: 3px;" title="Add tag" onclick="event.stopPropagation(); addTagWithValue(this);">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td id="basescore-example-score-0" class="basescore-example-score">
|
||||
</td>
|
||||
</tr>
|
||||
<tr onclick="genHelpBaseScoreComputation(event, 1)">
|
||||
<td>Attribute 1</td>
|
||||
<td id="basescore-example-tag-1"><?php echo __('Pick a Taxonomy'); ?></td>
|
||||
<td id="basescore-example-score-1" class="basescore-example-score"></td>
|
||||
</tr>
|
||||
<tr onclick="genHelpBaseScoreComputation(event, 2)">
|
||||
<td>Attribute 2</td>
|
||||
<td id="basescore-example-tag-2"><?php echo __('Pick a Taxonomy'); ?></td>
|
||||
<td id="basescore-example-score-2" class="basescore-example-score"></td>
|
||||
</tr>
|
||||
<tr onclick="genHelpBaseScoreComputation(event, 3)">
|
||||
<td>Attribute 3</td>
|
||||
<td id="basescore-example-tag-3"><?php echo __('Pick a Taxonomy'); ?></td>
|
||||
<td id="basescore-example-score-3" class="basescore-example-score"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3><?php echo __('Computation steps') ?></h3>
|
||||
<?php echo $this->element('DecayingModels/View/basescore_computation_steps'); ?>
|
||||
</div>
|
||||
<span class="btn btn-primary" style="margin-top: 5px;" onclick="applyBaseScoreConfig();"><i class="fas fa-wrench"> <?php echo __('Apply base score'); ?></i></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo $this->element('genericElements/assetLoader', array(
|
||||
'css' => array('treemap'),
|
||||
'js' => array('decayingToolBasescore')
|
||||
));
|
||||
?>
|
||||
|
||||
<script>
|
||||
var taxonomies_with_num_value = <?php echo json_encode($taxonomies); ?>;
|
||||
function collapseNamespace(clicked) {
|
||||
var $tr = $(clicked)
|
||||
var $icon = $tr.find('i.caretIconExpand');
|
||||
var namespace = $tr.data('namespace');
|
||||
$tr.parent().find('[data-namespace="' + namespace + '"]').not($tr).toggle();
|
||||
$icon.toggleClass('fa-caret-down').toggleClass('fa-caret-up');
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,91 @@
|
|||
<div id="attribute_div">
|
||||
<div class="pagination" style="margin: 0px;">
|
||||
<ul>
|
||||
<?php
|
||||
$this->Paginator->options(array(
|
||||
'update' => '#attribute_div',
|
||||
'evalScripts' => true,
|
||||
'before' => '$(".progress").show()',
|
||||
'complete' => '$(".progress").hide()',
|
||||
));
|
||||
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
$headers = array(
|
||||
'ID',
|
||||
$this->Paginator->sort('event_id'),
|
||||
|
||||
$this->Paginator->sort('date', __('Date')),
|
||||
$this->Paginator->sort('Event.orgc_id', __('Org')),
|
||||
$this->Paginator->sort('category', __('Category')),
|
||||
$this->Paginator->sort('type', __('Type')),
|
||||
$this->Paginator->sort('value', __('Value')),
|
||||
__('Tags'),
|
||||
__('Event Tags'),
|
||||
__('Galaxies'),
|
||||
$this->Paginator->sort('comment', __('Comment')),
|
||||
sprintf('<span title="%s">%s', $attrDescriptions['signature']['desc'], $this->Paginator->sort('IDS')),
|
||||
__('Sightings'),
|
||||
$this->Paginator->sort('decay_score.score', __('Score')),
|
||||
);
|
||||
foreach ($headers as $k => &$header) {
|
||||
$header = sprintf('<th>%s</th>', $header);
|
||||
}
|
||||
$header = sprintf('<thead><tr>%s</tr></thead>', implode('', $headers));
|
||||
$rows = array();
|
||||
foreach ($attributes as $k => $attribute) {
|
||||
$event = array(
|
||||
'Event' => $attribute['Event'],
|
||||
'Orgc' => $attribute['Event']['Orgc'],
|
||||
);
|
||||
$rows[] = $this->element('DecayingModels/View/row_attribute_simulation', array(
|
||||
'object' => $attribute['Attribute'],
|
||||
'event' => $event
|
||||
));
|
||||
}
|
||||
echo sprintf('<table class="table table-striped table-hover table-condensed">%s %s</table>', $header, implode('', $rows));
|
||||
?>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#attribute_div .pagination a, #attribute_div thead th > a').click(function(e) {
|
||||
var url = this.href;
|
||||
$.ajax({
|
||||
beforeSend:function() {
|
||||
$('#attributeTableContainer').html('<div style="height:100%; display:flex; align-items:center; justify-content:center;"><span class="fa fa-spinner fa-spin" style="font-size: xx-large;"></span></div>');
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
$('#attributeTableContainer').html(data);
|
||||
},
|
||||
error:function() {
|
||||
showMessage('fail', '<?php echo __('Failed to perform RestSearch') ?>');
|
||||
},
|
||||
type:'get',
|
||||
url: url,
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,8 @@
|
|||
<div class="hidden">
|
||||
<?php echo $this->Form->create('decayingToolRestSearch', array('url' => array('controller' => 'decayingModel', 'action' => 'decayingToolRestSearch', 'results')));?>
|
||||
<legend><?php echo __('Decaying Model RestSearch');?></legend>
|
||||
<fieldset>
|
||||
<?php echo $this->Form->input('filters'); ?>
|
||||
</fieldset>
|
||||
<?php echo $this->Form->end(); ?>
|
||||
</div>
|
|
@ -0,0 +1,291 @@
|
|||
<div class="view">
|
||||
<div id="simulationContainer">
|
||||
<div class="simulationSubContainer">
|
||||
<div style="height: 40%; display: flex">
|
||||
<div style="width: 20%; display: flex; flex-direction: column;">
|
||||
<div class="panel-container" style="display: flex; flex-direction: column; flex-grow: 1">
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<select id="select_model_to_simulate" onchange="modelChangeHandler(this)" style="flex-grow: 1;">
|
||||
<?php foreach ($all_models as $model): ?>
|
||||
<option value="<?php echo h($model['DecayingModel']['id']) ?>" <?php echo $decaying_model['DecayingModel']['id'] == $model['DecayingModel']['id'] ? 'selected' : '' ?>><?php echo h($model['DecayingModel']['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<span id="select_model_to_simulate_infobox" class="btn"><span class="fa fa-question-circle"></span></span>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs" style="margin-right: -5px; margin-bottom: 0px;" id="simulation-tabs">
|
||||
<li class="<?php echo isset($attribute_id) ? '' : 'active'; ?>"><a href="#restsearch" data-toggle="tab">RestSearch</a></li>
|
||||
<li class="<?php echo !isset($attribute_id) ? '' : 'active'; ?>"><a href="#specificid" data-toggle="tab">Specific ID</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" style="padding: 5px; height: 100%;">
|
||||
<div class="tab-pane <?php echo isset($attribute_id) ? '' : 'active'; ?>" id="restsearch" style="height: 100%;">
|
||||
<div style="display: flex; flex-direction: column; height: 100%;">
|
||||
<h3 style="">Attribute RestSearch<span style="vertical-align: top; font-size: x-small;" class="fa fa-question-circle" title="Enforced fields: [returnFormat, includeEventTags]"></span></h3>
|
||||
<?php
|
||||
$registered_taxonomies = array_keys($decaying_model['DecayingModel']['parameters']['base_score_config']);
|
||||
foreach ($registered_taxonomies as $i => &$taxonomy_name) {
|
||||
$taxonomy_name = $taxonomy_name . '%' ;
|
||||
}
|
||||
?>
|
||||
<textarea id="restSearchTextarea">
|
||||
{
|
||||
"includeDecayScore": 1,
|
||||
"includeFullModel": 0,
|
||||
"score": <?php echo h($decaying_model['DecayingModel']['parameters']['threshold']); ?>,
|
||||
"excludeDecayed": 0,
|
||||
"decayingModel": [<?php echo h($decaying_model['DecayingModel']['id']); ?>],
|
||||
"to_ids": 1,
|
||||
"tags": <?php echo json_encode($registered_taxonomies); ?>,
|
||||
"modelOverrides": {
|
||||
|
||||
}
|
||||
}</textarea>
|
||||
</br>
|
||||
<span class="btn btn-primary" style="width: fit-content;" role="button" onclick="doRestSearch(this)"><?php echo __('Search'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane <?php echo !isset($attribute_id) ? '' : 'active'; ?>" id="specificid">
|
||||
<h3 style=""><?php echo __('Specific Attribute'); ?></h3>
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<div style="margin-left: 4px; margin-bottom: 0px;" class="input-prepend">
|
||||
<span class="add-on">ID</span>
|
||||
<input type="text" value="<?php echo isset($attribute_id) ? h($attribute_id) : ''; ?>" placeholder="<?php echo __('Attribute ID or UUID') ?>" onkeypress="handle_input_key(event)" style="width: auto;">
|
||||
</div>
|
||||
<span id="performRestSearchButton" class="btn btn-primary" style="width: fit-content; margin-left: 4px;" role="button" onclick="doSpecificSearch(this)"><?php echo __('Simulate'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 80%; display: flex;">
|
||||
<div class="panel-container" style="flex-grow: 1; display: flex; width: 100%">
|
||||
<div id="basescore-simulation-container" style="width: 30%; min-width: 300px; height: 100%; margin-right: 10px;">
|
||||
<div>
|
||||
<h5 style="display: inline-block;"><?php echo __('Base score') ?> <i id="basescore_enlarge_icon" class="fas fa-expand useCursorPointer"></i></h5>
|
||||
<div id="alert-basescore-not-set" class="alert alert-warning" style="display: inline-block; margin-bottom: auto; margin-left: 5px; padding: 4px 8px;">
|
||||
<strong><?php echo __('Base score configuration'); ?></strong> <?php echo __('not set. But default value sets.') ?>
|
||||
</div>
|
||||
<div id="alert-basescore-not-set" class="alert alert-error" style="display: inline-block; margin-bottom: auto; margin-left: 5px; padding: 4px 8px;">
|
||||
<strong><?php echo __('Base score configuration'); ?></strong> <?php echo __('not set') ?>
|
||||
</div>
|
||||
</div>
|
||||
<div style="position: relative; max-height: calc(100% - 75px); overflow: auto; margin-bottom: 5px;">
|
||||
<?php echo $this->element('DecayingModels/View/basescore_computation_steps'); ?>
|
||||
</div>
|
||||
<div style="margin-bottom: 5px; white-space: nowrap;">
|
||||
<div style="margin-left: 4px; margin-bottom: 0px;" class="input-prepend input-append">
|
||||
<span class="add-on"><?php echo __('Sighting'); ?></span>
|
||||
<span id="simulation-sighting" class="add-on"></span>
|
||||
</div>
|
||||
<div style="margin-left: 4px; margin-bottom: 0px;" class="input-prepend input-append">
|
||||
<span class="add-on"><?php echo __('Current score'); ?></span>
|
||||
<span id="simulation-current-score" class="add-on"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="chart-decay-simulation-container" style="width: 70%; height: 100%; position: relative; overflow: hidden;">
|
||||
<div id="simulation_chart" class="svg-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 60%; overflow-y: auto; background-color: #ffffff; min-width: 1600px; " class="panel-container">
|
||||
<div style="height: 100%;" id="attributeTableContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => '')); ?>
|
||||
<?php
|
||||
echo $this->element('genericElements/assetLoader', array(
|
||||
'css' => array('treemap', 'decayingTool'),
|
||||
'js' => array('d3', 'decayingModelSimulation')
|
||||
));
|
||||
?>
|
||||
|
||||
<script>
|
||||
var model_list = <?php echo json_encode($all_models); ?>;
|
||||
var models = {};
|
||||
$('#alert-basescore-not-set').hide();
|
||||
$('#alert-basescore-not-set.alert-error').hide();
|
||||
$(document).ready(function() {
|
||||
model_list.forEach(function(m) {
|
||||
models[m.DecayingModel.id] = m.DecayingModel;
|
||||
});
|
||||
$('#select_model_to_simulate_infobox').popover({
|
||||
title: function() {
|
||||
return $('<div>').text($('#select_model_to_simulate option:selected').text()).html();
|
||||
},
|
||||
content: function() {
|
||||
return '<div>' + syntaxHighlightJson(models[$('#select_model_to_simulate').val()]) + '</div>';
|
||||
},
|
||||
html: true,
|
||||
placement: 'bottom'
|
||||
});
|
||||
|
||||
$('#basescore_enlarge_icon').click(function() {
|
||||
var $table = $('#computation_help_container > table');
|
||||
var css_container = 'width: 1000px; left: calc(50% - 500px); margin-left: 0;';
|
||||
var css_body = 'max-height: 80%;';
|
||||
openModal('<?php echo __('Basescore computation steps'); ?>', $table[0].outerHTML, '', {}, css_container, css_body);
|
||||
});
|
||||
|
||||
$('body').on('click', function (e) {
|
||||
if (
|
||||
$(e.target).attr('id') !== 'select_model_to_simulate'
|
||||
&& $(e.target).attr('id') !== 'select_model_to_simulate_infobox'
|
||||
&& $(e.target).parents('#select_model_to_simulate_infobox').length === 0
|
||||
&& $(e.target).parents('.popover.in').length === 0) {
|
||||
$('#select_model_to_simulate_infobox').popover('hide');
|
||||
}
|
||||
});
|
||||
|
||||
<?php echo isset($attribute_id) ? '$("#performRestSearchButton").click();' : ''; ?>
|
||||
});
|
||||
|
||||
|
||||
function doRestSearch(clicked, query) {
|
||||
var data = query === undefined ? $(clicked).parent().find('textarea').val() : query;
|
||||
var json;
|
||||
try {
|
||||
json = JSON.parse(data);
|
||||
} catch (SyntaxError) {
|
||||
showMessage('fail', 'Invalid JSON syntax');
|
||||
return;
|
||||
}
|
||||
fetchFormDataAjax('/decayingModel/decayingToolRestSearch/', function(formData) {
|
||||
var $formData = $(formData);
|
||||
url = $formData.find('form').attr('action');
|
||||
$('#simulationContainer').append($formData);
|
||||
$formData.find('#decayingToolRestSearchFilters').val(data);
|
||||
$.ajax({
|
||||
data: $formData.find('form').serialize(),
|
||||
beforeSend:function() {
|
||||
$('#attributeTableContainer').html('<div class="loading-spinner-container"><span class="fa fa-spinner fa-spin" style="font-size: xx-large;"></span></div>');
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
$('#attributeTableContainer').html(data);
|
||||
var $trs = $('#attributeTableContainer tbody > tr');
|
||||
if ($trs.length == 1) {
|
||||
$trs.click();
|
||||
}
|
||||
// pass potential model overrides
|
||||
if (json.modelOverrides !== undefined) {
|
||||
$trs.data('modelOverride', JSON.stringify(json.modelOverrides));
|
||||
}
|
||||
if (json.score !== undefined) {
|
||||
$trs.data('score', json.score);
|
||||
}
|
||||
},
|
||||
error:function(jqXHR, textStatus, errorThrown) {
|
||||
$('#attributeTableContainer').text(textStatus + ': ' + errorThrown);
|
||||
showMessage('fail', '<?php echo __('Failed to perform RestSearch') ?>');
|
||||
},
|
||||
type:'post',
|
||||
cache: false,
|
||||
url: url,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function doSpecificSearch(clicked) {
|
||||
var body = {
|
||||
id: $(clicked).parent().find('input').val(),
|
||||
decayingModel: $('#select_model_to_simulate').val()
|
||||
}
|
||||
doRestSearch(clicked, JSON.stringify(body));
|
||||
}
|
||||
|
||||
function handle_input_key(e) {
|
||||
if(e.keyCode === 13){
|
||||
e.preventDefault();
|
||||
$('#performRestSearchButton').click();
|
||||
}
|
||||
}
|
||||
|
||||
function doSimulation(clicked, attribute_id) {
|
||||
$('#attribute_div tr').removeClass('success');
|
||||
$(clicked).addClass('success');
|
||||
var model_id = $('#select_model_to_simulate').val();
|
||||
var simulation_chart = $('#simulation_chart').data('DecayingSimulation');
|
||||
var simulation_table = $('#basescore-simulation-container #computation_help_container_body').data('BasescoreComputationTable');
|
||||
if (simulation_chart === undefined) {
|
||||
simulation_chart = $('#simulation_chart').decayingSimulation({});
|
||||
}
|
||||
if (simulation_table === undefined) {
|
||||
simulation_table = $('#basescore-simulation-container #computation_help_container_body').basescoreComputationTable({});
|
||||
}
|
||||
var url = '/decayingModel/decayingToolComputeSimulation/' + model_id + '/' + attribute_id;
|
||||
var model_override = $(clicked).data('modelOverride');
|
||||
if (model_override !== undefined) {
|
||||
url += '/modelOverride:' + model_override;
|
||||
}
|
||||
var score = $(clicked).data('score');
|
||||
if (score !== undefined) {
|
||||
url += '/score:' + score;
|
||||
}
|
||||
$.ajax({
|
||||
beforeSend:function() {
|
||||
simulation_chart.toggleLoading(true);
|
||||
simulation_table.toggleLoading(true);
|
||||
},
|
||||
success:function (data, textStatus) {
|
||||
simulation_chart.update(data, data.Model);
|
||||
simulation_table.update(data, data.Model);
|
||||
if (Object.keys(data.base_score_config.taxonomy_effective_ratios).length > 0) { // show alert base_score not set
|
||||
$('#alert-basescore-not-set').hide();
|
||||
$('#alert-basescore-not-set.alert-error').hide();
|
||||
$('#basescore-simulation-container #computation_help_container_body tr').removeClass('warning').removeClass('error');
|
||||
} else {
|
||||
if (data.base_score_config.default_base_score == 0) { // show alert base_score not set
|
||||
$('#alert-basescore-not-set.alert-error').show('fade', {}, 250);
|
||||
$('#alert-basescore-not-set').hide();
|
||||
$('#basescore-simulation-container #computation_help_container_body tr').removeClass('warning').addClass('error');
|
||||
} else {
|
||||
$('#alert-basescore-not-set').show('fade', {}, 250);
|
||||
$('#alert-basescore-not-set.alert-error').hide();
|
||||
$('#basescore-simulation-container #computation_help_container_body tr').removeClass('error').addClass('warning');
|
||||
}
|
||||
}
|
||||
$('#simulation-sighting')
|
||||
.text(
|
||||
d3.time.format("%c")(new Date(parseInt(data.last_sighting.Sighting.date_sighting)*1000))
|
||||
);
|
||||
$('#simulation-sighting').parent().tooltip({
|
||||
title: 'From ' + (data.last_sighting.Organisation !== undefined ? data.last_sighting.Organisation.name : '?'),
|
||||
});
|
||||
$('#simulation-current-score')
|
||||
.text(data.current_score.toFixed(2))
|
||||
.removeClass(data.current_score > models[$('#select_model_to_simulate').val()].parameters.threshold ? 'alert-error' : 'alert-success')
|
||||
.addClass(data.current_score > models[$('#select_model_to_simulate').val()].parameters.threshold ? 'alert-success' : 'alert-error');
|
||||
|
||||
},
|
||||
error:function() {
|
||||
showMessage('fail', '<?php echo __('Failed to perform the simulation') ?>');
|
||||
},
|
||||
complete:function() {
|
||||
simulation_chart.toggleLoading(false);
|
||||
simulation_table.toggleLoading(false);
|
||||
},
|
||||
type:'get',
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
url: url,
|
||||
});
|
||||
}
|
||||
|
||||
function refreshSimulation() {
|
||||
var $row = $('#attribute_div tr.success');
|
||||
var attribute_id = $row.find('td:first').text();
|
||||
if (attribute_id !== '') {
|
||||
doSimulation($row, attribute_id);
|
||||
}
|
||||
}
|
||||
|
||||
function modelChangeHandler(clicked) {
|
||||
$('#select_model_to_simulate_infobox').popover('show');
|
||||
refreshSimulation();
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,30 @@
|
|||
<div class="form">
|
||||
<?php echo $this->Form->create('DecayingModel', array('enctype' => 'multipart/form-data'));?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('Import model data');?></legend>
|
||||
<p><?php echo __('Paste a MISP model JSON or provide a JSON file below to add models.');?></p>
|
||||
<div>
|
||||
<?php
|
||||
echo $this->Form->input('json', array(
|
||||
'div' => 'input clear',
|
||||
'label' => __('JSON'),
|
||||
'placeholder' => __('Model JSON'),
|
||||
'class' => 'form-control span6',
|
||||
'type' => 'textarea',
|
||||
'rows' => 18
|
||||
));
|
||||
echo $this->Form->input('submittedjson', array(
|
||||
'div' => 'input clear',
|
||||
'label' => __('JSON file'),
|
||||
'type' => 'file'
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo $this->Form->button(__('Add'), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => 'import'));
|
|
@ -0,0 +1,191 @@
|
|||
<div class="templates index">
|
||||
<h2><?php echo __('Decaying Models');?></h2>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
$this->Paginator->options(array(
|
||||
'update' => '.span12',
|
||||
'evalScripts' => true,
|
||||
'before' => '$(".progress").show()',
|
||||
'complete' => '$(".progress").hide()',
|
||||
));
|
||||
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$temp = $passedArgsArray;
|
||||
unset($temp['sort']);
|
||||
unset($temp['direction']);
|
||||
$filter_active = count(array_keys($temp)) > 0;
|
||||
$data = array(
|
||||
'children' => array(
|
||||
array(
|
||||
'children' => array(
|
||||
array(
|
||||
'title' => __('All Models'),
|
||||
'text' => __('All Models'),
|
||||
'url' => sprintf('%s/%s%s',
|
||||
$baseurl . '/decayingModel/index',
|
||||
isset($passedArgsArray['sort']) ? 'sort:' . $passedArgsArray['sort'] . '/' : '',
|
||||
isset($passedArgsArray['direction']) ? 'direction:' . $passedArgsArray['direction'] . '/' : ''
|
||||
),
|
||||
'class' => 'searchFilterButton',
|
||||
'active' => !$filter_active
|
||||
),
|
||||
array(
|
||||
'title' => __('My models only'),
|
||||
'text' => __('My Models'),
|
||||
'url' => sprintf('%s/%s%s%s',
|
||||
$baseurl . '/decayingModel/index',
|
||||
isset($passedArgsArray['sort']) ? 'sort:' . $passedArgsArray['sort'] . '/' : '',
|
||||
isset($passedArgsArray['direction']) ? 'direction:' . $passedArgsArray['direction'] . '/' : '',
|
||||
'my_models:' . (!isset($passedArgsArray['my_models']) || !$passedArgsArray['my_models'] ? '1' : '0')
|
||||
),
|
||||
'class' => 'searchFilterButton',
|
||||
'active' => isset($passedArgsArray['my_models']) && $passedArgsArray['my_models']
|
||||
),
|
||||
array(
|
||||
'title' => __('Models available to everyone'),
|
||||
'text' => __('Shared Models'),
|
||||
'url' => sprintf('%s/%s%s%s',
|
||||
$baseurl . '/decayingModel/index',
|
||||
isset($passedArgsArray['sort']) ? 'sort:' . $passedArgsArray['sort'] . '/' : '',
|
||||
isset($passedArgsArray['direction']) ? 'direction:' . $passedArgsArray['direction'] . '/' : '',
|
||||
'all_orgs:' . (!isset($passedArgsArray['all_orgs']) || !$passedArgsArray['all_orgs'] ? '1' : '0')
|
||||
),
|
||||
'class' => 'searchFilterButton',
|
||||
'active' => isset($passedArgsArray['all_orgs']) && $passedArgsArray['all_orgs']
|
||||
),
|
||||
array(
|
||||
'title' => __('Default models only'),
|
||||
'text' => __('Default Models'),
|
||||
'url' => sprintf('%s/%s%s%s',
|
||||
$baseurl . '/decayingModel/index',
|
||||
isset($passedArgsArray['sort']) ? 'sort:' . $passedArgsArray['sort'] . '/' : '',
|
||||
isset($passedArgsArray['direction']) ? 'direction:' . $passedArgsArray['direction'] . '/' : '',
|
||||
'default_models:' . (!isset($passedArgsArray['default_models']) || !$passedArgsArray['default_models'] ? '1' : '0')
|
||||
),
|
||||
'class' => 'searchFilterButton',
|
||||
'active' => isset($passedArgsArray['default_models']) && $passedArgsArray['default_models']
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
echo $this->element('/genericElements/ListTopBar/scaffold', array('data' => $data));
|
||||
?>
|
||||
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?php echo $this->Paginator->sort('ID');?></th>
|
||||
<th><?php echo $this->Paginator->sort('org', __('Organization'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('all_orgs', __('Usable to everyone'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('name', __('Name'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('description', __('Description'));?></th>
|
||||
<th>
|
||||
<?php echo __('Parameters'); ?>
|
||||
<a class="useCursorPointer" title="<?php echo __('Pretty print') ?>"><b style="font-size: larger;" onclick="prettyPrintJson();">{ }</b></a>
|
||||
|
||||
</th>
|
||||
<th><?php echo $this->Paginator->sort('formula', __('Formula'));?></th>
|
||||
<th><?php echo __('# Assigned Types') ?></th>
|
||||
<th><?php echo $this->Paginator->sort('version', __('Version'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('enabled', __('Enabled'));?></th>
|
||||
<th class="actions"><?php echo __('Actions');?></th>
|
||||
</tr><?php
|
||||
foreach ($decayingModels as $item): ?>
|
||||
<tr>
|
||||
<td class="short"><a href="<?php echo $baseurl."/decayingModel/view/" . h($item['DecayingModel']['id']); ?>"><?php echo h($item['DecayingModel']['id']); ?> </a></td>
|
||||
<td class="short">
|
||||
<?php
|
||||
echo $this->OrgImg->getOrgImg(array('name' => $item['DecayingModel']['org_id'], 'size' => 24));
|
||||
?>
|
||||
|
||||
</td>
|
||||
<td><i class="fas fa-<?php echo $item['DecayingModel']['all_orgs'] ? 'check' : 'times';?>"></i></td>
|
||||
<td>
|
||||
<a href="<?php echo $baseurl."/decayingModel/view/" . h($item['DecayingModel']['id']); ?>"><?php echo h($item['DecayingModel']['name']); ?> </a>
|
||||
<?php if ($item['DecayingModel']['default']): ?>
|
||||
<img src="<?php echo $baseurl;?>/img/orgs/MISP.png" width="24" height="24" style="padding-bottom:3px;" title="<?php echo __('Default Model from MISP Project'); ?>" />
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo h($item['DecayingModel']['description']); ?> </td>
|
||||
<?php
|
||||
if (isset($item['DecayingModel']['parameters']['base_score_config']) && empty($item['DecayingModel']['parameters']['base_score_config'])) {
|
||||
$item['DecayingModel']['parameters']['base_score_config'] = new stdClass(); // force output to be {} instead of []
|
||||
}
|
||||
?>
|
||||
<td data-toggle="json" ondblclick="document.location.href ='<?php echo $baseurl . '/decayingModel/view/' . h($item['DecayingModel']['id']); ?>'"><?php echo h(json_encode($item['DecayingModel']['parameters'])); ?> </td>
|
||||
<td>
|
||||
<?php echo h($item['DecayingModel']['formula']); ?>
|
||||
<?php if (isset($available_formulas[$item['DecayingModel']['formula']]['description'])): ?>
|
||||
<i class="fas fa-question-circle" data-toggle="tooltip" title="<?php echo h($available_formulas[$item['DecayingModel']['formula']]['description']); ?>"></i>
|
||||
<?php else: ?>
|
||||
 
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo count($item['DecayingModel']['attribute_types']); ?> </td>
|
||||
<td><?php echo h($item['DecayingModel']['version']); ?> </td>
|
||||
<td><i class="fas fa-<?php echo $item['DecayingModel']['enabled'] ? 'check' : 'times';?>"></i></td>
|
||||
<td class="short action-links">
|
||||
<?php echo $this->Html->link('', array('action' => 'view', $item['DecayingModel']['id']), array('class' => 'icon-list-alt', 'title' => 'View'));?>
|
||||
<?php echo $this->Html->link('', array('action' => 'export', $item['DecayingModel']['id'] . '.json'), array('download' => true, 'class' => 'fa fa-cloud-download-alt', 'title' => __('Download model')));?>
|
||||
<?php if ($me['Role']['perm_admin']): ?>
|
||||
<?php if ($me['Role']['perm_site_admin'] || $item['DecayingModel']['org_id'] == $me['org_id']): ?>
|
||||
<?php
|
||||
if (!$item['DecayingModel']['default']) {
|
||||
echo $this->Form->postLink('', array('action' => 'delete', $item['DecayingModel']['id']), array('class' => 'icon-trash', 'title' => 'Delete'), __('Are you sure you want to delete DecayingModel #' . h($item['DecayingModel']['id']) . '?'));
|
||||
}
|
||||
?>
|
||||
<?php echo $this->Html->link('', array('action' => 'edit', $item['DecayingModel']['id']), array('class' => 'icon-edit', 'title' => 'Edit'));?>
|
||||
<?php
|
||||
if ($item['DecayingModel']['enabled']):
|
||||
echo $this->Form->postLink('', array('action' => 'disable', $item['DecayingModel']['id']), array('class' => 'fa fa-pause', 'title' => 'Disable model'), __('Are you sure you want to disable DecayingModel #' . h($item['DecayingModel']['id']) . '?'));
|
||||
else:
|
||||
echo $this->Form->postLink('', array('action' => 'enable', $item['DecayingModel']['id']), array('class' => 'fa fa-play', 'title' => 'Enable model'), __('Are you sure you want to enable DecayingModel #' . h($item['DecayingModel']['id']) . '?'));
|
||||
endif;
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr><?php
|
||||
endforeach; ?>
|
||||
</table>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
function prettyPrintJson() {
|
||||
$('[data-toggle=\"json\"]').each(function() {
|
||||
$(this).attr('data-toggle', '')
|
||||
.html(syntaxHighlightJson($(this).text().trim()));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => 'index'));
|
||||
?>
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
$table_data = array();
|
||||
$table_data[] = array('key' => __('Model ID'), 'value' => $decaying_model['DecayingModel']['id']);
|
||||
$table_data[] = array(
|
||||
'key' => __('Creator org'),
|
||||
'html' => sprintf(
|
||||
'<a href="%s/organisations/view/%s">%s</a>',
|
||||
$baseurl,
|
||||
h($decaying_model['DecayingModel']['org_id']),
|
||||
h($decaying_model['DecayingModel']['org_id'])
|
||||
)
|
||||
);
|
||||
$table_data[] = array(
|
||||
'key' => __('Name'),
|
||||
'html' => sprintf(
|
||||
'%s %s',
|
||||
h($decaying_model['DecayingModel']['name']),
|
||||
$decaying_model['DecayingModel']['default'] ? '<img src="' . $baseurl . '/img/orgs/MISP.png" width="24" height="24" style="padding-bottom:3px;" title="' . __('Default Model from MISP Project') . '" />' : ''
|
||||
)
|
||||
);
|
||||
$table_data[] = array('key' => __('Description'), 'value' => $decaying_model['DecayingModel']['description']);
|
||||
if (isset($decaying_model['DecayingModel']['parameters']['base_score_config']) && empty($decaying_model['DecayingModel']['parameters']['base_score_config'])) {
|
||||
$decaying_model['DecayingModel']['parameters']['base_score_config'] = new stdClass(); // force output to be {} instead of []
|
||||
}
|
||||
$table_data[] = array('key' => __('Version'), 'value' => $decaying_model['DecayingModel']['version']);
|
||||
$table_data[] = array(
|
||||
'key' => __('All orgs'),
|
||||
'html' => '<i class="fas fa-' . ($decaying_model['DecayingModel']['all_orgs'] ? 'check' : 'times') . '"></i>'
|
||||
);
|
||||
$table_data[] = array(
|
||||
'key' => __('Enabled'),
|
||||
'html' => '<i class="fas fa-' . ($decaying_model['DecayingModel']['enabled'] ? 'check' : 'times') . '"></i>'
|
||||
);
|
||||
$table_data[] = array(
|
||||
'key' => __('Formula'),
|
||||
'html' => h($decaying_model['DecayingModel']['formula']) . (
|
||||
isset($available_formulas[$decaying_model['DecayingModel']['formula']]['description']) ? sprintf(' <i class="fas fa-question-circle" data-toggle="tooltip" title="%s"></i>', h($available_formulas[$decaying_model['DecayingModel']['formula']]['description'])) : ''
|
||||
)
|
||||
);
|
||||
$table_data[] = array('key' => __('Parameters'), 'value' => json_encode($decaying_model['DecayingModel']['parameters']), 'class' => 'json-transform');
|
||||
$table_data[] = array('key' => __('Reference(s)'), 'html' => implode('<br/>', (empty($decaying_model['DecayingModel']['ref']) ? array() : h($decaying_model['DecayingModel']['ref']))));
|
||||
$table_data[] = array('key' => __('Associated types'), 'value' => json_encode($decaying_model['DecayingModel']['attribute_types']), 'class' => 'json-transform');
|
||||
?>
|
||||
<div class='view'>
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
<?php echo $this->element('genericElements/viewMetaTable', array('table_data' => $table_data)); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('td.meta_table_value.json-transform').each(function(i) {
|
||||
var parsedJson = syntaxHighlightJson($(this).text().trim());
|
||||
$(this).html(parsedJson);
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip({placement: 'right'});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => 'view'));
|
||||
?>
|
|
@ -0,0 +1,21 @@
|
|||
<div class="form">
|
||||
<?php echo $this->Form->create('DecayingModelMapping');?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('Add DecayingModelMapping');?></legend>
|
||||
<?php
|
||||
echo $this->Form->input('model_id', array(
|
||||
'hidden' => true,
|
||||
'value' => $model_id
|
||||
));
|
||||
echo $this->Form->input('attributetypes', array());
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo $this->Form->button(__('Add'), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'decayingModel', 'menuItem' => 'add'));
|
||||
?>
|
|
@ -0,0 +1,18 @@
|
|||
<div>
|
||||
<?php if (isset($object['decay_score'])): ?>
|
||||
<?php foreach ($object['decay_score'] as $dc): ?>
|
||||
<?php $class_score = $dc['decayed'] ? 'alert-error' : 'alert-success'; ?>
|
||||
<?php echo(isset($uselink) && $uselink ? '<a' : '<div') ?>
|
||||
target="_blank"
|
||||
href="/decayingModel/decayingToolSimulation/<?php echo h($dc['DecayingModel']['id']); ?>/attribute_id:<?php echo h($object['id']); ?>"
|
||||
style="display: block; margin-bottom: 3px;"
|
||||
class="input-prepend input-append"
|
||||
>
|
||||
<span class="add-on ellipsis-overflow" style="max-width: 12em;" title="<?php echo h($dc['DecayingModel']['name']); ?>"><?php echo h($dc['DecayingModel']['name']); ?></span>
|
||||
<span id="simulation-current-score" class="add-on <?php echo $class_score ?>"><?php echo round($dc['score'], 2) ?></span>
|
||||
<?php echo(isset($uselink) && $uselink ? '</a>' : '</div>') ?>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
|
@ -0,0 +1,20 @@
|
|||
<div id="computation_help_container" style="margin-bottom: 0px; border: 1px solid #dddddd; border-radius: 4px; text-align: center; background-color: white; overflow: auto; ">
|
||||
<table class="table histogram-legendH4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" style="vertical-align: middle;"><?php echo __('Tag') ?></th>
|
||||
<th colspan="3"><?php echo __('Computation') ?></th>
|
||||
<th rowspan="2" style="vertical-align: middle;"><?php echo __('Result') ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="padding: 0px; width: 50px;" title="<?php echo __('Taxonomy effective ratio') ?>"><?php echo __('Eff. Ratio') ?></th>
|
||||
<th></th>
|
||||
<th style="padding: 0px; width: 50px;" title="<?php echo __('Tag numerical value') ?>"><?php echo __('Value') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="computation_help_container_body">
|
||||
<tr><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<b id="pick_notice"><?php echo __('Pick an Attribute') ?></b>
|
||||
</div>
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
$tr_class = array('useCursorPointer');
|
||||
if (!empty($object['object_relation'])) {
|
||||
$tr_class[] = '';
|
||||
}
|
||||
$tr_class = implode(' ', $tr_class);
|
||||
?>
|
||||
<tr id = "Attribute_<?php echo h($object['id']); ?>_tr" class="<?php echo $tr_class; ?>" tabindex="0" onclick="doSimulation(this, <?php echo h($object['id']); ?>)">
|
||||
<td class="short">
|
||||
<?php echo h($object['id']); ?>
|
||||
</td>
|
||||
<td class="short">
|
||||
<a href="<?php echo $baseurl . '/events/view/' . h($object['event_id']) ?>" target="_blank"><?php echo h($object['event_id']); ?></a>
|
||||
</td>
|
||||
<td class="short">
|
||||
<?php echo date('Y-m-d', $object['timestamp']); ?>
|
||||
</td>
|
||||
<td class="short">
|
||||
<?php echo $this->OrgImg->getOrgImg(array('name' => $event['Orgc']['name'], 'id' => $event['Orgc']['id'], 'size' => 24)); ?>
|
||||
|
||||
</td>
|
||||
<td class="short">
|
||||
<div id = "Attribute_<?php echo $object['id']; ?>_category_solid" class="inline-field-solid">
|
||||
<?php echo h($object['category']); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td class="short">
|
||||
<?php if (!empty($object['object_relation'])): ?>
|
||||
<div class="bold"><?php echo h($object['object_relation']); ?>:</div>
|
||||
<?php endif; ?>
|
||||
<div id = "Attribute_<?php echo $object['id']; ?>_type_solid" class="inline-field-solid">
|
||||
<?php echo h($object['type']); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td id="Attribute_<?php echo h($object['id']); ?>_container" class="showspaces limitedWidth shortish">
|
||||
<div id = "Attribute_<?php echo $object['id']; ?>_value_solid" class="inline-field-solid" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
||||
<span style="white-space: nowrap;" title="<?php echo $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => 'blue')) ?>"><?php echo $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => 'blue')) ?></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="shortish">
|
||||
<div class="attributeTagContainer" id="#Attribute_<?php echo h($object['id']);?>_tr .attributeTagContainer">
|
||||
<?php echo $this->element('ajaxAttributeTags', array('attributeId' => $object['id'], 'attributeTags' => $object['AttributeTag'], 'tagAccess' => false)); ?>
|
||||
</div>
|
||||
</td>
|
||||
<?php
|
||||
$element = '';
|
||||
if (!empty($object['EventTag'])) {
|
||||
$element = $this->element('ajaxAttributeTags', array('attributeId' => $object['id'], 'attributeTags' => $object['EventTag'], 'tagAccess' => false));
|
||||
}
|
||||
echo sprintf(
|
||||
'<td class="shortish"><div %s>%s</div></td>',
|
||||
'class="attributeRelatedTagContainer" id="#Attribute_' . h($object['id']) . 'Related_tr .attributeTagContainer"',
|
||||
$element
|
||||
);
|
||||
?>
|
||||
<td class="short" id="attribute_<?php echo h($object['id']); ?>_galaxy">
|
||||
<?php
|
||||
echo $this->element('galaxyQuickViewMini', array(
|
||||
'mayModify' => false,
|
||||
'isSiteAdmin' => false, // prevent add button
|
||||
'isAclTagger' => false,
|
||||
'data' => (!empty($object['Galaxy']) ? $object['Galaxy'] : array()),
|
||||
'target_id' => $object['id'],
|
||||
'target_type' => 'attribute'
|
||||
));
|
||||
?>
|
||||
</td>
|
||||
<td class="showspaces bitwider">
|
||||
<div id = "Attribute_<?php echo $object['id']; ?>_comment_solid" class="inline-field-solid">
|
||||
<?php echo nl2br(h($object['comment'])); ?>
|
||||
</div>
|
||||
</td>
|
||||
<td class="short">
|
||||
<div id = "Attribute_<?php echo $object['id']; ?>_to_ids_solid" class="inline-field-solid">
|
||||
<span class="fa fa-<?php echo $object['to_ids'] ? 'check' : 'times' ; ?>"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="short">
|
||||
<?php
|
||||
if (!empty($sightingsData['csv'][$object['id']])) {
|
||||
echo $this->element('sparkline', array('scope' => 'object', 'id' => $object['id'], 'csv' => $sightingsData['csv'][$object['id']]));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="short">
|
||||
<div id = "Attribute_<?php echo $object['id']; ?>_score_solid" class="inline-field-solid">
|
||||
<?php echo $this->element('DecayingModels/View/attribute_decay_score', array('scope' => 'object', 'object' => $object, 'uselink' => false)); ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
|
@ -120,6 +120,20 @@ function triggerEventFilteringTool(hide) {
|
|||
1: "Yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": "radio",
|
||||
"type": "integer",
|
||||
"operators": [
|
||||
"equal",
|
||||
],
|
||||
"unique": true,
|
||||
"id": "includeDecayScore",
|
||||
"label": "Decay Score",
|
||||
"values": {
|
||||
0: "No",
|
||||
1: "Yes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": "radio",
|
||||
"type": "integer",
|
||||
|
@ -310,6 +324,13 @@ function triggerEventFilteringTool(hide) {
|
|||
value: <?php echo isset($filters['includeRelatedTags']) ? h($filters['includeRelatedTags']) : 0; ?>
|
||||
},
|
||||
<?php endif; ?>
|
||||
<?php if (count($advancedFilteringActiveRules) == 0 || isset($advancedFilteringActiveRules['includeDecayScore'])): ?>
|
||||
{
|
||||
field: 'includeDecayScore',
|
||||
id: 'includeDecayScore',
|
||||
value: <?php echo isset($filters['includeDecayScore']) ? h($filters['includeDecayScore']) : 0; ?>
|
||||
},
|
||||
<?php endif; ?>
|
||||
<?php if (count($advancedFilteringActiveRules) == 0 || isset($advancedFilteringActiveRules['toIDS'])): ?>
|
||||
{
|
||||
field: 'toIDS',
|
||||
|
|
|
@ -348,6 +348,13 @@
|
|||
'page' => $page
|
||||
));
|
||||
?>
|
||||
<?php if (!empty($includeDecayScore)): ?>
|
||||
<td class="decayingScoreField">
|
||||
<div id = "Attribute_<?php echo h($object['id']); ?>_score_solid" class="inline-field-solid">
|
||||
<?php echo $this->element('DecayingModels/View/attribute_decay_score', array('scope' => 'object', 'object' => $object, 'uselink' => true)); ?>
|
||||
</div>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td class="short action-links">
|
||||
<?php
|
||||
if ($object['deleted']):
|
||||
|
|
|
@ -112,6 +112,9 @@
|
|||
</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<?php if (!empty($includeDecayScore)): ?>
|
||||
<td class="decayingScoreField"> </td>
|
||||
<?php endif; ?>
|
||||
<td class="short action-links">
|
||||
<?php
|
||||
if ($mayModify && empty($object['deleted'])) {
|
||||
|
|
|
@ -174,6 +174,9 @@
|
|||
<td class="shortish"> </td>
|
||||
<td class="shortish"> </td>
|
||||
<td class="short"> </td>
|
||||
<?php if (!empty($includeDecayScore)): ?>
|
||||
<td class="decayingScoreField"> </td>
|
||||
<?php endif; ?>
|
||||
<td class="short action-links">
|
||||
<?php
|
||||
if (($event['Orgc']['id'] == $me['org_id'] && $mayModify) || $isSiteAdmin) {
|
||||
|
|
|
@ -163,6 +163,10 @@
|
|||
<th title="<?php echo $attrDescriptions['distribution']['desc'];?>"><?php echo $this->Paginator->sort('distribution');?></th>
|
||||
<th><?php echo __('Sightings');?></th>
|
||||
<th><?php echo __('Activity');?></th>
|
||||
<?php if ($includeDecayScore): ?>
|
||||
<th class="decayingScoreField" title="<?php echo __('Decaying Score');?>"><?php echo __('Score');?></th>
|
||||
<?php $fieldCount += 1; ?>
|
||||
<?php endif; ?>
|
||||
<th class="actions"><?php echo __('Actions');?></th>
|
||||
</tr>
|
||||
<?php
|
||||
|
@ -182,7 +186,8 @@
|
|||
'mayChangeCorrelation' => $mayChangeCorrelation,
|
||||
'page' => $page,
|
||||
'fieldCount' => $fieldCount,
|
||||
'includeRelatedTags' => !empty($includeRelatedTags) ? 1 : 0
|
||||
'includeRelatedTags' => !empty($includeRelatedTags) ? 1 : 0,
|
||||
'includeDecayingScore' => !empty($includeDecayingScore) ? 1 : 0
|
||||
));
|
||||
if (!empty($focus) && ($object['objectType'] == 'object' || $object['objectType'] == 'attribute') && $object['uuid'] == $focus) {
|
||||
$focusedRow = $k;
|
||||
|
|
|
@ -168,6 +168,15 @@
|
|||
'onClickParams' => array($urlHere, 'deleted'),
|
||||
'requirement' => ($me['Role']['perm_sync'] || $event['Orgc']['id'] == $me['org_id'])
|
||||
),
|
||||
array(
|
||||
'id' => 'show_attribute_decaying_score',
|
||||
'title' => __('Show attribute decaying score'),
|
||||
'fa-icon' => 'chart-line',
|
||||
'text' => __('Decay score'),
|
||||
'active' => $includeDecayScore,
|
||||
'onClick' => 'toggleBoolFilter',
|
||||
'onClickParams' => array($urlHere, 'includeDecayScore')
|
||||
),
|
||||
array(
|
||||
'id' => 'show_attribute_context',
|
||||
'title' => __('Show attribute context fields'),
|
||||
|
|
|
@ -914,6 +914,55 @@
|
|||
}
|
||||
break;
|
||||
|
||||
case 'decayingModel':
|
||||
if ($isAdmin) {
|
||||
if ($isSiteAdmin && ($menuItem === 'view' || $menuItem === 'index')) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_post_link', array(
|
||||
'event_id' => 'update',
|
||||
'url' => '/decayingModel/update',
|
||||
'text' => __('Update Default Models')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_post_link', array(
|
||||
'event_id' => 'update',
|
||||
'url' => '/decayingModel/update/true',
|
||||
'text' => __('Force Update Default Models')
|
||||
));
|
||||
}
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => '/decayingModel/import',
|
||||
'text' => __('Import Decaying Model')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_divider');
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => '/decayingModel/add',
|
||||
'text' => __('Add Decaying Model')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => '/decayingModel/decayingTool',
|
||||
'text' => __('Decaying Tool')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_divider');
|
||||
}
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => '/decayingModel/index',
|
||||
'text' => __('List Decaying Models')
|
||||
));
|
||||
if (($menuItem === 'view' || $menuItem === 'edit')) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'view',
|
||||
'url' => '/decayingModel/view/' . h($id),
|
||||
'text' => __('View Decaying Model')
|
||||
));
|
||||
if ($isSiteAdmin) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'edit',
|
||||
'url' => '/decayingModel/edit/' . h($id),
|
||||
'text' => __('Edit Decaying Model')
|
||||
));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'feeds':
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => '/feeds/index',
|
||||
|
|
|
@ -182,6 +182,18 @@
|
|||
array(
|
||||
'type' => 'separator'
|
||||
),
|
||||
array(
|
||||
'text' => __('Decaying Models Tool'),
|
||||
'url' => '/decayingModel/decayingTool',
|
||||
'requirement' => $isAdmin
|
||||
),
|
||||
array(
|
||||
'text' => __('Decaying Models'),
|
||||
'url' => '/decayingModel/index',
|
||||
),
|
||||
array(
|
||||
'type' => 'separator'
|
||||
),
|
||||
array(
|
||||
'text' => __('User Guide'),
|
||||
'url' => 'https://www.circl.lu/doc/misp/'
|
||||
|
@ -291,7 +303,6 @@
|
|||
),
|
||||
array(
|
||||
'type' => 'separator',
|
||||
'requirement' => $isSiteAdmin
|
||||
),
|
||||
array(
|
||||
'text' => __('Server Settings & Maintenance'),
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<body>
|
||||
<div id="popover_form" class="ajax_popover_form"></div>
|
||||
<div id="popover_form_large" class="ajax_popover_form ajax_popover_form_large"></div>
|
||||
<div id="popover_form_x_large" class="ajax_popover_form ajax_popover_form_x_large"></div>
|
||||
<div id="popover_matrix" class="ajax_popover_form ajax_popover_matrix"></div>
|
||||
<div id="popover_box" class="popover_box"></div>
|
||||
<div id="screenshot_box" class="screenshot_box"></div>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f38d1604f1fbd602d59d5a88fd906a2d7c21dfb3
|
|
@ -0,0 +1,181 @@
|
|||
/* decaying tool */
|
||||
#table_type_search {
|
||||
width: 250px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.AttributeTypeTableContainer {
|
||||
height: calc(100vh - 175px - 25px);
|
||||
overflow-y: scroll;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.decayingGraphLine {
|
||||
fill: none;
|
||||
stroke: steelblue;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.decayingGraphLineThres {
|
||||
fill: none;
|
||||
stroke: firebrick;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.decayingGraphArea {
|
||||
fill: lightsteelblue;
|
||||
}
|
||||
|
||||
.decayingGraphAreaThres {
|
||||
fill: firebrick;
|
||||
}
|
||||
|
||||
.decayingGraphDot{
|
||||
stroke: #ffffff;
|
||||
fill: #da4f49;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.decayingGraphHandleDot{
|
||||
stroke: #ffffff;
|
||||
fill: steelblue;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
.decayingGraphAxis path {
|
||||
stroke-width: 2px;
|
||||
stroke: #000;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.decayingGraphAxis line {
|
||||
stroke: #000;
|
||||
}
|
||||
|
||||
.decayingGraphAxis text {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.decayingGraphAxis.grid line {
|
||||
stroke: lightgrey;
|
||||
stroke-opacity: 0.7;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.decayingGraphAxis.grid path {
|
||||
stroke-width: 0;
|
||||
}
|
||||
|
||||
|
||||
/* decaying basescore */
|
||||
#basescore_configurator {
|
||||
overflow: auto;
|
||||
padding: 15px;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
#basescore_configurator > div.taxonomyTableContainer {
|
||||
height: calc(90vh);
|
||||
overflow-y: scroll;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#basescore_configurator #body_taxonomies .taxonomySlider {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
margin: 0px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
#basescore_configurator #body_taxonomies span.numerical-value-label {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
margin-top: -9px;
|
||||
}
|
||||
|
||||
#treemapGraphTax {
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#basescore_configurator div.org-source-confidence-placeholder {
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#basescore_configurator #tableExamples td.basescore-example-score {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.decayingExampleTags {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
/* decaying simulation */
|
||||
div.simulationSubContainer{
|
||||
padding: 15px;
|
||||
height: 90vh;
|
||||
min-width: 1600px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#select_model_to_simulate_infobox {
|
||||
padding: 4px;
|
||||
height: fit-content;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#simulationContainer #restSearchTextarea {
|
||||
margin-bottom: 0px;
|
||||
margin-left: 4px;
|
||||
flex-grow: 3;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
div.loading-spinner-container {
|
||||
height:100%;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 500px;
|
||||
height: 100%;
|
||||
padding-bottom: 100%; /* aspect ratio */
|
||||
vertical-align: top;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-content-responsive {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
svg text.axis-label {
|
||||
font: 10px sans-serif;
|
||||
fill: #999;
|
||||
}
|
||||
|
||||
.tableRadioFilterOptionsContainer {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
margin-left: 10px;
|
||||
border-top: 1px solid #ddd;
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
|
@ -891,6 +891,13 @@ a.proposal_link_red:hover {
|
|||
.ajax_popover_form_large {
|
||||
width: 1400px;
|
||||
left: calc(50% - 700px);
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.ajax_popover_form_x_large {
|
||||
width: 1700px;
|
||||
left: calc(50% - 850px);
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.ajax_popover_matrix {
|
||||
|
@ -1124,6 +1131,10 @@ li .generic-picker-item-element-check {
|
|||
z-index:-111;
|
||||
}
|
||||
|
||||
span.success {
|
||||
background-color: #d0e9c6 !important;
|
||||
}
|
||||
|
||||
.ajaxMessage {
|
||||
display:none;
|
||||
margin-left:10px;
|
||||
|
@ -1139,6 +1150,14 @@ li .generic-picker-item-element-check {
|
|||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.panel-container {
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 4px;
|
||||
background-color: #fafafa;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.inline-input {
|
||||
width:100% !important;
|
||||
margin-bottom:0px !important;
|
||||
|
@ -1260,6 +1279,10 @@ li .generic-picker-item-element-check {
|
|||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.cellHeavyTopBorder {
|
||||
border-top: 2px solid #000;
|
||||
}
|
||||
|
||||
.tabMenuFilterFieldHeader {
|
||||
border-radius: 10px 0px 0 0 !important;
|
||||
height:14px !important;
|
||||
|
@ -1545,6 +1568,13 @@ li .generic-picker-item-element-check {
|
|||
border-top:0px !important;
|
||||
}
|
||||
|
||||
.fa.helptext-in-cell, .fas.helptext-in-cell {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
|
||||
.templateTableHeader {
|
||||
display:inline-block;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,664 @@
|
|||
(function(factory) {
|
||||
"use strict";
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['jquery'], factory);
|
||||
} else if (window.jQuery && !window.jQuery.fn.DecayingSimulation) {
|
||||
factory(window.jQuery);
|
||||
}
|
||||
}
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var DecayingSimulation = function(container, options, data) {
|
||||
this.container_id = '#' + container.id;
|
||||
this.$container = $(container);
|
||||
this._validateOptions(options);
|
||||
var default_options = {
|
||||
tick_num: 300,
|
||||
margin: {top: 10, right: 10, bottom: 35, left: 35},
|
||||
animation_duration: 250,
|
||||
animation_short_duration: 100,
|
||||
redraw_timeout: 200,
|
||||
time_format: '%Y-%m-%d %H:%M:%S'
|
||||
};
|
||||
this.options = $.extend(true, {}, default_options, options);
|
||||
this.chart_data = [];
|
||||
this.sightings = [];
|
||||
this._init();
|
||||
this._init_canvas();
|
||||
if (data !== undefined) {
|
||||
this.update(data)
|
||||
}
|
||||
};
|
||||
|
||||
DecayingSimulation.prototype = {
|
||||
constructor: DecayingSimulation,
|
||||
|
||||
_validateOptions: function(options) {
|
||||
|
||||
},
|
||||
_init: function() {
|
||||
var that = this;
|
||||
this.$loadingContainer = $('<div id="loadingSimulationContainer" style="background: #ffffff9f"><span class="fa fa-spinner fa-spin" style="font-size: xx-large;"></span></div>').css({
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
right: '0',
|
||||
top: '0',
|
||||
bottom: '0',
|
||||
display: 'flex',
|
||||
'align-items': 'center',
|
||||
'justify-content': 'center'
|
||||
}).hide();
|
||||
this.tooltip_container = d3.select('body').append('div')
|
||||
.classed('tooltip', true)
|
||||
.style('opacity', 0)
|
||||
.style('padding', '3px')
|
||||
.style('background-color', '#000')
|
||||
.style('color', 'white')
|
||||
.style('border-radius', '5px')
|
||||
.style('display', 'none');
|
||||
this.$container.append(this.$loadingContainer);
|
||||
this.timeFormatter = d3.time.format(this.options.time_format).parse;
|
||||
},
|
||||
|
||||
_init_canvas: function() {
|
||||
var that = this;
|
||||
this.$container.empty();
|
||||
this.svg_width = this.$container.width();
|
||||
this.svg_height = this.$container.height();
|
||||
this.width = this.svg_width - this.options.margin.left - this.options.margin.right;
|
||||
this.height = this.svg_height - this.options.margin.top - this.options.margin.bottom;
|
||||
|
||||
this.x = d3.time.scale()
|
||||
.domain(d3.extent(this.chart_data, function(d) { return d.date; }))
|
||||
.range([ 0, this.width ]);
|
||||
this.y = d3.scale.linear()
|
||||
.domain([0, 100])
|
||||
.range([ this.height, 0 ]);
|
||||
|
||||
this.yGrid = d3.svg.axis().scale(this.x).orient("bottom")
|
||||
.tickSize(-this.height)
|
||||
.tickFormat("");
|
||||
this.xGrid = d3.svg.axis().scale(this.y).orient("left")
|
||||
.ticks(3)
|
||||
.tickSize(-this.width)
|
||||
.tickFormat("");
|
||||
|
||||
this.value_line = d3.svg.line()
|
||||
.x(function(d) { return that.x(d.date); })
|
||||
.y(function(d) { return that.y(d.value); });
|
||||
|
||||
this.svg = d3.select(this.container_id)
|
||||
.append("svg")
|
||||
.classed('svg-content-responsive', true)
|
||||
.attr("width", this.svg_width)
|
||||
.attr("height", this.svg_height)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + this.options.margin.left + "," + this.options.margin.top + ")");
|
||||
|
||||
this.svg.append("g")
|
||||
.attr('class', 'decayingGraphAxis axis-x')
|
||||
.attr("transform", "translate(0," + this.height + ")")
|
||||
this.svg.append("g")
|
||||
.attr('class', 'decayingGraphAxis axis-y')
|
||||
|
||||
this.svg.append("g")
|
||||
.attr("class", "decayingGraphAxis grid grid-x");
|
||||
this.svg.append("g")
|
||||
.attr("class", "decayingGraphAxis grid grid-y")
|
||||
.attr("transform", "translate(0," + this.height + ")");
|
||||
|
||||
this.svg.append("text")
|
||||
.classed('axis-label', true)
|
||||
.attr("text-anchor", "end")
|
||||
.attr("x", this.width / 2)
|
||||
.attr("y", this.height)
|
||||
.attr("dy", '30px')
|
||||
.text("Date");
|
||||
|
||||
this.svg.append("text")
|
||||
.classed('axis-label', true)
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("transform", "rotate(-90 0 " + this.height / 2 + ")")
|
||||
.attr("x", 0)
|
||||
.attr("dy", '-25px')
|
||||
.attr("y", this.height / 2)
|
||||
.text("Score");
|
||||
|
||||
this.svg.append('g')
|
||||
.classed('line-group', true);
|
||||
|
||||
this.svg
|
||||
.append("g")
|
||||
.classed("d3-line-guides-group", true);
|
||||
|
||||
this.svg.insert('g')
|
||||
.classed('circles', true);
|
||||
|
||||
window.addEventListener("resize", function() {
|
||||
if (that.resize_timeout !== undefined) {
|
||||
clearTimeout(that.resize_timeout);
|
||||
}
|
||||
that.resize_timeout = setTimeout(function() { that.redraw_timeout_handler(that) }, that.options.redraw_timeout);
|
||||
});
|
||||
},
|
||||
|
||||
redraw_timeout_handler: function(inst) {
|
||||
clearTimeout(inst.resize_timeout);
|
||||
inst._init_canvas();
|
||||
inst._draw();
|
||||
},
|
||||
|
||||
update: function(data, model) {
|
||||
this.raw_data = data;
|
||||
this.chart_data = data.csv;
|
||||
this.sightings = data.sightings;
|
||||
this.current_score = data.current_score;
|
||||
this.model = model;
|
||||
this._parseDataset();
|
||||
this._draw();
|
||||
},
|
||||
|
||||
_draw: function() {
|
||||
var that = this;
|
||||
this.x.domain(d3.extent(this.chart_data, function(d) { return d.date; }))
|
||||
|
||||
this.xAxis = this.svg.select('.axis-x')
|
||||
.call(d3.svg.axis().scale(this.x).orient('bottom'));
|
||||
this.yAxis = this.svg.select('.axis-y')
|
||||
.call(d3.svg.axis().scale(this.y).orient("left"));
|
||||
|
||||
this.svg.select('.grid-x')
|
||||
.call(this.xGrid);
|
||||
this.svg.select('.grid-y')
|
||||
.call(this.yGrid);
|
||||
|
||||
this.line = this.svg.select('.line-group')
|
||||
.selectAll('.line')
|
||||
.data([this.chart_data]);
|
||||
this.line
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr("class","line")
|
||||
.attr("fill", "none")
|
||||
.attr("stroke", "steelblue")
|
||||
.attr("stroke-width", 2.5)
|
||||
this.line
|
||||
.transition()
|
||||
.duration(this.options.animation_duration)
|
||||
.attr("d", this.value_line);
|
||||
this.line.exit().remove();
|
||||
|
||||
this.line_guides = this.svg
|
||||
.select('.d3-line-guides-group')
|
||||
.selectAll('.d3-line-guides')
|
||||
.data(this.sightings_data);
|
||||
this.line_guides
|
||||
.enter()
|
||||
.append('line')
|
||||
.attr('class', 'd3-line-guides')
|
||||
this.line_guides // Update
|
||||
.attr('x1', function(d) { return that.x(d.date); })
|
||||
.attr('y1', function(d) { return that.height; })
|
||||
.attr('x2', function(d) { return that.x(d.date); })
|
||||
.attr('y2', function(d) { return that.height; })
|
||||
.style("stroke", "rgba(70, 130, 180, 0.5)")
|
||||
.style("stroke-dasharray", "4,2")
|
||||
.style("shape-rendering", "crispEdges")
|
||||
.transition()
|
||||
.duration(this.options.animation_duration)
|
||||
.attr('y2', function(d) { return that.y(d.value); });
|
||||
this.line_guides.exit().remove();
|
||||
|
||||
// current time
|
||||
this.line_guide_now = this.svg
|
||||
.selectAll('.d3-line-now')
|
||||
.data([new Date()]);
|
||||
this.line_guide_now
|
||||
.enter()
|
||||
.append('line')
|
||||
.attr('class', 'd3-line-now')
|
||||
this.line_guide_now
|
||||
.attr('x1', function(d) { return that.x(d); })
|
||||
.attr('y1', function(d) { return that.y(0); })
|
||||
.attr('x2', function(d) { return that.x(d); })
|
||||
.attr('y2', function(d) { return that.y(101); })
|
||||
.style("stroke", "#000")
|
||||
.attr("stroke-width", 2)
|
||||
.on('mouseover', function(d) {
|
||||
that.tooltipText(true, this, d3.time.format("%e %B @ %H:%M")(new Date()));
|
||||
})
|
||||
.on('mouseout', function() {
|
||||
that.tooltipText(false);
|
||||
});
|
||||
this.line_guide_now.exit().remove();
|
||||
this.carret_line_guide_now = this.svg
|
||||
.selectAll('.carret-time-now')
|
||||
.data([new Date()]);
|
||||
this.carret_line_guide_now
|
||||
.enter()
|
||||
.append('text')
|
||||
.attr('class', 'carret-time-now')
|
||||
this.carret_line_guide_now
|
||||
.attr('x', that.x(new Date())-5.5)
|
||||
.attr('y', that.y(99))
|
||||
.attr('font-family', 'FontAwesome')
|
||||
.attr('font-size', '20px')
|
||||
.text(function(d) { return '\uf0d7' });
|
||||
this.carret_line_guide_now.exit().remove();
|
||||
|
||||
this.svg.append('rect')
|
||||
.attr('class', 'decayingGraphAreaThres')
|
||||
.style('opacity', 0.6)
|
||||
.attr('x', 0)
|
||||
.attr('y', this.height)
|
||||
.attr('width', this.width)
|
||||
.attr('height', 0)
|
||||
.on('mouseover', function(d) {
|
||||
d3.select(this).transition()
|
||||
.duration(that.options.animation_duration)
|
||||
.style('opacity', 0.9)
|
||||
that.tooltipText(true, this, 'Cutoff threshold: <b>' + that.model.parameters.threshold + '</b>');
|
||||
})
|
||||
.on('mouseout', function() {
|
||||
d3.select(this).transition()
|
||||
.duration(that.options.animation_duration)
|
||||
.style('opacity', 0.6)
|
||||
that.tooltipText(false);
|
||||
});
|
||||
this.svg.select('.decayingGraphAreaThres')
|
||||
.transition()
|
||||
.duration(this.options.animation_duration)
|
||||
.attr('height', this.height-this.y(this.model.parameters.threshold))
|
||||
.attr('y', this.y(this.model.parameters.threshold));
|
||||
|
||||
this.points = this.svg
|
||||
.selectAll('.d3-line-circle')
|
||||
.data(this.sightings_data);
|
||||
this.points
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('class', 'decayingGraphHandleDot useCursorPointer d3-line-circle');
|
||||
this.points // Update
|
||||
.attr('cx', function (d) { return that.x(d.date); })
|
||||
.attr('cy', function (d) { return that.y(d.value); })
|
||||
.attr('r', 5)
|
||||
.on('mouseover', function(d) {
|
||||
d3.select(this).transition()
|
||||
.duration(that.options.animation_duration)
|
||||
.attr('r', 7);
|
||||
that.tooltipDate(true, this, d);
|
||||
})
|
||||
.on('mouseout', function() {
|
||||
d3.select(this).transition()
|
||||
.duration(that.options.animation_duration)
|
||||
.attr('r', 5);
|
||||
that.tooltipDate(false);
|
||||
})
|
||||
.style('opacity', 0)
|
||||
.transition()
|
||||
.duration(this.options.animation_duration)
|
||||
.delay(this.options.animation_duration)
|
||||
.ease('linear')
|
||||
.style('opacity', 1);
|
||||
this.points.exit().remove();
|
||||
|
||||
// current score
|
||||
this.current_score_target = this.svg
|
||||
.selectAll('.current-score-target')
|
||||
.data([new Date()]);
|
||||
this.current_score_target
|
||||
.enter()
|
||||
.append('circle')
|
||||
.classed('useCursorPointer current-score-target', true);
|
||||
this.current_score_target
|
||||
.attr('cx', that.x(new Date()))
|
||||
.attr('cy', that.y(this.current_score))
|
||||
.attr('fill', 'white')
|
||||
.attr('stroke', 'black')
|
||||
.attr('stroke-width', 2)
|
||||
.attr('r', 6);
|
||||
this.current_score_target = this.svg
|
||||
.selectAll('.current-score-target-center')
|
||||
.data([new Date()]);
|
||||
this.current_score_target
|
||||
.enter()
|
||||
.append('circle')
|
||||
.classed('useCursorPointer current-score-target-center', true);
|
||||
this.current_score_target
|
||||
.attr('cx', that.x(new Date()))
|
||||
.attr('cy', that.y(this.current_score))
|
||||
.attr('stroke', 'black')
|
||||
.attr('r', 2);
|
||||
d3.selectAll('.current-score-target, .current-score-target-center')
|
||||
.on('click', function(d) {
|
||||
$('#simulation-current-score').parent().children().effect('highlight');
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
toggleLoading: function(state) {
|
||||
if (state === undefined) {
|
||||
this.$loadingContainer.toggle();
|
||||
} else if(state) {
|
||||
this.$loadingContainer.show();
|
||||
} else {
|
||||
this.$loadingContainer.hide();
|
||||
}
|
||||
this.$container;
|
||||
},
|
||||
|
||||
tooltipDate: function(show, d3Element, datum) {
|
||||
var that = this;
|
||||
var tooltip = this._toggleTooltip(show, d3Element);
|
||||
if (show) {
|
||||
tooltip.html(this._generate_tooltip(datum));
|
||||
}
|
||||
},
|
||||
|
||||
tooltipText: function(show, d3Element, html) {
|
||||
var that = this;
|
||||
var tooltip = this._toggleTooltip(show, d3Element);
|
||||
if (show) {
|
||||
tooltip.html(html);
|
||||
}
|
||||
},
|
||||
|
||||
_toggleTooltip: function(show, d3Element) {
|
||||
var that = this;
|
||||
if (show) {
|
||||
var bb_rect = d3.select(d3Element)[0][0].getBoundingClientRect();
|
||||
var cx = bb_rect.left;
|
||||
var cy = bb_rect.top;
|
||||
this.tooltip_container
|
||||
.style('display', 'block')
|
||||
.style('left', (cx + 17) + 'px')
|
||||
.style('top', (cy - 6) + 'px')
|
||||
.transition()
|
||||
.duration(that.options.animation_short_duration)
|
||||
.delay(that.options.animation_short_duration/2)
|
||||
.style('opacity', '0.7');
|
||||
} else {
|
||||
this.tooltip_container.transition()
|
||||
.duration(this.options.animation_short_duration)
|
||||
.style('opacity', 0)
|
||||
.delay(this.options.animation_short_duration)
|
||||
.style('display', 'none');
|
||||
}
|
||||
return this.tooltip_container;
|
||||
},
|
||||
|
||||
_generate_tooltip: function(datum) {
|
||||
var formated_date = d3.time.format("%e %B @ %H:%M")(datum.date);
|
||||
var html = 'Sighting on ' + formated_date + ' by ' + datum.org;
|
||||
return html;
|
||||
},
|
||||
|
||||
_parseDataset: function() {
|
||||
var that = this;
|
||||
if (typeof this.chart_data === 'string') {
|
||||
this.chart_data = d3.csv.parse(this.chart_data, function(d){
|
||||
var parsed_date = that.timeFormatter(d.date);
|
||||
return { timestamp: Math.floor(parsed_date.getTime() / 1000), date: parsed_date, value : parseFloat(d.value) }
|
||||
});
|
||||
} else if (Array.isArray(this.chart_data)){
|
||||
this.chart_data.forEach(function(entry, i) {
|
||||
that.chart_data[i].date = that.timeFormatter(entry.date);
|
||||
})
|
||||
}
|
||||
this.sightings_data = this.sightings.map(function(d) {
|
||||
var sighting = d.Sighting;
|
||||
var res = { timestamp: sighting.rounded_timestamp, date: new Date(sighting.rounded_timestamp*1000), value : that.raw_data.base_score_config.base_score };
|
||||
res['org'] = d.Organisation !== undefined ? d.Organisation.name : '?';
|
||||
return res;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$.DecayingSimulation = DecayingSimulation;
|
||||
$.fn.decayingSimulation = function(options) {
|
||||
var pickedArgs = arguments;
|
||||
|
||||
var $elements = this.each(function() {
|
||||
var $this = $(this),
|
||||
inst = $this.data('DecayingSimulation');
|
||||
options = ((typeof options === 'object') ? options : {});
|
||||
if ((!inst) && (typeof options !== 'string')) {
|
||||
$this.data('DecayingSimulation', new DecayingSimulation(this, options));
|
||||
} else {
|
||||
if (typeof options === 'string') {
|
||||
inst[options].apply(inst, Array.prototype.slice.call(pickerArgs, 1));
|
||||
}
|
||||
}
|
||||
});
|
||||
return $elements.length == 1 ? $elements.data('DecayingSimulation') : $elements;
|
||||
};
|
||||
|
||||
$.fn.decayingSimulation.constructor = DecayingSimulation;
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
(function(factory) {
|
||||
"use strict";
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['jquery'], factory);
|
||||
} else if (window.jQuery && !window.jQuery.fn.BasescoreComputationTable) {
|
||||
factory(window.jQuery);
|
||||
}
|
||||
}
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var BasescoreComputationTable = function(container, options, data) {
|
||||
this.container_id = '#' + container.id;
|
||||
this.$container = $(container);
|
||||
this._validateOptions(options);
|
||||
var default_options = {
|
||||
animation_duration: 250,
|
||||
};
|
||||
this.options = $.extend(true, {}, default_options, options);
|
||||
this._init();
|
||||
if (data !== undefined) {
|
||||
this.update(data)
|
||||
}
|
||||
};
|
||||
|
||||
BasescoreComputationTable.prototype = {
|
||||
constructor: BasescoreComputationTable,
|
||||
|
||||
_validateOptions: function(options) {
|
||||
|
||||
},
|
||||
_init: function() {
|
||||
var that = this;
|
||||
this.$loadingContainer = $('<div id="loadingSimulationContainer" style="background: #ffffff9f"><span class="fa fa-spinner fa-spin" style="font-size: xx-large;"></span></div>').css({
|
||||
position: 'absolute',
|
||||
left: '0',
|
||||
right: '0',
|
||||
top: '0',
|
||||
bottom: '0',
|
||||
display: 'flex',
|
||||
'align-items': 'center',
|
||||
'justify-content': 'center'
|
||||
}).hide();
|
||||
this.tooltip_container = d3.select('body').append('div')
|
||||
.classed('tooltip', true)
|
||||
.style('opacity', 0)
|
||||
.style('padding', '3px')
|
||||
.style('background-color', '#000')
|
||||
.style('color', 'white')
|
||||
.style('border-radius', '5px')
|
||||
.style('display', 'none');
|
||||
this.$container.append(this.$loadingContainer);
|
||||
$('#basescore-simulation-container #pick_notice').remove();
|
||||
},
|
||||
|
||||
update: function(data, model) {
|
||||
this.base_score_config = data.base_score_config;
|
||||
this.base_score = data.base_score_config.base_score;
|
||||
this.tags = data.base_score_config.tags;
|
||||
this.overriddenTags = data.base_score_config.overridden;
|
||||
this._draw();
|
||||
},
|
||||
|
||||
_create_all_tag_html: function(tag) {
|
||||
var that = this;
|
||||
if (tag !== false) {
|
||||
var html_tag = this._create_tag_html(tag);
|
||||
var overridden_html = '';
|
||||
var namespace_predicate = tag.Tag.name.split('=')[0];
|
||||
this.overriddenTags.forEach(function(entry) {
|
||||
var cur_namespace_predicate = entry.AttributeTag.Tag.name.split('=')[0];
|
||||
if (namespace_predicate == cur_namespace_predicate) {
|
||||
overridden_html += '<div class="overriden_tag_wrapper" style="filter: grayscale(80%);">' + that._create_tag_html(entry.EventTag) + '</div>';
|
||||
}
|
||||
});
|
||||
if (overridden_html !== '') {
|
||||
return '<div style="position:relative;" class="useCursorPointer overridden_tags_container">'
|
||||
+ overridden_html
|
||||
+ '<div class="attribute_tag_wrapper" style="top:-12px;margin-bottom:-12px; left:4px;margin-right:-4px; float: left; position: relative;">' + html_tag + '</div>'
|
||||
+ '</div>';
|
||||
} else {
|
||||
return html_tag;
|
||||
}
|
||||
} else { // last row
|
||||
return '<span style="border-radius: 4px; border: 1px solid #ccc; background-color: #eeeeee; padding: 4px 5px;">base_score</span>';
|
||||
}
|
||||
},
|
||||
_create_tag_html: function(tag) {
|
||||
if (tag !== false) {
|
||||
var $span = $('<span></span>');
|
||||
$span.addClass('tag')
|
||||
.css({
|
||||
'white-space': 'nowrap',
|
||||
'background-color': tag.Tag.colour,
|
||||
'color': getTextColour(tag.Tag.colour)
|
||||
})
|
||||
.text(tag.Tag.name);
|
||||
return $span[0].outerHTML;
|
||||
} else { // last row
|
||||
return '<span style="border-radius: 4px; border: 1px solid #ccc; background-color: #eeeeee; padding: 4px 5px;">base_score</span>';
|
||||
}
|
||||
},
|
||||
|
||||
_get_computation_step: function(tag) {
|
||||
if (tag === false) {
|
||||
return ['', '', '', this.base_score.toFixed(2)];
|
||||
}
|
||||
var namespace = tag.Tag.name.split('=')[0];
|
||||
|
||||
if (this.base_score_config.taxonomy_effective_ratios[namespace] !== undefined) {
|
||||
var html1 = this.base_score_config.taxonomy_effective_ratios[namespace].toFixed(2);
|
||||
var html4 = (parseFloat(tag.Tag.numerical_value) * this.base_score_config.taxonomy_effective_ratios[namespace]).toFixed(2);
|
||||
} else {
|
||||
var html1 = '0';
|
||||
var html4 = '0';
|
||||
}
|
||||
var html2 = '<it class="fa fa-times" style=""></it>';
|
||||
var html3 = parseFloat(tag.Tag.numerical_value).toFixed(2);
|
||||
return [html1, html2, html3, html4];
|
||||
},
|
||||
|
||||
_draw: function() {
|
||||
var that = this;
|
||||
$('#basescore-simulation-container #computation_help_container_body').empty();
|
||||
var tbody = d3.select('#basescore-simulation-container #computation_help_container_body');
|
||||
|
||||
// create a row for each object in the data
|
||||
var rows = tbody.selectAll('tr')
|
||||
.data(this.tags.concat(false))
|
||||
.enter()
|
||||
.append('tr')
|
||||
.attr('class', function(e, row_i) {
|
||||
if (that.tags.length == row_i) {
|
||||
return 'cellHeavyTopBorder bold';
|
||||
}
|
||||
});
|
||||
|
||||
// create a cell in each row for each column
|
||||
var cells = rows.selectAll('td')
|
||||
.data(function (tag, row_i) {
|
||||
var html_computation = that._get_computation_step(tag);
|
||||
return [
|
||||
that._create_all_tag_html(tag),
|
||||
html_computation[0], html_computation[1], html_computation[2], html_computation[3]
|
||||
]
|
||||
});
|
||||
cells.enter()
|
||||
.append('td')
|
||||
.html(function (e) { return e; })
|
||||
.style('opacity', 0.0)
|
||||
.style('padding', function(e, col_i) {
|
||||
if (col_i == 2) {
|
||||
return '8px 2px 8px 8px';
|
||||
}
|
||||
return '';
|
||||
})
|
||||
.transition()
|
||||
.duration(this.options.animation_duration)
|
||||
.style('opacity', 1.0)
|
||||
.each("end", function(td_content, col_i){
|
||||
var $div = $(td_content);
|
||||
if (col_i == 0 && $div.hasClass('overridden_tags_container')) {
|
||||
$('.overridden_tags_container').popover({
|
||||
title: 'Event tag overridden by Attribute tag',
|
||||
content: that._generateOverridenExplanationPopoverHTML($div),
|
||||
html: true,
|
||||
trigger: 'hover',
|
||||
placement: 'left',
|
||||
container: 'body'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_generateOverridenExplanationPopoverHTML: function($div) {
|
||||
var $tags_event = $div.find('.overriden_tag_wrapper .tag');
|
||||
var $tag_attribute = $div.find('.attribute_tag_wrapper .tag');
|
||||
var html = '<div style="text-align: center;">';
|
||||
$tags_event.each(function() {
|
||||
html += '<div>' + $(this)[0].outerHTML + '</div>'
|
||||
});
|
||||
html += '<div><i class="fa fa-arrow-down"></i></div>'
|
||||
html += '<div>' + $tag_attribute[0].outerHTML + '</div>'
|
||||
html += '</div>';
|
||||
return html;
|
||||
},
|
||||
|
||||
toggleLoading: function(state) {
|
||||
if (state === undefined) {
|
||||
this.$loadingContainer.toggle();
|
||||
} else if(state) {
|
||||
this.$loadingContainer.show();
|
||||
} else {
|
||||
this.$loadingContainer.hide();
|
||||
}
|
||||
this.$container;
|
||||
},
|
||||
}
|
||||
|
||||
$.BasescoreComputationTable = BasescoreComputationTable;
|
||||
$.fn.basescoreComputationTable = function(options) {
|
||||
var pickedArgs = arguments;
|
||||
|
||||
var $elements = this.each(function() {
|
||||
var $this = $(this),
|
||||
inst = $this.data('BasescoreComputationTable');
|
||||
options = ((typeof options === 'object') ? options : {});
|
||||
if ((!inst) && (typeof options !== 'string')) {
|
||||
$this.data('BasescoreComputationTable', new BasescoreComputationTable(this, options));
|
||||
} else {
|
||||
if (typeof options === 'string') {
|
||||
inst[options].apply(inst, Array.prototype.slice.call(pickerArgs, 1));
|
||||
}
|
||||
}
|
||||
});
|
||||
return $elements.length == 1 ? $elements.data('BasescoreComputationTable') : $elements;
|
||||
};
|
||||
|
||||
$.fn.basescoreComputationTable.constructor = BasescoreComputationTable;
|
||||
})
|
||||
);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,435 @@
|
|||
var mapping_tag_name_to_tag = {};
|
||||
var base_score_computation = [];
|
||||
|
||||
function getRandomInt(max) {
|
||||
return Math.floor(Math.random() * Math.floor(max));
|
||||
}
|
||||
|
||||
function addTagWithValue(clicked) {
|
||||
var $select = regenerateValidTags();
|
||||
var html = '<div>' + $select[0].outerHTML + '<button class="btn btn-primary" style="margin-left: 5px;" onclick="addPickedTags(this)">Tag</button> </div>';
|
||||
openPopover(clicked, html, false, 'right', function($popover) {
|
||||
$popover.find('select').chosen({
|
||||
width: '300px',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addPickedTags(clicked) {
|
||||
var numerical_values = [];
|
||||
var $select = $('#basescore-example-tag-picker');
|
||||
var $previous_tags = $('#basescore-example-customtag-container span.decayingExampleTags');
|
||||
$previous_tags.each(function() {
|
||||
numerical_values.push({name: getPrefixTagName($(this).text()), value: parseInt($(this).data('numerical_value'))});
|
||||
});
|
||||
$select.val().forEach(function(tag_id) {
|
||||
var tag = mapping_tag_name_to_tag[tag_id];
|
||||
tag.numerical_value = parseInt(tag.numerical_value);
|
||||
|
||||
var $outer_tag = $('<div></div>').css({display: 'inline-block'})
|
||||
.attr('title', 'numerical_value=' + tag.numerical_value);
|
||||
var $inner_tag_1 = $('<span></span>').addClass('tagComplete decayingExampleTags')
|
||||
.css({'background-color': tag.colour, color: getTextColour(tag.colour)})
|
||||
.data('numerical_value', tag.numerical_value)
|
||||
.text(tag.name);
|
||||
var $inner_tag_2 = $('<span></span>').addClass('tagSecondHalf useCursorPointer')
|
||||
.css({'margin-right': '4px'})
|
||||
.attr('onclick', 'removeCustomTag(this);')
|
||||
.text('×');
|
||||
$outer_tag.append($inner_tag_1).append($inner_tag_2);
|
||||
|
||||
$('#basescore-example-customtag-container').append($outer_tag);
|
||||
var tag_name = getPrefixTagName(tag.name);
|
||||
numerical_values.push({name: tag_name, value: tag['numerical_value']});
|
||||
});
|
||||
base_score_computation[0] = compute_base_score(numerical_values);
|
||||
var base_score = base_score_computation[0].score.toFixed(1);
|
||||
$('#basescore-example-score-0').empty()
|
||||
.text(base_score)
|
||||
.append('<i class="fas fa-question-circle helptext-in-cell useCursorPointer" onclick="genHelpBaseScoreComputation(event, 0)"></i>');
|
||||
$('#basescore-example-score-addTagButton').popover('destroy');
|
||||
$('#basescore-example-customtag-container').find('span.tagFirstHalf').parent().tooltip({placement: 'right', container: 'body'});
|
||||
}
|
||||
|
||||
function removeCustomTag(clicked) {
|
||||
$(clicked).parent().tooltip('destroy');
|
||||
$(clicked).add($(clicked).prev()).remove();
|
||||
var numerical_values = [];
|
||||
var $previous_tags = $('#basescore-example-customtag-container span.decayingExampleTags');
|
||||
$previous_tags.each(function() {
|
||||
numerical_values.push({name: getPrefixTagName($(this).text()), value: parseInt($(this).data('numerical_value'))});
|
||||
});
|
||||
base_score_computation[0] = compute_base_score(numerical_values);
|
||||
var base_score = base_score_computation[0].score.toFixed(1);
|
||||
$('#basescore-example-score-0').empty()
|
||||
.text(base_score)
|
||||
.append('<i class="fas fa-question-circle helptext-in-cell useCursorPointer" onclick="genHelpBaseScoreComputation(event, 0)"></i>');
|
||||
}
|
||||
|
||||
function regenerateValidTags() {
|
||||
var $select = $('<select id="basescore-example-tag-picker" multiple="multiple"/>');
|
||||
Object.keys(taxonomies_with_num_value).forEach(function(taxonomy_name) {
|
||||
var taxonomy = taxonomies_with_num_value[taxonomy_name];
|
||||
var $optgroup = $('<optgroup></optgroup>').attr('label', taxonomy_name);
|
||||
taxonomy['TaxonomyPredicate'].forEach(function(predicate) {
|
||||
if (predicate['numerical_predicate'] !== undefined && predicate['numerical_predicate']) {
|
||||
mapping_tag_name_to_tag[predicate['Tag']['id']] = predicate['Tag'];
|
||||
var $option = $('<option></option>')
|
||||
.val(predicate['Tag']['id'])
|
||||
.text(predicate['Tag']['name'] + ' [' + predicate['Tag']['numerical_value'] + ']');
|
||||
$optgroup.append($option);
|
||||
} else {
|
||||
predicate['TaxonomyEntry'].forEach(function(entry) {
|
||||
mapping_tag_name_to_tag[entry['Tag']['id']] = entry['Tag'];
|
||||
var $option = $('<option></option>')
|
||||
.val(entry['Tag']['id'])
|
||||
.text(entry['Tag']['name'] + ' [' + entry['Tag']['numerical_value'] + ']');
|
||||
$optgroup.append($option);
|
||||
});
|
||||
}
|
||||
});
|
||||
$select.append($optgroup);
|
||||
});
|
||||
return $select;
|
||||
}
|
||||
|
||||
function applyBaseScoreConfig() {
|
||||
var base_score_default_value = $('#base_score_default_value').val() >= 0 ? $('#base_score_default_value').val() : 0;
|
||||
decayingTool.applyBaseScore(getRatioScore(), base_score_default_value);
|
||||
$('#popover_form_large').fadeOut();
|
||||
$('#gray_out').fadeOut();
|
||||
}
|
||||
|
||||
function fetchTaxonomyConfig() {
|
||||
var matching_inputs = $('#body_taxonomies > tr')
|
||||
.find('input[type="number"]')
|
||||
.filter(function() {
|
||||
return parseInt($(this).val()) > 0;
|
||||
});
|
||||
var taxonomy_config = {};
|
||||
matching_inputs.each(function() {
|
||||
taxonomy_config[$(this).data('taxonomyname')] = parseInt($(this).val());
|
||||
});
|
||||
return taxonomy_config;
|
||||
}
|
||||
|
||||
function getRatioScore(taxonomies_name) {
|
||||
var config = fetchTaxonomyConfig();
|
||||
if (taxonomies_name === undefined) {
|
||||
taxonomies_name = Object.keys(config);
|
||||
}
|
||||
var ratioScore = {};
|
||||
total_score = taxonomies_name.reduce(function(acc, name) {
|
||||
var inc = 0;
|
||||
if (config[name] !== undefined) {
|
||||
inc = config[name];
|
||||
}
|
||||
return acc + inc;
|
||||
}, 0)
|
||||
taxonomies_name.forEach(function(name) {
|
||||
if (config[name] !== undefined) {
|
||||
ratioScore[name] = config[name] / total_score;
|
||||
}
|
||||
});
|
||||
return ratioScore;
|
||||
}
|
||||
|
||||
// return namespace:predicate for 3-components tagnames and namespace for 2-components tagnames
|
||||
function getPrefixTagName(tag_name) {
|
||||
var temp_tag_name = tag_name.split('='); // split on value
|
||||
var prefix = temp_tag_name.length == 1 ? temp_tag_name[0].split(':')[0] : temp_tag_name[0];
|
||||
return prefix;
|
||||
}
|
||||
|
||||
function pickRandomTags() {
|
||||
var taxonomies_name = Object.keys(fetchTaxonomyConfig());
|
||||
var tags = [];
|
||||
|
||||
if (taxonomies_name.length == 0) {
|
||||
return [];
|
||||
}
|
||||
var temp_taxonomies_name = taxonomies_name.slice();
|
||||
var max_tag_num = taxonomies_name.length > 3 ? 3 : taxonomies_name.length;
|
||||
var picked_tag_number = getRandomInt(max_tag_num) + 1;
|
||||
for (var i = 0; i < picked_tag_number; i++) { // number of tags
|
||||
// pick a taxonomy
|
||||
var picked_number_taxonomy = getRandomInt(temp_taxonomies_name.length);
|
||||
var picked_taxonomy_name_full = temp_taxonomies_name[picked_number_taxonomy];
|
||||
var temp_split = picked_taxonomy_name_full.split(':');
|
||||
var picked_taxonomy_namespace = temp_split[0];
|
||||
var picked_taxonomy_predicate = temp_split[1]
|
||||
var picked_taxonomy = taxonomies_with_num_value[picked_taxonomy_namespace];
|
||||
// pick the predicate
|
||||
var picked_predicate, picked_entry;
|
||||
if (picked_taxonomy['TaxonomyPredicate'][0]['numerical_predicate'] !== undefined && picked_taxonomy['TaxonomyPredicate'][0]['numerical_predicate']) { // predicate is an entry
|
||||
var picked_number_predicate = getRandomInt(picked_taxonomy['TaxonomyPredicate'].length);
|
||||
picked_entry = picked_taxonomy['TaxonomyPredicate'][picked_number_predicate];
|
||||
} else {
|
||||
for (var j=0; j<picked_taxonomy['TaxonomyPredicate'].length; j++) {
|
||||
if (picked_taxonomy['TaxonomyPredicate'][j]['value'] == picked_taxonomy_predicate) {
|
||||
picked_predicate = picked_taxonomy['TaxonomyPredicate'][j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
// pick a random entry -> tag
|
||||
var picked_number_entry = getRandomInt(picked_predicate['TaxonomyEntry'].length);
|
||||
picked_entry = picked_predicate['TaxonomyEntry'][picked_number_entry];
|
||||
}
|
||||
picked_entry['Tag']['numerical_value'] = parseInt(picked_entry['Tag']['numerical_value']);
|
||||
tags.push(picked_entry['Tag']);
|
||||
temp_taxonomies_name.splice(picked_number_taxonomy, 1);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
function html_computation_step(steps, i) {
|
||||
var step = steps.steps.computation[i];
|
||||
if (step === undefined) {
|
||||
return ['', '', ''];
|
||||
}
|
||||
var html1 = step.ratio.toFixed(2);
|
||||
var html2 = '*';
|
||||
var html3 = step.tag_value.toFixed(2);
|
||||
return [html1, html2, html3];
|
||||
}
|
||||
|
||||
function computation_step(steps, i) {
|
||||
var step = steps.steps.computation[i];
|
||||
if (step === undefined) { // last row, just sum everything up
|
||||
return (steps.score).toFixed(2);
|
||||
}
|
||||
return (step.ratio * step.tag_value).toFixed(2);
|
||||
}
|
||||
|
||||
function genHelpBaseScoreComputation(e, index) {
|
||||
e.preventDefault();
|
||||
$('#tableExamples > tbody > tr').removeClass('success').css('font-weight', 'inherit');
|
||||
$('#tableExamples > tbody > tr:nth-child(' + (index+1) + ')').addClass('success').css('font-weight', 'bold');
|
||||
var steps = base_score_computation[index];
|
||||
if (steps === undefined) {
|
||||
steps = {
|
||||
score: 0,
|
||||
steps: {
|
||||
computation: [],
|
||||
init: { config: [] }
|
||||
}
|
||||
};
|
||||
}
|
||||
var $tags = $('#basescore-example-tag-'+index + ' span.decayingExampleTags');
|
||||
var last_tag_index = $tags.length;
|
||||
$tags.push($(''));
|
||||
$('#computation_help_container_body').empty();
|
||||
var tbody = d3.select('#computation_help_container_body');
|
||||
|
||||
// create a row for each object in the data
|
||||
var rows = tbody.selectAll('tr')
|
||||
.data($tags)
|
||||
.enter()
|
||||
.append('tr')
|
||||
.attr('class', function(e, row_i) {
|
||||
if (last_tag_index == row_i) {
|
||||
return 'cellHeavyTopBorder bold';
|
||||
}
|
||||
});
|
||||
|
||||
// create a cell in each row for each column
|
||||
var cells = rows.selectAll('td')
|
||||
.data(function (tag, row_i) {
|
||||
var html_computation = html_computation_step(steps, row_i);
|
||||
return [
|
||||
tag.outerHTML,
|
||||
html_computation[0], html_computation[1], html_computation[2],
|
||||
computation_step(steps, row_i),
|
||||
]
|
||||
});
|
||||
cells.enter()
|
||||
.append('td')
|
||||
.html(function (e) { return e; })
|
||||
.style('opacity', 0.0)
|
||||
.transition().duration(500)
|
||||
.style('opacity', 1.0);
|
||||
|
||||
$('#pick_notice').remove();
|
||||
|
||||
}
|
||||
|
||||
function refreshExamples() {
|
||||
for (var i = 1; i <= 3; i++) {
|
||||
var numerical_values = [];
|
||||
var tags = pickRandomTags();
|
||||
var $tag_container = $('<div></div>').css({'display': 'flex', 'flex-flow': 'wrap' });
|
||||
tags.forEach(function(tag) {
|
||||
var tag_name = getPrefixTagName(tag.name);
|
||||
numerical_values.push({name: tag_name, value: tag['numerical_value']});
|
||||
var text_color = getTextColour(tag.colour);
|
||||
var $tag = $('<span></span>').addClass('tagComplete decayingExampleTags')
|
||||
.css({'background-color': tag.colour, color: text_color, 'margin-right': '4px'})
|
||||
.attr('title', 'numerical_value=' + tag['numerical_value'])
|
||||
.data('placement', 'right')
|
||||
.text(tag.name);
|
||||
$tag_container.append($tag);
|
||||
});
|
||||
base_score_computation[i] = compute_base_score(numerical_values);
|
||||
var base_score = base_score_computation[i].score.toFixed(1);
|
||||
var base_score_computation_steps = base_score_computation[i].steps;
|
||||
$('#basescore-example-tag-'+i).empty().append($tag_container);
|
||||
$('#basescore-example-score-'+i).empty()
|
||||
.text(base_score)
|
||||
.append('<i class="fas fa-question-circle helptext-in-cell useCursorPointer" onclick="genHelpBaseScoreComputation(event, ' + i + ')"></i>');
|
||||
$('span.decayingExampleTags').tooltip({ container: 'body' });
|
||||
}
|
||||
}
|
||||
|
||||
function compute_base_score(numerical_values) {
|
||||
var base_score = 0;
|
||||
var config = getRatioScore(numerical_values.map(x => x.name));
|
||||
var steps = {
|
||||
init: {
|
||||
config
|
||||
},
|
||||
computation: []
|
||||
};
|
||||
numerical_values.forEach(function(tag) {
|
||||
var coefficient = 0;
|
||||
if (!isNaN(config[tag.name])) {
|
||||
coefficient = config[tag.name];
|
||||
base_score += coefficient * tag.value;
|
||||
}
|
||||
steps.computation.push({ ratio: coefficient, tag_value: tag.value });
|
||||
});
|
||||
return { score: base_score, steps: steps };
|
||||
}
|
||||
|
||||
function filterTableTaxonomy(searchString) {
|
||||
var $table = $('#tableTaxonomy');
|
||||
var $body = $table.find('tbody');
|
||||
if (searchString === '') {
|
||||
$body.find('tr').forceClass('hidden', false);
|
||||
} else {
|
||||
$body.find('tr').forceClass('hidden', true);
|
||||
// show only matching elements
|
||||
var $cells = $body.find('tr > td:nth-child(1)');
|
||||
$cells.each(function() {
|
||||
if ($(this).text().trim().toUpperCase().indexOf(searchString.toUpperCase()) != -1) {
|
||||
$(this).parent().forceClass('hidden', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$('#table_taxonomy_search').on('input', function() {
|
||||
filterTableTaxonomy(this.value);
|
||||
});
|
||||
|
||||
var refreshExamplesTimeout = null;
|
||||
function refreshExamplesThrottle() {
|
||||
if (refreshExamplesTimeout !== null) {
|
||||
clearTimeout(refreshExamplesTimeout);
|
||||
}
|
||||
refreshExamplesTimeout = setTimeout(function() { refreshExamples(); }, 200);
|
||||
}
|
||||
|
||||
function sliderChanged(changed) {
|
||||
$(changed).parent().find('input[type="number"]').val(changed.value);
|
||||
var new_data = genTreeData();
|
||||
updateTree(new_data);
|
||||
refreshExamplesThrottle();
|
||||
}
|
||||
function inputChanged(changed) {
|
||||
$(changed).parent().find('input[type="range"]').val(changed.value);
|
||||
var new_data = genTreeData();
|
||||
updateTree(new_data);
|
||||
refreshExamplesThrottle();
|
||||
}
|
||||
|
||||
function updateTree(new_data) {
|
||||
var treemap = d3.layout.treemap()
|
||||
.size([width, height])
|
||||
.sticky(true)
|
||||
.value(function(d) { return d.size; });
|
||||
var nodes = div.datum(new_data).selectAll(".node")
|
||||
.data(treemap.nodes);
|
||||
|
||||
nodes.enter()
|
||||
.append("div")
|
||||
.attr("class", "node useCursorPointer")
|
||||
.style("background", function(d) {
|
||||
if (d.depth == 0) {
|
||||
return 'white';
|
||||
} else if (!d.children) {
|
||||
return color(d.name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.attr("id", function(d) { return d.name + '-node'})
|
||||
.on('click', function() { $('#table_taxonomy_search').val(d3.select(this).data()[0].name).trigger('input');})
|
||||
nodes.transition().duration(100)
|
||||
.call(position)
|
||||
.attr("title", function(d) { return d.name + ': ' + d.size})
|
||||
.text(function(d) {
|
||||
if (d.children) {
|
||||
return '';
|
||||
} else if (d.name !== '' && !isNaN(d.ratio) ) {
|
||||
return d.name + ' ('+parseInt(d.ratio*100)+'%)';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
});
|
||||
|
||||
nodes.exit()
|
||||
.remove();
|
||||
}
|
||||
|
||||
function genTreeData() {
|
||||
var root = {
|
||||
name: '',
|
||||
children: []
|
||||
};
|
||||
var sum = 0;
|
||||
var $sliders = $('#body_taxonomies').find('input[type="range"]');
|
||||
$sliders.each(function(){
|
||||
sum += parseInt($(this).val());
|
||||
});
|
||||
$sliders.each(function(){
|
||||
var val = parseInt($(this).val());
|
||||
if (val > 0) {
|
||||
var tmp = {
|
||||
name: $(this).data('taxonomyname'),
|
||||
size: val,
|
||||
ratio: val/sum
|
||||
};
|
||||
root.children.push(tmp);
|
||||
}
|
||||
});
|
||||
return root;
|
||||
}
|
||||
|
||||
var root = genTreeData();
|
||||
var margin = {top: 0, right: 0, bottom: 0, left: 0},
|
||||
width = 620 - margin.left - margin.right,
|
||||
height = 500 - margin.top - margin.bottom;
|
||||
|
||||
var color = d3.scale.category20c();
|
||||
|
||||
var treemap = d3.layout.treemap()
|
||||
.size([width, height])
|
||||
.sticky(true)
|
||||
.value(function(d) { return d.size; });
|
||||
|
||||
var div = d3.select("#treemapGraphTax").append("div").text('No taxonomy')
|
||||
.style("position", "relative")
|
||||
.style("width", (width + margin.left + margin.right) + "px")
|
||||
.style("height", (height + margin.top + margin.bottom) + "px")
|
||||
.style("left", margin.left + "px")
|
||||
.style("top", margin.top + "px");
|
||||
|
||||
updateTree(root);
|
||||
refreshExamples();
|
||||
|
||||
function position() {
|
||||
this.style("left", function(d) { return d.x + "px"; })
|
||||
.style("top", function(d) { return d.y + "px"; })
|
||||
.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
|
||||
.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
|
||||
}
|
|
@ -1492,7 +1492,7 @@ function templateElementFileCategoryChange(category) {
|
|||
}
|
||||
}
|
||||
|
||||
function openPopup(id, adjust_layout) {
|
||||
function openPopup(id, adjust_layout, callback) {
|
||||
adjust_layout = adjust_layout === undefined ? true : adjust_layout;
|
||||
if (adjust_layout) {
|
||||
var window_height = $(window).height();
|
||||
|
@ -1511,10 +1511,14 @@ function openPopup(id, adjust_layout) {
|
|||
}
|
||||
}
|
||||
$("#gray_out").fadeIn();
|
||||
$(id).fadeIn();
|
||||
$(id).fadeIn(400, function() {
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openPopover(clicked, data, hover, placement) {
|
||||
function openPopover(clicked, data, hover, placement, callback) {
|
||||
hover = hover === undefined ? false : hover;
|
||||
placement = placement === undefined ? 'right' : placement;
|
||||
/* popup handling */
|
||||
|
@ -1549,6 +1553,9 @@ function openPopover(clicked, data, hover, placement) {
|
|||
}
|
||||
var popoverTitle = popover.find('h3.popover-title');
|
||||
popoverTitle.html(title + closeButtonHtml);
|
||||
if (callback !== undefined) {
|
||||
callback(popover);
|
||||
}
|
||||
})
|
||||
.on('keydown.volatilePopover', function(e) {
|
||||
if(e.keyCode == 27) { // ESC
|
||||
|
@ -1743,6 +1750,26 @@ function choicePopup(legend, list) {
|
|||
openPopup("#popover_form");
|
||||
}
|
||||
|
||||
function openModal(heading, body, footer, modal_option, css_container, css_body) {
|
||||
var modal_id = 'dynamic_modal_' + new Date().getTime();
|
||||
var modal_html = '<div id="' + modal_id + '" class="modal hide fade" style="' + (css_container !== undefined ? css_container : '') + '" tabindex="-1" role="dialog" aria-hidden="true">';
|
||||
if (heading !== undefined && heading !== '') {
|
||||
modal_html += '<div class="modal-header">'
|
||||
+ '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>'
|
||||
+ '<h3 id="myModalLabel">' + heading + '</h3>'
|
||||
+ '</div>';
|
||||
}
|
||||
if (body !== undefined && body !== '') {
|
||||
modal_html += '<div class="modal-body" style="' + (css_body !== undefined ? css_body : '') + '">' + body + '</div>';
|
||||
}
|
||||
if (footer !== undefined && footer !== '') {
|
||||
modal_html += '<div class="modal-footer">' + footer + '</div>';
|
||||
}
|
||||
modal_html += '</div>';
|
||||
$('body').append($(modal_html));
|
||||
$('#'+modal_id).modal(modal_option !== undefined ? modal_option : {});
|
||||
}
|
||||
|
||||
function resizePopoverBody() {
|
||||
var bodyheight = $(window).height();
|
||||
bodyheight = 3 * bodyheight / 4 - 150;
|
||||
|
@ -3049,6 +3076,19 @@ function testConnection(id) {
|
|||
})
|
||||
}
|
||||
|
||||
function getTextColour(hex) {
|
||||
hex = hex.slice(1);
|
||||
var r = parseInt(hex.substring(0,2), 16);
|
||||
var g = parseInt(hex.substring(2,4), 16);
|
||||
var b = parseInt(hex.substring(4,6), 16);
|
||||
var avg = ((2 * r) + b + (3 * g))/6;
|
||||
if (avg < 128) {
|
||||
return 'white';
|
||||
} else {
|
||||
return 'black';
|
||||
}
|
||||
}
|
||||
|
||||
function pgpChoiceSelect(uri) {
|
||||
$("#popover_form").fadeOut();
|
||||
$("#gray_out").fadeOut();
|
||||
|
@ -3307,11 +3347,18 @@ function toggleBoolFilter(url, param) {
|
|||
url = url.replace(re, '');
|
||||
}
|
||||
});
|
||||
|
||||
if (res[param] !== undefined) { // allow toggle for `deleted`.
|
||||
res[param] = res[param] == '0' ? '2' : '0';
|
||||
if (res[param] !== undefined) {
|
||||
if (param == 'deleted') {
|
||||
res[param] = res[param] == 0 ? 2 : 0;
|
||||
} else {
|
||||
res[param] = res[param] == 0 ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
res[param] = '0';
|
||||
if (param == 'deleted') {
|
||||
res[param] = 0;
|
||||
} else {
|
||||
res[param] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
url += buildFilterURL(res);
|
||||
|
@ -4259,6 +4306,42 @@ function syntaxHighlightJson(json, indent) {
|
|||
});
|
||||
}
|
||||
|
||||
function jsonToNestedTable(json, header, table_classes) {
|
||||
if (typeof json == 'string') {
|
||||
json = JSON.parse(json);
|
||||
}
|
||||
if (Object.keys(json).length == 0) {
|
||||
return '';
|
||||
}
|
||||
header = header === undefined ? [] : header;
|
||||
table_classes = table_classes === undefined ? [] : table_classes;
|
||||
var $table = $('<table></table>');
|
||||
table_classes.forEach(function(classname) {
|
||||
$table.addClass(classname);
|
||||
});
|
||||
if (header.length > 0) {
|
||||
var $header = $('<thead><tr></tr></thead>');
|
||||
header.forEach(function(col) {
|
||||
$header.child().append($('<td></td>').text(col));
|
||||
});
|
||||
$table.append($header);
|
||||
}
|
||||
var $body = $('<tbody></tbody>');
|
||||
Object.keys(json).forEach(function(k) {
|
||||
var value = json[k];
|
||||
if (typeof value === 'object') {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
$body.append(
|
||||
$('<tr></tr>')
|
||||
.append($('<td></td>').text(k))
|
||||
.append($('<td></td>').text(value))
|
||||
);
|
||||
});
|
||||
$table.append($body);
|
||||
return $table[0].outerHTML;
|
||||
}
|
||||
|
||||
function liveFilter() {
|
||||
var lookupString = $('#liveFilterField').val();
|
||||
if (lookupString == '') {
|
||||
|
|
|
@ -23,7 +23,6 @@ Install the AWS PHP SDK
|
|||
|
||||
```bash
|
||||
cd /var/www/MISP/app
|
||||
sudo -u www-data php composer.phar config vendor-dir Vendor
|
||||
sudo -u www-data php composer.phar require aws/aws-sdk-php
|
||||
```
|
||||
|
||||
|
|
|
@ -327,8 +327,6 @@ installCake_RHEL ()
|
|||
#$SUDO_WWW $RUN_PHP -- php -r "if (hash_file('SHA384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
#$SUDO_WWW $RUN_PHP "php composer-setup.php"
|
||||
#$SUDO_WWW $RUN_PHP -- php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar require kamisama/cake-resque:4.1.2"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar config vendor-dir Vendor"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar install"
|
||||
|
||||
## sudo yum install php-redis -y
|
||||
|
|
|
@ -304,8 +304,6 @@ installCake_RHEL ()
|
|||
$SUDO_WWW php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
$SUDO_WWW php composer-setup.php
|
||||
$SUDO_WWW php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
|
||||
## sudo yum install php-redis -y
|
||||
|
|
|
@ -206,8 +206,6 @@ installCake () {
|
|||
# Make composer cache happy
|
||||
# /!\ composer on Ubuntu when invoked with sudo -u doesn't set $HOME to /var/www but keeps it /home/misp \!/
|
||||
sudo mkdir /var/www/.composer ; sudo chown $WWW_USER:$WWW_USER /var/www/.composer
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
|
|
|
@ -160,8 +160,6 @@ cd /var/www/MISP/app
|
|||
# Make composer cache happy
|
||||
# /!\ composer on Ubuntu when invoked with sudo -u doesn't set $HOME to /var/www but keeps it /home/misp \!/
|
||||
sudo mkdir /var/www/.composer ; sudo chown www-data:www-data /var/www/.composer
|
||||
sudo -H -u www-data php composer.phar require kamisama/cake-resque:4.1.2
|
||||
sudo -H -u www-data php composer.phar config vendor-dir Vendor
|
||||
sudo -H -u www-data php composer.phar install
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
|
|
|
@ -251,8 +251,6 @@ sudo -H -u www ${PATH_TO_MISP}/venv/bin/pip install .
|
|||
```bash
|
||||
# Install CakeResque along with its dependencies if you intend to use the built in background jobs:
|
||||
cd ${PATH_TO_MISP}/app
|
||||
sudo -u www php composer.phar require kamisama/cake-resque:4.1.2
|
||||
sudo -u www php composer.phar config vendor-dir Vendor
|
||||
sudo -u www php composer.phar install
|
||||
|
||||
# To use the scheduler worker for scheduled tasks, do the following:
|
||||
|
|
|
@ -788,8 +788,6 @@ alias composer70='composer72'
|
|||
composer72 () {
|
||||
cd $PATH_TO_MISP/app
|
||||
mkdir /var/www/.composer ; chown $WWW_USER:$WWW_USER /var/www/.composer
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
}
|
||||
|
||||
|
@ -806,8 +804,6 @@ composer73 () {
|
|||
checkFail "composer.phar checksum failed, please investigate manually. " $?
|
||||
$SUDO_WWW php composer-setup.php
|
||||
$SUDO_WWW php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
}
|
||||
|
||||
|
|
|
@ -238,9 +238,6 @@ sudo -u www php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe
|
|||
('composer-setup.php'); } echo PHP_EOL;"
|
||||
sudo -u www env HOME=/tmp php composer-setup.php
|
||||
sudo -u www php -r "unlink('composer-setup.php');"
|
||||
|
||||
sudo -u www HOME=/tmp php composer.phar require kamisama/cake-resque:4.1.2
|
||||
sudo -u www HOME=/tmp php composer.phar config vendor-dir Vendor
|
||||
sudo -u www HOME=/tmp php composer.phar install
|
||||
|
||||
# To use the scheduler worker for scheduled tasks, do the following:
|
||||
|
|
|
@ -413,8 +413,6 @@ doas -u www php -r "copy('https://getcomposer.org/installer', 'composer-setup.ph
|
|||
doas -u www php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
doas -u www env HOME=/var/www php composer-setup.php
|
||||
doas -u www php -r "unlink('composer-setup.php');"
|
||||
doas -u www env HOME=/var/www php composer.phar require kamisama/cake-resque:4.1.2
|
||||
doas -u www env HOME=/var/www php composer.phar config vendor-dir Vendor
|
||||
doas -u www env HOME=/var/www php composer.phar install
|
||||
|
||||
# To use the scheduler worker for scheduled tasks, do the following:
|
||||
|
|
|
@ -244,8 +244,6 @@ cd $PATH_TO_MISP/app
|
|||
#$SUDO_WWW $RUN_PHP -- php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
#$SUDO_WWW $RUN_PHP "php composer-setup.php"
|
||||
#$SUDO_WWW $RUN_PHP -- php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar require kamisama/cake-resque:4.1.2"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar config vendor-dir Vendor"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar install"
|
||||
|
||||
sudo yum install php-redis -y
|
||||
|
|
|
@ -231,8 +231,6 @@ cd $PATH_TO_MISP/app
|
|||
#$SUDO_WWW $RUN_PHP -- php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
#$SUDO_WWW $RUN_PHP "php composer-setup.php"
|
||||
#$SUDO_WWW $RUN_PHP -- php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar require kamisama/cake-resque:4.1.2"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar config vendor-dir Vendor"
|
||||
$SUDO_WWW $RUN_PHP "php composer.phar install"
|
||||
|
||||
sudo yum install php-redis -y
|
||||
|
|
|
@ -201,8 +201,6 @@ $SUDO_WWW php -r "copy('https://getcomposer.org/installer', 'composer-setup.php'
|
|||
$SUDO_WWW php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
$SUDO_WWW php composer-setup.php
|
||||
$SUDO_WWW php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
|
|
|
@ -221,8 +221,6 @@ sudo mkdir /var/www/.composer ; sudo chown $WWW_USER:$WWW_USER /var/www/.compose
|
|||
# $SUDO_WWW php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
|
||||
# $SUDO_WWW php composer-setup.php
|
||||
# $SUDO_WWW php -r "unlink('composer-setup.php');"
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
|
|
|
@ -228,8 +228,6 @@ function installMISPonTsurugi() {
|
|||
|
||||
cd $PATH_TO_MISP/app
|
||||
mkdir /var/www/.composer ; chown www-data:www-data /var/www/.composer
|
||||
$SUDO_WWW php composer.phar require kamisama/cake-resque:4.1.2
|
||||
$SUDO_WWW php composer.phar config vendor-dir Vendor
|
||||
$SUDO_WWW php composer.phar install
|
||||
|
||||
$SUDO_WWW cp -fa $PATH_TO_MISP/INSTALL/setup/config.php $PATH_TO_MISP/app/Plugin/CakeResque/Config/config.php
|
||||
|
|
|
@ -202,8 +202,6 @@ ${PATH_TO_MISP}/venv/bin/pip install .
|
|||
|
||||
# Install CakeResque along with its dependencies if you intend to use the built in background jobs:
|
||||
cd ${PATH_TO_MISP}/app
|
||||
php composer.phar require kamisama/cake-resque:4.1.2
|
||||
php composer.phar config vendor-dir Vendor
|
||||
php composer.phar install
|
||||
|
||||
# Enable CakeResque with php-redis
|
||||
|
|
Loading…
Reference in New Issue