2016-03-16 01:30:39 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Campaign section of the CMS
|
|
|
|
*
|
|
|
|
* @package framework
|
|
|
|
* @subpackage admin
|
|
|
|
*/
|
|
|
|
class CampaignAdmin extends LeftAndMain implements PermissionProvider {
|
|
|
|
|
|
|
|
private static $allowed_actions = [
|
2016-03-29 06:35:10 +02:00
|
|
|
'set',
|
|
|
|
'sets',
|
2016-03-29 04:38:48 +02:00
|
|
|
'schema',
|
|
|
|
'DetailEditForm',
|
|
|
|
'readCampaigns',
|
2016-03-16 01:30:39 +01:00
|
|
|
'createCampaign',
|
|
|
|
'readCampaign',
|
|
|
|
'updateCampaign',
|
|
|
|
'deleteCampaign',
|
|
|
|
];
|
|
|
|
|
|
|
|
private static $menu_priority = 11;
|
|
|
|
|
|
|
|
private static $menu_title = 'Campaigns';
|
|
|
|
|
|
|
|
private static $url_handlers = [
|
2016-03-29 06:35:10 +02:00
|
|
|
'GET sets' => 'readCampaigns',
|
|
|
|
'POST set/$ID' => 'createCampaign',
|
|
|
|
'GET set/$ID' => 'readCampaign',
|
|
|
|
'PUT set/$ID' => 'updateCampaign',
|
|
|
|
'DELETE set/$ID' => 'deleteCampaign',
|
2016-03-16 01:30:39 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
private static $url_segment = 'campaigns';
|
|
|
|
|
2016-03-22 04:27:44 +01:00
|
|
|
public function getClientConfig() {
|
2016-03-23 11:16:03 +01:00
|
|
|
return array_merge(parent::getClientConfig(), [
|
|
|
|
'forms' => [
|
|
|
|
// TODO Use schemaUrl instead
|
|
|
|
'editForm' => [
|
|
|
|
'schemaUrl' => $this->Link('schema/EditForm')
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function schema($request) {
|
2016-03-23 00:12:48 +01:00
|
|
|
// TODO Hardcoding schema until we can get GridField to generate a schema dynamically
|
|
|
|
$json = <<<JSON
|
|
|
|
{
|
|
|
|
"id": "EditForm",
|
|
|
|
"schema": {
|
|
|
|
"name": "EditForm",
|
|
|
|
"id": "EditForm",
|
|
|
|
"action": "schema",
|
|
|
|
"method": "GET",
|
|
|
|
"schema_url": "admin\/campaigns\/schema\/EditForm",
|
|
|
|
"attributes": {
|
|
|
|
"id": "Form_EditForm",
|
|
|
|
"action": "admin\/campaigns\/EditForm",
|
|
|
|
"method": "POST",
|
|
|
|
"enctype": "multipart\/form-data",
|
|
|
|
"target": null,
|
|
|
|
"class": "cms-edit-form CampaignAdmin LeftAndMain"
|
|
|
|
},
|
|
|
|
"data": [],
|
|
|
|
"fields": [{
|
|
|
|
"name": "ID",
|
|
|
|
"id": "Form_EditForm_ID",
|
|
|
|
"type": "Hidden",
|
|
|
|
"component": null,
|
|
|
|
"holder_id": null,
|
|
|
|
"title": false,
|
|
|
|
"source": null,
|
|
|
|
"extraClass": "hidden nolabel",
|
|
|
|
"description": null,
|
|
|
|
"rightTitle": null,
|
|
|
|
"leftTitle": null,
|
|
|
|
"readOnly": false,
|
|
|
|
"disabled": false,
|
|
|
|
"customValidationMessage": "",
|
|
|
|
"attributes": [],
|
|
|
|
"data": []
|
|
|
|
}, {
|
|
|
|
"name": "ChangeSets",
|
|
|
|
"id": "Form_EditForm_ChangeSets",
|
|
|
|
"type": "Custom",
|
|
|
|
"component": "GridField",
|
|
|
|
"holder_id": null,
|
|
|
|
"title": "Campaigns",
|
|
|
|
"source": null,
|
|
|
|
"extraClass": null,
|
|
|
|
"description": null,
|
|
|
|
"rightTitle": null,
|
|
|
|
"leftTitle": null,
|
|
|
|
"readOnly": false,
|
|
|
|
"disabled": false,
|
|
|
|
"customValidationMessage": "",
|
|
|
|
"attributes": [],
|
|
|
|
"data": {
|
2016-03-29 04:38:48 +02:00
|
|
|
"recordType": "ChangeSet",
|
|
|
|
"collectionReadEndpoint": {
|
2016-03-29 06:35:10 +02:00
|
|
|
"url": "admin\/campaigns\/sets",
|
2016-03-22 00:25:23 +01:00
|
|
|
"method": "GET"
|
2016-03-23 00:12:48 +01:00
|
|
|
},
|
2016-03-29 04:38:48 +02:00
|
|
|
"itemReadEndpoint": {
|
2016-03-29 06:35:10 +02:00
|
|
|
"url": "admin\/campaigns\/set\/:id",
|
2016-03-22 00:25:23 +01:00
|
|
|
"method": "GET"
|
2016-03-23 00:12:48 +01:00
|
|
|
},
|
2016-03-29 04:38:48 +02:00
|
|
|
"itemUpdateEndpoint": {
|
2016-03-29 06:35:10 +02:00
|
|
|
"url": "admin\/campaigns\/set\/:id",
|
2016-03-22 00:25:23 +01:00
|
|
|
"method": "PUT"
|
2016-03-23 00:12:48 +01:00
|
|
|
},
|
2016-03-29 04:38:48 +02:00
|
|
|
"itemCreateEndpoint": {
|
2016-03-29 06:35:10 +02:00
|
|
|
"url": "admin\/campaigns\/set\/:id",
|
2016-03-22 00:25:23 +01:00
|
|
|
"method": "POST"
|
2016-03-23 00:12:48 +01:00
|
|
|
},
|
2016-03-29 04:38:48 +02:00
|
|
|
"itemDeleteEndpoint": {
|
2016-03-29 06:35:10 +02:00
|
|
|
"url": "admin\/campaigns\/set\/:id",
|
2016-03-22 00:25:23 +01:00
|
|
|
"method": "DELETE"
|
2016-03-23 00:12:48 +01:00
|
|
|
},
|
2016-03-29 04:38:48 +02:00
|
|
|
"editFormSchemaEndpoint": "admin\/campaigns\/schema\/DetailEditForm",
|
|
|
|
"columns": [
|
|
|
|
{"name": "Title", "field": "Name"},
|
|
|
|
{"name": "Changes", "field": "_embedded.ChangeSetItems.length"},
|
|
|
|
{"name": "Description", "field": "Description"}
|
|
|
|
]
|
2016-03-23 00:12:48 +01:00
|
|
|
}
|
|
|
|
}, {
|
|
|
|
"name": "SecurityID",
|
|
|
|
"id": "Form_EditForm_SecurityID",
|
|
|
|
"type": "Hidden",
|
|
|
|
"component": null,
|
|
|
|
"holder_id": null,
|
|
|
|
"title": "Security ID",
|
|
|
|
"source": null,
|
|
|
|
"extraClass": "hidden",
|
|
|
|
"description": null,
|
|
|
|
"rightTitle": null,
|
|
|
|
"leftTitle": null,
|
|
|
|
"readOnly": false,
|
|
|
|
"disabled": false,
|
|
|
|
"customValidationMessage": "",
|
|
|
|
"attributes": [],
|
|
|
|
"data": []
|
|
|
|
}],
|
|
|
|
"actions": []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
JSON;
|
|
|
|
|
2016-03-23 11:16:03 +01:00
|
|
|
$formName = $request->param('ID');
|
|
|
|
if($formName == 'EditForm') {
|
|
|
|
$response = $this->getResponse();
|
|
|
|
$response->addHeader('Content-Type', 'application/json');
|
|
|
|
$response->setBody($json);
|
|
|
|
return $response;
|
|
|
|
} else {
|
|
|
|
return parent::schema($request);
|
|
|
|
}
|
2016-03-23 00:12:48 +01:00
|
|
|
}
|
|
|
|
|
2016-03-16 01:30:39 +01:00
|
|
|
/**
|
|
|
|
* REST endpoint to create a campaign.
|
|
|
|
*
|
|
|
|
* @param SS_HTTPRequest $request
|
|
|
|
*
|
|
|
|
* @return SS_HTTPResponse
|
|
|
|
*/
|
|
|
|
public function createCampaign(SS_HTTPRequest $request) {
|
|
|
|
$response = new SS_HTTPResponse();
|
|
|
|
$response->addHeader('Content-Type', 'application/json');
|
|
|
|
$response->setBody(Convert::raw2json(['campaign' => 'create']));
|
|
|
|
|
2016-04-07 07:13:54 +02:00
|
|
|
// TODO Implement permission check and data creation
|
|
|
|
|
2016-03-16 01:30:39 +01:00
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2016-03-23 00:12:48 +01:00
|
|
|
/**
|
|
|
|
* REST endpoint to get a list of campaigns.
|
|
|
|
*
|
|
|
|
* @param SS_HTTPRequest $request
|
|
|
|
*
|
|
|
|
* @return SS_HTTPResponse
|
|
|
|
*/
|
|
|
|
public function readCampaigns(SS_HTTPRequest $request) {
|
|
|
|
$response = new SS_HTTPResponse();
|
|
|
|
$response->addHeader('Content-Type', 'application/json');
|
2016-03-29 06:35:10 +02:00
|
|
|
$hal = $this->getListResource();
|
|
|
|
$response->setBody(Convert::array2json($hal));
|
|
|
|
return $response;
|
2016-03-29 04:38:48 +02:00
|
|
|
}
|
2016-03-29 06:35:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get list contained as a hal wrapper
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function getListResource() {
|
|
|
|
$items = $this->getListItems();
|
|
|
|
$count = $items->count();
|
|
|
|
$hal = [
|
|
|
|
'count' => $count,
|
|
|
|
'total' => $count,
|
|
|
|
'_links' => [
|
|
|
|
'self' => [
|
|
|
|
'href' => $this->Link('items')
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'_embedded' => ['ChangeSets' => []]
|
|
|
|
];
|
|
|
|
foreach($items as $item) {
|
|
|
|
/** @var ChangeSet $item */
|
|
|
|
$resource = $this->getChangeSetResource($item);
|
|
|
|
$hal['_embedded']['ChangeSets'][] = $resource;
|
|
|
|
}
|
|
|
|
return $hal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build item resource from a changeset
|
|
|
|
*
|
|
|
|
* @param ChangeSet $changeSet
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function getChangeSetResource(ChangeSet $changeSet) {
|
|
|
|
$hal = [
|
|
|
|
'_links' => [
|
|
|
|
'self' => [
|
|
|
|
'href' => $this->SetLink($changeSet->ID)
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'ID' => $changeSet->ID,
|
|
|
|
'Name' => $changeSet->Name,
|
2016-04-07 02:48:40 +02:00
|
|
|
'Description' => $changeSet->getDescription(),
|
2016-03-29 06:35:10 +02:00
|
|
|
'Created' => $changeSet->Created,
|
|
|
|
'LastEdited' => $changeSet->LastEdited,
|
|
|
|
'State' => $changeSet->State,
|
|
|
|
'_embedded' => ['ChangeSetItems' => []]
|
|
|
|
];
|
|
|
|
foreach($changeSet->Changes() as $changeSetItem) {
|
2016-04-07 07:14:12 +02:00
|
|
|
if(!$changeSetItem) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-03-29 06:35:10 +02:00
|
|
|
/** @var ChangesetItem $changeSetItem */
|
|
|
|
$resource = $this->getChangeSetItemResource($changeSetItem);
|
|
|
|
$hal['_embedded']['ChangeSetItems'][] = $resource;
|
|
|
|
}
|
|
|
|
return $hal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build item resource from a changesetitem
|
|
|
|
*
|
|
|
|
* @param ChangeSetItem $changeSetItem
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function getChangeSetItemResource(ChangeSetItem $changeSetItem) {
|
2016-04-07 02:48:40 +02:00
|
|
|
$objectSingleton = DataObject::singleton($changeSetItem->ObjectClass);
|
2016-03-29 06:35:10 +02:00
|
|
|
$hal = [
|
|
|
|
'_links' => [
|
|
|
|
'self' => [
|
|
|
|
'href' => $this->ItemLink($changeSetItem->ID)
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'ID' => $changeSetItem->ID,
|
|
|
|
'Created' => $changeSetItem->Created,
|
|
|
|
'LastEdited' => $changeSetItem->LastEdited,
|
|
|
|
'Title' => $changeSetItem->getTitle(),
|
|
|
|
'ChangeType' => $changeSetItem->getChangeType(),
|
|
|
|
'Added' => $changeSetItem->Added,
|
2016-04-07 02:48:40 +02:00
|
|
|
'ObjectClass' => $changeSetItem->ObjectClass,
|
|
|
|
'ObjectID' => $changeSetItem->ObjectID,
|
|
|
|
'ObjectSingular' => $objectSingleton->i18n_singular_name(),
|
|
|
|
'ObjectPlural' => $objectSingleton->i18n_plural_name(),
|
2016-03-29 06:35:10 +02:00
|
|
|
];
|
|
|
|
// Depending on whether the object was added implicitly or explicitly, set
|
|
|
|
// other related objects.
|
|
|
|
if($changeSetItem->Added === ChangeSetItem::IMPLICITLY) {
|
|
|
|
$referencedItems = $changeSetItem->ReferencedBy();
|
|
|
|
$referencedBy = [];
|
|
|
|
foreach($referencedItems as $referencedItem) {
|
|
|
|
$referencedBy[] = [
|
|
|
|
'href' => $this->SetLink($referencedItem->ID)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
if($referencedBy) {
|
|
|
|
$hal['_links']['referenced_by'] = $referencedBy;
|
2016-03-29 04:38:48 +02:00
|
|
|
}
|
2016-03-29 06:35:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $hal;
|
2016-03-29 04:38:48 +02:00
|
|
|
}
|
2016-03-23 00:12:48 +01:00
|
|
|
|
2016-03-29 06:35:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets viewable list of campaigns
|
|
|
|
*
|
|
|
|
* @return SS_List
|
|
|
|
*/
|
|
|
|
protected function getListItems() {
|
|
|
|
return ChangeSet::get()
|
2016-04-07 07:14:12 +02:00
|
|
|
->filter('State', ChangeSet::STATE_OPEN)
|
|
|
|
->filterByCallback(function($item) {
|
|
|
|
return ($item->canView());
|
|
|
|
});
|
2016-03-23 00:12:48 +01:00
|
|
|
}
|
|
|
|
|
2016-03-29 06:35:10 +02:00
|
|
|
|
2016-03-16 01:30:39 +01:00
|
|
|
/**
|
|
|
|
* REST endpoint to get a campaign.
|
|
|
|
*
|
|
|
|
* @param SS_HTTPRequest $request
|
|
|
|
*
|
|
|
|
* @return SS_HTTPResponse
|
|
|
|
*/
|
|
|
|
public function readCampaign(SS_HTTPRequest $request) {
|
|
|
|
$response = new SS_HTTPResponse();
|
|
|
|
$response->addHeader('Content-Type', 'application/json');
|
2016-03-29 04:38:48 +02:00
|
|
|
$response->setBody('');
|
2016-03-16 01:30:39 +01:00
|
|
|
|
2016-04-07 07:13:54 +02:00
|
|
|
// TODO Implement data retrieval and serialisation
|
|
|
|
|
2016-03-16 01:30:39 +01:00
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* REST endpoint to update a campaign.
|
|
|
|
*
|
|
|
|
* @param SS_HTTPRequest $request
|
|
|
|
*
|
|
|
|
* @return SS_HTTPResponse
|
|
|
|
*/
|
|
|
|
public function updateCampaign(SS_HTTPRequest $request) {
|
|
|
|
$response = new SS_HTTPResponse();
|
|
|
|
$response->addHeader('Content-Type', 'application/json');
|
|
|
|
$response->setBody(Convert::raw2json(['campaign' => 'update']));
|
|
|
|
|
2016-04-07 07:13:54 +02:00
|
|
|
// TODO Implement data update and permission checks
|
|
|
|
|
2016-03-16 01:30:39 +01:00
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* REST endpoint to delete a campaign.
|
|
|
|
*
|
|
|
|
* @param SS_HTTPRequest $request
|
|
|
|
*
|
|
|
|
* @return SS_HTTPResponse
|
|
|
|
*/
|
|
|
|
public function deleteCampaign(SS_HTTPRequest $request) {
|
2016-03-30 05:38:48 +02:00
|
|
|
$id = $request->param('ID');
|
|
|
|
if (!$id || !is_numeric($id)) {
|
|
|
|
return (new SS_HTTPResponse(json_encode(['status' => 'error']), 400))
|
|
|
|
->addHeader('Content-Type', 'application/json');
|
|
|
|
}
|
|
|
|
|
|
|
|
$record = ChangeSet::get()->byID($id);
|
|
|
|
if(!$record) {
|
|
|
|
return (new SS_HTTPResponse(json_encode(['status' => 'error']), 404))
|
|
|
|
->addHeader('Content-Type', 'application/json');
|
|
|
|
}
|
2016-03-16 01:30:39 +01:00
|
|
|
|
2016-03-30 05:38:48 +02:00
|
|
|
if(!$record->canDelete()) {
|
|
|
|
return (new SS_HTTPResponse(json_encode(['status' => 'error']), 401))
|
|
|
|
->addHeader('Content-Type', 'application/json');
|
|
|
|
}
|
|
|
|
|
|
|
|
$record->delete();
|
|
|
|
|
|
|
|
return (new SS_HTTPResponse('', 204));
|
2016-03-16 01:30:39 +01:00
|
|
|
}
|
|
|
|
|
2016-03-23 00:12:48 +01:00
|
|
|
/**
|
|
|
|
* @todo Use GridFieldDetailForm once it can handle structured data and form schemas
|
|
|
|
*
|
|
|
|
* @return Form
|
|
|
|
*/
|
|
|
|
public function getDetailEditForm() {
|
|
|
|
return Form::create(
|
|
|
|
$this,
|
|
|
|
'DetailEditForm',
|
2016-03-29 06:35:10 +02:00
|
|
|
ChangeSet::singleton()->getCMSFields(),
|
2016-03-23 00:12:48 +01:00
|
|
|
FieldList::create(
|
|
|
|
FormAction::create('save', 'Save')
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-03-29 06:35:10 +02:00
|
|
|
/**
|
|
|
|
* Gets user-visible url to edit a specific {@see ChangeSet}
|
|
|
|
*
|
|
|
|
* @param $itemID
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function SetLink($itemID) {
|
|
|
|
return Controller::join_links(
|
|
|
|
$this->Link('set'),
|
|
|
|
$itemID
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets user-visible url to edit a specific {@see ChangeSetItem}
|
|
|
|
*
|
|
|
|
* @param int $itemID
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function ItemLink($itemID) {
|
|
|
|
return Controller::join_links(
|
|
|
|
$this->Link('item'),
|
|
|
|
$itemID
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function FindReferencedChanges() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-03-16 01:30:39 +01:00
|
|
|
}
|