From 57b12c5b430d46a194c5ac01249a7b96f829f5a5 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Tue, 25 Nov 2014 19:29:57 +0100 Subject: [PATCH 1/9] Updated README and Plugin version --- AuditLogPlugin.php | 2 +- README.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AuditLogPlugin.php b/AuditLogPlugin.php index 3e8fe5b..6ced1e5 100644 --- a/AuditLogPlugin.php +++ b/AuditLogPlugin.php @@ -11,7 +11,7 @@ function getName() function getVersion() { - return '0.2.7'; + return '0.2.8'; } function getDeveloper() diff --git a/README.md b/README.md index ae95900..57fcb45 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ The plugin's folder should be named "auditlog" Changelog ================= +###0.2.8### + - Fixed a bug where the user couldn't be shown in some cases + ###0.2.7### - Fixed origin url in some cases From 55914919d7accf03b369fbba9fcc0aa9e635bf01 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 13:17:34 +0100 Subject: [PATCH 2/9] - Removed ability to clear log - you can uninstall the plugin to do this - Added a date range selector - Made sorting work --- controllers/AuditLogController.php | 18 ------ elementtypes/AuditLogElementType.php | 24 +++++++- services/AuditLogService.php | 45 ++++++++++++--- templates/index.html | 83 +++++++++++++++++++++++++++- 4 files changed, 141 insertions(+), 29 deletions(-) delete mode 100644 controllers/AuditLogController.php diff --git a/controllers/AuditLogController.php b/controllers/AuditLogController.php deleted file mode 100644 index 9569956..0000000 --- a/controllers/AuditLogController.php +++ /dev/null @@ -1,18 +0,0 @@ -deleteAll(); - - // Redirect - $this->redirect('auditlog'); - - } - -} \ No newline at end of file diff --git a/elementtypes/AuditLogElementType.php b/elementtypes/AuditLogElementType.php index 6c77c89..4533554 100644 --- a/elementtypes/AuditLogElementType.php +++ b/elementtypes/AuditLogElementType.php @@ -74,7 +74,9 @@ public function defineCriteriaAttributes() 'userId' => AttributeType::Number, 'origin' => AttributeType::String, 'modified' => AttributeType::DateTime, - 'status' => AttributeType::String + 'status' => AttributeType::String, + 'before' => AttributeType::DateTime, + 'after' => AttributeType::DateTime ); } @@ -128,12 +130,30 @@ public function getIndexHtml($criteria, $disabledElementIds, $viewState, $source 'elementType' => new ElementTypeVariable($this), 'disabledElementIds' => $disabledElementIds, 'attributes' => $this->defineTableAttributes($sourceKey), - 'elements' => craft()->auditLog->log($criteria), + 'elements' => craft()->auditLog->log($criteria, $viewState), 'showCheckboxes' => $showCheckboxes, ); $template = '_elements/'.$viewState['mode'].'view/'.($includeContainer ? 'container' : 'elements'); return craft()->templates->render($template, $variables); } + + // Set sortable attributes + public function defineSortableAttributes() + { + + // Set modified first + $attributes['dateUpdated'] = Craft::t('Modified'); + + // Get table attributes + $attributes = array_merge($attributes, $this->defineTableAttributes()); + + // Unset unsortable attributes + unset($attributes['user'], $attributes['changes']); + + // Return attributes + return $attributes; + + } } \ No newline at end of file diff --git a/services/AuditLogService.php b/services/AuditLogService.php index d2c4bdf..a955551 100644 --- a/services/AuditLogService.php +++ b/services/AuditLogService.php @@ -4,32 +4,61 @@ class AuditLogService extends BaseApplicationComponent { - public function log($criteria) + public function log($criteria, $viewState = false) { - // Build specific criteria $condition = ''; $params = array(); + + // Default -7 days + if(empty($criteria->after)) { + $criteria->after = array('date' => DateTimeHelper::fromString('-7 days')); + } + + // Default today + if(empty($criteria->before)) { + $criteria->before = array('date' => DateTimeHelper::currentUTCDateTime()); + } + + // Sorting + if($viewState) { + $criteria->order = $viewState['order'] . ' ' . $viewState['sort']; + } + + // Check for date after + if(!empty($criteria->after)) { + $condition .= 'dateUpdated > :after and '; + $params[':after'] = DateTimeHelper::formatTimeForDb($criteria->after); + } + + // Check for date before + if(!empty($criteria->before)) { + $condition .= 'dateUpdated < :before and '; + $params[':before'] = DateTimeHelper::formatTimeForDb($criteria->before); + } + + // Check for type if(!empty($criteria->type)) { $condition .= 'type = :type and '; $params[':type'] = $criteria->type; } + + // Check for status if(!empty($criteria->status)) { $condition .= 'status = :status and '; $params[':status'] = $criteria->status; } + + // Search if(!empty($criteria->search)) { $condition .= 'origin like :search and '; $params[':search'] = '%' . addcslashes($criteria->search, '%_') . '%'; } - $condition = substr($condition, 0, -5); - + // Get logs from record return AuditLogModel::populateModels(AuditLogRecord::model()->findAll(array( - 'order' => 'id desc', - 'limit' => $criteria->limit, - 'offset' => $criteria->offset, - 'condition' => $condition, + 'order' => $criteria->order, + 'condition' => substr($condition, 0, -5), 'params' => $params ))); diff --git a/templates/index.html b/templates/index.html index f7079b9..16bbd26 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2,12 +2,93 @@ {% set title = "Audit Log"|t %} {% set elementType = 'AuditLog' %} +{% block initCss %} +.buttons { + margin: 10px 0px; +} +.buttons th, .buttons td { + padding: 0px 0px 5px 0px; +} +{% endblock %} +{% includeCss block('initCss') %} + {% block sidebar %} {% if currentUser.admin %} +
- {{ "Clear"|t }} +
+ + + + + + + + + + +
{{ "From"|t }} + {% include '_includes/forms/date' with { + 'id': 'auditlog-modified-from', + 'value': now|date_modify('-7 days') + } %} +
{{ "To"|t }} + {% include '_includes/forms/date' with { + 'id': 'auditlog-modified-to', + 'value': now + } %} +
+
+ {% endif %} {{ parent() }} +{% endblock %} + +{% block initJs %} +// Init with datepicker values +Craft.elementIndex = Craft.createElementIndex('AuditLog', $('#main'), { + context: 'index', + showStatusMenu: 'auto', + showLocaleMenu: 'auto', + storageKey: 'elementindex.AuditLog', + criteria: { + after: { + date: $('#auditlog-modified-from-date').val() + }, + before: { + date: $('#auditlog-modified-to-date').val() + } + } +}) + +// Sort descending +Craft.elementIndex.setSelecetedSourceState('sort', 'desc'); + +// When a datepicker changes +$(document).on('change', 'input.hasDatepicker', function() { + + // Get new criteria values + Craft.elementIndex.settings.criteria = { + after: { + date: $('#auditlog-modified-from-date').val() + }, + before: { + date: $('#auditlog-modified-to-date').val() + } + }; + + // Update elements + Craft.elementIndex.updateElements(); + +}); {% endblock %} \ No newline at end of file From 9eb41ea49d79b8862643e6554871563c4b2a924f Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 13:28:17 +0100 Subject: [PATCH 3/9] Fixed search sorting --- elementtypes/AuditLogElementType.php | 46 ++++++++++++++++++++++++++-- services/AuditLogService.php | 7 +---- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/elementtypes/AuditLogElementType.php b/elementtypes/AuditLogElementType.php index 4533554..e041617 100644 --- a/elementtypes/AuditLogElementType.php +++ b/elementtypes/AuditLogElementType.php @@ -129,13 +129,53 @@ public function getIndexHtml($criteria, $disabledElementIds, $viewState, $source 'context' => $context, 'elementType' => new ElementTypeVariable($this), 'disabledElementIds' => $disabledElementIds, - 'attributes' => $this->defineTableAttributes($sourceKey), - 'elements' => craft()->auditLog->log($criteria, $viewState), 'showCheckboxes' => $showCheckboxes, ); - + + // In case of "score" (searching) + if(!empty($viewState['order']) && $viewState['order'] == 'score') { + + // Order by id + $criteria->order = 'id'; + + } else { + + // Get sortable attribuets + $sortableAttributes = $this->defineSortableAttributes(); + + if($sortableAttributes) { + + // Get order and sort + $order = (!empty($viewState['order']) && isset($sortableAttributes[$viewState['order']])) ? $viewState['order'] : array_shift(array_keys($sortableAttributes)); + $sort = (!empty($viewState['sort']) && in_array($viewState['sort'], array('asc', 'desc'))) ? $viewState['sort'] : 'asc'; + + // Set sort on criteria + $criteria->order = $order.' '.$sort; + + } + + } + + switch($viewState['mode']) { + + case 'table': + + // Get the table columns + $variables['attributes'] = $this->defineTableAttributes($sourceKey); + + break; + + } + + // Get elements + $variables['elements'] = craft()->auditLog->log($criteria); + + // Get template $template = '_elements/'.$viewState['mode'].'view/'.($includeContainer ? 'container' : 'elements'); + + // Return template return craft()->templates->render($template, $variables); + } // Set sortable attributes diff --git a/services/AuditLogService.php b/services/AuditLogService.php index a955551..defb4bf 100644 --- a/services/AuditLogService.php +++ b/services/AuditLogService.php @@ -4,7 +4,7 @@ class AuditLogService extends BaseApplicationComponent { - public function log($criteria, $viewState = false) + public function log($criteria) { // Build specific criteria $condition = ''; @@ -20,11 +20,6 @@ public function log($criteria, $viewState = false) $criteria->before = array('date' => DateTimeHelper::currentUTCDateTime()); } - // Sorting - if($viewState) { - $criteria->order = $viewState['order'] . ' ' . $viewState['sort']; - } - // Check for date after if(!empty($criteria->after)) { $condition .= 'dateUpdated > :after and '; From 2b2015c2cc4cf262e9c12577f67dbd6854fb03cc Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 14:01:18 +0100 Subject: [PATCH 4/9] Added ModifyAuditLogTableAttributes and getAuditLogTableAttributeHtml hooks --- elementtypes/AuditLogElementType.php | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/elementtypes/AuditLogElementType.php b/elementtypes/AuditLogElementType.php index e041617..2b0a42e 100644 --- a/elementtypes/AuditLogElementType.php +++ b/elementtypes/AuditLogElementType.php @@ -28,17 +28,40 @@ public function getStatuses() // Define table column names public function defineTableAttributes($source = null) { - return array( + + // Define default attributes + $attributes = array( 'type' => Craft::t('Type'), 'user' => Craft::t('User'), 'origin' => Craft::t('Origin'), - 'dateUpdated' => Craft::t('Modified'), - 'changes' => Craft::t('Changes') + 'dateUpdated' => Craft::t('Modified') ); + + // Allow plugins to modify the attributes + craft()->plugins->call('modifyAuditLogTableAttributes', array(&$attributes, $source)); + + // Set changes at last + $attributes['changes'] = Craft::t('Changes'); + + // Return the attributes + return $attributes; + } public function getTableAttributeHtml(BaseElementModel $element, $attribute) { + + // First give plugins a chance to set this + $pluginAttributeHtml = craft()->plugins->callFirst('getAuditLogTableAttributeHtml', array($element, $attribute), true); + + // Check if that had a valid result + if($pluginAttributeHtml) { + + // Return it + return $pluginAttributeHtml; + + } + switch ($attribute) { case 'dateCreated': From bed59d3e90635c2fd4d7a5b19b21c0195a464ae4 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 14:02:56 +0100 Subject: [PATCH 5/9] Updated plugin version and README --- AuditLogPlugin.php | 2 +- README.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/AuditLogPlugin.php b/AuditLogPlugin.php index 6ced1e5..2b6f637 100644 --- a/AuditLogPlugin.php +++ b/AuditLogPlugin.php @@ -11,7 +11,7 @@ function getName() function getVersion() { - return '0.2.8'; + return '0.3.0'; } function getDeveloper() diff --git a/README.md b/README.md index 57fcb45..fca68ee 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,12 @@ The plugin's folder should be named "auditlog" Changelog ================= +###0.3.0### + - Removed ability to clear log - you can uninstall the plugin to do this + - Added a date range selector + - Made sorting work + - Added ModifyAuditLogTableAttributes and getAuditLogTableAttributeHtml hooks + ###0.2.8### - Fixed a bug where the user couldn't be shown in some cases From 0d9e15a8330f2d4dccb8db923f7525e6bba3af84 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 14:53:54 +0100 Subject: [PATCH 6/9] Added a version warning --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fca68ee..c2d077d 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Changelog - Added a date range selector - Made sorting work - Added ModifyAuditLogTableAttributes and getAuditLogTableAttributeHtml hooks +Warning! This version is updated for Craft 2.3 and does NOT work on Craft 2.2 ###0.2.8### - Fixed a bug where the user couldn't be shown in some cases From 8d8c8e1461ac442aaea8cb17a25a47c3f2031992 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 14:56:10 +0100 Subject: [PATCH 7/9] Improved README MD markup --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c2d077d..afb5e19 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Changelog - Added a date range selector - Made sorting work - Added ModifyAuditLogTableAttributes and getAuditLogTableAttributeHtml hooks + Warning! This version is updated for Craft 2.3 and does NOT work on Craft 2.2 ###0.2.8### From 7be219f51387a333d56938cf510b76e400f1f1b6 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Mon, 1 Dec 2014 15:01:17 +0100 Subject: [PATCH 8/9] Removed default range from service --- elementtypes/AuditLogElementType.php | 15 ++++++++++++++- services/AuditLogService.php | 10 ---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/elementtypes/AuditLogElementType.php b/elementtypes/AuditLogElementType.php index 2b0a42e..3daf101 100644 --- a/elementtypes/AuditLogElementType.php +++ b/elementtypes/AuditLogElementType.php @@ -61,32 +61,45 @@ public function getTableAttributeHtml(BaseElementModel $element, $attribute) return $pluginAttributeHtml; } - + + // Modify custom attributes switch ($attribute) { + + // Format dates case 'dateCreated': case 'dateUpdated': { return craft()->dateFormatter->formatDateTime($element->$attribute); } + + // Return clickable user link case 'user': { $user = $element->getUser(); return $user ? '' . $user . '' : Craft::t('Guest'); } + + // Return clickable event origin case 'origin': { return '' . $element->origin . ''; } + + // Return view changes button case 'changes': { return '' . Craft::t('View') . ''; } + + // Default behavior default: { return $element->$attribute; } + } + } // Define criteria diff --git a/services/AuditLogService.php b/services/AuditLogService.php index defb4bf..886976e 100644 --- a/services/AuditLogService.php +++ b/services/AuditLogService.php @@ -10,16 +10,6 @@ public function log($criteria) $condition = ''; $params = array(); - // Default -7 days - if(empty($criteria->after)) { - $criteria->after = array('date' => DateTimeHelper::fromString('-7 days')); - } - - // Default today - if(empty($criteria->before)) { - $criteria->before = array('date' => DateTimeHelper::currentUTCDateTime()); - } - // Check for date after if(!empty($criteria->after)) { $condition .= 'dateUpdated > :after and '; From 7603419c2d389ae66c113e0c2d703ac4aa7715e3 Mon Sep 17 00:00:00 2001 From: Bob Olde Hampsink Date: Tue, 2 Dec 2014 14:03:58 +0100 Subject: [PATCH 9/9] Added a Audit Log Unit Test --- tests/AuditLogTest.php | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/AuditLogTest.php diff --git a/tests/AuditLogTest.php b/tests/AuditLogTest.php new file mode 100644 index 0000000..24aec87 --- /dev/null +++ b/tests/AuditLogTest.php @@ -0,0 +1,52 @@ + '/../models/AuditLogModel.php', + '\\Craft\\AuditLogRecord' => '/../records/AuditLogRecord.php', + '\\Craft\\AuditLogService' => '/../services/AuditLogService.php' + ); + + // Inject them + foreach($map as $classPath => $filePath) { + if(!class_exists($classPath, false)) { + require_once($dir . $filePath); + } + } + + // Set components we're going to use + $this->setComponent(craft(), 'auditLog', new AuditLogService); + + } + + public function testActionDownload() + { + + // Get first log item + $log = craft()->auditLog->view(1); + + // Only test if already set + if($log) { + + // $log is a model, want to break that down + $result = craft()->auditLog->parseFieldData('title', $log); + + // Result is always a string + $this->assertInternalType('string', $result); + + } + + } + +} \ No newline at end of file