diff --git a/src/routes/well-known.js b/src/routes/well-known.js
index becd1370f8..399668b679 100644
--- a/src/routes/well-known.js
+++ b/src/routes/well-known.js
@@ -39,8 +39,8 @@ module.exports = function (app, middleware, controllers) {
const oneMonthAgo = addMonths(new Date(), -1);
const sixMonthsAgo = addMonths(new Date(), -6);
- const [{ postCount, userCount }, activeMonth, activeHalfyear] = await Promise.all([
- db.getObjectFields('global', ['postCount', 'userCount']),
+ const [{ postCount, topicCount, userCount }, activeMonth, activeHalfyear] = await Promise.all([
+ db.getObjectFields('global', ['postCount', 'topicCount', 'userCount']),
db.sortedSetCount('users:online', oneMonthAgo.getTime(), '+inf'),
db.sortedSetCount('users:online', sixMonthsAgo.getTime(), '+inf'),
]);
@@ -64,7 +64,8 @@ module.exports = function (app, middleware, controllers) {
activeMonth: activeMonth,
activeHalfyear: activeHalfyear,
},
- localPosts: postCount,
+ localPosts: topicCount,
+ localComments: postCount - topicCount,
},
openRegistrations: meta.config.registrationType === 'normal',
metadata: {
diff --git a/src/user/email.js b/src/user/email.js
index aec9379f41..c14c9c93fc 100644
--- a/src/user/email.js
+++ b/src/user/email.js
@@ -36,8 +36,10 @@ UserEmail.remove = async function (uid, sessionId) {
email: '',
'email:confirmed': 0,
}),
- db.sortedSetRemove('email:uid', email.toLowerCase()),
- db.sortedSetRemove('email:sorted', `${email.toLowerCase()}:${uid}`),
+ db.sortedSetRemoveBulk([
+ ['email:uid', email.toLowerCase()],
+ ['email:sorted', `${email.toLowerCase()}:${uid}`],
+ ]),
user.email.expireValidation(uid),
sessionId ? user.auth.revokeAllSessions(uid, sessionId) : Promise.resolve(),
events.log({
@@ -53,7 +55,7 @@ UserEmail.getEmailForValidation = async (uid) => {
let email = '';
// check email from confirmObj
const code = await db.get(`confirm:byUid:${uid}`);
- const confirmObj = await db.getObject(`confirm:${code}`);
+ const confirmObj = code ? await db.getObject(`confirm:${code}`) : null;
if (confirmObj && confirmObj.email && parseInt(uid, 10) === parseInt(confirmObj.uid, 10)) {
email = confirmObj.email;
}
diff --git a/src/user/profile.js b/src/user/profile.js
index c150675d6a..3009d0a3d5 100644
--- a/src/user/profile.js
+++ b/src/user/profile.js
@@ -282,6 +282,9 @@ module.exports = function (User) {
if (oldEmail === newEmail) {
return;
}
+ if (await User.email.isValidationPending(uid, newEmail)) {
+ return;
+ }
// 👉 Looking for email change logic? src/user/email.js (UserEmail.confirmByUid)
if (newEmail) {
diff --git a/src/views/partials/chats/parent.tpl b/src/views/partials/chats/parent.tpl
index 2d2e66bf3b..68f91414c5 100644
--- a/src/views/partials/chats/parent.tpl
+++ b/src/views/partials/chats/parent.tpl
@@ -4,7 +4,7 @@
diff --git a/src/views/partials/topic/post-parent.tpl b/src/views/partials/topic/post-parent.tpl
index cabc6bb36c..38f22da616 100644
--- a/src/views/partials/topic/post-parent.tpl
+++ b/src/views/partials/topic/post-parent.tpl
@@ -3,7 +3,7 @@
diff --git a/test/activitypub.js b/test/activitypub.js
index d2c2334140..d05f50e4e6 100644
--- a/test/activitypub.js
+++ b/test/activitypub.js
@@ -350,7 +350,7 @@ describe('ActivityPub integration', () => {
});
});
- describe.only('Category Actor endpoint', () => {
+ describe('Category Actor endpoint', () => {
let cid;
let slug;
let description;
diff --git a/test/activitypub/notes.js b/test/activitypub/notes.js
index 482b706d14..803c345c4b 100644
--- a/test/activitypub/notes.js
+++ b/test/activitypub/notes.js
@@ -3,6 +3,8 @@
const assert = require('assert');
const db = require('../../src/database');
+const meta = require('../../src/meta');
+const install = require('../../src/install');
const user = require('../../src/user');
const categories = require('../../src/categories');
const topics = require('../../src/topics');
@@ -10,6 +12,62 @@ const activitypub = require('../../src/activitypub');
const utils = require('../../src/utils');
describe('Notes', () => {
+ describe('Assertion', () => {
+ const baseUrl = 'https://example.org';
+
+ before(async () => {
+ meta.config.activitypubEnabled = 1;
+ await install.giveWorldPrivileges();
+ });
+
+ it('should pull a remote root-level object by its id and create a new topic', async () => {
+ const uuid = utils.generateUUID();
+ const id = `${baseUrl}/resource/${uuid}`;
+ activitypub._cache.set(`0;${id}`, {
+ '@context': 'https://www.w3.org/ns/activitystreams',
+ id,
+ url: id,
+ type: 'Note',
+ to: ['https://www.w3.org/ns/activitystreams#Public'],
+ cc: ['https://example.org/user/foobar/followers'],
+ inReplyTo: null,
+ attributedTo: 'https://example.org/user/foobar',
+ name: 'Foo Bar',
+ content: 'Baz quux',
+ published: new Date().toISOString(),
+ });
+
+ const { tid, count } = await activitypub.notes.assert(0, id, { skipChecks: true });
+ assert.strictEqual(count, 1);
+
+ const exists = await topics.exists(tid);
+ assert(exists);
+ });
+
+ it('should assert if the cc property is missing', async () => {
+ const uuid = utils.generateUUID();
+ const id = `${baseUrl}/resource/${uuid}`;
+ activitypub._cache.set(`0;${id}`, {
+ '@context': 'https://www.w3.org/ns/activitystreams',
+ id,
+ url: id,
+ type: 'Note',
+ to: ['https://www.w3.org/ns/activitystreams#Public'],
+ inReplyTo: null,
+ attributedTo: 'https://example.org/user/foobar',
+ name: 'Foo Bar',
+ content: 'Baz quux',
+ published: new Date().toISOString(),
+ });
+
+ const { tid, count } = await activitypub.notes.assert(0, id, { skipChecks: true });
+ assert.strictEqual(count, 1);
+
+ const exists = await topics.exists(tid);
+ assert(exists);
+ });
+ });
+
describe('Inbox Synchronization', () => {
let cid;
let uid;