Skip to content

Commit bda0f77

Browse files
authored
Merge branch 'main' into pro-7798-fix-ordering
2 parents 75df7a4 + b87d4cf commit bda0f77

7 files changed

Lines changed: 112 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
### Adds
66

7+
* Implemented GET /api/v1/@apostrophecms/login/whoami route such that it returns the details of the currently logged in user; added the route to the login module.
78
* Adds keyboard shortcuts for manipulating widgets in areas. Includes Cut, Copy, Paste, Delete, and Duplicate.
89
* Adds dynamic choices working with piece manager filters.
10+
* Allow `import.imageTags` (array of image tag IDs) to be passed to the rich text widget when importing (see https://docs.apostrophecms.org/reference/api/rich-text.html#importing-inline-images).
911

1012
### Changes
1113

@@ -14,6 +16,7 @@
1416
* Add missing Pages manager shortcuts list helper.
1517
* Improve the `isEmpty` method of the rich text widget to take into account the HTML blocks (`<figure>` and `<table>`) that are not empty but do not contain any plain text.
1618
* Fixed admin bar item ordering to correctly respect the precedence hierarchy: groups (when leader is positioned) > explicit order array > groups (when leader has positioning options) > individual `last`/`after` options.
19+
* (Backward compatibility break) Conditional field that depends on already hidden field is also hidden, again.
1720

1821
## 4.18.0 (2025-06-11)
1922

modules/@apostrophecms/area/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ module.exports = {
604604
return {};
605605
}
606606
const schema = manager.schema;
607-
const field = _.find(schema, 'name', name);
607+
const field = schema?.find(field => field.name === name);
608608
if (!(field && field.options)) {
609609
return {};
610610
}

modules/@apostrophecms/login/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ module.exports = {
6969
allowedAttempts: 3,
7070
perMinutes: 1,
7171
lockoutMinutes: 1
72-
}
72+
},
73+
minimumWhoamiFields: [ '_id', 'username', 'title', 'email' ],
74+
whoamiFields: []
7375
},
7476
async init(self) {
7577
self.passport = new Passport();
@@ -351,6 +353,22 @@ module.exports = {
351353
// it should be accessed via POST because the result
352354
// may differ by individual user session and should not
353355
// be cached
356+
async whoami (req) {
357+
if (!req.user) {
358+
throw self.apos.error('notfound');
359+
}
360+
361+
const fields = new Set([ ...self.options.minimumWhoamiFields, ...self.options.whoamiFields ]);
362+
const user = {};
363+
364+
for (const field of fields) {
365+
if (req.user[field] !== undefined) {
366+
user[field] = req.user[field];
367+
}
368+
}
369+
370+
return user;
371+
},
354372
async context(req) {
355373
return self.getContext(req);
356374
},

modules/@apostrophecms/rich-text-widget/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,8 @@ module.exports = {
10701070
});
10711071
const image = await self.apos.image.insert(req, {
10721072
title: name,
1073-
attachment
1073+
attachment,
1074+
tagsIds: input.import.imageTags || []
10741075
});
10751076
const newSrc = `${self.apos.image.action}/${image.aposDocId}/src`;
10761077
$image.replaceWith(

modules/@apostrophecms/schema/ui/apos/lib/conditionalFields.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export function getConditionalFields(
124124
values,
125125
field[conditionType],
126126
(propName, condition, docValue) =>
127-
evaluateExternal(propName, condition, conditionType)
127+
evaluateExternalAndHidden(propName, condition, conditionType)
128128
);
129129
}
130130
}
@@ -134,10 +134,14 @@ export function getConditionalFields(
134134

135135
// Handle external conditions as a voter function.
136136
// Non-boolean returns are ignored by the `checkIfConditions` function.
137-
function evaluateExternal(propName, conditionValue, conditionType) {
137+
function evaluateExternalAndHidden(propName, conditionValue, conditionType) {
138138
if (isExternalCondition(propName, conditionType)) {
139139
return externalConditionsResults[conditionType]?.[propName] === conditionValue;
140140
}
141+
142+
if (result[conditionType]?.[propName] === false) {
143+
return false;
144+
}
141145
}
142146
}
143147

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"@apostrophecms/vue-material-design-icons": "^1.0.0",
3737
"@ctrl/tinycolor": "^4.1.0",
3838
"@floating-ui/dom": "^1.5.3",
39-
"@opentelemetry/api": "^1.0.4",
39+
"@opentelemetry/api": "^1.9.0",
4040
"@opentelemetry/semantic-conventions": "^1.0.1",
4141
"@paralleldrive/cuid2": "^2.2.2",
4242
"@tiptap/extension-color": "^2.4.0",

test/login.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,4 +867,84 @@ describe('Login', function() {
867867
}
868868
);
869869
});
870+
871+
it('should return an error with code 404 at GET login/whoami when user is not logged in', async function() {
872+
try {
873+
await apos.http.get('/api/v1/@apostrophecms/login/whoami');
874+
assert.fail('Expected error but got success');
875+
} catch (err) {
876+
assert.strictEqual(err.status, 404);
877+
}
878+
});
879+
880+
it('should return user data at GET login/whoami when user is logged in', async function() {
881+
882+
const jar = apos.http.jar();
883+
884+
await apos.http.post(
885+
'/api/v1/@apostrophecms/login/login',
886+
{
887+
method: 'POST',
888+
body: {
889+
username: 'HarryPutter',
890+
password: 'AnotherLovelyPassword',
891+
session: true
892+
},
893+
jar
894+
}
895+
);
896+
897+
const whoamiResponse = await apos.http.get('/api/v1/@apostrophecms/login/whoami', { jar });
898+
assert.ok(whoamiResponse._id);
899+
assert.strictEqual(whoamiResponse.username, 'HarryPutter');
900+
assert.strictEqual(whoamiResponse.title, 'Extra Cool Putter');
901+
assert.strictEqual(whoamiResponse.email, 'hputter@aol.com');
902+
});
903+
904+
it('should return user data with additional whoamiFields if explicitly added at GET login/whoami when user is logged in', async function() {
905+
906+
const jar = apos.http.jar();
907+
908+
apos.modules['@apostrophecms/login'].options.whoamiFields = [ 'role' ];
909+
910+
await apos.http.post(
911+
'/api/v1/@apostrophecms/login/login',
912+
{
913+
method: 'POST',
914+
body: {
915+
username: 'HarryPutter',
916+
password: 'AnotherLovelyPassword',
917+
session: true
918+
},
919+
jar
920+
}
921+
);
922+
923+
const whoamiResponse = await apos.http.get('/api/v1/@apostrophecms/login/whoami', { jar });
924+
assert.strictEqual(whoamiResponse.role, 'admin');
925+
});
926+
927+
it('should not return user data with additional whoamiFields if not explicitly added at GET login/whoami when user is logged in', async function() {
928+
929+
const jar = apos.http.jar();
930+
931+
// Reset the whoamiFields to default (empty)
932+
apos.modules['@apostrophecms/login'].options.whoamiFields = [];
933+
934+
await apos.http.post(
935+
'/api/v1/@apostrophecms/login/login',
936+
{
937+
method: 'POST',
938+
body: {
939+
username: 'HarryPutter',
940+
password: 'AnotherLovelyPassword',
941+
session: true
942+
},
943+
jar
944+
}
945+
);
946+
947+
const whoamiResponse = await apos.http.get('/api/v1/@apostrophecms/login/whoami', { jar });
948+
assert.ok(!('role' in whoamiResponse));
949+
});
870950
});

0 commit comments

Comments
 (0)