Merge remote-tracking branch 'misskey-original/develop' into develop
# Conflicts: # package.json # packages/frontend/src/components/MkEmojiEditDialog.vue # packages/frontend/src/components/MkMenu.vue # packages/frontend/src/components/MkNote.vue # packages/frontend/src/pages/timeline.vue
This commit is contained in:
commit
78a34d3de3
115 changed files with 4837 additions and 2932 deletions
|
|
@ -648,6 +648,8 @@ export class ActivityPubServerService {
|
|||
});
|
||||
|
||||
fastify.get<{ Params: { user: string; } }>('/users/:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||
vary(reply.raw, 'Accept');
|
||||
|
||||
const userId = request.params.user;
|
||||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
|
|
@ -660,6 +662,8 @@ export class ActivityPubServerService {
|
|||
});
|
||||
|
||||
fastify.get<{ Params: { user: string; } }>('/@:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||
vary(reply.raw, 'Accept');
|
||||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
usernameLower: request.params.user.toLowerCase(),
|
||||
host: IsNull(),
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ import * as ep___reversi_match from './endpoints/reversi/match.js';
|
|||
import * as ep___reversi_invitations from './endpoints/reversi/invitations.js';
|
||||
import * as ep___reversi_showGame from './endpoints/reversi/show-game.js';
|
||||
import * as ep___reversi_surrender from './endpoints/reversi/surrender.js';
|
||||
import * as ep___reversi_verify from './endpoints/reversi/verify.js';
|
||||
import { GetterService } from './GetterService.js';
|
||||
import { ApiLoggerService } from './ApiLoggerService.js';
|
||||
import type { Provider } from '@nestjs/common';
|
||||
|
|
@ -764,6 +765,7 @@ const $reversi_match: Provider = { provide: 'ep:reversi/match', useClass: ep___r
|
|||
const $reversi_invitations: Provider = { provide: 'ep:reversi/invitations', useClass: ep___reversi_invitations.default };
|
||||
const $reversi_showGame: Provider = { provide: 'ep:reversi/show-game', useClass: ep___reversi_showGame.default };
|
||||
const $reversi_surrender: Provider = { provide: 'ep:reversi/surrender', useClass: ep___reversi_surrender.default };
|
||||
const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep___reversi_verify.default };
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
@ -1149,6 +1151,7 @@ const $reversi_surrender: Provider = { provide: 'ep:reversi/surrender', useClass
|
|||
$reversi_invitations,
|
||||
$reversi_showGame,
|
||||
$reversi_surrender,
|
||||
$reversi_verify,
|
||||
],
|
||||
exports: [
|
||||
$admin_meta,
|
||||
|
|
@ -1525,6 +1528,7 @@ const $reversi_surrender: Provider = { provide: 'ep:reversi/surrender', useClass
|
|||
$reversi_invitations,
|
||||
$reversi_showGame,
|
||||
$reversi_surrender,
|
||||
$reversi_verify,
|
||||
],
|
||||
})
|
||||
export class EndpointsModule {}
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ import * as ep___reversi_match from './endpoints/reversi/match.js';
|
|||
import * as ep___reversi_invitations from './endpoints/reversi/invitations.js';
|
||||
import * as ep___reversi_showGame from './endpoints/reversi/show-game.js';
|
||||
import * as ep___reversi_surrender from './endpoints/reversi/surrender.js';
|
||||
import * as ep___reversi_verify from './endpoints/reversi/verify.js';
|
||||
|
||||
const eps = [
|
||||
['admin/meta', ep___admin_meta],
|
||||
|
|
@ -762,6 +763,7 @@ const eps = [
|
|||
['reversi/invitations', ep___reversi_invitations],
|
||||
['reversi/show-game', ep___reversi_showGame],
|
||||
['reversi/surrender', ep___reversi_surrender],
|
||||
['reversi/verify', ep___reversi_verify],
|
||||
];
|
||||
|
||||
interface IEndpointMetaBase {
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const query = this.queryService.makePaginationQuery(this.reversiGamesRepository.createQueryBuilder('game'), ps.sinceId, ps.untilId)
|
||||
.andWhere('game.isStarted = TRUE');
|
||||
.andWhere('game.isStarted = TRUE')
|
||||
.innerJoinAndSelect('game.user1', 'user1')
|
||||
.innerJoinAndSelect('game.user2', 'user2');
|
||||
|
||||
if (ps.my && me) {
|
||||
query.andWhere(new Brackets(qb => {
|
||||
|
|
@ -55,7 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
const games = await query.take(ps.limit).getMany();
|
||||
|
||||
return await this.reversiGameEntityService.packLiteMany(games, me);
|
||||
return await this.reversiGameEntityService.packLiteMany(games);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
if (game == null) return;
|
||||
|
||||
return await this.reversiGameEntityService.packDetail(game, me);
|
||||
return await this.reversiGameEntityService.packDetail(game);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
throw new ApiError(meta.errors.noSuchGame);
|
||||
}
|
||||
|
||||
return await this.reversiGameEntityService.packDetail(game, me);
|
||||
return await this.reversiGameEntityService.packDetail(game);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
64
packages/backend/src/server/api/endpoints/reversi/verify.ts
Normal file
64
packages/backend/src/server/api/endpoints/reversi/verify.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { ReversiService } from '@/core/ReversiService.js';
|
||||
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
errors: {
|
||||
noSuchGame: {
|
||||
message: 'No such game.',
|
||||
code: 'NO_SUCH_GAME',
|
||||
id: '8fb05624-b525-43dd-90f7-511852bdfeee',
|
||||
},
|
||||
},
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
desynced: { type: 'boolean' },
|
||||
game: {
|
||||
type: 'object',
|
||||
optional: true, nullable: true,
|
||||
ref: 'ReversiGameDetailed',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
gameId: { type: 'string', format: 'misskey:id' },
|
||||
crc32: { type: 'string' },
|
||||
},
|
||||
required: ['gameId', 'crc32'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private reversiService: ReversiService,
|
||||
private reversiGameEntityService: ReversiGameEntityService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const game = await this.reversiService.checkCrc(ps.gameId, ps.crc32);
|
||||
if (game) {
|
||||
return {
|
||||
desynced: true,
|
||||
game: await this.reversiGameEntityService.packDetail(game),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
desynced: false,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { MiReversiGame, ReversiGamesRepository } from '@/models/_.js';
|
||||
import type { MiReversiGame } from '@/models/_.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { ReversiService } from '@/core/ReversiService.js';
|
||||
|
|
@ -19,7 +19,6 @@ class ReversiGameChannel extends Channel {
|
|||
|
||||
constructor(
|
||||
private reversiService: ReversiService,
|
||||
private reversiGamesRepository: ReversiGamesRepository,
|
||||
private reversiGameEntityService: ReversiGameEntityService,
|
||||
|
||||
id: string,
|
||||
|
|
@ -42,7 +41,6 @@ class ReversiGameChannel extends Channel {
|
|||
case 'updateSettings': this.updateSettings(body.key, body.value); break;
|
||||
case 'cancel': this.cancelGame(); break;
|
||||
case 'putStone': this.putStone(body.pos, body.id); break;
|
||||
case 'checkState': this.checkState(body.crc32); break;
|
||||
case 'claimTimeIsUp': this.claimTimeIsUp(); break;
|
||||
}
|
||||
}
|
||||
|
|
@ -75,16 +73,6 @@ class ReversiGameChannel extends Channel {
|
|||
this.reversiService.putStoneToGame(this.gameId!, this.user, pos, id);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async checkState(crc32: string | number) {
|
||||
if (crc32 != null) return;
|
||||
|
||||
const game = await this.reversiService.checkCrc(this.gameId!, crc32);
|
||||
if (game) {
|
||||
this.send('rescue', game);
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async claimTimeIsUp() {
|
||||
if (this.user == null) return;
|
||||
|
|
@ -106,9 +94,6 @@ export class ReversiGameChannelService implements MiChannelService<false> {
|
|||
public readonly kind = ReversiGameChannel.kind;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.reversiGamesRepository)
|
||||
private reversiGamesRepository: ReversiGamesRepository,
|
||||
|
||||
private reversiService: ReversiService,
|
||||
private reversiGameEntityService: ReversiGameEntityService,
|
||||
) {
|
||||
|
|
@ -118,7 +103,6 @@ export class ReversiGameChannelService implements MiChannelService<false> {
|
|||
public create(id: string, connection: Channel['connection']): ReversiGameChannel {
|
||||
return new ReversiGameChannel(
|
||||
this.reversiService,
|
||||
this.reversiGamesRepository,
|
||||
this.reversiGameEntityService,
|
||||
id,
|
||||
connection,
|
||||
|
|
|
|||
|
|
@ -40,12 +40,13 @@ import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
|||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||
import type Logger from '@/logger.js';
|
||||
import { deepClone } from '@/misc/clone.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
|
||||
import { FeedService } from './FeedService.js';
|
||||
import { UrlPreviewService } from './UrlPreviewService.js';
|
||||
import { ClientLoggerService } from './ClientLoggerService.js';
|
||||
|
|
@ -92,6 +93,9 @@ export class ClientServerService {
|
|||
@Inject(DI.flashsRepository)
|
||||
private flashsRepository: FlashsRepository,
|
||||
|
||||
@Inject(DI.reversiGamesRepository)
|
||||
private reversiGamesRepository: ReversiGamesRepository,
|
||||
|
||||
private flashEntityService: FlashEntityService,
|
||||
private userEntityService: UserEntityService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
|
|
@ -99,6 +103,7 @@ export class ClientServerService {
|
|||
private galleryPostEntityService: GalleryPostEntityService,
|
||||
private clipEntityService: ClipEntityService,
|
||||
private channelEntityService: ChannelEntityService,
|
||||
private reversiGameEntityService: ReversiGameEntityService,
|
||||
private metaService: MetaService,
|
||||
private urlPreviewService: UrlPreviewService,
|
||||
private feedService: FeedService,
|
||||
|
|
@ -487,6 +492,8 @@ export class ClientServerService {
|
|||
isSuspended: false,
|
||||
});
|
||||
|
||||
vary(reply.raw, 'Accept');
|
||||
|
||||
if (user != null) {
|
||||
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
|
||||
const meta = await this.metaService.fetch();
|
||||
|
|
@ -526,6 +533,8 @@ export class ClientServerService {
|
|||
return;
|
||||
}
|
||||
|
||||
vary(reply.raw, 'Accept');
|
||||
|
||||
reply.redirect(`/@${user.username}${ user.host == null ? '' : '@' + user.host}`);
|
||||
});
|
||||
|
||||
|
|
@ -693,6 +702,25 @@ export class ClientServerService {
|
|||
return await renderBase(reply);
|
||||
}
|
||||
});
|
||||
|
||||
// Reversi game
|
||||
fastify.get<{ Params: { game: string; } }>('/reversi/g/:game', async (request, reply) => {
|
||||
const game = await this.reversiGamesRepository.findOneBy({
|
||||
id: request.params.game,
|
||||
});
|
||||
|
||||
if (game) {
|
||||
const _game = await this.reversiGameEntityService.packDetail(game);
|
||||
const meta = await this.metaService.fetch();
|
||||
reply.header('Cache-Control', 'public, max-age=3600');
|
||||
return await reply.view('reversi-game', {
|
||||
game: _game,
|
||||
...this.generateCommonPugData(meta),
|
||||
});
|
||||
} else {
|
||||
return await renderBase(reply);
|
||||
}
|
||||
});
|
||||
//#endregion
|
||||
|
||||
fastify.get('/_info_card_', async (request, reply) => {
|
||||
|
|
|
|||
20
packages/backend/src/server/web/views/reversi-game.pug
Normal file
20
packages/backend/src/server/web/views/reversi-game.pug
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
extends ./base
|
||||
|
||||
block vars
|
||||
- const user1 = game.user1;
|
||||
- const user2 = game.user2;
|
||||
- const title = `${user1.username} vs ${user2.username}`;
|
||||
- const url = `${config.url}/reversi/g/${game.id}`;
|
||||
|
||||
block title
|
||||
= `${title} | ${instanceName}`
|
||||
|
||||
block desc
|
||||
meta(name='description' content='⚫⚪Misskey Reversi⚪⚫')
|
||||
|
||||
block og
|
||||
meta(property='og:type' content='article')
|
||||
meta(property='og:title' content= title)
|
||||
meta(property='og:description' content='⚫⚪Misskey Reversi⚪⚫')
|
||||
meta(property='og:url' content= url)
|
||||
meta(property='twitter:card' content='summary')
|
||||
Loading…
Add table
Add a link
Reference in a new issue