Merge branch 'develop' into reimplement-rate-limit

This commit is contained in:
anatawa12 2024-06-15 11:08:06 +09:00 committed by GitHub
commit fce656b5e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 107 additions and 28 deletions

View file

@ -2,3 +2,7 @@ contact_links:
- name: 💬 Misskey official Discord - name: 💬 Misskey official Discord
url: https://discord.gg/Wp8gVStHW3 url: https://discord.gg/Wp8gVStHW3
about: Chat freely about Misskey about: Chat freely about Misskey
# 仮
- name: 💬 Start discussion
url: https://github.com/misskey-dev/misskey/discussions
about: The official forum to join conversation and ask question

View file

@ -5,6 +5,7 @@
- Fix: 配信停止したインスタンス一覧が見れなくなる問題を修正 - Fix: 配信停止したインスタンス一覧が見れなくなる問題を修正
### Client ### Client
- `/about#federation` ページなどで各インスタンスのチャートが表示されなくなっていた問題を修正
- Fix: ユーザーページの追加情報のラベルを投稿者のサーバーの絵文字で表示する (#13968) - Fix: ユーザーページの追加情報のラベルを投稿者のサーバーの絵文字で表示する (#13968)
### Server ### Server

View file

@ -82,34 +82,14 @@ import { MiReversiGame } from '@/models/ReversiGame.js';
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js'; import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
export interface MiRepository<T extends ObjectLiteral> { export interface MiRepository<T extends ObjectLiteral> {
createTableColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[]; createTableColumnNames(this: Repository<T> & MiRepository<T>): string[];
createTableColumnNamesWithPrimaryKey(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>): string[];
insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>; insertOne(this: Repository<T> & MiRepository<T>, entity: QueryDeepPartialEntity<T>, findOptions?: Pick<FindOneOptions<T>, 'relations'>): Promise<T>;
selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void; selectAliasColumnNames(this: Repository<T> & MiRepository<T>, queryBuilder: InsertQueryBuilder<T>, builder: SelectQueryBuilder<T>): void;
} }
export const miRepository = { export const miRepository = {
createTableColumnNames(queryBuilder) { createTableColumnNames() {
// @ts-expect-error -- protected return this.metadata.columns.filter(column => column.isSelect && !column.isVirtual).map(column => column.databaseName);
const insertedColumns = queryBuilder.getInsertedColumns();
if (insertedColumns.length) {
return insertedColumns.map(column => column.databaseName);
}
if (!queryBuilder.expressionMap.mainAlias?.hasMetadata && !queryBuilder.expressionMap.insertColumns.length) {
// @ts-expect-error -- protected
const valueSets = queryBuilder.getValueSets();
if (valueSets.length === 1) {
return Object.keys(valueSets[0]);
}
}
return queryBuilder.expressionMap.insertColumns;
},
createTableColumnNamesWithPrimaryKey(queryBuilder) {
const columnNames = this.createTableColumnNames(queryBuilder);
if (!columnNames.includes('id')) {
columnNames.unshift('id');
}
return columnNames;
}, },
async insertOne(entity, findOptions?) { async insertOne(entity, findOptions?) {
const queryBuilder = this.createQueryBuilder().insert().values(entity); const queryBuilder = this.createQueryBuilder().insert().values(entity);
@ -117,7 +97,7 @@ export const miRepository = {
const mainAlias = queryBuilder.expressionMap.mainAlias!; const mainAlias = queryBuilder.expressionMap.mainAlias!;
const name = mainAlias.name; const name = mainAlias.name;
mainAlias.name = 't'; mainAlias.name = 't';
const columnNames = this.createTableColumnNamesWithPrimaryKey(queryBuilder); const columnNames = this.createTableColumnNames();
queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2)); queryBuilder.returning(columnNames.reduce((a, c) => `${a}, ${queryBuilder.escape(c)}`, '').slice(2));
const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames }); const builder = this.createQueryBuilder().addCommonTableExpression(queryBuilder, 'cte', { columnNames });
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@ -138,7 +118,7 @@ export const miRepository = {
selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName); selectOrAddSelect = (selection, selectionAliasName) => builder.addSelect(selection, selectionAliasName);
return builder.select(selection, selectionAliasName); return builder.select(selection, selectionAliasName);
}; };
for (const columnName of this.createTableColumnNamesWithPrimaryKey(queryBuilder)) { for (const columnName of this.createTableColumnNames()) {
selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`); selectOrAddSelect(`${builder.alias}.${columnName}`, `${builder.alias}_${columnName}`);
} }
}, },

View file

@ -125,6 +125,35 @@ export function file(isSensitive = false) {
}; };
} }
export function federationInstance(): entities.FederationInstance {
return {
id: 'someinstanceid',
firstRetrievedAt: '2021-01-01T00:00:00.000Z',
host: 'misskey-hub.net',
usersCount: 10,
notesCount: 20,
followingCount: 5,
followersCount: 15,
isNotResponding: false,
isSuspended: false,
suspensionState: 'none',
isBlocked: false,
softwareName: 'misskey',
softwareVersion: '2024.5.0',
openRegistrations: false,
name: 'Misskey Hub',
description: '',
maintainerName: '',
maintainerEmail: '',
isSilenced: false,
iconUrl: 'https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true',
faviconUrl: '',
themeColor: '',
infoUpdatedAt: '',
latestRequestReceivedAt: '',
};
}
export function userDetailed(id = 'someuserid', username = 'miskist', host = 'misskey-hub.net', name = 'Misskey User'): entities.UserDetailed { export function userDetailed(id = 'someuserid', username = 'miskist', host = 'misskey-hub.net', name = 'Misskey User'): entities.UserDetailed {
return { return {
id, id,

View file

@ -403,6 +403,7 @@ function toStories(component: string): Promise<string> {
glob('src/components/MkSignupServerRules.vue'), glob('src/components/MkSignupServerRules.vue'),
glob('src/components/MkUserSetupDialog.vue'), glob('src/components/MkUserSetupDialog.vue'),
glob('src/components/MkUserSetupDialog.*.vue'), glob('src/components/MkUserSetupDialog.*.vue'),
glob('src/components/MkInstanceCardMini.vue'),
glob('src/components/MkInviteCode.vue'), glob('src/components/MkInviteCode.vue'),
glob('src/pages/user/home.vue'), glob('src/pages/user/home.vue'),
]); ]);

View file

@ -29,7 +29,7 @@ function getChartArray(seed: string, limit: number, option?: { accumulate?: bool
return array; return array;
} }
function getChartResolver(fields: string[], option?: { accumulate?: boolean, mulMap?: Record<string, number> }): HttpResponseResolver<PathParams, DefaultBodyType, JsonBodyType> { export function getChartResolver(fields: string[], option?: { accumulate?: boolean, mulMap?: Record<string, number> }): HttpResponseResolver<PathParams, DefaultBodyType, JsonBodyType> {
return ({ request }) => { return ({ request }) => {
action(`GET ${request.url}`)(); action(`GET ${request.url}`)();
const limitParam = new URL(request.url).searchParams.get('limit'); const limitParam = new URL(request.url).searchParams.get('limit');

View file

@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { federationInstance } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js';
import MkInstanceCardMini from './MkInstanceCardMini.vue';
import { getChartResolver } from './MkChart.stories.impl.js';
export const Default = {
render(args) {
return {
components: {
MkInstanceCardMini,
},
setup() {
return {
args,
};
},
computed: {
props() {
return {
...this.args,
};
},
},
template: '<MkInstanceCardMini v-bind="props" />',
};
},
args: {
instance: federationInstance(),
},
parameters: {
layout: 'centered',
msw: {
handlers: [
...commonHandlers,
http.get('/undefined/preview.webp', async ({ request }) => {
const urlStr = new URL(request.url).searchParams.get('url');
if (urlStr == null) {
return new HttpResponse(null, { status: 404 });
}
const url = new URL(urlStr);
if (url.href.startsWith('https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/')) {
const image = await (await fetch(`client-assets/${url.pathname.split('/').pop()}`)).blob();
return new HttpResponse(image, {
headers: {
'Content-Type': 'image/jpeg',
},
});
} else {
return new HttpResponse(null, { status: 404 });
}
}),
http.get('/api/charts/instance', getChartResolver(['requests.received'])),
],
},
},
} satisfies StoryObj<typeof MkInstanceCardMini>;

View file

@ -29,8 +29,8 @@ const chartValues = ref<number[] | null>(null);
misskeyApiGet('charts/instance', { host: props.instance.host, limit: 16 + 1, span: 'day' }).then(res => { misskeyApiGet('charts/instance', { host: props.instance.host, limit: 16 + 1, span: 'day' }).then(res => {
// //
res['requests.received'].splice(0, 1); res.requests.received.splice(0, 1);
chartValues.value = res['requests.received']; chartValues.value = res.requests.received;
}); });
function getInstanceIcon(instance): string { function getInstanceIcon(instance): string {