new: First implementation of the freetext feed pull

pull/1580/merge
Iglocska 2016-10-07 17:33:54 +02:00
parent 69c0fd8a57
commit 503661a240
10 changed files with 546 additions and 65 deletions

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":51}
{"major":2, "minor":4, "hotfix":52}

View File

@ -27,6 +27,7 @@ class FeedsController extends AppController {
public function index() {
$this->set('feeds', $this->paginate());
$this->loadModel('Event');
$this->set('feed_types', $this->Feed->feed_types);
$this->set('distributionLevels', $this->Event->distributionLevels);
}
@ -36,15 +37,26 @@ class FeedsController extends AppController {
public function add() {
if ($this->request->is('post')) {
$error = false;
if (isset($this->request->data['Feed']['pull_rules'])) $this->request->data['Feed']['rules'] = $this->request->data['Feed']['pull_rules'];
if ($this->request->data['Feed']['distribution'] != 4) $this->request->data['Feed']['sharing_group_id'] = 0;
$this->request->data['Feed']['default'] = 0;
$result = $this->Feed->save($this->request->data);
if ($result) {
$this->Session->setFlash('Feed added.');
$this->redirect(array('controller' => 'feeds', 'action' => 'index'));
if ($this->request->data['Feed']['source_format'] == 'freetext') {
if ($this->request->data['Feed']['fixed_event'] == 1) {
if (is_numeric($this->request->data['Feed']['target_event'])) {
$this->request->data['Feed']['event_id'] = $this->request->data['Feed']['target_event'];
}
}
}
$this->request->data['Feed']['event_id'] = $this->request->data['Feed']['fixed_event'] ? $this->request->data['Feed']['target_event'] : 0;
if (!$error) {
$result = $this->Feed->save($this->request->data);
if ($result) {
$this->Session->setFlash('Feed added.');
$this->redirect(array('controller' => 'feeds', 'action' => 'index'));
}
else $this->Session->setFlash('Feed could not be added.');
}
else $this->Session->setFlash('Feed could not be added.');
} else {
$this->loadModel('Event');
$sgs = $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1);
@ -52,6 +64,7 @@ class FeedsController extends AppController {
if (empty($sgs)) unset($distributionLevels[4]);
$this->set('distributionLevels', $distributionLevels);
$this->set('sharingGroups', $sgs);
$this->set('feed_types', $this->Feed->getFeedTypesOptions());
$tags = $this->Event->EventTag->Tag->find('list', array('fields' => array('Tag.name'), 'order' => array('lower(Tag.name) asc')));
$tags[0] = 'None';
$this->set('tags', $tags);
@ -66,7 +79,15 @@ class FeedsController extends AppController {
if (isset($this->request->data['Feed']['pull_rules'])) $this->request->data['Feed']['rules'] = $this->request->data['Feed']['pull_rules'];
if ($this->request->data['Feed']['distribution'] != 4) $this->request->data['Feed']['sharing_group_id'] = 0;
$this->request->data['Feed']['id'] = $feedId;
$fields = array('id', 'name', 'provider', 'enabled', 'rules', 'url', 'distribution', 'sharing_group_id', 'tag_id');
if ($this->request->data['Feed']['source_format'] == 'freetext') {
if ($this->request->data['Feed']['fixed_event'] == 1) {
if (is_numeric($this->request->data['Feed']['target_event'])) {
$this->request->data['Feed']['event_id'] = $this->request->data['Feed']['target_event'];
}
}
}
$this->request->data['Feed']['event_id'] = $this->request->data['Feed']['fixed_event'] ? $this->request->data['Feed']['target_event'] : 0;
$fields = array('id', 'name', 'provider', 'enabled', 'rules', 'url', 'distribution', 'sharing_group_id', 'tag_id', 'fixed_event', 'event_id', 'publish', 'delta_merge');
$feed = array();
foreach ($fields as $field) $feed[$field] = $this->request->data['Feed'][$field];
$result = $this->Feed->save($feed);
@ -76,18 +97,24 @@ class FeedsController extends AppController {
}
else $this->Session->setFlash('Feed could not be updated.');
} else {
$this->request->data = $this->Feed->data;
if (!isset($this->request->data['Feed'])) {
$this->request->data = $this->Feed->data;
if ($this->Feed->data['Feed']['event_id']) {
$this->request->data['Feed']['target_event'] = $this->Feed->data['Feed']['event_id'];
}
}
$this->request->data['Feed']['pull_rules'] = $this->request->data['Feed']['rules'];
$this->loadModel('Event');
$sgs = $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1);
$distributionLevels = $this->Event->distributionLevels;
if (empty($sgs)) unset($distributionLevels[4]);
$this->set('distributionLevels', $distributionLevels);
$this->set('sharingGroups', $sgs);
$tags = $this->Event->EventTag->Tag->find('list', array('fields' => array('Tag.name'), 'order' => array('lower(Tag.name) asc')));
$tags[0] = 'None';
$this->set('tags', $tags);
}
$this->loadModel('Event');
$sgs = $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1);
$distributionLevels = $this->Event->distributionLevels;
if (empty($sgs)) unset($distributionLevels[4]);
$this->set('distributionLevels', $distributionLevels);
$this->set('sharingGroups', $sgs);
$tags = $this->Event->EventTag->Tag->find('list', array('fields' => array('Tag.name'), 'order' => array('lower(Tag.name) asc')));
$tags[0] = 'None';
$this->set('feed_types', $this->Feed->getFeedTypesOptions());
$this->set('tags', $tags);
}
public function delete($feedId) {
@ -166,16 +193,21 @@ class FeedsController extends AppController {
public function previewIndex($feedId) {
$this->Feed->id = $feedId;
if (!$this->Feed->exists()) throw new NotFoundException('Invalid feed.');
$this->Feed->read();
if ($this->Feed->data['Feed']['source_format'] == 'misp') {
$this->__previewIndex($this->Feed->data);
} else if ($this->Feed->data['Feed']['source_format'] == 'freetext') {
$this->__previewFreetext($this->Feed->data);
}
}
private function __previewIndex($feed) {
if (isset($this->passedArgs['pages'])) $currentPage = $this->passedArgs['pages'];
else $currentPage = 1;
$urlparams = '';
$passedArgs = array();
App::uses('SyncTool', 'Tools');
$syncTool = new SyncTool();
$this->Feed->read();
$HttpSocket = $syncTool->setupHttpSocketFeed($this->Feed->data);
$events = $this->Feed->getManifest($this->Feed->data, $HttpSocket);
$HttpSocket = $syncTool->setupHttpSocketFeed($feed);
$events = $this->Feed->getManifest($feed, $HttpSocket);
if (isset($events['code'])) throw new NotFoundException('Feed could not be fetched. The HTTP error code returned was: ' .$events['code']);
$pageCount = count($events);
App::uses('CustomPaginationTool', 'Tools');
@ -184,7 +216,7 @@ class FeedsController extends AppController {
$this->params->params['paging'] = array($this->modelClass => $params);
if (is_array($events)) $customPagination->truncateByPagination($events, $params);
else ($events = array());
$this->set('events', $events);
$this->loadModel('Event');
$threat_levels = $this->Event->ThreatLevel->find('all');
@ -194,12 +226,32 @@ class FeedsController extends AppController {
$this->set('distributionLevels', $this->Event->distributionLevels);
$shortDist = array(0 => 'Organisation', 1 => 'Community', 2 => 'Connected', 3 => 'All', 4 => ' sharing Group');
$this->set('shortDist', $shortDist);
$this->set('id', $feedId);
$this->set('feed', $this->Feed->data);
$this->set('id', $feed['Feed']['id']);
$this->set('feed', $feed);
$this->set('urlparams', $urlparams);
$this->set('passedArgs', json_encode($passedArgs));
$this->set('passedArgsArray', $passedArgs);
}
private function __previewFreetext($feed) {
App::uses('SyncTool', 'Tools');
$syncTool = new SyncTool();
if ($feed['Feed']['source_format'] != 'freetext') throw new MethodNotAllowedException('Invalid feed type.');
$HttpSocket = $syncTool->setupHttpSocketFeed($feed);
$resultArray = $this->Feed->getFreetextFeed($feed, $HttpSocket);
// remove all duplicates
foreach ($resultArray as $k => $v) {
for ($i = 0; $i < $k; $i++) {
if (isset($resultArray[$i]) && $v == $resultArray[$i]) unset($resultArray[$k]);
}
}
$resultArray = array_values($resultArray);
$this->loadModel('Attribute');
$this->set('distributionLevels', $this->Attribute->distributionLevels);
$this->set('feed', $feed);
$this->set('attributes', $resultArray);
$this->render('freetext_index');
}
public function previewEvent($feedId, $eventUuid, $all = false) {
@ -278,4 +330,24 @@ class FeedsController extends AppController {
$result['message'] = $fail ? 'Could not ' . $action . ' feed.' : 'Feed ' . $action . 'd.';
return $result;
}
public function fetchSelectedFromFreetextIndex($id) {
if (!$this->request->is('Post')) {
throw new MethodNotAllowedException('Only POST requests are allowed.');
}
$this->Feed->id = $id;
if (!$this->Feed->exists()) {
throw new NotFoundException('Feed not found.');
}
$feed = $this->Feed->read();
$data = json_decode($this->request->data['Feed']['data'], true);
$result = $this->Feed->saveFreetextFeedData($feed, $data, $this->Auth->user());
if (is_numeric($result)) {
$this->Session->setFlash('Data pulled.');
$this->redirect(array('controller' => 'events', 'action' => 'view', $result));
} else {
$this->Session->setFlash('Could not pull the selected data. Reason: ' . $result);
$this->redirect(array('controller' => 'feeds', 'action' => 'index'));
}
}
}

View File

@ -121,7 +121,9 @@ class ComplexTypeTool {
foreach ($this->__hexHashTypes as $k => $v) {
if (strlen($compositeParts[1]) == $k && preg_match("#[0-9a-f]{" . $k . "}$#i", $compositeParts[1])) return array('types' => $v['composite'], 'to_ids' => true, 'default_type' => $v['composite'][0]);
}
if (preg_match('#^[0-9]+:.+:.+$#', $compositeParts[1])) return array('types' => array('ssdeep'), 'to_ids' => true, 'default_type' => 'filename|ssdeep');
if (preg_match('#^[0-9]+:.+:.+$#', $compositeParts[1]) && !preg_match('#^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}$#', $compositeParts[1])) {
return array('types' => array('ssdeep'), 'to_ids' => true, 'default_type' => 'filename|ssdeep');
}
}
}
}
@ -130,7 +132,7 @@ class ComplexTypeTool {
foreach ($this->__hexHashTypes as $k => $v) {
if (strlen($input) == $k && preg_match("#[0-9a-f]{" . $k . "}$#i", $input)) return array('types' => $v['single'], 'to_ids' => true, 'default_type' => $v['single'][0]);
}
if (preg_match('#^[0-9]+:.+:.+$#', $input)) return array('types' => array('ssdeep'), 'to_ids' => true, 'default_type' => 'ssdeep');
if (preg_match('#^[0-9]+:.+:.+$#', $input) && !preg_match('#^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}$#', $input)) return array('types' => array('ssdeep'), 'to_ids' => true, 'default_type' => 'ssdeep');
$inputRefanged = $input;
foreach ($this->__refangRegexTable as $regex => $replacement) $inputRefanged = preg_replace($regex, $replacement , $inputRefanged);
$inputRefanged = rtrim($inputRefanged, ".");

View File

@ -36,7 +36,7 @@ class AppModel extends Model {
// major -> minor -> hotfix -> requires_logout
public $db_changes = array(
2 => array(
4 => array(18 => false, 19 => false, 20 => false, 25 => false, 27 => false, 32 => false, 33 => true, 38 => true, 39 => true, 40 => false, 42 => false, 44 => false, 45 => false, 49 => true, 50 => false, 51 => false)
4 => array(18 => false, 19 => false, 20 => false, 25 => false, 27 => false, 32 => false, 33 => true, 38 => true, 39 => true, 40 => false, 42 => false, 44 => false, 45 => false, 49 => true, 50 => false, 51 => false, 52 => false)
)
);
@ -433,6 +433,14 @@ class AppModel extends Model {
$sqlArray[] = 'ALTER TABLE `servers` ADD `internal` tinyint(1) NOT NULL DEFAULT 0;';
$sqlArray[] = 'ALTER TABLE `roles` ADD `default_role` tinyint(1) NOT NULL DEFAULT 0;';
break;
case '2.4.52':
$sqlArray[] = "ALTER TABLE feeds ADD source_format varchar(255) COLLATE utf8_bin DEFAULT 'misp';";
$sqlArray[] = 'ALTER TABLE feeds ADD fixed_event tinyint(1) NOT NULL DEFAULT 0;';
$sqlArray[] = 'ALTER TABLE feeds ADD delta_merge tinyint(1) NOT NULL DEFAULT 0;';
$sqlArray[] = 'ALTER TABLE feeds ADD event_id int(11) NOT NULL DEFAULT 0;';
$sqlArray[] = 'ALTER TABLE feeds ADD publish tinyint(1) NOT NULL DEFAULT 0;';
$sqlArray[] = "ALTER TABLE feeds ADD settings text NOT NULL DEFAULT '';";
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;';

View File

@ -37,6 +37,24 @@ class Feed extends AppModel {
),
),
);
// currently we only have an internal name and a display name, but later on we can expand this with versions, default settings, etc
public $feed_types = array(
'misp' => array(
'name' => 'MISP Feed'
),
'freetext' => array(
'name' => 'Freetext Parsed Feed'
)
);
public function getFeedTypesOptions() {
$result = array();
foreach ($this->feed_types as $key => $value) {
$result[$key] = $value['name'];
}
return $result;
}
// gets the event UUIDs from the feed by ID
// returns an array with the UUIDs of events that are new or that need updating
@ -78,6 +96,21 @@ class Feed extends AppModel {
$events = $this->__filterEventsIndex($events, $feed);
return $events;
}
public function getFreetextFeed($feed, $HttpSocket) {
$result = array();
$response = $HttpSocket->get($feed['Feed']['url'], '', array());
if ($response->code == 200) {
App::uses('ComplexTypeTool', 'Tools');
$complexTypeTool = new ComplexTypeTool();
$resultArray = $complexTypeTool->checkComplexRouter($response->body, 'FreeText');
}
$this->Attribute = ClassRegistry::init('Attribute');
foreach ($resultArray as $key => $value) {
$resultArray[$key]['category'] = $this->Attribute->typeDefinitions[$value['default_type']]['default_category'];
}
return $resultArray;
}
public function downloadFromFeed($actions, $feed, $HttpSocket, $user, $jobId = false) {
if ($jobId) {
@ -380,4 +413,68 @@ class Feed extends AppModel {
}
return $result;
}
public function saveFreetextFeedData($feed, $data, $user) {
$this->Event = ClassRegistry::init('Event');
$event = false;
if ($feed['Feed']['fixed_event'] && $feed['Feed']['event_id']) {
$event = $this->Event->find('first', array('conditions' => array('Event.id' => $feed['Feed']['event_id']), 'recursive' => -1));
if (empty($event)) return 'The target event is no longer valid. Make sure that the target event exists.';
}
if (!$event) {
$this->Event->create();
$event = array(
'info' => $feed['Feed']['name'] . ' feed',
'analysis' => 2,
'threat_level_id' => 4,
'orgc_id' => $user['org_id'],
'org_id' => $user['org_id'],
'date' => date('Y-m-d'),
'distribution' => $feed['Feed']['distribution'],
'sharing_group_id' => $feed['Feed']['sharing_group_id'],
'user_id' => $user['id']
);
$result = $this->Event->save($event);
if (!$result) return 'Something went wrong while creating a new event.';
$event = $this->Event->find('first', array('conditions' => array('Event.id' => $this->Event->id), 'recursive' => -1));
if (empty($event)) return 'The newly created event is no longer valid. Make sure that the target event exists.';
if ($feed['Feed']['fixed_event']) {
$feed['Feed']['event_id'] = $event['Event']['id'];
$this->save($feed);
}
}
if ($feed['Feed']['fixed_event'] && $feed['Feed']['delta_merge']) {
$event = $this->Event->find('first', array('conditions' => array('Event.id' => $event['Event']['id']), 'recursive' => -1, 'contain' => array('Attribute')));
$to_delete = array();
foreach ($data as $k => $dataPoint) {
foreach ($event['Attribute'] as $attribute_key => $attribute) {
if ($dataPoint['value'] == $attribute['value']) {
unset($data[$k]);
unset($event['Attribute'][$attribute_key]);
}
}
}
foreach ($event['Attribute'] as $attribute) {
$to_delete[] = $attribute['id'];
}
if (!empty($to_delete)) {
$this->Event->Attribute->deleteAll(array('Attribute.id' => $to_delete));
}
}
foreach ($data as $key => $value) {
$data[$key]['event_id'] = $event['Event']['id'];
$data[$key]['distribution'] = $feed['Feed']['distribution'];
$data[$key]['sharing_group_id'] = $feed['Feed']['sharing_group_id'];
}
if (!$this->Event->Attribute->saveMany($data)) {
return 'Could not save the parsed attributes.';
}
if ($feed['Feed']['publish']) {
$this->Event->publishRouter($event['Event']['id'], null, $user);
}
if ($feed['Feed']['tag_id']) {
$this->Event->EventTag->attachTagToEvent($event['Event']['id'], $feed['Feed']['tag_id']);
}
return $event['Event']['id'];
}
}

View File

@ -0,0 +1,47 @@
<div class="events">
<div id="eventIndexTable">
<h2>Events</h2>
<div class="pagination">
<ul>
<?php
$this->Paginator->options(array(
'update' => '#eventIndexTable',
'evalScripts' => true,
'before' => '$(".progress").show()',
'complete' => '$(".progress").hide()',
));
echo $this->Paginator->prev('&laquo; ' . __('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') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
</ul>
</div>
<?php
$tab = "Center";
if (!isset($simple)) $simple = false;
$filtered = false;
if (!$simple && count($passedArgsArray) > 0) {
$tab = "Left";
$filtered = true;
}
echo $this->element('Events/eventIndexTable');
?>
<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('&laquo; ' . __('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') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
</ul>
</div>
</div>
</div>
<?php echo $this->Js->writeBuffer(); ?>

View File

@ -20,6 +20,54 @@
'placeholder' => 'URL of the feed',
'class' => 'form-control span6'
));
echo $this->Form->input('source_format', array(
'label' => 'Source Format',
'div' => 'input clear',
'options' => $feed_types,
'class' => 'form-control span6'
));
?>
<div id="TargetDiv">
<?php
echo $this->Form->input('fixed_event', array(
'label' => 'Target Event',
'div' => 'input clear',
'options' => array('New Event Each Pull', 'Fixed Event'),
'class' => 'form-control span6'
));
?>
</div>
<div id="TargetEventDiv">
<?php
echo $this->Form->input('target_event', array(
'label' => 'Target Event ID',
'div' => 'input clear',
'placeholder' => 'Leave blank unless you want to reuse an existing event.',
'class' => 'form-control span6'
));
?>
</div>
<div id="PublishDiv" class="input clear">
<?php
echo $this->Form->input('publish', array(
'label' => 'Auto Publish',
'title' => 'Publish events directly after pulling the feed - if you would like to review the event before publishing uncheck this',
'type' => 'checkbox',
'class' => 'form-control'
));
?>
</div>
<div id="DeltaMergeDiv" class="input clear">
<?php
echo $this->Form->input('delta_merge', array(
'label' => 'Delta Merge',
'title' => 'Merge attributes (only add new attributes, remove revoked attributes)',
'type' => 'checkbox',
'class' => 'form-control'
));
?>
</div>
<?php
echo $this->Form->input('distribution', array(
'options' => array($distributionLevels),
'div' => 'input clear',
@ -65,18 +113,6 @@
echo $this->element('side_menu', array('menuList' => 'feeds', 'menuItem' => 'add'));
?>
<script type="text/javascript">
//
var formInfoValues = {
'ServerUrl' : "The base-url to the external server you want to sync with. Example: https://foo.sig.mil.be",
'ServerName' : "A name that will make it clear to your users what this instance is. For example: Organisation A's instance",
'ServerOrganization' : "The organization having the external server you want to sync with. Example: BE",
'ServerAuthkey' : "You can find the authentication key on your profile on the external server.",
'ServerPush' : "Allow the upload of events and their attributes.",
'ServerPull' : "Allow the download of events and their attributes from the server.",
'ServerSubmittedCert' : "You can also upload a certificate file if the instance you are trying to connect to has its own signing authority.",
'ServerSelfSigned' : "Click this, if you would like to allow a connection despite the other instance using a self-signed certificate (not recommended)."
};
var rules = {"pull": {"tags": {"OR":[], "NOT":[]}, "orgs": {"OR":[], "NOT":[]}}};
var validOptions = ['pull'];
@ -91,5 +127,29 @@ $(document).ready(function() {
$("#FeedDistribution").change(function() {
feedDistributionChange();
});
feedFormUpdate();
});
$("#FeedSourceFormat, #FeedTarget").change(function() {
feedFormUpdate();
});
function feedFormUpdate() {
if ($('#FeedSourceFormat').val() == 'misp') {
$('#TargetDiv').hide();
$('#TargetEventDiv').hide();
$('#PublishDiv').hide();
} else if ($('#FeedSourceFormat').val() == 'freetext') {
$('#TargetDiv').show();
$('#PublishDiv').show();
if ($('#FeedTarget').val() == 0) {
$('#TargetEventDiv').hide();
$('#DeltaMergeDiv').hide();
} else {
$('#TargetEventDiv').show();
$('#DeltaMergeDiv').show();
}
}
}
</script>

View File

@ -4,29 +4,76 @@
<legend>Edit MISP Feed</legend>
<p>Edit a new MISP feed source.</p>
<?php
echo $this->Form->input('enabled', array());
echo $this->Form->input('name', array(
'div' => 'input clear',
'placeholder' => 'Feed name',
'class' => 'form-control span6',
));
echo $this->Form->input('provider', array(
'div' => 'input clear',
'placeholder' => 'Name of the content provider',
'class' => 'form-control span6'
));
echo $this->Form->input('url', array(
'div' => 'input clear',
'placeholder' => 'URL of the feed',
'class' => 'form-control span6'
));
echo $this->Form->input('distribution', array(
'options' => array($distributionLevels),
'div' => 'input clear',
'label' => 'Distribution',
));
echo $this->Form->input('enabled', array());
echo $this->Form->input('name', array(
'div' => 'input clear',
'placeholder' => 'Feed name',
'class' => 'form-control span6',
));
echo $this->Form->input('provider', array(
'div' => 'input clear',
'placeholder' => 'Name of the content provider',
'class' => 'form-control span6'
));
echo $this->Form->input('url', array(
'div' => 'input clear',
'placeholder' => 'URL of the feed',
'class' => 'form-control span6'
));
echo $this->Form->input('source_format', array(
'label' => 'Source Format',
'div' => 'input clear',
'options' => $feed_types,
'class' => 'form-control span6'
));
?>
<div id="SGContainer" style="display:none;">
<div id="TargetDiv">
<?php
echo $this->Form->input('fixed_event', array(
'label' => 'Target Event',
'div' => 'input clear',
'options' => array('New Event Each Pull', 'Fixed Event'),
'class' => 'form-control span6'
));
?>
</div>
<div id="TargetEventDiv">
<?php
echo $this->Form->input('target_event', array(
'label' => 'Target Event ID',
'div' => 'input clear',
'placeholder' => 'Leave blank unless you want to reuse an existing event.',
'class' => 'form-control span6'
));
?>
</div>
<div id="PublishDiv" class="input clear">
<?php
echo $this->Form->input('publish', array(
'label' => 'Auto Publish',
'type' => 'checkbox',
'class' => 'form-control'
));
?>
</div>
<div id="DeltaMergeDiv" class="input clear">
<?php
echo $this->Form->input('delta_merge', array(
'label' => 'Delta Merge',
'title' => 'Merge attributes (only add new attributes, remove revoked attributes)',
'type' => 'checkbox',
'class' => 'form-control'
));
?>
</div>
<?php
echo $this->Form->input('distribution', array(
'options' => array($distributionLevels),
'div' => 'input clear',
'label' => 'Distribution',
));
?>
<div id="SGContainer" style="display:none;">
<?php
if (!empty($sharingGroups)) {
echo $this->Form->input('sharing_group_id', array(
@ -35,8 +82,8 @@
));
}
?>
</div>
<div class="input clear"></div>
</div>
<div class="input clear"></div>
<?php
echo $this->Form->input('tag_id', array(
'options' => $tags,
@ -90,5 +137,28 @@ $(document).ready(function() {
$("#FeedDistribution").change(function() {
feedDistributionChange();
});
feedFormUpdate();
});
$("#FeedSourceFormat, #FeedFixedEvent").change(function() {
feedFormUpdate();
});
function feedFormUpdate() {
if ($('#FeedSourceFormat').val() == 'misp') {
$('#TargetDiv').hide();
$('#TargetEventDiv').hide();
$('#PublishDiv').hide();
} else if ($('#FeedSourceFormat').val() == 'freetext') {
$('#TargetDiv').show();
$('#PublishDiv').show();
if ($('#FeedFixedEvent').val() == 0) {
$('#TargetEventDiv').hide();
$('#DeltaMergeDiv').hide();
} else {
$('#TargetEventDiv').show();
$('#DeltaMergeDiv').show();
}
}
}
</script>

View File

@ -0,0 +1,81 @@
<div class="attributes index">
<h2>Parsed attributes from feed <?php echo h($feed['Feed']['name']);?></h2>
<?php
echo $this->Form->create('Feed', array('url' => array('controller' => 'feeds', 'action' => 'fetchSelectedFromFreetextIndex', $feed['Feed']['id'])));
echo $this->Form->input('data', array('style' => 'display:none;', 'label' => false, 'div' => false));
?>
<span id="FetchSelected" class="btn btn-inverse">Fetch selected</span>
<?php
echo $this->Form->end();
?>
<table class="table table-striped table-hover table-condensed">
<tr>
<th><input class="select_all" type="checkbox" onClick="toggleAllAttributeCheckboxes();" /></th>
<th>Category</th>
<th>Type</th>
<th>Value</th>
<th>IDS</th>
<th>Distribution</th>
</tr>
<?php
foreach ($attributes as $key => $attribute):
?>
<tr>
<td style="width:10px;">
<input class="select_attribute" type="checkbox" data-rowid="<?php echo h($key); ?>" />
</td>
<td class="short" id="<?php echo h($key);?>_category"><?php echo h($attribute['category']);?></td>
<td class="short" id="<?php echo h($key);?>_type"><?php echo h($attribute['default_type']);?></td>
<td id="<?php echo h($key);?>_value"><?php echo h($attribute['value']);?></td>
<td class="short" id="<?php echo h($key);?>_to_ids" data-value="<?php echo h($attribute['to_ids']); ?>"><span class="icon-<?php echo $attribute['to_ids'] ? 'ok' : 'remove';?>"></span></td>
<td class="short">
<?php
if ($feed['Feed']['distribution'] == 4):
?>
<a href="<?php echo $baseurl; ?>/sharing_groups/view/<?php echo h($feed['Feed']['sharing_group_id']); ?>"><?php echo h($feed['SharingGroup']['name']); ?></a>
<?php
else:
echo h($distributionLevels[$feed['Feed']['distribution']]);
endif;
?>
</td>
</tr>
<?php
endforeach;
?>
</table>
</div>
<?php
echo $this->element('side_menu', array('menuList' => 'feeds', 'menuItem' => 'add'));
?>
<script type="text/javascript">
var data = [];
$(document).ready(function() {
});
$('#FetchSelected').click(freetextFeedFetchSelected);
function freetextFeedFetchSelected() {
var payload = [];
var checkedIds = [];
$('.select_attribute').each(function () {
if (this.checked) {
var row_id = $(this).data('rowid');
payload.push({
'category': $('#' + row_id + '_category').html(),
'type': $('#' + row_id + '_type').html(),
'value': $('#' + row_id + '_value').html(),
'to_ids': $('#' + row_id + '_to_ids').data('value'),
});
}
});
$('#FeedData').val(JSON.stringify(payload));
$("#FeedFetchSelectedFromFreetextIndexForm").submit();
}
</script>

View File

@ -20,8 +20,12 @@
<tr>
<th><?php echo $this->Paginator->sort('id');?></th>
<th><?php echo $this->Paginator->sort('name');?></th>
<th><?php echo $this->Paginator->sort('source_format', 'Feed Format');?></th>
<th><?php echo $this->Paginator->sort('provider');?></th>
<th><?php echo $this->Paginator->sort('url');?></th>
<th>Target</th>
<th>Publish</th>
<th>Delta Merge</th>
<th><?php echo $this->Paginator->sort('distribution');?></th>
<th><?php echo $this->Paginator->sort('tag');?></th>
<th><?php echo $this->Paginator->sort('enabled');?></th>
@ -61,8 +65,48 @@ foreach ($feeds as $item):
endif;
?>
</td>
<td><?php echo $feed_types[$item['Feed']['source_format']]['name']; ?>&nbsp;</td>
<td><?php echo h($item['Feed']['provider']); ?>&nbsp;</td>
<td><?php echo h($item['Feed']['url']); ?>&nbsp;</td>
<td class="shortish">
<?php
if ($item['Feed']['source_format'] == 'freetext'):
if ($item['Feed']['fixed_event']):
if ($item['Feed']['event_id']):
?>
<a href="<?php echo $baseurl;?>/events/view/<?php echo h($item['Feed']['event_id']); ?>">Fixed event <?php echo h($item['Feed']['event_id']); ?></a>
<?php
else:
echo 'New fixed event';
endif;
endif;
else:
echo ' ';
endif;
?>
</td>
<td>
<?php
if ($item['Feed']['source_format'] == 'freetext'):
?>
<span class="<?php echo ($item['Feed']['publish'] ? 'icon-ok' : 'icon-remove'); ?>"></span>
<?php
else:
echo ' ';
endif;
?>
</td>
<td>
<?php
if ($item['Feed']['source_format'] == 'freetext'):
?>
<span class="<?php echo ($item['Feed']['delta_merge'] ? 'icon-ok' : 'icon-remove'); ?>"></span>
<?php
else:
echo ' ';
endif;
?>
</td>
<td <?php if ($item['Feed']['distribution'] == 0) echo 'class="red"'; ?>>
<?php
echo $item['Feed']['distribution'] == 4 ? '<a href="' . $baseurl . '/sharing_groups/view/' . h($item['SharingGroup']['id']) . '">' . h($item['SharingGroup']['name']) . '</a>' : $distributionLevels[$item['Feed']['distribution']] ;