feat: stop extraneous vote and tids_read data from being saved for remote users

This commit is contained in:
Julian Lam
2025-12-11 10:56:57 -05:00
parent 3adcbe0f7d
commit 097d0802b7
4 changed files with 81 additions and 20 deletions

View File

@@ -177,16 +177,18 @@ module.exports = function (Posts) {
} }
const now = Date.now(); const now = Date.now();
if (type === 'upvote' && !unvote) { if (utils.isNumber(uid)) {
await db.sortedSetAdd(`uid:${uid}:upvote`, now, pid); if (type === 'upvote' && !unvote) {
} else { await db.sortedSetAdd(`uid:${uid}:upvote`, now, pid);
await db.sortedSetRemove(`uid:${uid}:upvote`, pid); } else {
} await db.sortedSetRemove(`uid:${uid}:upvote`, pid);
}
if (type === 'upvote' || unvote) { if (type === 'upvote' || unvote) {
await db.sortedSetRemove(`uid:${uid}:downvote`, pid); await db.sortedSetRemove(`uid:${uid}:downvote`, pid);
} else { } else {
await db.sortedSetAdd(`uid:${uid}:downvote`, now, pid); await db.sortedSetAdd(`uid:${uid}:downvote`, now, pid);
}
} }
const postData = await Posts.getPostFields(pid, ['pid', 'uid', 'tid']); const postData = await Posts.getPostFields(pid, ['pid', 'uid', 'tid']);

View File

@@ -290,7 +290,7 @@ module.exports = function (Topics) {
}; };
Topics.markAsRead = async function (tids, uid) { Topics.markAsRead = async function (tids, uid) {
if (!Array.isArray(tids) || !tids.length) { if (!Array.isArray(tids) || !tids.length || !utils.isNumber(uid)) {
return false; return false;
} }

View File

@@ -0,0 +1,24 @@
'use strict';
const db = require('../../database');
const batch = require('../../batch');
module.exports = {
name: 'Remove extraneous upvote and tids_read data for remote users',
timestamp: Date.UTC(2025, 11, 11),
method: async function () {
const { progress } = this;
await batch.processSortedSet('usersRemote:lastCrawled', async (uids) => {
const readKeys = uids.map(uid => `uid:${uid}:tids_read`);
const voteKeys = uids.map(uid => `uid:${uid}:upvote`);
const combined = readKeys.concat(voteKeys);
await db.deleteAll(combined);
}, {
batch: 500,
progress,
});
},
};

View File

@@ -432,6 +432,7 @@ describe('Notes', () => {
describe('Create', () => { describe('Create', () => {
let uid; let uid;
let cid;
before(async () => { before(async () => {
uid = await user.create({ username: utils.generateUUID() }); uid = await user.create({ username: utils.generateUUID() });
@@ -451,6 +452,17 @@ describe('Notes', () => {
assert.strictEqual(cid, -1); assert.strictEqual(cid, -1);
}); });
it('should not append to the tids_read sorted set', async () => {
const { note, id } = helpers.mocks.note();
const { activity } = helpers.mocks.create(note);
await db.sortedSetAdd(`followersRemote:${note.attributedTo}`, Date.now(), uid);
await activitypub.inbox.create({ body: activity });
const exists = await db.exists(`uid:${note.attributedTo}:tids_read`);
assert(!exists);
});
it('should create a new topic in a remote category if addressed (category same-origin)', async () => { it('should create a new topic in a remote category if addressed (category same-origin)', async () => {
const { id: remoteCid } = helpers.mocks.group(); const { id: remoteCid } = helpers.mocks.group();
const { note, id } = helpers.mocks.note({ const { note, id } = helpers.mocks.note({
@@ -467,40 +479,63 @@ describe('Notes', () => {
}); });
it('should create a new topic in cid -1 if a non-same origin remote category is addressed', async function () { it('should create a new topic in cid -1 if a non-same origin remote category is addressed', async function () {
this.timeout(30000);
const start = Date.now();
const { id: remoteCid } = helpers.mocks.group({ const { id: remoteCid } = helpers.mocks.group({
id: `https://example.com/${utils.generateUUID()}`, id: `https://example.com/${utils.generateUUID()}`,
}); });
console.log('1', Date.now() - start);
const { note, id } = helpers.mocks.note({ const { note, id } = helpers.mocks.note({
audience: [remoteCid], audience: [remoteCid],
}); });
console.log('2', Date.now() - start);
const { activity } = helpers.mocks.create(note); const { activity } = helpers.mocks.create(note);
console.log('3', Date.now() - start);
try { try {
await activitypub.inbox.create({ body: activity }); await activitypub.inbox.create({ body: activity });
} catch (err) { } catch (err) {
console.log('error in test', err.stack);
assert(false); assert(false);
} }
console.log('4', Date.now() - start);
assert(await posts.exists(id)); assert(await posts.exists(id));
console.log('5', Date.now() - start);
const cid = await posts.getCidByPid(id); const cid = await posts.getCidByPid(id);
console.log('6', Date.now() - start);
assert.strictEqual(cid, -1); assert.strictEqual(cid, -1);
}); });
}); });
describe('(Like)', () => {
let pid;
let voterUid;
before(async () => {
({ cid } = await categories.create({ name: utils.generateUUID() }));
const { postData } = await topics.post({
uid,
cid,
title: utils.generateUUID(),
content: utils.generateUUID(),
});
pid = postData.pid;
const object = await activitypub.mocks.notes.public(postData);
const { activity } = helpers.mocks.like({ object });
voterUid = activity.actor;
await activitypub.inbox.like({ body: activity });
});
it('should increment a like for the post', async () => {
const voted = await posts.hasVoted(pid, voterUid);
const count = await posts.getPostField(pid, 'upvotes');
assert(voted);
assert.strictEqual(count, 1);
});
it('should not append to the uid upvotes zset', async () => {
const exists = await db.exists(`uid:${voterUid}:upvote`);
assert(!exists);
});
});
}); });
describe('Announce', () => { describe('Announce', () => {
let cid; let cid;
before(async () => { before(async () => {
({ cid } = await categories.create({ name: utils.generateUUID().slice(0, 8) })); ({ cid } = await categories.create({ name: utils.generateUUID() }));
}); });
describe('(Create)', () => { describe('(Create)', () => {