1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-17 14:55:34 +02:00

Merge branch 'develop' into renovate/major-backend-update-dependencies

This commit is contained in:
kakkokari-gtyih
2025-11-01 12:30:36 +09:00
162 changed files with 5313 additions and 4464 deletions

View File

@@ -517,40 +517,43 @@ export class DriveService {
this.registerLogger.debug(`ADD DRIVE FILE: user ${user?.id ?? 'not set'}, name ${detectedName}, tmp ${path}`);
//#region Check drive usage and mime type
if (user && !isLink) {
if (user != null && !isLink) {
const isLocalUser = this.userEntityService.isLocalUser(user);
const policies = await this.roleService.getUserPolicies(user.id);
const isModerator = isLocalUser ? await this.roleService.isModerator(user) : false;
if (!isModerator) {
const policies = await this.roleService.getUserPolicies(user.id);
const allowedMimeTypes = policies.uploadableFileTypes;
const isAllowed = allowedMimeTypes.some((mimeType) => {
if (mimeType === '*' || mimeType === '*/*') return true;
if (mimeType.endsWith('/*')) return info.type.mime.startsWith(mimeType.slice(0, -1));
return info.type.mime === mimeType;
});
if (!isAllowed) {
throw new IdentifiableError('bd71c601-f9b0-4808-9137-a330647ced9b', `Unallowed file type: ${info.type.mime}`);
}
const driveCapacity = 1024 * 1024 * policies.driveCapacityMb;
const maxFileSize = 1024 * 1024 * policies.maxFileSizeMb;
if (maxFileSize < info.size) {
if (isLocalUser) {
throw new IdentifiableError('f9e4e5f3-4df4-40b5-b400-f236945f7073', 'Max file size exceeded.');
const allowedMimeTypes = policies.uploadableFileTypes;
const isAllowed = allowedMimeTypes.some((mimeType) => {
if (mimeType === '*' || mimeType === '*/*') return true;
if (mimeType.endsWith('/*')) return info.type.mime.startsWith(mimeType.slice(0, -1));
return info.type.mime === mimeType;
});
if (!isAllowed) {
throw new IdentifiableError('bd71c601-f9b0-4808-9137-a330647ced9b', `Unallowed file type: ${info.type.mime}`);
}
}
const usage = await this.driveFileEntityService.calcDriveUsageOf(user);
const driveCapacity = 1024 * 1024 * policies.driveCapacityMb;
const maxFileSize = 1024 * 1024 * policies.maxFileSizeMb;
this.registerLogger.debug('drive capacity override applied');
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
// If usage limit exceeded
if (driveCapacity < usage + info.size) {
if (isLocalUser) {
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.');
if (maxFileSize < info.size) {
if (isLocalUser) {
throw new IdentifiableError('f9e4e5f3-4df4-40b5-b400-f236945f7073', 'Max file size exceeded.');
}
}
const usage = await this.driveFileEntityService.calcDriveUsageOf(user);
this.registerLogger.debug('drive capacity override applied');
this.registerLogger.debug(`overrideCap: ${driveCapacity}bytes, usage: ${usage}bytes, u+s: ${usage + info.size}bytes`);
// If usage limit exceeded
if (driveCapacity < usage + info.size) {
if (isLocalUser) {
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.');
}
await this.expireOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as MiRemoteUser, driveCapacity - info.size);
}
await this.expireOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as MiRemoteUser, driveCapacity - info.size);
}
}
//#endregion

View File

@@ -20,8 +20,8 @@ import { AiService } from '@/core/AiService.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import type { PredictionType } from 'nsfwjs';
import { isMimeImage } from '@/misc/is-mime-image.js';
import type { PredictionType } from 'nsfwjs';
export type FileInfo = {
size: number;

View File

@@ -172,6 +172,14 @@ export class NoteDraftService {
me: MiLocalUser,
data: Partial<NoteDraftOptions>,
): Promise<void> {
if (data.isActuallyScheduled) {
if (data.scheduledAt == null) {
throw new IdentifiableError('94a89a43-3591-400a-9c17-dd166e71fdfa', 'scheduledAt is required when isActuallyScheduled is true');
} else if (data.scheduledAt.getTime() < Date.now()) {
throw new IdentifiableError('b34d0c1b-996f-4e34-a428-c636d98df457', 'scheduledAt must be in the future');
}
}
if (data.pollExpiresAt != null) {
if (data.pollExpiresAt.getTime() < Date.now()) {
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
@@ -320,6 +328,7 @@ export class NoteDraftService {
@bindThis
public async clearSchedule(draftId: MiNoteDraft['id']): Promise<void> {
// TODO: 線形探索なのをどうにかする
const jobs = await this.queueService.postScheduledNoteQueue.getJobs(['delayed', 'waiting', 'active']);
for (const job of jobs) {
if (job.data.noteDraftId === draftId) {

View File

@@ -109,8 +109,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
canImportUserLists: false,
chatAvailability: 'available',
uploadableFileTypes: [
'text/plain',
'text/csv',
'text/*',
'application/json',
'image/*',
'video/*',

View File

@@ -512,8 +512,8 @@ export class UserEntityService implements OnModuleInit {
} : undefined) : undefined,
emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
onlineStatus: this.getOnlineStatus(user),
// パフォーマンス上の理由でローカルユーザーのみ
badgeRoles: user.host == null ? this.roleService.getUserBadgeRoles(user.id).then((rs) => rs
// パフォーマンス上の理由で、明示的に設定しない場合はローカルユーザーのみ取得
badgeRoles: (this.meta.showRoleBadgesOfRemoteUsers || user.host == null) ? this.roleService.getUserBadgeRoles(user.id).then((rs) => rs
.filter((r) => r.isPublic || iAmModerator)
.sort((a, b) => b.displayOrder - a.displayOrder)
.map((r) => ({

View File

@@ -717,6 +717,11 @@ export class MiMeta {
})
public remoteNotesCleaningExpiryDaysForEachNotes: number;
@Column('boolean', {
default: false,
})
public showRoleBadgesOfRemoteUsers: boolean;
@Column('jsonb', {
default: { },
})

View File

@@ -153,11 +153,14 @@ export class MiNoteDraft {
//#endregion
// 予約日時
// これがあるだけでは実際に予約されているかどうかはわからない
@Column('timestamp with time zone', {
nullable: true,
})
public scheduledAt: Date | null;
// scheduledAtに基づいて実際にスケジュールされているか
@Column('boolean', {
default: false,
})

View File

@@ -593,6 +593,10 @@ export const meta = {
type: 'number',
optional: false, nullable: false,
},
showRoleBadgesOfRemoteUsers: {
type: 'boolean',
optional: false, nullable: false,
},
},
},
} as const;
@@ -748,6 +752,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
enableRemoteNotesCleaning: instance.enableRemoteNotesCleaning,
remoteNotesCleaningExpiryDaysForEachNotes: instance.remoteNotesCleaningExpiryDaysForEachNotes,
remoteNotesCleaningMaxProcessingDurationInMinutes: instance.remoteNotesCleaningMaxProcessingDurationInMinutes,
showRoleBadgesOfRemoteUsers: instance.showRoleBadgesOfRemoteUsers,
};
});
}

View File

@@ -209,6 +209,7 @@ export const paramDef = {
enableRemoteNotesCleaning: { type: 'boolean' },
remoteNotesCleaningExpiryDaysForEachNotes: { type: 'number' },
remoteNotesCleaningMaxProcessingDurationInMinutes: { type: 'number' },
showRoleBadgesOfRemoteUsers: { type: 'boolean' },
},
required: [],
} as const;
@@ -743,6 +744,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.remoteNotesCleaningMaxProcessingDurationInMinutes = ps.remoteNotesCleaningMaxProcessingDurationInMinutes;
}
if (ps.showRoleBadgesOfRemoteUsers !== undefined) {
set.showRoleBadgesOfRemoteUsers = ps.showRoleBadgesOfRemoteUsers;
}
const before = await this.metaService.fetch(true);
await this.metaService.update(set);