diff --git a/ghost/admin/app/components/settings/audit-log/table.hbs b/ghost/admin/app/components/settings/audit-log/table.hbs
index 31714d0e16..8a10106dca 100644
--- a/ghost/admin/app/components/settings/audit-log/table.hbs
+++ b/ghost/admin/app/components/settings/audit-log/table.hbs
@@ -31,14 +31,16 @@
- {{#if (or ev.resource.title ev.resource.name)}}
- {{#if ev.linkable}}
+ {{#if ev.contextResource}}
+ {{capitalize-first-letter ev.contextResource.first}} - {{ev.contextResource.second}}
+ {{else if (or ev.resource.title ev.resource.name ev.original.context.primary_name)}}
+ {{#if (and (or ev.resource.title ev.resource.name) ev.linkable)}}
{{or ev.resource.title ev.resource.name}}
{{else}}
- {{or ev.resource.title ev.resource.name}}
+ {{or ev.resource.title ev.resource.name ev.original.context.primary_name}}
{{/if}}
{{else}}
diff --git a/ghost/admin/app/helpers/audit-log-event-fetcher.js b/ghost/admin/app/helpers/audit-log-event-fetcher.js
index 11ac85503f..95b76d164f 100644
--- a/ghost/admin/app/helpers/audit-log-event-fetcher.js
+++ b/ghost/admin/app/helpers/audit-log-event-fetcher.js
@@ -82,6 +82,10 @@ export default class AuditLogEventFetcher extends Resource {
this.hasReachedEnd = true;
}
+ actions.forEach((a) => {
+ a.context = JSON.parse(a.context);
+ });
+
this.data.push(...actions);
} catch (e) {
this.isError = true;
diff --git a/ghost/admin/app/helpers/parse-audit-log-event.js b/ghost/admin/app/helpers/parse-audit-log-event.js
index 27f360be2e..0aaaecb5be 100644
--- a/ghost/admin/app/helpers/parse-audit-log-event.js
+++ b/ghost/admin/app/helpers/parse-audit-log-event.js
@@ -9,7 +9,9 @@ export default class ParseAuditLogEvent extends Helper {
const actionIcon = getActionIcon(ev);
const getActor = () => this.store.findRecord(ev.actor_type, ev.actor_id, {reload: false});
const getResource = () => this.store.findRecord(ev.resource_type, ev.resource_id, {reload: false});
- const linkable = ['page', 'post'].includes(ev.resource_type);
+ const contextResource = getContextResource(ev);
+
+ const linkable = ['page', 'post'].includes(ev.resource_type) && ev.event !== 'deleted';
return {
get actor() {
@@ -18,6 +20,7 @@ export default class ParseAuditLogEvent extends Helper {
get resource() {
return getResource();
},
+ contextResource,
linkable,
actionIcon,
action,
@@ -50,3 +53,16 @@ function getAction(ev) {
return `${ev.event} ${resourceType}`;
}
+
+function getContextResource(ev) {
+ if (ev.resource_type === 'setting') {
+ if (ev.context?.group && ev.context?.key) {
+ return {
+ first: ev.context.group,
+ second: ev.context.key
+ };
+ }
+ }
+
+ return null;
+}
diff --git a/ghost/core/core/server/models/action.js b/ghost/core/core/server/models/action.js
index 37293c1bf2..4648453667 100644
--- a/ghost/core/core/server/models/action.js
+++ b/ghost/core/core/server/models/action.js
@@ -19,16 +19,6 @@ const Action = ghostBookshelf.Model.extend({
resource() {
return this.morphTo('resource', ['resource_type', 'resource_id'], ...candidates);
- },
-
- toJSON(unfilteredOptions) {
- const options = Action.filterOptions(unfilteredOptions, 'toJSON');
- const attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options);
-
- // @TODO: context is not implemented yet
- delete attrs.context;
-
- return attrs;
}
}, {
orderDefaultOptions: function orderDefaultOptions() {
diff --git a/ghost/core/core/server/models/base/plugins/actions.js b/ghost/core/core/server/models/base/plugins/actions.js
index f6b44747b7..9f7b1e54f6 100644
--- a/ghost/core/core/server/models/base/plugins/actions.js
+++ b/ghost/core/core/server/models/base/plugins/actions.js
@@ -29,14 +29,33 @@ module.exports = function (Bookshelf) {
resourceType = resourceType.bind(this)();
}
- // @TODO: implement context
- return {
- event: event,
+ let context = {};
+
+ if (this.actionsExtraContext && Array.isArray(this.actionsExtraContext)) {
+ for (const c of this.actionsExtraContext) {
+ context[c] = this.get(c) || this.previous(c);
+ }
+ }
+
+ if (event === 'deleted') {
+ context.primary_name = (this.previous('title') || this.previous('name'));
+ } else if (event === 'edited') {
+ context.primary_name = (this.get('title') || this.get('name') || this.previous('title') || this.previous('name'));
+ }
+
+ const data = {
+ event,
resource_id: this.id || this.previous('id'),
resource_type: resourceType,
actor_id: actor.id,
actor_type: actor.type
};
+
+ if (context && Object.keys(context).length) {
+ data.context = context;
+ }
+
+ return data;
},
/**
diff --git a/ghost/core/core/server/models/settings.js b/ghost/core/core/server/models/settings.js
index 6655307b93..e906f05a6f 100644
--- a/ghost/core/core/server/models/settings.js
+++ b/ghost/core/core/server/models/settings.js
@@ -99,6 +99,7 @@ Settings = ghostBookshelf.Model.extend({
actionsCollectCRUD: true,
actionsResourceType: 'setting',
+ actionsExtraContext: ['key', 'group'],
emitChange: function emitChange(event, options) {
const eventToTrigger = 'settings' + '.' + event;
diff --git a/ghost/core/test/e2e-api/admin/utils.js b/ghost/core/test/e2e-api/admin/utils.js
index a736d28e75..0b595cf4e1 100644
--- a/ghost/core/test/e2e-api/admin/utils.js
+++ b/ghost/core/test/e2e-api/admin/utils.js
@@ -26,7 +26,7 @@ const expectedProperties = {
members: ['members', 'meta'],
snippets: ['snippets', 'meta'],
- action: ['id', 'resource_type', 'actor_type', 'event', 'created_at', 'actor'],
+ action: ['id', 'resource_type', 'actor_type', 'event', 'created_at', 'actor', 'context'],
config: [
'version',