diff --git a/ghost/admin/app/components/settings/audit-log/table.hbs b/ghost/admin/app/components/settings/audit-log/table.hbs
index dfa999b798..f2fc61a8b2 100644
--- a/ghost/admin/app/components/settings/audit-log/table.hbs
+++ b/ghost/admin/app/components/settings/audit-log/table.hbs
@@ -36,14 +36,14 @@
{{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 if (or ev.original.resource.title ev.original.resource.name ev.original.context.primary_name)}}
+ {{#if ev.linkTarget}}
+
+ {{or ev.original.resource.title ev.original.resource.name}}
{{else}}
- {{or ev.resource.title ev.resource.name ev.original.context.primary_name}}
+ {{or ev.original.resource.title ev.original.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 95b76d164f..5db8845f56 100644
--- a/ghost/admin/app/helpers/audit-log-event-fetcher.js
+++ b/ghost/admin/app/helpers/audit-log-event-fetcher.js
@@ -75,7 +75,10 @@ export default class AuditLogEventFetcher extends Resource {
this.isLoading = true;
const url = this.ghostPaths.url.api('actions');
- const data = Object.assign({}, queryParams, {limit: this.args.named.pageSize});
+ const data = Object.assign({}, queryParams, {
+ include: 'resource',
+ limit: this.args.named.pageSize
+ });
const {actions} = yield this.ajax.request(url, {data});
if (actions.length < data.limit) {
diff --git a/ghost/admin/app/helpers/parse-audit-log-event.js b/ghost/admin/app/helpers/parse-audit-log-event.js
index 0aaaecb5be..73538234ea 100644
--- a/ghost/admin/app/helpers/parse-audit-log-event.js
+++ b/ghost/admin/app/helpers/parse-audit-log-event.js
@@ -8,20 +8,15 @@ export default class ParseAuditLogEvent extends Helper {
const action = getAction(ev);
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 contextResource = getContextResource(ev);
-
- const linkable = ['page', 'post'].includes(ev.resource_type) && ev.event !== 'deleted';
+ const linkTarget = getLinkTarget(ev);
return {
get actor() {
return getActor();
},
- get resource() {
- return getResource();
- },
contextResource,
- linkable,
+ linkTarget,
actionIcon,
action,
original: ev
@@ -29,6 +24,51 @@ export default class ParseAuditLogEvent extends Helper {
}
}
+function getLinkTarget(ev) {
+ let resourceType = ev.resource_type;
+
+ if (ev.event !== 'deleted') {
+ switch (ev.resource_type) {
+ case 'page':
+ case 'post':
+ if (!ev.resource.id) {
+ return null;
+ }
+
+ if (resourceType === 'post') {
+ if (ev.context?.type) {
+ resourceType = ev.context?.type;
+ }
+ }
+
+ return {
+ route: 'editor.edit',
+ models: [resourceType, ev.resource.id]
+ };
+ case 'tag':
+ if (!ev.resource.slug) {
+ return null;
+ }
+
+ return {
+ route: 'tag',
+ models: [ev.resource.slug]
+ };
+ case 'user':
+ if (!ev.resource.slug) {
+ return null;
+ }
+
+ return {
+ route: 'settings.staff.user',
+ models: [ev.resource.slug]
+ };
+ }
+ }
+
+ return null;
+}
+
function getActionIcon(ev) {
switch (ev.event) {
case 'added':
@@ -51,6 +91,14 @@ function getAction(ev) {
resourceType = 'settings';
}
+ // Because a `page` and `post` both use the same model, we store the
+ // actual type in the context, so let's check if that exists
+ if (resourceType === 'post') {
+ if (ev.context?.type) {
+ resourceType = ev.context?.type;
+ }
+ }
+
return `${ev.event} ${resourceType}`;
}
diff --git a/ghost/core/core/server/api/endpoints/utils/serializers/output/utils/clean.js b/ghost/core/core/server/api/endpoints/utils/serializers/output/utils/clean.js
index b230305747..a3c7e484d5 100644
--- a/ghost/core/core/server/api/endpoints/utils/serializers/output/utils/clean.js
+++ b/ghost/core/core/server/api/endpoints/utils/serializers/output/utils/clean.js
@@ -130,9 +130,6 @@ const post = (attrs, frame) => {
const action = (attrs) => {
if (attrs.actor) {
- delete attrs.actor_id;
- delete attrs.resource_id;
-
if (attrs.actor_type === 'user') {
attrs.actor = _.pick(attrs.actor, ['id', 'name', 'slug', 'profile_image']);
attrs.actor.image = attrs.actor.profile_image;
@@ -142,12 +139,11 @@ const action = (attrs) => {
attrs.actor.image = attrs.actor.icon_image;
delete attrs.actor.icon_image;
}
- } else if (attrs.resource) {
- delete attrs.actor_id;
- delete attrs.resource_id;
+ }
+ if (attrs.resource) {
// @NOTE: we only support posts right now
- attrs.resource = _.pick(attrs.resource, ['id', 'title', 'slug', 'feature_image']);
+ attrs.resource = _.pick(attrs.resource, ['id', 'title', 'slug', 'feature_image', 'name']);
attrs.resource.image = attrs.resource.feature_image;
delete attrs.resource.feature_image;
}
diff --git a/ghost/core/test/e2e-api/admin/utils.js b/ghost/core/test/e2e-api/admin/utils.js
index 0b595cf4e1..d1781c10dd 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', 'context'],
+ action: ['id', 'resource_type', 'actor_type', 'event', 'created_at', 'actor', 'context', 'resource_id', 'actor_id'],
config: [
'version',