Implement featured note injection
This commit is contained in:
parent
3d79e7a136
commit
d9986b7a2f
|
@ -416,6 +416,7 @@ promotion: "プロモーション"
|
||||||
promote: "プロモート"
|
promote: "プロモート"
|
||||||
numberOfDays: "日数"
|
numberOfDays: "日数"
|
||||||
hideThisNote: "このノートを非表示"
|
hideThisNote: "このノートを非表示"
|
||||||
|
showFeaturedNotesInTimeline: "タイムラインにおすすめのノートを表示する"
|
||||||
|
|
||||||
_ago:
|
_ago:
|
||||||
unknown: "謎"
|
unknown: "謎"
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class featuredInjecttion1582019042083 implements MigrationInterface {
|
||||||
|
name = 'featuredInjecttion1582019042083'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ADD "injectFeaturedNote" boolean NOT NULL DEFAULT true`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<any> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "injectFeaturedNote"`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
<sequential-entrance class="sqadhkmv" ref="list" :direction="direction" :reversed="reversed">
|
<sequential-entrance class="sqadhkmv" ref="list" :direction="direction" :reversed="reversed">
|
||||||
<template v-for="(item, i) in items">
|
<template v-for="(item, i) in items">
|
||||||
<slot :item="item" :i="i"></slot>
|
<slot :item="item" :i="i"></slot>
|
||||||
<div class="separator" :key="item.id + '_date'" v-if="i != items.length - 1 && new Date(item.createdAt).getDate() != new Date(items[i + 1].createdAt).getDate() && !item._prInjectionId_ && !items[i + 1]._prInjectionId_">
|
<div class="separator" :key="item.id + '_date'" v-if="showDate(i, item)">
|
||||||
<p class="date">
|
<p class="date">
|
||||||
<span><fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span>
|
<span><fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span>
|
||||||
<span>{{ getDateText(items[i + 1].createdAt) }}<fa class="icon" :icon="faAngleDown"/></span>
|
<span>{{ getDateText(items[i + 1].createdAt) }}<fa class="icon" :icon="faAngleDown"/></span>
|
||||||
|
@ -52,6 +52,16 @@ export default Vue.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showDate(i, item) {
|
||||||
|
return (
|
||||||
|
i != this.items.length - 1 &&
|
||||||
|
new Date(item.createdAt).getDate() != new Date(this.items[i + 1].createdAt).getDate() &&
|
||||||
|
!item._prId_ &&
|
||||||
|
!this.items[i + 1]._prId_ &&
|
||||||
|
!item._featuredId_ &&
|
||||||
|
!this.items[i + 1]._featuredId_);
|
||||||
|
},
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
this.$refs.list.focus();
|
this.$refs.list.focus();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
|
<x-sub v-for="note in conversation" :key="note.id" :note="note"/>
|
||||||
<x-sub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/>
|
<x-sub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/>
|
||||||
<div class="info" v-if="pinned"><fa :icon="faThumbtack"/> {{ $t('pinnedNote') }}</div>
|
<div class="info" v-if="pinned"><fa :icon="faThumbtack"/> {{ $t('pinnedNote') }}</div>
|
||||||
<div class="info" v-if="appearNote._prInjectionId_"><fa :icon="faBullhorn"/> {{ $t('promotion') }}<button class="_textButton hide" @click="readPromo()">{{ $t('hideThisNote') }}</button></div>
|
<div class="info" v-if="appearNote._prId_"><fa :icon="faBullhorn"/> {{ $t('promotion') }}<button class="_textButton hide" @click="readPromo()">{{ $t('hideThisNote') }} <fa :icon="faTimes"/></button></div>
|
||||||
|
<div class="info" v-if="appearNote._featuredId_"><fa :icon="faBolt"/> {{ $t('featured') }}</div>
|
||||||
<div class="renote" v-if="isRenote">
|
<div class="renote" v-if="isRenote">
|
||||||
<mk-avatar class="avatar" :user="note.user"/>
|
<mk-avatar class="avatar" :user="note.user"/>
|
||||||
<fa :icon="faRetweet"/>
|
<fa :icon="faRetweet"/>
|
||||||
|
@ -84,7 +85,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight } from '@fortawesome/free-solid-svg-icons';
|
import { faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faCopy, faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
import { faCopy, faTrashAlt, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { parse } from '../../mfm/parse';
|
import { parse } from '../../mfm/parse';
|
||||||
import { sum, unique } from '../../prelude/array';
|
import { sum, unique } from '../../prelude/array';
|
||||||
|
@ -141,7 +142,7 @@ export default Vue.extend({
|
||||||
replies: [],
|
replies: [],
|
||||||
showContent: false,
|
showContent: false,
|
||||||
hideThisNote: false,
|
hideThisNote: false,
|
||||||
faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan
|
faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed">
|
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed">
|
||||||
<x-note :note="note" :detail="detail" :key="note._prInjectionId_ || note.id"/>
|
<x-note :note="note" :detail="detail" :key="note._featuredId_ || note._prId_ || note.id"/>
|
||||||
</x-list>
|
</x-list>
|
||||||
|
|
||||||
<div class="more" v-if="more && !reversed" style="margin-top: var(--margin);">
|
<div class="more" v-if="more && !reversed" style="margin-top: var(--margin);">
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
<mk-switch v-model="$store.state.i.autoWatch" @change="onChangeAutoWatch">
|
<mk-switch v-model="$store.state.i.autoWatch" @change="onChangeAutoWatch">
|
||||||
{{ $t('autoNoteWatch') }}<template #desc>{{ $t('autoNoteWatchDescription') }}</template>
|
{{ $t('autoNoteWatch') }}<template #desc>{{ $t('autoNoteWatchDescription') }}</template>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
|
<mk-switch v-model="$store.state.i.injectFeaturedNote" @change="onChangeInjectFeaturedNote">
|
||||||
|
{{ $t('showFeaturedNotesInTimeline') }}
|
||||||
|
</mk-switch>
|
||||||
</div>
|
</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<mk-button @click="readAllNotifications">{{ $t('markAsReadAllNotifications') }}</mk-button>
|
<mk-button @click="readAllNotifications">{{ $t('markAsReadAllNotifications') }}</mk-button>
|
||||||
|
@ -84,6 +87,12 @@ export default Vue.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onChangeInjectFeaturedNote(v) {
|
||||||
|
this.$root.api('i/update', {
|
||||||
|
injectFeaturedNote: v
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
readAllUnreadNotes() {
|
readAllUnreadNotes() {
|
||||||
this.$root.api('i/read_all_unread_notes');
|
this.$root.api('i/read_all_unread_notes');
|
||||||
},
|
},
|
||||||
|
|
|
@ -125,6 +125,11 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public carefulBot: boolean;
|
public carefulBot: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: true,
|
||||||
|
})
|
||||||
|
public injectFeaturedNote: boolean;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
...id(),
|
...id(),
|
||||||
nullable: true
|
nullable: true
|
||||||
|
|
|
@ -196,7 +196,8 @@ export class NoteRepository extends Repository<Note> {
|
||||||
renoteId: note.renoteId,
|
renoteId: note.renoteId,
|
||||||
mentions: note.mentions.length > 0 ? note.mentions : undefined,
|
mentions: note.mentions.length > 0 ? note.mentions : undefined,
|
||||||
uri: note.uri || undefined,
|
uri: note.uri || undefined,
|
||||||
_prInjectionId_: (note as any)._prInjectionId_ || undefined,
|
_featuredId_: (note as any)._featuredId_ || undefined,
|
||||||
|
_prId_: (note as any)._prId_ || undefined,
|
||||||
|
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
reply: note.replyId ? this.pack(note.replyId, meId, {
|
reply: note.replyId ? this.pack(note.replyId, meId, {
|
||||||
|
|
|
@ -227,6 +227,7 @@ export class UserRepository extends Repository<User> {
|
||||||
avatarId: user.avatarId,
|
avatarId: user.avatarId,
|
||||||
bannerId: user.bannerId,
|
bannerId: user.bannerId,
|
||||||
autoWatch: profile!.autoWatch,
|
autoWatch: profile!.autoWatch,
|
||||||
|
injectFeaturedNote: profile!.injectFeaturedNote,
|
||||||
alwaysMarkNsfw: profile!.alwaysMarkNsfw,
|
alwaysMarkNsfw: profile!.alwaysMarkNsfw,
|
||||||
carefulBot: profile!.carefulBot,
|
carefulBot: profile!.carefulBot,
|
||||||
autoAcceptFollowed: profile!.autoAcceptFollowed,
|
autoAcceptFollowed: profile!.autoAcceptFollowed,
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import rndstr from 'rndstr';
|
||||||
|
import { Note } from '../../../models/entities/note';
|
||||||
|
import { User } from '../../../models/entities/user';
|
||||||
|
import { Notes, UserProfiles } from '../../../models';
|
||||||
|
import { generateMuteQuery } from './generate-mute-query';
|
||||||
|
import { ensure } from '../../../prelude/ensure';
|
||||||
|
|
||||||
|
// TODO: リアクション、Renote、返信などをしたノートは除外する
|
||||||
|
|
||||||
|
export async function injectFeatured(timeline: Note[], user?: User | null) {
|
||||||
|
if (timeline.length < 5) return;
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
const profile = await UserProfiles.findOne(user.id).then(ensure);
|
||||||
|
if (!profile.injectFeaturedNote) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const max = 30;
|
||||||
|
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
|
||||||
|
|
||||||
|
const query = Notes.createQueryBuilder('note')
|
||||||
|
.addSelect('note.score')
|
||||||
|
.where('note.userHost IS NULL')
|
||||||
|
.andWhere(`note.score > 0`)
|
||||||
|
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
|
||||||
|
.andWhere(`note.visibility = 'public'`)
|
||||||
|
.leftJoinAndSelect('note.user', 'user');
|
||||||
|
|
||||||
|
if (user) generateMuteQuery(query, user);
|
||||||
|
|
||||||
|
const notes = await query
|
||||||
|
.orderBy('note.score', 'DESC')
|
||||||
|
.take(max)
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
if (notes.length === 0) return;
|
||||||
|
|
||||||
|
// Pick random one
|
||||||
|
const featured = notes[Math.floor(Math.random() * notes.length)];
|
||||||
|
|
||||||
|
(featured as any)._featuredId_ = rndstr('a-z0-9', 8);
|
||||||
|
|
||||||
|
// Inject featured
|
||||||
|
timeline.splice(3, 0, featured);
|
||||||
|
}
|
|
@ -4,14 +4,14 @@ import { User } from '../../../models/entities/user';
|
||||||
import { PromoReads, PromoNotes, Notes, Users } from '../../../models';
|
import { PromoReads, PromoNotes, Notes, Users } from '../../../models';
|
||||||
import { ensure } from '../../../prelude/ensure';
|
import { ensure } from '../../../prelude/ensure';
|
||||||
|
|
||||||
export async function injectPromo(user: User, timeline: Note[]) {
|
export async function injectPromo(timeline: Note[], user?: User | null) {
|
||||||
if (timeline.length < 5) return;
|
if (timeline.length < 5) return;
|
||||||
|
|
||||||
// TODO: readやexpireフィルタはクエリ側でやる
|
// TODO: readやexpireフィルタはクエリ側でやる
|
||||||
|
|
||||||
const reads = await PromoReads.find({
|
const reads = user ? await PromoReads.find({
|
||||||
userId: user.id
|
userId: user.id
|
||||||
});
|
}) : [];
|
||||||
|
|
||||||
let promos = await PromoNotes.find();
|
let promos = await PromoNotes.find();
|
||||||
|
|
||||||
|
@ -20,15 +20,15 @@ export async function injectPromo(user: User, timeline: Note[]) {
|
||||||
|
|
||||||
if (promos.length === 0) return;
|
if (promos.length === 0) return;
|
||||||
|
|
||||||
|
// Pick random promo
|
||||||
const promo = promos[Math.floor(Math.random() * promos.length)];
|
const promo = promos[Math.floor(Math.random() * promos.length)];
|
||||||
|
|
||||||
// Pick random promo
|
|
||||||
const note = await Notes.findOne(promo.noteId).then(ensure);
|
const note = await Notes.findOne(promo.noteId).then(ensure);
|
||||||
|
|
||||||
// Join
|
// Join
|
||||||
note.user = await Users.findOne(note.userId).then(ensure);
|
note.user = await Users.findOne(note.userId).then(ensure);
|
||||||
|
|
||||||
(note as any)._prInjectionId_ = rndstr('a-z0-9', 8);
|
(note as any)._prId_ = rndstr('a-z0-9', 8);
|
||||||
|
|
||||||
// Inject promo
|
// Inject promo
|
||||||
timeline.splice(3, 0, note);
|
timeline.splice(3, 0, note);
|
||||||
|
|
|
@ -88,7 +88,6 @@ export async function signup(username: User['username'], password: UserProfile['
|
||||||
await transactionalEntityManager.save(new UserProfile({
|
await transactionalEntityManager.save(new UserProfile({
|
||||||
userId: account.id,
|
userId: account.id,
|
||||||
autoAcceptFollowed: true,
|
autoAcceptFollowed: true,
|
||||||
autoWatch: false,
|
|
||||||
password: hash,
|
password: hash,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { ApiError } from './error';
|
||||||
import { App } from '../../models/entities/app';
|
import { App } from '../../models/entities/app';
|
||||||
import { SchemaType } from '../../misc/schema';
|
import { SchemaType } from '../../misc/schema';
|
||||||
|
|
||||||
|
// TODO: defaultが設定されている場合はその型も考慮する
|
||||||
type Params<T extends IEndpointMeta> = {
|
type Params<T extends IEndpointMeta> = {
|
||||||
[P in keyof T['params']]: NonNullable<T['params']>[P]['transform'] extends Function
|
[P in keyof T['params']]: NonNullable<T['params']>[P]['transform'] extends Function
|
||||||
? ReturnType<NonNullable<T['params']>[P]['transform']>
|
? ReturnType<NonNullable<T['params']>[P]['transform']>
|
||||||
|
|
|
@ -126,6 +126,10 @@ export const meta = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
injectFeaturedNote: {
|
||||||
|
validator: $.optional.bool,
|
||||||
|
},
|
||||||
|
|
||||||
alwaysMarkNsfw: {
|
alwaysMarkNsfw: {
|
||||||
validator: $.optional.bool,
|
validator: $.optional.bool,
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -195,6 +199,7 @@ export default define(meta, async (ps, user, app) => {
|
||||||
if (typeof ps.autoAcceptFollowed == 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
|
if (typeof ps.autoAcceptFollowed == 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
|
||||||
if (typeof ps.isCat == 'boolean') updates.isCat = ps.isCat;
|
if (typeof ps.isCat == 'boolean') updates.isCat = ps.isCat;
|
||||||
if (typeof ps.autoWatch == 'boolean') profileUpdates.autoWatch = ps.autoWatch;
|
if (typeof ps.autoWatch == 'boolean') profileUpdates.autoWatch = ps.autoWatch;
|
||||||
|
if (typeof ps.injectFeaturedNote == 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
||||||
if (typeof ps.alwaysMarkNsfw == 'boolean') profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw;
|
if (typeof ps.alwaysMarkNsfw == 'boolean') profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw;
|
||||||
|
|
||||||
if (ps.avatarId) {
|
if (ps.avatarId) {
|
||||||
|
|
|
@ -46,6 +46,7 @@ export default define(meta, async (ps, user) => {
|
||||||
const query = Notes.createQueryBuilder('note')
|
const query = Notes.createQueryBuilder('note')
|
||||||
.addSelect('note.score')
|
.addSelect('note.score')
|
||||||
.where('note.userHost IS NULL')
|
.where('note.userHost IS NULL')
|
||||||
|
.andWhere(`note.score > 0`)
|
||||||
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
|
.andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
|
||||||
.andWhere(`note.visibility = 'public'`)
|
.andWhere(`note.visibility = 'public'`)
|
||||||
.leftJoinAndSelect('note.user', 'user');
|
.leftJoinAndSelect('note.user', 'user');
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { generateMuteQuery } from '../../common/generate-mute-query';
|
||||||
import { activeUsersChart } from '../../../../services/chart';
|
import { activeUsersChart } from '../../../../services/chart';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
import { injectPromo } from '../../common/inject-promo';
|
import { injectPromo } from '../../common/inject-promo';
|
||||||
|
import { injectFeatured } from '../../common/inject-featured';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -90,7 +91,8 @@ export default define(meta, async (ps, user) => {
|
||||||
|
|
||||||
const timeline = await query.take(ps.limit!).getMany();
|
const timeline = await query.take(ps.limit!).getMany();
|
||||||
|
|
||||||
await injectPromo(user, timeline);
|
await injectPromo(timeline, user);
|
||||||
|
await injectFeatured(timeline, user);
|
||||||
|
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { generateMuteQuery } from '../../common/generate-mute-query';
|
||||||
import { activeUsersChart } from '../../../../services/chart';
|
import { activeUsersChart } from '../../../../services/chart';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
import { injectPromo } from '../../common/inject-promo';
|
import { injectPromo } from '../../common/inject-promo';
|
||||||
|
import { injectFeatured } from '../../common/inject-featured';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -170,7 +171,8 @@ export default define(meta, async (ps, user) => {
|
||||||
|
|
||||||
const timeline = await query.take(ps.limit!).getMany();
|
const timeline = await query.take(ps.limit!).getMany();
|
||||||
|
|
||||||
await injectPromo(user, timeline);
|
await injectPromo(timeline, user);
|
||||||
|
await injectFeatured(timeline, user);
|
||||||
|
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { activeUsersChart } from '../../../../services/chart';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
import { injectPromo } from '../../common/inject-promo';
|
import { injectPromo } from '../../common/inject-promo';
|
||||||
|
import { injectFeatured } from '../../common/inject-featured';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -123,7 +124,8 @@ export default define(meta, async (ps, user) => {
|
||||||
|
|
||||||
const timeline = await query.take(ps.limit!).getMany();
|
const timeline = await query.take(ps.limit!).getMany();
|
||||||
|
|
||||||
await injectPromo(user, timeline);
|
await injectPromo(timeline, user);
|
||||||
|
await injectFeatured(timeline, user);
|
||||||
|
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { activeUsersChart } from '../../../../services/chart';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
import { generateRepliesQuery } from '../../common/generate-replies-query';
|
||||||
import { injectPromo } from '../../common/inject-promo';
|
import { injectPromo } from '../../common/inject-promo';
|
||||||
|
import { injectFeatured } from '../../common/inject-featured';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -156,7 +157,8 @@ export default define(meta, async (ps, user) => {
|
||||||
|
|
||||||
const timeline = await query.take(ps.limit!).getMany();
|
const timeline = await query.take(ps.limit!).getMany();
|
||||||
|
|
||||||
await injectPromo(user, timeline);
|
await injectPromo(timeline, user);
|
||||||
|
await injectFeatured(timeline, user);
|
||||||
|
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
Loading…
Reference in New Issue