wip
This commit is contained in:
parent
f124e4c561
commit
5d07426e23
104
src/backend/controllers/questions.ts
Normal file
104
src/backend/controllers/questions.ts
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* バージョン情報など、サーバーのメタデータを返すAPI
|
||||
* @author Xeltica
|
||||
*/
|
||||
|
||||
import { BadRequestError, Body, CurrentUser, Delete, Get, JsonController, NotFoundError, OnUndefined, Param, Post, Put } from 'routing-controllers';
|
||||
import { IUser } from '../../common/types/user.js';
|
||||
import { Questions } from '../models/index.js';
|
||||
import { AnnounceCreate } from './body/announce-create.js';
|
||||
import { AnnounceUpdate } from './body/announce-update.js';
|
||||
import { IdProp } from './body/id-prop.js';
|
||||
|
||||
@JsonController('/questions')
|
||||
export class AnnouncementController {
|
||||
@Get() get() {
|
||||
const query = Questions.createQueryBuilder('announcement')
|
||||
.orderBy('"announcement"."createdAt"', 'DESC');
|
||||
|
||||
return query.getMany();
|
||||
}
|
||||
|
||||
@OnUndefined(204)
|
||||
@Post() async post(@CurrentUser({ required: true }) user: IUser, @Body({required: true}) {title, body}: AnnounceCreate) {
|
||||
if (!user.isAdmin) {
|
||||
throw new BadRequestError('Not an Admin');
|
||||
}
|
||||
if (!title || !body) {
|
||||
throw new BadRequestError();
|
||||
}
|
||||
await Questions.insert({
|
||||
createdAt: new Date(),
|
||||
title,
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
@OnUndefined(204)
|
||||
@Put() async update(@CurrentUser({ required: true }) user: IUser, @Body() {id, title, body}: AnnounceUpdate) {
|
||||
if (!user.isAdmin) {
|
||||
throw new BadRequestError('Not an Admin');
|
||||
}
|
||||
if (!id || !title || !body) {
|
||||
throw new BadRequestError();
|
||||
}
|
||||
if (!(await Questions.findOne(id))) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
|
||||
await Questions.update(id, {
|
||||
title,
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
||||
@OnUndefined(204)
|
||||
@Post('/like/:id') async like(@CurrentUser({ required: true }) user: IUser, @Param('id') id: string) {
|
||||
if (!user.isAdmin) {
|
||||
throw new BadRequestError('Not an Admin');
|
||||
}
|
||||
const idNumber = Number(id);
|
||||
if (isNaN(idNumber)) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
if (!id) {
|
||||
throw new BadRequestError();
|
||||
}
|
||||
|
||||
const announcement = await Questions.findOne(Number(idNumber));
|
||||
|
||||
if (!announcement) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
|
||||
await Questions.update(id, {
|
||||
like: announcement.like + 1,
|
||||
});
|
||||
|
||||
return announcement.like + 1;
|
||||
}
|
||||
|
||||
@Delete() async delete(@CurrentUser({ required: true }) user: IUser, @Body() {id}: IdProp) {
|
||||
if (!user.isAdmin) {
|
||||
throw new BadRequestError('Not an Admin');
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
throw new BadRequestError();
|
||||
}
|
||||
|
||||
await Questions.delete(id);
|
||||
}
|
||||
|
||||
@Get('/:id') async getDetail(@Param('id') id: string) {
|
||||
const idNumber = Number(id);
|
||||
if (isNaN(idNumber)) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
const announcement = await Questions.findOne(idNumber);
|
||||
if (!announcement) {
|
||||
throw new NotFoundError();
|
||||
}
|
||||
return announcement;
|
||||
}
|
||||
}
|
@ -40,6 +40,7 @@ export class SessionController {
|
||||
if (setting.notificationIcon !== undefined) s.notificationIcon = setting.notificationIcon;
|
||||
if (setting.useRanking !== undefined) s.useRanking = setting.useRanking;
|
||||
if (setting.appendHashtag !== undefined) s.appendHashtag = setting.appendHashtag;
|
||||
if se
|
||||
if (Object.keys(s).length === 0) return;
|
||||
await updateUser(user.username, user.host, s);
|
||||
}
|
||||
|
71
src/backend/models/entities/question.ts
Normal file
71
src/backend/models/entities/question.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Entity, PrimaryGeneratedColumn, Column, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { User } from './user.js';
|
||||
import { IQuestion } from '../../../common/types/question.js';
|
||||
|
||||
@Entity()
|
||||
export class Question implements IQuestion {
|
||||
@PrimaryGeneratedColumn()
|
||||
public id: number;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
type: 'number' as const,
|
||||
nullable: true,
|
||||
comment: 'The ID of reply target.',
|
||||
})
|
||||
public recipientId: User['id'];
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public recipient: User;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
type: 'number' as const,
|
||||
nullable: true,
|
||||
comment: 'The ID of reply target.',
|
||||
})
|
||||
public senderId: User['id'] | null;
|
||||
|
||||
@ManyToOne(type => User, {
|
||||
onDelete: 'SET NULL',
|
||||
})
|
||||
@JoinColumn()
|
||||
public sender: User | null;
|
||||
|
||||
@Column({
|
||||
type: 'timestamp without time zone',
|
||||
})
|
||||
public createdAt: Date;
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
length: 8192,
|
||||
})
|
||||
public question: string;
|
||||
|
||||
@Column({
|
||||
type: 'timestamp without time zone',
|
||||
})
|
||||
public repliedAt: Date;
|
||||
|
||||
@Column({
|
||||
type: 'varchar',
|
||||
length: 8192,
|
||||
})
|
||||
public reply: string;
|
||||
|
||||
@Column({
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
})
|
||||
public isDeleted: boolean;
|
||||
|
||||
@Column({
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
})
|
||||
public isNSFW: boolean;
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
import { User } from './entities/user.js';
|
||||
import { UsedToken } from './entities/used-token.js';
|
||||
import { getRepository } from 'typeorm';
|
||||
import { Announcement } from './entities/announcement.js';
|
||||
import { Question } from './entities/question.js';
|
||||
import { getRepository } from 'typeorm';
|
||||
|
||||
export const Users = getRepository(User);
|
||||
export const UsedTokens = getRepository(UsedToken);
|
||||
export const Announcements = getRepository(Announcement);
|
||||
export const Questions = getRepository(Question);
|
||||
|
@ -1,11 +1,17 @@
|
||||
const allTexts: string[] = [
|
||||
'아무말 빔----',
|
||||
'휴대폰용 보험은 가입하셨나요?',
|
||||
'아, 뭐하려고 했더라...?',
|
||||
'여기 재밌는 이야기가 있어요! https://youtu.be/dQw4w9WgXcQ',
|
||||
'모니터를 청소하려고 물을 뿌렸더니, 아무것도 보이지 않게 됐어요...'
|
||||
];
|
||||
|
||||
const getRandomText = () => allTexts[Math.floor(Math.random() * allTexts.length)];
|
||||
function getRandomText(texts: string[]): string {
|
||||
if (texts.length < 1) texts = allTexts;
|
||||
return texts[Math.floor(Math.random() * texts.length)];
|
||||
}
|
||||
|
||||
export const createGacha = () => {
|
||||
const result = getRandomText();
|
||||
export function createGacha(texts: string[]): string {
|
||||
const result = getRandomText(texts);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ export const variables: Record<string, Variable> = {
|
||||
username: (_, user) => String(user.username),
|
||||
host: (_, user) => String(user.host),
|
||||
rating: (_, user) => String(user.rating),
|
||||
gacha: () => createGacha(),
|
||||
gacha: () => createGacha(user.gachaTexts),
|
||||
};
|
||||
|
||||
const variableRegex = /\{([a-zA-Z0-9_]+?)}/g;
|
||||
@ -47,7 +47,7 @@ export const format = (user: IUser, count: Count): string => {
|
||||
return !v ? m : typeof v === 'function' ? v(score, user) : v;
|
||||
});
|
||||
if (user.appendHashtag) {
|
||||
result = result + '\n\n#misshaialert';
|
||||
result = result + '\n\n<small>Powered by #misshaialert</small>';
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
13
src/common/types/question.ts
Normal file
13
src/common/types/question.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { IUser } from './user.js';
|
||||
|
||||
export interface IQuestion {
|
||||
id: number;
|
||||
recipient: IUser;
|
||||
sender: IUser | null;
|
||||
createdAt: Date;
|
||||
question: string;
|
||||
repliedAt: Date;
|
||||
reply: string;
|
||||
isDeleted: boolean;
|
||||
isNSFW: boolean;
|
||||
}
|
Loading…
Reference in New Issue
Block a user