From 664dfbeae8fc3085e29b810183871027a5f8c4e2 Mon Sep 17 00:00:00 2001 From: Thibaut Patel Date: Tue, 22 Feb 2022 19:20:31 +0100 Subject: [PATCH] Added the `last_seen_at` field to the member API answers refs https://github.com/TryGhost/Team/issues/1389 --- .../utils/serializers/output/members.js | 1 + .../admin/__snapshots__/members.test.js.snap | 78 +++++++++++++++---- test/e2e-api/admin/utils.js | 1 + 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/core/server/api/canary/utils/serializers/output/members.js b/core/server/api/canary/utils/serializers/output/members.js index d6aef1a4fc..ff146ebab3 100644 --- a/core/server/api/canary/utils/serializers/output/members.js +++ b/core/server/api/canary/utils/serializers/output/members.js @@ -124,6 +124,7 @@ function serializeMember(member, options) { email_opened_count: json.email_opened_count, email_open_rate: json.email_open_rate, email_recipients: json.email_recipients, + last_seen_at: json.last_seen_at, status: json.status }; diff --git a/test/e2e-api/admin/__snapshots__/members.test.js.snap b/test/e2e-api/admin/__snapshots__/members.test.js.snap index 9ed4de9e14..02a9955f58 100644 --- a/test/e2e-api/admin/__snapshots__/members.test.js.snap +++ b/test/e2e-api/admin/__snapshots__/members.test.js.snap @@ -72,6 +72,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "test", "note": "test note", "products": Array [], @@ -89,7 +90,7 @@ exports[`Members API Can add 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "588", + "content-length": "608", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -186,6 +187,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "products": Array [], @@ -238,7 +240,7 @@ exports[`Members API Can add a subscription 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1333", + "content-length": "1353", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -260,6 +262,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Array [], + "last_seen_at": null, "name": "Send Me Confirmation", "note": null, "products": Array [], @@ -277,7 +280,7 @@ exports[`Members API Can add and send a signup confirmation email 2: [headers] 1 Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "457", + "content-length": "477", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": Any, @@ -310,6 +313,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Name", "note": null, "products": Array [], @@ -327,7 +331,7 @@ exports[`Members API Can add complimentary subscription 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "424", + "content-length": "444", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -350,6 +354,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Name", "note": null, "products": Array [], @@ -367,7 +372,7 @@ exports[`Members API Can add complimentary subscription 4: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "424", + "content-length": "444", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -389,6 +394,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "status": "free", @@ -408,6 +414,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": null, "note": null, "status": "free", @@ -427,6 +434,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Egon Spengler", "note": null, "status": "paid", @@ -446,6 +454,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Ray Stantz", "note": null, "status": "paid", @@ -465,6 +474,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Vinz Clortho", "note": null, "status": "paid", @@ -484,6 +494,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Winston Zeddemore", "note": null, "status": "free", @@ -503,6 +514,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Peter Venkman", "note": null, "status": "paid", @@ -522,6 +534,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Dana Barrett", "note": null, "status": "paid", @@ -548,7 +561,7 @@ exports[`Members API Can browse 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "8051", + "content-length": "8211", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -570,6 +583,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "status": "free", @@ -596,7 +610,7 @@ exports[`Members API Can browse with filter 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "644", + "content-length": "664", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -618,6 +632,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "status": "free", @@ -644,7 +659,7 @@ exports[`Members API Can browse with search 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "644", + "content-length": "664", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -690,6 +705,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "test", "note": null, "products": Array [], @@ -707,7 +723,7 @@ exports[`Members API Can destroy 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "431", + "content-length": "451", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -771,6 +787,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "change me", "note": "initial note", "products": Array [], @@ -788,7 +805,7 @@ exports[`Members API Can edit by id 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "442", + "content-length": "462", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/members\\\\/\\[a-f0-9\\]\\{24\\}\\\\//, @@ -811,6 +828,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "changed", "note": "edited note", "products": Array [], @@ -828,7 +846,7 @@ exports[`Members API Can edit by id 4: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "439", + "content-length": "459", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -907,6 +925,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Egon Spengler", "note": null, "status": "paid", @@ -926,6 +945,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Ray Stantz", "note": null, "status": "paid", @@ -945,6 +965,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Vinz Clortho", "note": null, "status": "paid", @@ -964,6 +985,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Peter Venkman", "note": null, "status": "paid", @@ -983,6 +1005,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Dana Barrett", "note": null, "status": "paid", @@ -1009,7 +1032,7 @@ exports[`Members API Can filter by paid status 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "6576", + "content-length": "6676", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -1031,6 +1054,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Egon Spengler", "note": null, "status": "paid", @@ -1050,6 +1074,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": null, "note": null, "status": "free", @@ -1069,6 +1094,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "status": "free", @@ -1088,6 +1114,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Ray Stantz", "note": null, "status": "paid", @@ -1107,6 +1134,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Vinz Clortho", "note": null, "status": "paid", @@ -1126,6 +1154,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Winston Zeddemore", "note": null, "status": "free", @@ -1145,6 +1174,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Peter Venkman", "note": null, "status": "paid", @@ -1164,6 +1194,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Dana Barrett", "note": null, "status": "paid", @@ -1393,6 +1424,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": null, "note": null, "status": "free", @@ -1412,6 +1444,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Egon Spengler", "note": null, "status": "paid", @@ -1431,6 +1464,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "status": "free", @@ -1450,6 +1484,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Ray Stantz", "note": null, "status": "paid", @@ -1469,6 +1504,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Vinz Clortho", "note": null, "status": "paid", @@ -1488,6 +1524,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Winston Zeddemore", "note": null, "status": "free", @@ -1507,6 +1544,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Peter Venkman", "note": null, "status": "paid", @@ -1526,6 +1564,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Dana Barrett", "note": null, "status": "paid", @@ -1755,6 +1794,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "products": Array [], @@ -1772,7 +1812,7 @@ exports[`Members API Can read 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "570", + "content-length": "590", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -1795,6 +1835,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "products": Array [], @@ -1812,7 +1853,7 @@ exports[`Members API Can read and include email_recipients 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "592", + "content-length": "612", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -1988,6 +2029,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": null, "note": null, "status": "free", @@ -2014,7 +2056,7 @@ exports[`Members API Search by case-insensitive email MEMBER2 receives member wi Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "491", + "content-length": "511", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -2036,6 +2078,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Mr Egg", "note": null, "status": "free", @@ -2062,7 +2105,7 @@ exports[`Members API Search by case-insensitive name egg receives member with na Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "644", + "content-length": "664", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", @@ -2140,6 +2183,7 @@ Object { "geolocation": null, "id": StringMatching /\\[a-f0-9\\]\\{24\\}/, "labels": Any, + "last_seen_at": null, "name": "Egon Spengler", "note": null, "status": "paid", @@ -2166,7 +2210,7 @@ exports[`Members API Search for paid members retrieves member with email paid@te Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "1640", + "content-length": "1660", "content-type": "application/json; charset=utf-8", "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, "vary": "Origin, Accept-Encoding", diff --git a/test/e2e-api/admin/utils.js b/test/e2e-api/admin/utils.js index 0c55f6ab96..86a3dfb446 100644 --- a/test/e2e-api/admin/utils.js +++ b/test/e2e-api/admin/utils.js @@ -147,6 +147,7 @@ const expectedProperties = { 'updated_at', 'avatar_image', 'comped', + 'last_seen_at', 'labels' ], member_signin_url: ['member_id', 'url'],