mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-07 12:36:57 +00:00
additional fixes and cleanup to all note endpoints
This commit is contained in:
parent
65983d0030
commit
05d7aa0b91
19 changed files with 282 additions and 202 deletions
|
@ -7,6 +7,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import type { LatestNotesRepository, NotesRepository } from '@/models/_.js';
|
import type { LatestNotesRepository, NotesRepository } from '@/models/_.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
|
import { QueryService } from './QueryService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LatestNoteService {
|
export class LatestNoteService {
|
||||||
|
@ -14,11 +15,12 @@ export class LatestNoteService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.notesRepository)
|
@Inject(DI.notesRepository)
|
||||||
private notesRepository: NotesRepository,
|
private readonly notesRepository: NotesRepository,
|
||||||
|
|
||||||
@Inject(DI.latestNotesRepository)
|
@Inject(DI.latestNotesRepository)
|
||||||
private latestNotesRepository: LatestNotesRepository,
|
private readonly latestNotesRepository: LatestNotesRepository,
|
||||||
|
|
||||||
|
private readonly queryService: QueryService,
|
||||||
loggerService: LoggerService,
|
loggerService: LoggerService,
|
||||||
) {
|
) {
|
||||||
this.logger = loggerService.getLogger('LatestNoteService');
|
this.logger = loggerService.getLogger('LatestNoteService');
|
||||||
|
@ -91,7 +93,7 @@ export class LatestNoteService {
|
||||||
|
|
||||||
// Find the newest remaining note for the user.
|
// Find the newest remaining note for the user.
|
||||||
// We exclude DMs and pure renotes.
|
// We exclude DMs and pure renotes.
|
||||||
const nextLatest = await this.notesRepository
|
const query = this.notesRepository
|
||||||
.createQueryBuilder('note')
|
.createQueryBuilder('note')
|
||||||
.select()
|
.select()
|
||||||
.where({
|
.where({
|
||||||
|
@ -106,18 +108,11 @@ export class LatestNoteService {
|
||||||
? Not(null)
|
? Not(null)
|
||||||
: null,
|
: null,
|
||||||
})
|
})
|
||||||
.andWhere(`
|
.orderBy({ id: 'DESC' });
|
||||||
(
|
|
||||||
note."renoteId" IS NULL
|
this.queryService.andIsNotRenote(query, 'note');
|
||||||
OR note.text IS NOT NULL
|
|
||||||
OR note.cw IS NOT NULL
|
const nextLatest = await query.getOne();
|
||||||
OR note."replyId" IS NOT NULL
|
|
||||||
OR note."hasPoll"
|
|
||||||
OR note."fileIds" != '{}'
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
.orderBy({ id: 'DESC' })
|
|
||||||
.getOne();
|
|
||||||
if (!nextLatest) return;
|
if (!nextLatest) return;
|
||||||
|
|
||||||
// Record it as the latest
|
// Record it as the latest
|
||||||
|
|
|
@ -188,15 +188,8 @@ export class QueryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public generateExcludedRenotesQueryForNotes<E extends ObjectLiteral>(q: SelectQueryBuilder<E>): SelectQueryBuilder<E> {
|
public generateExcludedRenotesQueryForNotes<Q extends WhereExpressionBuilder>(q: Q): Q {
|
||||||
return q
|
return this.andIsNotRenote(q, 'note');
|
||||||
.andWhere(new Brackets(qb => qb
|
|
||||||
.orWhere('note.renoteId IS NULL')
|
|
||||||
.orWhere('note.text IS NOT NULL')
|
|
||||||
.orWhere('note.cw IS NOT NULL')
|
|
||||||
.orWhere('note.replyId IS NOT NULL')
|
|
||||||
.orWhere('note.hasPoll = true')
|
|
||||||
.orWhere('note.fileIds != \'{}\'')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -256,6 +249,120 @@ export class QueryService {
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds OR condition that noteProp (note ID) refers to a quote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public orIsQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsQuote(q, noteProp, 'orWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds AND condition that noteProp (note ID) refers to a quote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public andIsQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsQuote(q, noteProp, 'andWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
private addIsQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||||
|
return q[join](new Brackets(qb => qb
|
||||||
|
.andWhere(`${noteProp}.renoteId IS NOT NULL`)
|
||||||
|
.andWhere(new Brackets(qbb => qbb
|
||||||
|
.orWhere(`${noteProp}.text IS NOT NULL`)
|
||||||
|
.orWhere(`${noteProp}.cw IS NOT NULL`)
|
||||||
|
.orWhere(`${noteProp}.replyId IS NOT NULL`)
|
||||||
|
.orWhere(`${noteProp}.hasPoll = true`)
|
||||||
|
.orWhere(`${noteProp}.fileIds != '{}'`)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds OR condition that noteProp (note ID) does not refer to a quote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public orIsNotQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsNotQuote(q, noteProp, 'orWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds AND condition that noteProp (note ID) does not refer to a quote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public andIsNotQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsNotQuote(q, noteProp, 'andWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
private addIsNotQuote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||||
|
return q[join](new Brackets(qb => qb
|
||||||
|
.orWhere(`${noteProp}.renoteId IS NULL`)
|
||||||
|
.orWhere(new Brackets(qb => qb
|
||||||
|
.andWhere(`${noteProp}.text IS NULL`)
|
||||||
|
.andWhere(`${noteProp}.cw IS NULL`)
|
||||||
|
.andWhere(`${noteProp}.replyId IS NULL`)
|
||||||
|
.andWhere(`${noteProp}.hasPoll = false`)
|
||||||
|
.andWhere(`${noteProp}.fileIds = '{}'`)))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds OR condition that noteProp (note ID) refers to a renote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public orIsRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsRenote(q, noteProp, 'orWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds AND condition that noteProp (note ID) refers to a renote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public andIsRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsRenote(q, noteProp, 'andWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
private addIsRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||||
|
return q[join](new Brackets(qb => qb
|
||||||
|
.andWhere(`${noteProp}.renoteId IS NOT NULL`)
|
||||||
|
.andWhere(`${noteProp}.text IS NULL`)
|
||||||
|
.andWhere(`${noteProp}.cw IS NULL`)
|
||||||
|
.andWhere(`${noteProp}.replyId IS NULL`)
|
||||||
|
.andWhere(`${noteProp}.hasPoll = false`)
|
||||||
|
.andWhere(`${noteProp}.fileIds = '{}'`)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds OR condition that noteProp (note ID) does not refer to a renote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public orIsNotRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsNotRenote(q, noteProp, 'orWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds AND condition that noteProp (note ID) does not refer to a renote.
|
||||||
|
* The prop should be an expression, not a raw value.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public andIsNotRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string): Q {
|
||||||
|
return this.addIsNotRenote(q, noteProp, 'andWhere');
|
||||||
|
}
|
||||||
|
|
||||||
|
private addIsNotRenote<Q extends WhereExpressionBuilder>(q: Q, noteProp: string, join: 'andWhere' | 'orWhere'): Q {
|
||||||
|
return q[join](new Brackets(qb => qb
|
||||||
|
.orWhere(`${noteProp}.renoteId IS NULL`)
|
||||||
|
.orWhere(`${noteProp}.text IS NOT NULL`)
|
||||||
|
.orWhere(`${noteProp}.cw IS NOT NULL`)
|
||||||
|
.orWhere(`${noteProp}.replyId IS NOT NULL`)
|
||||||
|
.orWhere(`${noteProp}.hasPoll = true`)
|
||||||
|
.orWhere(`${noteProp}.fileIds != '{}'`)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds OR condition that followerProp (user ID) is following followeeProp (user ID).
|
* Adds OR condition that followerProp (user ID) is following followeeProp (user ID).
|
||||||
* Both props should be expressions, not raw values.
|
* Both props should be expressions, not raw values.
|
||||||
|
|
|
@ -114,8 +114,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId');
|
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||||
|
|
||||||
// NOTE: センシティブ除外の設定はこのエンドポイントでは無視する。
|
// NOTE: センシティブ除外の設定はこのエンドポイントでは無視する。
|
||||||
// https://github.com/misskey-dev/misskey/pull/15346#discussion_r1929950255
|
// https://github.com/misskey-dev/misskey/pull/15346#discussion_r1929950255
|
||||||
|
|
|
@ -137,12 +137,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId')
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
.leftJoinAndSelect('note.channel', 'channel');
|
.leftJoinAndSelect('note.channel', 'channel')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
if (me) {
|
if (me) {
|
||||||
this.queryService.generateMutedUserQueryForNotes(query, me);
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
@ -159,6 +161,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
return await query.limit(ps.limit).getMany();
|
return await query.getMany();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchFile);
|
throw new ApiError(meta.errors.noSuchFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId);
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
query.andWhere(':file <@ note.fileIds', { file: [file.id] });
|
.andWhere(':file <@ note.fileIds', { file: [file.id] })
|
||||||
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
const notes = await query.limit(ps.limit).getMany();
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
|
||||||
|
const notes = await query.getMany();
|
||||||
|
|
||||||
return await this.noteEntityService.packMany(notes, me, {
|
return await this.noteEntityService.packMany(notes, me, {
|
||||||
detail: true,
|
detail: true,
|
||||||
|
|
|
@ -64,7 +64,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
if (me) {
|
||||||
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.local) {
|
if (ps.local) {
|
||||||
query.andWhere('note.userHost IS NULL');
|
query.andWhere('note.userHost IS NULL');
|
||||||
|
@ -75,7 +84,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.renote !== undefined) {
|
if (ps.renote !== undefined) {
|
||||||
query.andWhere(ps.renote ? 'note.renoteId IS NOT NULL' : 'note.renoteId IS NULL');
|
if (ps.renote) {
|
||||||
|
this.queryService.andIsRenote(query, 'note');
|
||||||
|
|
||||||
|
if (me) {
|
||||||
|
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.queryService.andIsNotRenote(query, 'note');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.withFiles !== undefined) {
|
if (ps.withFiles !== undefined) {
|
||||||
|
@ -91,7 +108,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
// query.isBot = bot;
|
// query.isBot = bot;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
const notes = await query.limit(ps.limit).getMany();
|
const notes = await query.getMany();
|
||||||
|
|
||||||
return await this.noteEntityService.packMany(notes);
|
return await this.noteEntityService.packMany(notes);
|
||||||
});
|
});
|
||||||
|
|
|
@ -82,8 +82,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
// This subquery mess teaches postgres how to use the right indexes.
|
// This subquery mess teaches postgres how to use the right indexes.
|
||||||
// Using WHERE or ON conditions causes a fallback to full sequence scan, which times out.
|
// Using WHERE or ON conditions causes a fallback to full sequence scan, which times out.
|
||||||
|
@ -114,7 +115,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const timeline = await query.limit(ps.limit).getMany();
|
const timeline = await query.getMany();
|
||||||
|
|
||||||
if (me) {
|
if (me) {
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
|
|
|
@ -57,26 +57,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
qb
|
qb.orWhere('note.replyId = :noteId');
|
||||||
.where('note.replyId = :noteId', { noteId: ps.noteId });
|
|
||||||
if (ps.showQuotes) {
|
if (ps.showQuotes) {
|
||||||
qb.orWhere(new Brackets(qb => {
|
qb.orWhere(new Brackets(qbb => this.queryService
|
||||||
qb
|
.andIsQuote(qbb, 'note')
|
||||||
.where('note.renoteId = :noteId', { noteId: ps.noteId })
|
.andWhere('note.renoteId = :noteId'),
|
||||||
.andWhere(new Brackets(qb => {
|
));
|
||||||
qb
|
}
|
||||||
.where('note.text IS NOT NULL')
|
|
||||||
.orWhere('note.fileIds != \'{}\'')
|
|
||||||
.orWhere('note.hasPoll = TRUE');
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}))
|
}))
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.setParameters({ noteId: ps.noteId })
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
@ -85,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
}
|
}
|
||||||
|
|
||||||
const notes = await query.limit(ps.limit).getMany();
|
const notes = await query.getMany();
|
||||||
|
|
||||||
return await this.noteEntityService.packMany(notes, me);
|
return await this.noteEntityService.packMany(notes, me);
|
||||||
});
|
});
|
||||||
|
|
|
@ -87,7 +87,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
const query = this.notesRepository
|
const query = this.notesRepository
|
||||||
.createQueryBuilder('note')
|
.createQueryBuilder('note')
|
||||||
.setParameter('me', me.id)
|
.setParameters({ meId: me.id })
|
||||||
|
|
||||||
// Limit to latest notes
|
// Limit to latest notes
|
||||||
.innerJoin(
|
.innerJoin(
|
||||||
|
@ -130,8 +130,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId')
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
|
||||||
// Exclude channel notes
|
// Exclude channel notes
|
||||||
.andWhere({ channelId: IsNull() })
|
.andWhere({ channelId: IsNull() })
|
||||||
|
@ -177,14 +177,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
* Limit to followers (they follow us)
|
* Limit to followers (they follow us)
|
||||||
*/
|
*/
|
||||||
function addFollower<T extends SelectQueryBuilder<ObjectLiteral>>(query: T): T {
|
function addFollower<T extends SelectQueryBuilder<ObjectLiteral>>(query: T): T {
|
||||||
return query.innerJoin(MiFollowing, 'follower', 'follower."followerId" = latest.user_id AND follower."followeeId" = :me');
|
return query.innerJoin(MiFollowing, 'follower', 'follower."followerId" = latest.user_id AND follower."followeeId" = :meId');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limit to followees (we follow them)
|
* Limit to followees (we follow them)
|
||||||
*/
|
*/
|
||||||
function addFollowee<T extends SelectQueryBuilder<ObjectLiteral>>(query: T): T {
|
function addFollowee<T extends SelectQueryBuilder<ObjectLiteral>>(query: T): T {
|
||||||
return query.innerJoin(MiFollowing, 'followee', 'followee."followerId" = :me AND followee."followeeId" = latest.user_id');
|
return query.innerJoin(MiFollowing, 'followee', 'followee."followerId" = :meId AND followee."followeeId" = latest.user_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -82,8 +82,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId');
|
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||||
|
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
|
|
|
@ -197,51 +197,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
withBots: boolean,
|
withBots: boolean,
|
||||||
withRenotes: boolean,
|
withRenotes: boolean,
|
||||||
}, me: MiLocalUser) {
|
}, me: MiLocalUser) {
|
||||||
const followees = await this.userFollowingService.getFollowees(me.id);
|
|
||||||
const followingChannels = await this.channelFollowingsRepository.find({
|
|
||||||
where: {
|
|
||||||
followerId: me.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere(new Brackets(qb => {
|
// 1. by a user I follow, 2. a public local post, 3. my own post
|
||||||
if (followees.length > 0) {
|
.andWhere(new Brackets(qb => this.queryService
|
||||||
const meOrFolloweeIds = [me.id, ...followees.map(f => f.followeeId)];
|
.orFollowingUser(qb, ':meId', 'note.userId')
|
||||||
qb.where('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds });
|
.orWhere(new Brackets(qbb => qbb
|
||||||
qb.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)');
|
.andWhere('note.visibility = \'public\'')
|
||||||
} else {
|
.andWhere('note.userHost IS NULL')))
|
||||||
qb.where('note.userId = :meId', { meId: me.id });
|
.orWhere(':meId = note.userId')))
|
||||||
qb.orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)');
|
// 1. in a channel I follow, 2. not in a channel
|
||||||
}
|
.andWhere(new Brackets(qb => this.queryService
|
||||||
}))
|
.orFollowingChannel(qb, ':meId', 'note.channelId')
|
||||||
|
.orWhere('note.channelId IS NULL')))
|
||||||
|
.setParameters({ meId: me.id })
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
if (followingChannels.length > 0) {
|
|
||||||
const followingChannelIds = followingChannels.map(x => x.followeeId);
|
|
||||||
|
|
||||||
query.andWhere(new Brackets(qb => {
|
|
||||||
qb.where('note.channelId IN (:...followingChannelIds)', { followingChannelIds });
|
|
||||||
qb.orWhere('note.channelId IS NULL');
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
query.andWhere('note.channelId IS NULL');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ps.withReplies) {
|
if (!ps.withReplies) {
|
||||||
query.andWhere(new Brackets(qb => {
|
query
|
||||||
qb
|
// 1. Not a reply, 2. a self-reply
|
||||||
.where('note.replyId IS NULL') // 返信ではない
|
.andWhere(new Brackets(qb => qb
|
||||||
.orWhere(new Brackets(qb => {
|
.orWhere('note.replyId IS NULL') // 返信ではない
|
||||||
qb // 返信だけど投稿者自身への返信
|
.orWhere('note.replyUserId = note.userId')));
|
||||||
.where('note.replyId IS NOT NULL')
|
|
||||||
.andWhere('note.replyUserId = note.userId');
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
|
@ -263,6 +244,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
return await query.limit(ps.limit).getMany();
|
return await query.getMany();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,8 +168,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
|
if (!ps.withReplies) {
|
||||||
|
query
|
||||||
|
// 1. Not a reply, 2. a self-reply
|
||||||
|
.andWhere(new Brackets(qb => qb
|
||||||
|
.orWhere('note.replyId IS NULL') // 返信ではない
|
||||||
|
.orWhere('note.replyUserId = note.userId')));
|
||||||
|
}
|
||||||
|
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
|
@ -190,18 +199,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ps.withReplies) {
|
return await query.getMany();
|
||||||
query.andWhere(new Brackets(qb => {
|
|
||||||
qb
|
|
||||||
.where('note.replyId IS NULL') // 返信ではない
|
|
||||||
.orWhere(new Brackets(qb => {
|
|
||||||
qb // 返信だけど投稿者自身への返信
|
|
||||||
.where('note.replyId IS NOT NULL')
|
|
||||||
.andWhere('note.replyUserId = note.userId');
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return await query.limit(ps.limit).getMany();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
noteId: { type: 'string', format: 'misskey:id' },
|
noteId: { type: 'string', format: 'misskey:id' },
|
||||||
userId: { type: "string", format: "misskey:id" },
|
userId: { type: 'string', format: 'misskey:id' },
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
@ -81,19 +81,21 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||||
|
|
||||||
if (ps.userId) {
|
if (ps.userId) {
|
||||||
query.andWhere("user.id = :userId", { userId: ps.userId });
|
query.andWhere('user.id = :userId', { userId: ps.userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.quote) {
|
if (ps.quote) {
|
||||||
query.andWhere("note.text IS NOT NULL");
|
this.queryService.andIsQuote(query, 'note');
|
||||||
} else {
|
} else {
|
||||||
query.andWhere("note.text IS NULL");
|
this.queryService.andIsRenote(query, 'note');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
|
if (me) {
|
||||||
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
}
|
||||||
|
|
||||||
const renotes = await query.limit(ps.limit).getMany();
|
const renotes = await query.limit(ps.limit).getMany();
|
||||||
|
|
||||||
|
|
|
@ -59,14 +59,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
if (me) this.queryService.generateMutedUserQueryForNotes(query, me);
|
if (me) {
|
||||||
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
}
|
||||||
|
|
||||||
const timeline = await query.limit(ps.limit).getMany();
|
const timeline = await query.getMany();
|
||||||
|
|
||||||
return await this.noteEntityService.packMany(timeline, me);
|
return await this.noteEntityService.packMany(timeline, me);
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,8 +12,6 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['notes', 'hashtags'],
|
tags: ['notes', 'hashtags'],
|
||||||
|
@ -82,19 +80,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
private cacheService: CacheService,
|
|
||||||
private utilityService: UtilityService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.andWhere("note.visibility IN ('public', 'home')") // keep in sync with NoteCreateService call to `hashtagService.updateHashtags()`
|
.andWhere(new Brackets(qb => qb
|
||||||
|
.orWhere('note.visibility = \'public\'')
|
||||||
|
.orWhere('note.visibility = \'home\''))) // keep in sync with NoteCreateService call to `hashtagService.updateHashtags()`
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
if (!this.serverSettings.enableBotTrending) query.andWhere('user.isBot = FALSE');
|
|
||||||
|
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
|
@ -102,7 +99,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
|
if (me) this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
||||||
|
|
||||||
const followings = me ? await this.cacheService.userFollowingsCache.fetch(me.id) : {};
|
if (!this.serverSettings.enableBotTrending) query.andWhere('user.isBot = FALSE');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (ps.tag) {
|
if (ps.tag) {
|
||||||
|
@ -135,9 +132,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
if (ps.renote != null) {
|
if (ps.renote != null) {
|
||||||
if (ps.renote) {
|
if (ps.renote) {
|
||||||
query.andWhere('note.renoteId IS NOT NULL');
|
this.queryService.andIsRenote(query, 'note');
|
||||||
} else {
|
} else {
|
||||||
query.andWhere('note.renoteId IS NULL');
|
this.queryService.andIsNotRenote(query, 'note');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,16 +151,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search notes
|
// Search notes
|
||||||
let notes = await query.limit(ps.limit).getMany();
|
const notes = await query.getMany();
|
||||||
|
|
||||||
notes = notes.filter(note => {
|
|
||||||
if (note.user?.isSilenced && me && followings && note.userId !== me.id && !followings[note.userId]) return false;
|
|
||||||
if (note.user?.isSuspended) return false;
|
|
||||||
if (note.userHost) {
|
|
||||||
if (!this.utilityService.isFederationAllowedHost(note.userHost)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return await this.noteEntityService.packMany(notes, me);
|
return await this.noteEntityService.packMany(notes, me);
|
||||||
});
|
});
|
||||||
|
|
|
@ -142,11 +142,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private async getFromDb(ps: { untilId: string | null; sinceId: string | null; limit: number; withFiles: boolean; withRenotes: boolean; withBots: boolean; }, me: MiLocalUser) {
|
private async getFromDb(ps: { untilId: string | null; sinceId: string | null; limit: number; withFiles: boolean; withRenotes: boolean; withBots: boolean; }, me: MiLocalUser) {
|
||||||
//#region Construct query
|
//#region Construct query
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser')
|
|
||||||
// 1. in a channel I follow, 2. my own post, 3. by a user I follow
|
// 1. in a channel I follow, 2. my own post, 3. by a user I follow
|
||||||
.andWhere(new Brackets(qb => this.queryService
|
.andWhere(new Brackets(qb => this.queryService
|
||||||
.orFollowingChannel(qb, ':meId', 'note.channelId')
|
.orFollowingChannel(qb, ':meId', 'note.channelId')
|
||||||
|
@ -160,10 +155,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.orWhere('note.replyId IS NULL') // 返信ではない
|
.orWhere('note.replyId IS NULL') // 返信ではない
|
||||||
.orWhere('note.replyUserId = note.userId')))
|
.orWhere('note.replyUserId = note.userId')))
|
||||||
.setParameters({ meId: me.id })
|
.setParameters({ meId: me.id })
|
||||||
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
.limit(ps.limit);
|
.limit(ps.limit);
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateMutedUserQueryForNotes(query, me);
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
|
|
||||||
|
|
|
@ -154,32 +154,25 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
//#region Construct query
|
//#region Construct query
|
||||||
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
|
||||||
.innerJoin(this.userListMembershipsRepository.metadata.targetName, 'userListMemberships', 'userListMemberships.userId = note.userId')
|
.innerJoin(this.userListMembershipsRepository.metadata.targetName, 'userListMemberships', 'userListMemberships.userId = note.userId')
|
||||||
|
.andWhere('userListMemberships.userListId = :userListId', { userListId: list.id })
|
||||||
|
.andWhere('note.channelId IS NULL') // チャンネルノートではない
|
||||||
|
.andWhere(new Brackets(qb => qb
|
||||||
|
// 返信ではない
|
||||||
|
.orWhere('note.replyId IS NULL')
|
||||||
|
// 返信だけど投稿者自身への返信
|
||||||
|
.orWhere('note.replyUserId = note.userId')
|
||||||
|
// 返信だけど自分宛ての返信
|
||||||
|
.orWhere('note.replyUserId = :meId')
|
||||||
|
// 返信だけどwithRepliesがtrueの場合
|
||||||
|
.orWhere('userListMemberships.withReplies = true'),
|
||||||
|
))
|
||||||
|
.setParameters({ meId: me.id })
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId')
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
.andWhere('userListMemberships.userListId = :userListId', { userListId: list.id })
|
.limit(ps.limit);
|
||||||
.andWhere('note.channelId IS NULL') // チャンネルノートではない
|
|
||||||
.andWhere(new Brackets(qb => {
|
|
||||||
qb
|
|
||||||
.where('note.replyId IS NULL') // 返信ではない
|
|
||||||
.orWhere(new Brackets(qb => {
|
|
||||||
qb // 返信だけど投稿者自身への返信
|
|
||||||
.where('note.replyId IS NOT NULL')
|
|
||||||
.andWhere('note.replyUserId = note.userId');
|
|
||||||
}))
|
|
||||||
.orWhere(new Brackets(qb => {
|
|
||||||
qb // 返信だけど自分宛ての返信
|
|
||||||
.where('note.replyId IS NOT NULL')
|
|
||||||
.andWhere('note.replyUserId = :meId', { meId: me.id });
|
|
||||||
}))
|
|
||||||
.orWhere(new Brackets(qb => {
|
|
||||||
qb // 返信だけどwithRepliesがtrueの場合
|
|
||||||
.where('note.replyId IS NOT NULL')
|
|
||||||
.andWhere('userListMemberships.withReplies = true');
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.queryService.generateVisibilityQuery(query, me);
|
this.queryService.generateVisibilityQuery(query, me);
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
@ -192,12 +185,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
if (!ps.withRenotes) {
|
if (!ps.withRenotes) {
|
||||||
this.queryService.generateExcludedRenotesQueryForNotes(query);
|
this.queryService.generateExcludedRenotesQueryForNotes(query);
|
||||||
} else if (me) {
|
} else {
|
||||||
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
return await query.limit(ps.limit).getMany();
|
return await query.getMany();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,10 +107,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.innerJoinAndSelect('note.user', 'user')
|
.innerJoinAndSelect('note.user', 'user')
|
||||||
.leftJoinAndSelect('note.reply', 'reply')
|
.leftJoinAndSelect('note.reply', 'reply')
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser', 'replyUser.id = note.replyUserId')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser', 'renoteUser.id = note.renoteUserId');
|
.leftJoinAndSelect('renote.user', 'renoteUser');
|
||||||
|
|
||||||
this.queryService.generateBlockedHostQueryForNote(query);
|
this.queryService.generateBlockedHostQueryForNote(query);
|
||||||
|
this.queryService.generateSilencedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateMutedUserQueryForNotes(query, me);
|
this.queryService.generateMutedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
this.queryService.generateBlockedUserQueryForNotes(query, me);
|
||||||
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
this.queryService.generateMutedUserRenotesQueryForNotes(query, me);
|
||||||
|
|
|
@ -205,7 +205,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.leftJoinAndSelect('note.renote', 'renote')
|
.leftJoinAndSelect('note.renote', 'renote')
|
||||||
.leftJoinAndSelect('note.channel', 'channel')
|
.leftJoinAndSelect('note.channel', 'channel')
|
||||||
.leftJoinAndSelect('reply.user', 'replyUser')
|
.leftJoinAndSelect('reply.user', 'replyUser')
|
||||||
.leftJoinAndSelect('renote.user', 'renoteUser');
|
.leftJoinAndSelect('renote.user', 'renoteUser')
|
||||||
|
.limit(ps.limit);
|
||||||
|
|
||||||
if (ps.withChannelNotes) {
|
if (ps.withChannelNotes) {
|
||||||
if (!isSelf) query.andWhere(new Brackets(qb => {
|
if (!isSelf) query.andWhere(new Brackets(qb => {
|
||||||
|
@ -230,26 +231,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
if (!ps.withRenotes && !ps.withQuotes) {
|
if (!ps.withRenotes && !ps.withQuotes) {
|
||||||
query.andWhere('note.renoteId IS NULL');
|
query.andWhere('note.renoteId IS NULL');
|
||||||
} else if (!ps.withRenotes) {
|
} else if (!ps.withRenotes) {
|
||||||
query.andWhere(new Brackets(qb => {
|
this.queryService.andIsNotRenote(query, 'note');
|
||||||
qb.orWhere('note.userId != :userId', { userId: ps.userId });
|
|
||||||
qb.orWhere('note.renoteId IS NULL');
|
|
||||||
qb.orWhere('note.text IS NOT NULL');
|
|
||||||
qb.orWhere('note.fileIds != \'{}\'');
|
|
||||||
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
|
|
||||||
}));
|
|
||||||
} else if (!ps.withQuotes) {
|
} else if (!ps.withQuotes) {
|
||||||
query.andWhere(`
|
this.queryService.andIsNotQuote(query, 'note');
|
||||||
(
|
|
||||||
note."renoteId" IS NULL
|
|
||||||
OR (
|
|
||||||
note.text IS NULL
|
|
||||||
AND note.cw IS NULL
|
|
||||||
AND note."replyId" IS NULL
|
|
||||||
AND note."hasPoll" IS FALSE
|
|
||||||
AND note."fileIds" = '{}'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ps.withRepliesToOthers && !ps.withRepliesToSelf) {
|
if (!ps.withRepliesToOthers && !ps.withRepliesToSelf) {
|
||||||
|
@ -268,6 +252,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
query.andWhere('"user"."isBot" = false');
|
query.andWhere('"user"."isBot" = false');
|
||||||
}
|
}
|
||||||
|
|
||||||
return await query.limit(ps.limit).getMany();
|
return await query.getMany();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue