forked from FoundKeyGang/FoundKey
Remove promo entities and endpoints
This commit is contained in:
parent
534666f762
commit
c7bf29fd49
8 changed files with 25 additions and 210 deletions
|
@ -0,0 +1,25 @@
|
||||||
|
export class removePromoEntities1660251834642 {
|
||||||
|
name = 'removePromoEntities1660251834642';
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "promo_read" DROP CONSTRAINT "FK_a46a1a603ecee695d7db26da5f4"`, undefined);
|
||||||
|
await queryRunner.query(`ALTER TABLE "promo_read" DROP CONSTRAINT "FK_9657d55550c3d37bfafaf7d4b05"`, undefined);
|
||||||
|
await queryRunner.query(`ALTER TABLE "promo_note" DROP CONSTRAINT "FK_e263909ca4fe5d57f8d4230dd5c"`, undefined);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_2882b8a1a07c7d281a98b6db16"`, undefined);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_9657d55550c3d37bfafaf7d4b0"`, undefined);
|
||||||
|
await queryRunner.query(`DROP TABLE "promo_read"`, undefined);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_83f0862e9bae44af52ced7099e"`, undefined);
|
||||||
|
await queryRunner.query(`DROP TABLE "promo_note"`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`CREATE TABLE "promo_note" ("noteId" character varying(32) NOT NULL, "expiresAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, CONSTRAINT "REL_e263909ca4fe5d57f8d4230dd5" UNIQUE ("noteId"), CONSTRAINT "PK_e263909ca4fe5d57f8d4230dd5c" PRIMARY KEY ("noteId"))`, undefined);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_83f0862e9bae44af52ced7099e" ON "promo_note" ("userId") `, undefined);
|
||||||
|
await queryRunner.query(`CREATE TABLE "promo_read" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, CONSTRAINT "PK_61917c1541002422b703318b7c9" PRIMARY KEY ("id"))`, undefined);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_9657d55550c3d37bfafaf7d4b0" ON "promo_read" ("userId") `, undefined);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_2882b8a1a07c7d281a98b6db16" ON "promo_read" ("userId", "noteId") `, undefined);
|
||||||
|
await queryRunner.query(`ALTER TABLE "promo_note" ADD CONSTRAINT "FK_e263909ca4fe5d57f8d4230dd5c" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||||
|
await queryRunner.query(`ALTER TABLE "promo_read" ADD CONSTRAINT "FK_9657d55550c3d37bfafaf7d4b05" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||||
|
await queryRunner.query(`ALTER TABLE "promo_read" ADD CONSTRAINT "FK_a46a1a603ecee695d7db26da5f4" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, undefined);
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,8 +57,6 @@ import { Clip } from '@/models/entities/clip.js';
|
||||||
import { ClipNote } from '@/models/entities/clip-note.js';
|
import { ClipNote } from '@/models/entities/clip-note.js';
|
||||||
import { Antenna } from '@/models/entities/antenna.js';
|
import { Antenna } from '@/models/entities/antenna.js';
|
||||||
import { AntennaNote } from '@/models/entities/antenna-note.js';
|
import { AntennaNote } from '@/models/entities/antenna-note.js';
|
||||||
import { PromoNote } from '@/models/entities/promo-note.js';
|
|
||||||
import { PromoRead } from '@/models/entities/promo-read.js';
|
|
||||||
import { Relay } from '@/models/entities/relay.js';
|
import { Relay } from '@/models/entities/relay.js';
|
||||||
import { MutedNote } from '@/models/entities/muted-note.js';
|
import { MutedNote } from '@/models/entities/muted-note.js';
|
||||||
import { Channel } from '@/models/entities/channel.js';
|
import { Channel } from '@/models/entities/channel.js';
|
||||||
|
@ -159,8 +157,6 @@ export const entities = [
|
||||||
ClipNote,
|
ClipNote,
|
||||||
Antenna,
|
Antenna,
|
||||||
AntennaNote,
|
AntennaNote,
|
||||||
PromoNote,
|
|
||||||
PromoRead,
|
|
||||||
Relay,
|
Relay,
|
||||||
MutedNote,
|
MutedNote,
|
||||||
Channel,
|
Channel,
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm';
|
|
||||||
import { id } from '../id.js';
|
|
||||||
import { Note } from './note.js';
|
|
||||||
import { User } from './user.js';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class PromoNote {
|
|
||||||
@PrimaryColumn(id())
|
|
||||||
public noteId: Note['id'];
|
|
||||||
|
|
||||||
@OneToOne(type => Note, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public note: Note | null;
|
|
||||||
|
|
||||||
@Column('timestamp with time zone')
|
|
||||||
public expiresAt: Date;
|
|
||||||
|
|
||||||
//#region Denormalized fields
|
|
||||||
@Index()
|
|
||||||
@Column({
|
|
||||||
...id(),
|
|
||||||
comment: '[Denormalized]',
|
|
||||||
})
|
|
||||||
public userId: User['id'];
|
|
||||||
//#endregion
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
|
||||||
import { id } from '../id.js';
|
|
||||||
import { Note } from './note.js';
|
|
||||||
import { User } from './user.js';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
@Index(['userId', 'noteId'], { unique: true })
|
|
||||||
export class PromoRead {
|
|
||||||
@PrimaryColumn(id())
|
|
||||||
public id: string;
|
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
|
||||||
comment: 'The created date of the PromoRead.',
|
|
||||||
})
|
|
||||||
public createdAt: Date;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column(id())
|
|
||||||
public userId: User['id'];
|
|
||||||
|
|
||||||
@ManyToOne(type => User, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public user: User | null;
|
|
||||||
|
|
||||||
@Column(id())
|
|
||||||
public noteId: Note['id'];
|
|
||||||
|
|
||||||
@ManyToOne(type => Note, {
|
|
||||||
onDelete: 'CASCADE',
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public note: Note | null;
|
|
||||||
}
|
|
|
@ -50,8 +50,6 @@ import { ClipRepository } from './repositories/clip.js';
|
||||||
import { ClipNote } from './entities/clip-note.js';
|
import { ClipNote } from './entities/clip-note.js';
|
||||||
import { AntennaRepository } from './repositories/antenna.js';
|
import { AntennaRepository } from './repositories/antenna.js';
|
||||||
import { AntennaNote } from './entities/antenna-note.js';
|
import { AntennaNote } from './entities/antenna-note.js';
|
||||||
import { PromoNote } from './entities/promo-note.js';
|
|
||||||
import { PromoRead } from './entities/promo-read.js';
|
|
||||||
import { EmojiRepository } from './repositories/emoji.js';
|
import { EmojiRepository } from './repositories/emoji.js';
|
||||||
import { RelayRepository } from './repositories/relay.js';
|
import { RelayRepository } from './repositories/relay.js';
|
||||||
import { ChannelRepository } from './repositories/channel.js';
|
import { ChannelRepository } from './repositories/channel.js';
|
||||||
|
@ -116,8 +114,6 @@ export const Clips = (ClipRepository);
|
||||||
export const ClipNotes = db.getRepository(ClipNote);
|
export const ClipNotes = db.getRepository(ClipNote);
|
||||||
export const Antennas = (AntennaRepository);
|
export const Antennas = (AntennaRepository);
|
||||||
export const AntennaNotes = db.getRepository(AntennaNote);
|
export const AntennaNotes = db.getRepository(AntennaNote);
|
||||||
export const PromoNotes = db.getRepository(PromoNote);
|
|
||||||
export const PromoReads = db.getRepository(PromoRead);
|
|
||||||
export const Relays = (RelayRepository);
|
export const Relays = (RelayRepository);
|
||||||
export const MutedNotes = db.getRepository(MutedNote);
|
export const MutedNotes = db.getRepository(MutedNote);
|
||||||
export const Channels = (ChannelRepository);
|
export const Channels = (ChannelRepository);
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import rndstr from 'rndstr';
|
|
||||||
import { Note } from '@/models/entities/note.js';
|
|
||||||
import { User } from '@/models/entities/user.js';
|
|
||||||
import { PromoReads, PromoNotes, Notes, Users } from '@/models/index.js';
|
|
||||||
|
|
||||||
export async function injectPromo(timeline: Note[], user?: User | null) {
|
|
||||||
if (timeline.length < 5) return;
|
|
||||||
|
|
||||||
// TODO: readやexpireフィルタはクエリ側でやる
|
|
||||||
|
|
||||||
const reads = user ? await PromoReads.findBy({
|
|
||||||
userId: user.id,
|
|
||||||
}) : [];
|
|
||||||
|
|
||||||
let promos = await PromoNotes.find();
|
|
||||||
|
|
||||||
promos = promos.filter(n => n.expiresAt.getTime() > Date.now());
|
|
||||||
promos = promos.filter(n => !reads.map(r => r.noteId).includes(n.noteId));
|
|
||||||
|
|
||||||
if (promos.length === 0) return;
|
|
||||||
|
|
||||||
// Pick random promo
|
|
||||||
const promo = promos[Math.floor(Math.random() * promos.length)];
|
|
||||||
|
|
||||||
const note = await Notes.findOneByOrFail({ id: promo.noteId });
|
|
||||||
|
|
||||||
// Join
|
|
||||||
note.user = await Users.findOneByOrFail({ id: note.userId });
|
|
||||||
|
|
||||||
(note as any)._prId_ = rndstr('a-z0-9', 8);
|
|
||||||
|
|
||||||
// Inject promo
|
|
||||||
timeline.splice(3, 0, note);
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
import { PromoNotes } from '@/models/index.js';
|
|
||||||
import define from '../../../define.js';
|
|
||||||
import { ApiError } from '../../../error.js';
|
|
||||||
import { getNote } from '../../../common/getters.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['admin'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
requireModerator: true,
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchNote: {
|
|
||||||
message: 'No such note.',
|
|
||||||
code: 'NO_SUCH_NOTE',
|
|
||||||
id: 'ee449fbe-af2a-453b-9cae-cf2fe7c895fc',
|
|
||||||
},
|
|
||||||
|
|
||||||
alreadyPromoted: {
|
|
||||||
message: 'The note has already promoted.',
|
|
||||||
code: 'ALREADY_PROMOTED',
|
|
||||||
id: 'ae427aa2-7a41-484f-a18c-2c1104051604',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
noteId: { type: 'string', format: 'misskey:id' },
|
|
||||||
expiresAt: { type: 'integer' },
|
|
||||||
},
|
|
||||||
required: ['noteId', 'expiresAt'],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
|
||||||
const note = await getNote(ps.noteId, user).catch(err => {
|
|
||||||
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
const exist = await PromoNotes.findOneBy({ noteId: note.id });
|
|
||||||
|
|
||||||
if (exist != null) {
|
|
||||||
throw new ApiError(meta.errors.alreadyPromoted);
|
|
||||||
}
|
|
||||||
|
|
||||||
await PromoNotes.insert({
|
|
||||||
noteId: note.id,
|
|
||||||
expiresAt: new Date(ps.expiresAt),
|
|
||||||
userId: note.userId,
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,51 +0,0 @@
|
||||||
import { PromoReads } from '@/models/index.js';
|
|
||||||
import { genId } from '@/misc/gen-id.js';
|
|
||||||
import define from '../../define.js';
|
|
||||||
import { ApiError } from '../../error.js';
|
|
||||||
import { getNote } from '../../common/getters.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
tags: ['notes'],
|
|
||||||
|
|
||||||
requireCredential: true,
|
|
||||||
|
|
||||||
errors: {
|
|
||||||
noSuchNote: {
|
|
||||||
message: 'No such note.',
|
|
||||||
code: 'NO_SUCH_NOTE',
|
|
||||||
id: 'd785b897-fcd3-4fe9-8fc3-b85c26e6c932',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export const paramDef = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
noteId: { type: 'string', format: 'misskey:id' },
|
|
||||||
},
|
|
||||||
required: ['noteId'],
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-default-export
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
|
||||||
const note = await getNote(ps.noteId, user).catch(err => {
|
|
||||||
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
const exist = await PromoReads.findOneBy({
|
|
||||||
noteId: note.id,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exist != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await PromoReads.insert({
|
|
||||||
id: genId(),
|
|
||||||
createdAt: new Date(),
|
|
||||||
noteId: note.id,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in a new issue