mirror of https://github.com/MISP/MISP
new: [collections] feature added. Still missing sync integration - WiP
parent
553e328f1d
commit
846c130fa3
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
use PHPUnit\Framework\MockObject\InvalidMethodNameException;
|
||||
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
class CollectionElementsController extends AppController
|
||||
{
|
||||
|
||||
public $components = ['Session', 'RequestHandler'];
|
||||
|
||||
public $paginate = [
|
||||
'limit' => 60,
|
||||
'order' => []
|
||||
];
|
||||
|
||||
public $uses = [
|
||||
];
|
||||
|
||||
public function add($collection_id)
|
||||
{
|
||||
$this->CollectionElement->Collection->current_user = $this->Auth->user();
|
||||
if (!$this->CollectionElement->Collection->mayModify($this->Auth->user('id'), intval($collection_id))) {
|
||||
throw new MethodNotAllowedException(__('Invalid Collection or insuficient privileges'));
|
||||
}
|
||||
$this->CRUD->add([
|
||||
'beforeSave' => function (array $collectionElement) use ($collection_id) {
|
||||
$collectionElement['CollectionElement']['collection_id'] = intval($collection_id);
|
||||
return $collectionElement;
|
||||
}
|
||||
]);
|
||||
if ($this->restResponsePayload) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$dropdownData = [
|
||||
'types' => array_combine($this->CollectionElement->valid_types, $this->CollectionElement->valid_types)
|
||||
];
|
||||
$this->set(compact('dropdownData'));
|
||||
$this->set('menuData', array('menuList' => 'collections', 'menuItem' => 'add_element'));
|
||||
}
|
||||
|
||||
public function delete($element_id)
|
||||
{
|
||||
$collectionElement = $this->CollectionElement->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => [
|
||||
'CollectionElement.id' => $element_id
|
||||
]
|
||||
]);
|
||||
$collection_id = $collectionElement['CollectionElement']['collection_id'];
|
||||
if (!$this->CollectionElement->Collection->mayModify($this->Auth->user('id'), $collection_id)) {
|
||||
throw new MethodNotAllowedException(__('Invalid Collection or insuficient privileges'));
|
||||
}
|
||||
$this->CRUD->delete($element_id);
|
||||
if ($this->restResponsePayload) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
}
|
||||
|
||||
public function index($collection_id)
|
||||
{
|
||||
$this->set('menuData', array('menuList' => 'collections', 'menuItem' => 'index'));
|
||||
if (!$this->CollectionElement->Collection->mayView($this->Auth->user('id'), intval($collection_id))) {
|
||||
throw new NotFoundException(__('Invalid collection or no access.'));
|
||||
}
|
||||
$params = [
|
||||
'filters' => ['uuid', 'type', 'name'],
|
||||
'quickFilters' => ['name'],
|
||||
'conditions' => ['collection_id' => $collection_id]
|
||||
];
|
||||
$this->loadModel('Event');
|
||||
$this->set('distributionLevels', $this->Event->distributionLevels);
|
||||
$this->CRUD->index($params);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
}
|
||||
|
||||
public function addElementToCollection($element_type, $element_uuid)
|
||||
{
|
||||
if ($this->request->is('get')) {
|
||||
$validCollections = $this->CollectionElement->Collection->find('list', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['Collection.id', 'Collection.name'],
|
||||
'conditions' => ['Collection.orgc_id' => $this->Auth->user('org_id')]
|
||||
]);
|
||||
if (empty($validCollections)) {
|
||||
throw new NotFoundException(__('You don\'t have any collections yet. Make sure you create one first before you can start adding elements.'));
|
||||
}
|
||||
$dropdownData = [
|
||||
'collections' => $validCollections
|
||||
];
|
||||
$this->set(compact('dropdownData'));
|
||||
} else if ($this->request->is('post')) {
|
||||
if (!isset($this->request->data['CollectionElement'])) {
|
||||
$this->request->data = ['CollectionElement' => $this->request->data];
|
||||
}
|
||||
if (!isset($this->request->data['CollectionElement']['collection_id'])) {
|
||||
throw new NotFoundException(__('No collection_id specified.'));
|
||||
}
|
||||
$collection_id = intval($this->request->data['CollectionElement']['collection_id']);
|
||||
if (!$this->CollectionElement->Collection->mayModify($this->Auth->user('id'), $collection_id)) {
|
||||
throw new NotFoundException(__('Invalid collection or not authorized.'));
|
||||
}
|
||||
$description = empty($this->request->data['CollectionElement']['description']) ? '' : $this->request->data['CollectionElement']['description'];
|
||||
$dataToSave = [
|
||||
'CollectionElement' => [
|
||||
'element_uuid' => $element_uuid,
|
||||
'element_type' => $element_type,
|
||||
'description' => $description,
|
||||
'collection_id' => $collection_id
|
||||
]
|
||||
];
|
||||
$this->CollectionElement->create();
|
||||
$error = '';
|
||||
try {
|
||||
$result = $this->CollectionElement->save($dataToSave);
|
||||
} catch (PDOException $e) {
|
||||
if ($e->errorInfo[0] == 23000) {
|
||||
$error = __(' Element already in Collection.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
$message = __('Element added to the Collection.');
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->RestResponse->saveSuccessResponse('CollectionElements', 'addElementToCollection', false, $this->response->type(), $message);
|
||||
} else {
|
||||
$this->Flash->success($message);
|
||||
$this->redirect(Router::url($this->referer(), true));
|
||||
}
|
||||
} else {
|
||||
$message = __('Element could not be added to the Collection.%s', $error);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->RestResponse->saveFailResponse('CollectionElements', 'addElementToCollection', false, $message, $this->response->type());
|
||||
} else {
|
||||
$this->Flash->error($message);
|
||||
$this->redirect(Router::url($this->referer(), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
class CollectionsController extends AppController
|
||||
{
|
||||
|
||||
public $components = ['Session', 'RequestHandler'];
|
||||
|
||||
public $paginate = [
|
||||
'limit' => 60,
|
||||
'order' => []
|
||||
];
|
||||
|
||||
public $uses = [
|
||||
];
|
||||
|
||||
private $valid_types = [
|
||||
'campaign',
|
||||
'intrusion_set',
|
||||
'named_threat',
|
||||
'other',
|
||||
'research'
|
||||
];
|
||||
|
||||
public function add()
|
||||
{
|
||||
$this->Collection->current_user = $this->Auth->user();
|
||||
$params = [];
|
||||
if ($this->request->is('post')) {
|
||||
$data = $this->request->data;
|
||||
$params = [
|
||||
'afterSave' => function (array $collection) use ($data) {
|
||||
$this->Collection->CollectionElement->captureElements($collection);
|
||||
return $collection;
|
||||
}
|
||||
];
|
||||
}
|
||||
$this->CRUD->add($params);
|
||||
if ($this->restResponsePayload) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('menuData', array('menuList' => 'collections', 'menuItem' => 'add'));
|
||||
$this->loadModel('Event');
|
||||
$dropdownData = [
|
||||
'types' => array_combine($this->valid_types, $this->valid_types),
|
||||
'distributionLevels' => $this->Event->distributionLevels,
|
||||
'sgs' => $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1)
|
||||
];
|
||||
$this->set('initialDistribution', Configure::read('MISP.default_event_distribution'));
|
||||
$this->set(compact('dropdownData'));
|
||||
$this->render('add');
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$this->Collection->current_user = $this->Auth->user();
|
||||
if (!$this->Collection->mayModify($this->Auth->user('id'), $id)) {
|
||||
throw new MethodNotAllowedException(__('Invalid Collection or insuficient privileges'));
|
||||
}
|
||||
$params = [];
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$oldCollection = $this->Collection->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['Collection.id' => intval($id)]
|
||||
]);
|
||||
if (empty($oldCollection)) {
|
||||
throw new NotFoundException(__('Invalid collection.'));
|
||||
}
|
||||
if (empty($this->request->data['Collection'])) {
|
||||
$this->request->data = ['Collection' => $this->request->data];
|
||||
}
|
||||
$data = $this->request->data;
|
||||
if (
|
||||
isset($data['Collection']['modified']) &&
|
||||
$data['Collection']['modified'] <= $oldCollection['Collection']['modified']
|
||||
) {
|
||||
throw new ForbiddenException(__('Collection received older or same as local version.'));
|
||||
}
|
||||
$params = [
|
||||
'afterSave' => function (array &$collection) use ($data) {
|
||||
$collection = $this->Collection->CollectionElement->captureElements($collection);
|
||||
return $collection;
|
||||
}
|
||||
];
|
||||
}
|
||||
$this->set('id', $id);
|
||||
$this->CRUD->edit($id, $params);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('menuData', array('menuList' => 'collections', 'menuItem' => 'edit'));
|
||||
$this->loadModel('Event');
|
||||
$dropdownData = [
|
||||
'types' => $this->valid_types,
|
||||
'distributionLevels' => $this->Event->distributionLevels,
|
||||
'sgs' => $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1)
|
||||
];
|
||||
$this->set(compact('dropdownData'));
|
||||
$this->render('add');
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
if (!$this->Collection->mayModify($this->Auth->user('id'), $id)) {
|
||||
throw new MethodNotAllowedException(__('Invalid Collection or insuficient privileges'));
|
||||
}
|
||||
$this->CRUD->delete($id);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
}
|
||||
|
||||
public function view($id)
|
||||
{
|
||||
$this->set('mayModify', $this->Collection->mayModify($this->Auth->user('id'), $id));
|
||||
if (!$this->Collection->mayView($this->Auth->user('id'), $id)) {
|
||||
throw new MethodNotAllowedException(__('Invalid Collection or insuficient privileges'));
|
||||
}
|
||||
$this->set('menuData', array('menuList' => 'collections', 'menuItem' => 'view'));
|
||||
$params = [
|
||||
'contain' => [
|
||||
'Orgc',
|
||||
'Org',
|
||||
'User',
|
||||
'CollectionElement'
|
||||
],
|
||||
'afterFind' => function (array $collection){
|
||||
return $this->Collection->rearrangeCollection($collection);
|
||||
}
|
||||
];
|
||||
$this->CRUD->view($id, $params);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
$this->set('id', $id);
|
||||
$this->loadModel('Event');
|
||||
$this->set('distributionLevels', $this->Event->distributionLevels);
|
||||
$this->render('view');
|
||||
}
|
||||
|
||||
public function index($filter = null)
|
||||
{
|
||||
$this->set('menuData', array('menuList' => 'collections', 'menuItem' => 'index'));
|
||||
$params = [
|
||||
'filters' => ['Collection.uuid', 'Collection.type', 'Collection.name'],
|
||||
'quickFilters' => ['Collection.name'],
|
||||
'contain' => ['Orgc'],
|
||||
'afterFind' => function($collections) {
|
||||
foreach ($collections as $k => $collection) {
|
||||
$collections[$k]['Collection']['element_count'] = $this->Collection->CollectionElement->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['CollectionElement.collection_id' => $collection['Collection']['id']]
|
||||
]);
|
||||
}
|
||||
return $collections;
|
||||
}
|
||||
];
|
||||
if ($filter === 'my_collections') {
|
||||
$params['conditions']['Collection.user_id'] = $this->Auth->user('id');
|
||||
}
|
||||
if ($filter === 'org_collections') {
|
||||
$params['conditions']['Collection.orgc_id'] = $this->Auth->user('org_id');
|
||||
}
|
||||
$this->loadModel('Event');
|
||||
$this->set('distributionLevels', $this->Event->distributionLevels);
|
||||
$this->CRUD->index($params);
|
||||
if ($this->IndexFilter->isRest()) {
|
||||
return $this->restResponsePayload;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -89,6 +89,19 @@ class ACLComponent extends Component
|
|||
'pull_sgs' => [],
|
||||
'view' => []
|
||||
],
|
||||
'collections' => [
|
||||
'add' => ['perm_modify'],
|
||||
'delete' => ['perm_modify'],
|
||||
'edit' => ['perm_modify'],
|
||||
'index' => ['*'],
|
||||
'view' => ['*']
|
||||
],
|
||||
'collectionElements' => [
|
||||
'add' => ['perm_modify'],
|
||||
'addElementToCollection' => ['perm_modify'],
|
||||
'delete' => ['perm_modify'],
|
||||
'index' => ['*']
|
||||
],
|
||||
'correlationExclusions' => [
|
||||
'add' => [],
|
||||
'edit' => [],
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
class Collection extends AppModel
|
||||
{
|
||||
|
||||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'Containable'
|
||||
);
|
||||
|
||||
public $belongsTo = [
|
||||
'Orgc' => array(
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'orgc_id',
|
||||
'fields' => [
|
||||
'Orgc.id',
|
||||
'Orgc.uuid',
|
||||
'Orgc.name'
|
||||
]
|
||||
),
|
||||
'Org' => array(
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'org_id',
|
||||
'fields' => [
|
||||
'Org.id',
|
||||
'Org.uuid',
|
||||
'Org.name'
|
||||
]
|
||||
),
|
||||
'User' => array(
|
||||
'className' => 'User',
|
||||
'foreignKey' => 'user_id',
|
||||
'fields' => [
|
||||
'User.id',
|
||||
'User.email'
|
||||
]
|
||||
)
|
||||
];
|
||||
|
||||
public $hasMany = [
|
||||
'CollectionElement'
|
||||
];
|
||||
|
||||
public $valid_targets = [
|
||||
'Attribute',
|
||||
'Event',
|
||||
'GalaxyCluster',
|
||||
'Galaxy',
|
||||
'Object',
|
||||
'Note',
|
||||
'Opinion',
|
||||
'Relationship',
|
||||
'Organisation',
|
||||
'SharingGroup'
|
||||
];
|
||||
|
||||
public $current_user = null;
|
||||
|
||||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
if (empty($this->data['Collection'])) {
|
||||
$this->data = ['Collection' => $this->data];
|
||||
}
|
||||
if (empty($this->id) && empty($this->data['Collection']['uuid'])) {
|
||||
$this->data['Collection']['uuid'] = CakeText::uuid();
|
||||
}
|
||||
if (empty($this->id)) {
|
||||
$this->data['Collection']['user_id'] = $this->current_user['id'];
|
||||
if (empty($this->data['Collection']['orgc_id']) || empty($this->current_user['Role']['perm_sync'])) {
|
||||
$this->data['Collection']['orgc_id'] = $this->current_user['Organisation']['id'];
|
||||
}
|
||||
$this->data['Collection']['org_id'] = $this->current_user['Organisation']['id'];
|
||||
$this->data['Collection']['user_id'] = $this->current_user['id'];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function mayModify($user_id, $collection_id)
|
||||
{
|
||||
$user = $this->User->getAuthUser($user_id);
|
||||
$collection = $this->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['Collection.id' => $collection_id]
|
||||
]);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
return true;
|
||||
}
|
||||
if (empty($user['Role']['perm_modify'])) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($user['Role']['perm_modify_org'])) {
|
||||
if ($user['org_id'] == $collection['Collection']['Orgc_id']) {
|
||||
return true;
|
||||
}
|
||||
if ($user['Role']['perm_sync'] && $user['org_id'] == $collection['Collection']['Org_id']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!empty($user['Role']['perm_modify']) && $user['id'] === $collection['Collection']['user_id']) {
|
||||
}
|
||||
}
|
||||
|
||||
public function mayView($user_id, $collection_id)
|
||||
{
|
||||
$user = $this->User->getAuthUser($user_id);
|
||||
$collection = $this->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['Collection.id' => $collection_id]
|
||||
]);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
return true;
|
||||
}
|
||||
if ($collection['Collection']['org_id'] == $user('org_id')) {
|
||||
return true;
|
||||
}
|
||||
if (in_array($collection['Collection']['distribution'], [1,2,3])) {
|
||||
return true;
|
||||
}
|
||||
if ($collection['Collection']['distribution'] === 4) {
|
||||
$SharingGroup = ClassRegistry::init('SharingGroup');
|
||||
$sgs = $this->SharingGroup->fetchAllAuthorised($user, 'uuid');
|
||||
if (isset($sgs[$collection['Collection']['sharing_group_id']])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function rearrangeCollection(array $collection) {
|
||||
foreach ($collection as $key => $elements) {
|
||||
if ($key !== 'Collection') {
|
||||
$collection['Collection'][$key] = $elements;
|
||||
unset($collection[$key]);
|
||||
}
|
||||
}
|
||||
return $collection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
class CollectionElement extends AppModel
|
||||
{
|
||||
|
||||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'Containable'
|
||||
);
|
||||
|
||||
public $belongsTo = array(
|
||||
'Collection' => array(
|
||||
'className' => 'Collection',
|
||||
'foreignKey' => 'collection_id'
|
||||
)
|
||||
);
|
||||
|
||||
// Make sure you also update the validation for element_type to include anything you add here.
|
||||
public $valid_types = [
|
||||
'Event',
|
||||
'GalaxyCluster'
|
||||
];
|
||||
|
||||
public $validate = [
|
||||
'collection_id' => [
|
||||
'numeric' => [
|
||||
'rule' => ['numeric']
|
||||
]
|
||||
],
|
||||
'uuid' => [
|
||||
'uuid' => [
|
||||
'rule' => 'uuid',
|
||||
'message' => 'Please provide a valid RFC 4122 UUID'
|
||||
]
|
||||
],
|
||||
'element_uuid' => [
|
||||
'element_uuid' => [
|
||||
'rule' => 'uuid',
|
||||
'message' => 'Please provide a valid RFC 4122 UUID'
|
||||
]
|
||||
],
|
||||
'element_type' => [
|
||||
'element_type' => [
|
||||
'rule' => ['inList', ['Event', 'GalaxyCluster']],
|
||||
'message' => 'Invalid object type.'
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
// Massage to a common format
|
||||
if (empty($this->data['CollectionElement'])) {
|
||||
$this->data = ['CollectionElement' => $this->data];
|
||||
}
|
||||
|
||||
// if we're creating a new element, assign a uuid (unless provided)
|
||||
if (empty($this->id) && empty($this->data['CollectionElement']['uuid'])) {
|
||||
$this->data['CollectionElement']['uuid'] = CakeText::uuid();
|
||||
}
|
||||
if (
|
||||
empty($this->id) &&
|
||||
empty($this->data['CollectionElement']['element_type']) &&
|
||||
!empty($this->data['CollectionElement']['element_uuid'])
|
||||
) {
|
||||
$this->data['CollectionElement']['element_type'] = $this->deduceType($this->data['CollectionElement']['element_uuid']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function mayModify(int $user_id, int $collection_id)
|
||||
{
|
||||
$user = $this->User->getAuthUser($user_id);
|
||||
$collection = $this->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['Collection.id' => $collection_id]
|
||||
]);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
return true;
|
||||
}
|
||||
if (empty($user['Role']['perm_modify'])) {
|
||||
return false;
|
||||
}
|
||||
if (!empty($user['Role']['perm_modify_org'])) {
|
||||
if ($user['org_id'] == $collection['Collection']['Orgc_id']) {
|
||||
return true;
|
||||
}
|
||||
if ($user['Role']['perm_sync'] && $user['org_id'] == $collection['Collection']['Org_id']) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!empty($user['Role']['perm_modify']) && $user['id'] === $collection['Collection']['user_id']) {
|
||||
}
|
||||
}
|
||||
|
||||
public function mayView(int $user_id, int $collection_id)
|
||||
{
|
||||
$user = $this->User->getAuthUser($user_id);
|
||||
$collection = $this->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['Collection.id' => $collection_id]
|
||||
]);
|
||||
if ($user['Role']['perm_site_admin']) {
|
||||
return true;
|
||||
}
|
||||
if ($collection['Collection']['org_id'] == $user('org_id')) {
|
||||
return true;
|
||||
}
|
||||
if (in_array($collection['Collection']['distribution'], [1,2,3])) {
|
||||
return true;
|
||||
}
|
||||
if ($collection['Collection']['distribution'] === 4) {
|
||||
$SharingGroup = ClassRegistry::init('SharingGroup');
|
||||
$sgs = $this->SharingGroup->fetchAllAuthorised($user, 'uuid');
|
||||
if (isset($sgs[$collection['Collection']['sharing_group_id']])) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function deduceType(string $uuid)
|
||||
{
|
||||
foreach ($this->valid_types as $valid_type) {
|
||||
$this->{$valid_type} = ClassRegistry::init($valid_type);
|
||||
$result = $this->$valid_type->find('first', [
|
||||
'conditions' => [$valid_type.'.uuid' => $uuid],
|
||||
'recursive' => -1
|
||||
]);
|
||||
if (!empty($result)) {
|
||||
return $valid_type;
|
||||
}
|
||||
}
|
||||
throw new NotFoundException(__('Invalid UUID'));
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass a Collection as received from another instance to this function to capture the elements
|
||||
* The received object is authoritative, so all elements that no longer exist in the upstream will be culled.
|
||||
*/
|
||||
public function captureElements($data) {
|
||||
$temp = $this->find('all', [
|
||||
'recursive' => -1,
|
||||
'conditions' => ['CollectionElement.collection_id' => $data['Collection']['id']]
|
||||
]);
|
||||
$oldElements = [];
|
||||
foreach ($temp as $oldElement) {
|
||||
$oldElements[$oldElement['CollectionElement']['uuid']] = $oldElement['CollectionElement'];
|
||||
}
|
||||
if (isset($data['Collection']['CollectionElement'])) {
|
||||
$elementsToSave = [];
|
||||
foreach ($data['Collection']['CollectionElement'] as $k => $element) {
|
||||
if (empty($element['uuid'])) {
|
||||
$element['uuid'] = CakeText::uuid();
|
||||
}
|
||||
if (isset($oldElements[$element['uuid']])) {
|
||||
if (isset($element['description'])) {
|
||||
$oldElements[$element['uuid']]['description'] = $element['description'];
|
||||
}
|
||||
$elementsToSave[$k] = $oldElements[$element['uuid']];
|
||||
unset($oldElements[$element['uuid']]);
|
||||
} else {
|
||||
$elementsToSave[$k] = [
|
||||
'CollectionElement' => [
|
||||
'uuid' => $element['uuid'],
|
||||
'element_uuid' => $element['element_uuid'],
|
||||
'element_type' => $element['element_type'],
|
||||
'description' => $element['description'],
|
||||
'collection_id' => $data['Collection']['id']
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
foreach ($elementsToSave as $k => $element) {
|
||||
if (empty($element['CollectionElement']['id'])) {
|
||||
$this->create();
|
||||
}
|
||||
try{
|
||||
$this->save($element);
|
||||
} catch (PDOException $e) {
|
||||
// duplicate value?
|
||||
}
|
||||
}
|
||||
foreach ($oldElements as $toDelete) {
|
||||
$this->delete($toDelete['id']);
|
||||
}
|
||||
$temp = $this->find('all', [
|
||||
'conditions' => ['CollectionElement.collection_id' => $data['Collection']['id']],
|
||||
'recursive' => -1
|
||||
]);
|
||||
$data['Collection']['CollectionElement'] = [];
|
||||
foreach ($temp as $element) {
|
||||
$data['Collection']['CollectionElement'][] = $element['CollectionElement'];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
$edit = $this->request->params['action'] === 'edit' ? true : false;
|
||||
$fields = [
|
||||
[
|
||||
'field' => 'element_uuid',
|
||||
'class' => 'input span6',
|
||||
'onChange' => 'alert(1);'
|
||||
],
|
||||
[
|
||||
'field' => 'element_type',
|
||||
'class' => 'input span6',
|
||||
'options' => $dropdownData['types'],
|
||||
'type' => 'dropdown'
|
||||
],
|
||||
[
|
||||
'field' => 'description',
|
||||
'class' => 'span6',
|
||||
'type' => 'textarea'
|
||||
]
|
||||
];
|
||||
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'description' => null,
|
||||
'model' => 'CollectionElement',
|
||||
'title' => __('Add element to Collection'),
|
||||
'fields' => $fields,
|
||||
'submit' => [
|
||||
'action' => $this->request->params['action'],
|
||||
'ajaxSubmit' => 'submitGenericFormInPlace();'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
if (!$ajax) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', $menuData);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
$fields = [
|
||||
[
|
||||
'field' => 'collection_id',
|
||||
'class' => 'input span6',
|
||||
'options' => $dropdownData['collections'],
|
||||
'type' => 'dropdown'
|
||||
],
|
||||
[
|
||||
'field' => 'description',
|
||||
'class' => 'span6',
|
||||
'type' => 'textarea'
|
||||
]
|
||||
];
|
||||
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'description' => null,
|
||||
'model' => 'CollectionElement',
|
||||
'title' => __('Add element to Collection'),
|
||||
'fields' => $fields,
|
||||
'submit' => [
|
||||
'action' => $this->request->params['action'],
|
||||
//'ajaxSubmit' => 'submitGenericFormInPlace();'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
$fields = [
|
||||
[
|
||||
'name' => __('Id'),
|
||||
'sort' => 'CollectionElement.id',
|
||||
'data_path' => 'CollectionElement.id'
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'data_path' => 'CollectionElement.uuid'
|
||||
],
|
||||
[
|
||||
'name' => __('Element'),
|
||||
'sort' => 'CollectionElement.element_type',
|
||||
'element' => 'model',
|
||||
'model_name' => 'CollectionElement.element_type',
|
||||
'model_id' => 'CollectionElement.element_uuid'
|
||||
],
|
||||
[
|
||||
'name' => __('Element type'),
|
||||
'data_path' => 'CollectionElement.element_type'
|
||||
],
|
||||
[
|
||||
'name' => __('Description'),
|
||||
'data_path' => 'CollectionElement.description'
|
||||
]
|
||||
];
|
||||
|
||||
echo $this->element('genericElements/IndexTable/scaffold', [
|
||||
'scaffold_data' => [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'quickFilter'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => $fields,
|
||||
'title' => empty($ajax) ? __('Collection element index') : false,
|
||||
'actions' => [
|
||||
[
|
||||
'onclick' => sprintf(
|
||||
'openGenericModal(\'%s/collectionElements/delete/[onclick_params_data_path]\');',
|
||||
$baseurl
|
||||
),
|
||||
'onclick_params_data_path' => 'CollectionElement.id',
|
||||
'icon' => 'trash'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
?>
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
$edit = $this->request->params['action'] === 'edit' ? true : false;
|
||||
$fields = [
|
||||
[
|
||||
'field' => 'name',
|
||||
'class' => 'span6'
|
||||
],
|
||||
[
|
||||
'field' => 'type',
|
||||
'class' => 'input span6',
|
||||
'options' => $dropdownData['types'],
|
||||
'type' => 'dropdown'
|
||||
],
|
||||
[
|
||||
'field' => 'description',
|
||||
'class' => 'span6',
|
||||
'type' => 'textarea'
|
||||
],
|
||||
[
|
||||
'field' => 'distribution',
|
||||
'class' => 'input',
|
||||
'options' => $dropdownData['distributionLevels'],
|
||||
'default' => isset($data['Collection']['distribution']) ? $data['Collection']['distribution'] : $initialDistribution,
|
||||
'stayInLine' => 1,
|
||||
'type' => 'dropdown'
|
||||
],
|
||||
[
|
||||
'field' => 'sharing_group_id',
|
||||
'class' => 'input',
|
||||
'options' => $dropdownData['sgs'],
|
||||
'label' => __("Sharing Group"),
|
||||
'type' => 'dropdown'
|
||||
]
|
||||
];
|
||||
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'data' => [
|
||||
'description' => __('Create collections to organise data shared by the community into buckets based on commonalities or as part of your research process. Collections are first class citizens and adhere to the same sharing rules as for example events do.'),
|
||||
'model' => 'Collection',
|
||||
'title' => $edit ? __('Edit collection') : __('Add new collection'),
|
||||
'fields' => $fields,
|
||||
'submit' => [
|
||||
'action' => $this->request->params['action'],
|
||||
'ajaxSubmit' => 'submitGenericFormInPlace();'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
if (!$ajax) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', $menuData);
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
$fields = [
|
||||
[
|
||||
'name' => __('Id'),
|
||||
'sort' => 'Collection.id',
|
||||
'data_path' => 'Collection.id'
|
||||
],
|
||||
[
|
||||
'name' => __('Name'),
|
||||
'sort' => 'Collection.name',
|
||||
'data_path' => 'Collection.name'
|
||||
],
|
||||
[
|
||||
'name' => __('Organisation'),
|
||||
'sort' => 'Orgc.name',
|
||||
'data_path' => 'Orgc',
|
||||
'element' => 'org'
|
||||
],
|
||||
[
|
||||
'name' => __('Elements'),
|
||||
'sort' => 'Collection.element_count',
|
||||
'data_path' => 'Collection.element_count'
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'data_path' => 'Collection.uuid'
|
||||
],
|
||||
[
|
||||
'name' => __('Type'),
|
||||
'data_path' => 'Collection.type'
|
||||
],
|
||||
[
|
||||
'name' => __('Created'),
|
||||
'sort' => 'Collection.created',
|
||||
'data_path' => 'Collection.created'
|
||||
],
|
||||
[
|
||||
'name' => __('Modified'),
|
||||
'sort' => 'Collection.modified',
|
||||
'data_path' => 'Collection.modified'
|
||||
],
|
||||
[
|
||||
'name' => __('Distribution'),
|
||||
'sort' => 'distribution',
|
||||
'data_path' => 'Collection.distribution',
|
||||
'element' => 'distribution_levels'
|
||||
],
|
||||
];
|
||||
|
||||
echo $this->element('genericElements/IndexTable/scaffold', [
|
||||
'scaffold_data' => [
|
||||
'data' => [
|
||||
'data' => $data,
|
||||
'top_bar' => [
|
||||
'pull' => 'right',
|
||||
'children' => [
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
'searchKey' => 'quickFilter'
|
||||
]
|
||||
]
|
||||
],
|
||||
'fields' => $fields,
|
||||
'title' => empty($ajax) ? __('Collections index') : false,
|
||||
'actions' => [
|
||||
[
|
||||
'url' => $baseurl . '/collections/view',
|
||||
'url_params_data_paths' => ['Collection.id'],
|
||||
'icon' => 'eye'
|
||||
],
|
||||
[
|
||||
'onclick' => sprintf(
|
||||
'openGenericModal(\'%s/collections/edit/[onclick_params_data_path]\');',
|
||||
$baseurl
|
||||
),
|
||||
'onclick_params_data_path' => 'Collection.id',
|
||||
'title' => __('Edit Collection'),
|
||||
'icon' => 'edit'
|
||||
],
|
||||
[
|
||||
'onclick' => sprintf(
|
||||
'openGenericModal(\'%s/collections/delete/[onclick_params_data_path]\');',
|
||||
$baseurl
|
||||
),
|
||||
'onclick_params_data_path' => 'Collection.id',
|
||||
'icon' => 'trash'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
?>
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
echo $this->element(
|
||||
'genericElements/SingleViews/single_view',
|
||||
[
|
||||
'title' => __('Collection view'),
|
||||
'data' => $data,
|
||||
'fields' => [
|
||||
[
|
||||
'key' => __('ID'),
|
||||
'path' => 'Collection.id'
|
||||
],
|
||||
[
|
||||
'key' => __('UUID'),
|
||||
'path' => 'Collection.uuid'
|
||||
],
|
||||
[
|
||||
'key' => __('Creator org'),
|
||||
'path' => 'Collection.orgc_id',
|
||||
'pathName' => 'Collection.Orgc.name',
|
||||
'type' => 'model',
|
||||
'model' => 'organisations'
|
||||
],
|
||||
[
|
||||
'key' => __('Owner org'),
|
||||
'path' => 'Collection.org_id',
|
||||
'pathName' => 'Collection.Org.name',
|
||||
'type' => 'model',
|
||||
'model' => 'organisations'
|
||||
],
|
||||
[
|
||||
'key' => __('Created'),
|
||||
'path' => 'Collection.created'
|
||||
],
|
||||
[
|
||||
'key' => __('Modified'),
|
||||
'path' => 'Collection.modified'
|
||||
],
|
||||
[
|
||||
'key' => __('Name'),
|
||||
'path' => 'Collection.name'
|
||||
],
|
||||
[
|
||||
'key' => __('Description'),
|
||||
'path' => 'Collection.description'
|
||||
],
|
||||
[
|
||||
'key' => __('Distribution'),
|
||||
'path' => 'Collection.distribution',
|
||||
'event_id_path' => 'Collection.id',
|
||||
'disable_distribution_graph' => true,
|
||||
'sg_path' => 'Collection.sharing_group_id',
|
||||
'type' => 'distribution'
|
||||
]
|
||||
],
|
||||
'children' => [
|
||||
[
|
||||
'url' => '/collectionElements/index/{{0}}/',
|
||||
'url_params' => ['Collection.id'],
|
||||
'title' => __('Collection elements'),
|
||||
'elementId' => 'preview_elements_container'
|
||||
]
|
||||
]
|
||||
]
|
||||
);
|
|
@ -1,3 +1,22 @@
|
|||
<?php
|
||||
$data = Hash::extract($row, $field['data_path']);
|
||||
echo h($data['model']) . ' #' . intval($data['model_id']);
|
||||
if (!empty($field['data_path'])) {
|
||||
$data = Hash::extract($row, $field['data_path']);
|
||||
if (isset($data['model_id'])) {
|
||||
echo h($data['model']) . ' #' . intval($data['model_id']);
|
||||
}
|
||||
} else {
|
||||
$model_name = Hash::extract($row, $field['model_name'])[0];
|
||||
$model_path = Inflector::Pluralize($model_name);
|
||||
$model_id = Hash::extract($row, $field['model_id'])[0];
|
||||
echo sprintf(
|
||||
'<a href="%s/%s/view/%s">%s (%s)</a>',
|
||||
$baseurl,
|
||||
h($model_path),
|
||||
h($model_id),
|
||||
h($model_name),
|
||||
h($model_id)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -265,6 +265,22 @@ $divider = '<li class="divider"></li>';
|
|||
'text' => __('Download as…')
|
||||
));
|
||||
echo $divider;
|
||||
if ($me['Role']['perm_modify']) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => [
|
||||
sprintf(
|
||||
'%s/collectionElements/addElementToCollection/Event/%s',
|
||||
$baseurl,
|
||||
h($event['Event']['uuid'])
|
||||
)
|
||||
]
|
||||
),
|
||||
'text' => __('Add Event to Collection')
|
||||
));
|
||||
echo $divider;
|
||||
}
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => $baseurl . '/events/index',
|
||||
'text' => __('List Events')
|
||||
|
@ -314,7 +330,50 @@ $divider = '<li class="divider"></li>';
|
|||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'collections':
|
||||
if ($menuItem === 'edit' || $menuItem === 'view') {
|
||||
if ($this->Acl->canAccess('collections', 'add') && $mayModify) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', [
|
||||
'element_id' => 'edit',
|
||||
'url' => $baseurl . '/collections/edit/' . h($id),
|
||||
'text' => __('Edit Collection')
|
||||
]);
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', [
|
||||
'element_id' => 'delete',
|
||||
'onClick' => [
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/Collections/delete/' . h($id))
|
||||
],
|
||||
'text' => __('Delete Collection')
|
||||
]);
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', [
|
||||
'text' => __('Add Element to Collection'),
|
||||
'onClick' => [
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/CollectionElements/add/' . h($id))
|
||||
],
|
||||
]);
|
||||
echo $divider;
|
||||
}
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'view',
|
||||
'url' => $baseurl . '/collections/view/' . h($id),
|
||||
'text' => __('View Collection')
|
||||
));
|
||||
}
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'index',
|
||||
'url' => $baseurl . '/collections/index',
|
||||
'text' => __('List Collections')
|
||||
));
|
||||
if ($this->Acl->canAccess('collection', 'add')) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'add',
|
||||
'url' => $baseurl . '/collections/add',
|
||||
'text' => __('Add Collection')
|
||||
));
|
||||
}
|
||||
break;
|
||||
case 'event-collection':
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'index',
|
||||
|
@ -1493,6 +1552,22 @@ $divider = '<li class="divider"></li>';
|
|||
'text' => __('View Correlation Graph')
|
||||
));
|
||||
}
|
||||
if ($me['Role']['perm_modify']) {
|
||||
echo $divider;
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => [
|
||||
sprintf(
|
||||
'%s/collectionElements/addElementToCollection/GalaxyCluster/%s',
|
||||
$baseurl,
|
||||
h($cluster['GalaxyCluster']['uuid'])
|
||||
)
|
||||
]
|
||||
),
|
||||
'text' => __('Add Cluster to Collection')
|
||||
));
|
||||
}
|
||||
}
|
||||
if ($menuItem === 'view' || $menuItem === 'export') {
|
||||
echo $divider;
|
||||
|
|
|
@ -31,6 +31,13 @@
|
|||
array(
|
||||
'type' => 'separator'
|
||||
),
|
||||
array(
|
||||
'text' => __('List Collections'),
|
||||
'url' => $baseurl . '/collections/index'
|
||||
),
|
||||
[
|
||||
'type' => 'separator'
|
||||
],
|
||||
array(
|
||||
'text' => __('View Proposals'),
|
||||
'url' => $baseurl . '/shadow_attributes/index/all:0'
|
||||
|
|
Loading…
Reference in New Issue