Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 連合系エラーの解消とactionsの一部修正 #73

Merged
merged 12 commits into from
Jul 31, 2024
13 changes: 8 additions & 5 deletions .github/workflows/dockle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ on:
- develop
pull_request:

env:
DOCKER_IMAGE_TAG: 'misskeydream-web'

jobs:
dockle:
runs-on: ubuntu-latest
Expand All @@ -23,8 +26,8 @@ jobs:
cp ./docker-compose_example.yml ./docker-compose.yml
- run: |
docker compose up -d web
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest
- run: |
cmd="dockle --exit-code 1 misskey-web:latest ${image_name}"
echo "> ${cmd}"
eval "${cmd}"
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" ${{ env.DOCKER_IMAGE_TAG }}:latest
- uses: erzz/dockle-action@v1
with:
image: ${{ env.DOCKER_IMAGE_TAG }}
exit-code: 1
25 changes: 25 additions & 0 deletions packages/backend/migration/1721666053703-fixDriveUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export class FixDriveUrl1721666053703 {
name = 'FixDriveUrl1721666053703'

async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "url" TYPE character varying(1024), ALTER COLUMN "url" SET NOT NULL`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
await queryRunner.query(`DROP INDEX "public"."IDX_e5848eac4940934e23dbc17581"`);
await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "uri" TYPE character varying(1024)`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "src" TYPE character varying(1024)`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "preservedUsernames" SET DEFAULT '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }'`);
await queryRunner.query(`CREATE INDEX "IDX_e5848eac4940934e23dbc17581" ON "drive_file" ("uri") `);
}

async down(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_e5848eac4940934e23dbc17581"`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "preservedUsernames" SET DEFAULT '{admin,administrator,root,system,maintainer,host,mod,moderator,owner,superuser,staff,auth,i,me,everyone,all,mention,mentions,example,user,users,account,accounts,official,help,helps,support,supports,info,information,informations,announce,announces,announcement,announcements,notice,notification,notifications,dev,developer,developers,tech,misskey}'`);
await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "src" TYPE character varying(512)`);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "uri" TYPE character varying(512)`);
await queryRunner.query(`CREATE INDEX "IDX_e5848eac4940934e23dbc17581" ON "drive_file" ("uri") `);
await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "url" TYPE character varying(512), ALTER COLUMN "url" SET NOT NULL`);
}
}
6 changes: 4 additions & 2 deletions packages/backend/src/core/CustomEmojiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,9 @@ export class CustomEmojiService implements OnApplicationShutdown {

await this.emojisRepository.delete(emoji.id);

if (userId)
if (userId) {
await this.usersRepository.decrement({ id: userId }, 'emojiCount', 1);
}

this.localEmojisCache.refresh();

Expand All @@ -306,8 +307,9 @@ export class CustomEmojiService implements OnApplicationShutdown {
for (const emoji of emojis) {
await this.emojisRepository.delete(emoji.id);

if (emoji.userId)
if (emoji.userId) {
await this.usersRepository.decrement({ id: emoji.userId }, 'emojiCount', 1);
}
if (moderator) {
this.moderationLogService.log(moderator, 'deleteCustomEmoji', {
emojiId: emoji.id,
Expand Down
6 changes: 3 additions & 3 deletions packages/backend/src/core/activitypub/ApInboxService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { bindThis } from '@/decorators.js';
import type { MiRemoteUser } from '@/models/User.js';
import { isNotNull } from '@/misc/is-not-null.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, isValidActor, isValidPost } from './type.js';
import { ApNoteService } from './models/ApNoteService.js';
import { ApLoggerService } from './ApLoggerService.js';
import { ApDbResolverService } from './ApDbResolverService.js';
Expand Down Expand Up @@ -471,9 +471,9 @@ export class ApInboxService {
formerType = 'Note';
}

if (validPost.includes(formerType)) {
if (isValidPost(formerType)) {
return await this.deleteNote(actor, uri);
} else if (validActor.includes(formerType)) {
} else if (isValidActor(formerType)) {
return await this.deleteActor(actor, uri);
} else {
return `Unknown type ${formerType}`;
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/core/activitypub/models/ApNoteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { bindThis } from '@/decorators.js';
import { checkHttps } from '@/misc/check-https.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { isNotNull } from '@/misc/is-not-null.js';
import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js';
import { getOneApId, getApId, getOneApHrefNullable, isEmoji, getApType, isPost } from '../type.js';
import { ApLoggerService } from '../ApLoggerService.js';
import { ApMfmService } from '../ApMfmService.js';
import { ApDbResolverService } from '../ApDbResolverService.js';
Expand Down Expand Up @@ -80,7 +80,7 @@ export class ApNoteService {
public validateNote(object: IObject, uri: string): Error | null {
const expectHost = this.utilityService.extractDbHost(uri);

if (!validPost.includes(getApType(object))) {
if (!isPost(object)) {
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: invalid object type ${getApType(object)}`);
}

Expand Down
34 changes: 22 additions & 12 deletions packages/backend/src/core/activitypub/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ export function getApId(value: string | IObject): string {
/**
* Get ActivityStreams Object type
*/
export function getApType(value: IObject): string {
export function getApType(value: IObject): string | null {
if (typeof value.type === 'string') return value.type;
if (Array.isArray(value.type) && typeof value.type[0] === 'string') return value.type[0];
throw new Error('cannot detect type');
return null;
}

export function getOneApHrefNullable(value: ApObject | undefined): string | undefined {
Expand Down Expand Up @@ -106,13 +106,17 @@ export interface IOrderedCollection extends IObject {
orderedItems: ApObject;
}

export const validPost = ['Note', 'Question', 'Article', 'Audio', 'Document', 'Image', 'Page', 'Video', 'Event'];
// つまるところこれをしないとnull許容でincludesできないので必須
type ValidArrayIncludesNullable = readonly (string | null)[];
const validPost = ['Note', 'Question', 'Article', 'Audio', 'Document', 'Image', 'Page', 'Video', 'Event'] as const;
export const isValidPost = (type: string | null): boolean =>
(validPost as ValidArrayIncludesNullable).includes(type);

export const isPost = (object: IObject): object is IPost =>
validPost.includes(getApType(object));
isValidPost(getApType(object));

export interface IPost extends IObject {
type: 'Note' | 'Question' | 'Article' | 'Audio' | 'Document' | 'Image' | 'Page' | 'Video' | 'Event';
type: (typeof validPost)[number];
source?: {
content: string;
mediaType: string;
Expand Down Expand Up @@ -154,13 +158,15 @@ export interface ITombstone extends IObject {
export const isTombstone = (object: IObject): object is ITombstone =>
getApType(object) === 'Tombstone';

export const validActor = ['Person', 'Service', 'Group', 'Organization', 'Application'];
const validActor = ['Person', 'Service', 'Group', 'Organization', 'Application'] as const;
export const isValidActor = (type: string | null): boolean =>
(validActor as ValidArrayIncludesNullable).includes(type);

export const isActor = (object: IObject): object is IActor =>
validActor.includes(getApType(object));
isValidActor(getApType(object));

export interface IActor extends IObject {
type: 'Person' | 'Service' | 'Organization' | 'Group' | 'Application';
type: (typeof validActor)[number];
name?: string;
preferredUsername?: string;
manuallyApprovesFollowers?: boolean;
Expand Down Expand Up @@ -240,12 +246,16 @@ export interface IKey extends IObject {
publicKeyPem: string | Buffer;
}

export interface IApDocument extends IObject {
type: 'Audio' | 'Document' | 'Image' | 'Page' | 'Video';
}
const validDocument = ['Audio', 'Document', 'Image', 'Page', 'Video'] as const;
export const isValidDocument = (type: string | null): boolean =>
(validDocument as ValidArrayIncludesNullable).includes(type);

export const isDocument = (object: IObject): object is IApDocument =>
['Audio', 'Document', 'Image', 'Page', 'Video'].includes(getApType(object));
isValidDocument(getApType(object));

export interface IApDocument extends IObject {
type: (typeof validDocument)[number];
}

export interface IApImage extends IApDocument {
type: 'Image';
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/misc/json-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,11 @@ type ObjectSchemaTypeDef<p extends Schema> = p['ref'] extends keyof typeof refs
? p['anyOf'] extends ReadonlyArray<Schema>
? p['anyOf'][number]['required'] extends ReadonlyArray<
keyof p['properties']
>
>
? UnionObjType<
p['properties'],
NonNullable<p['anyOf'][number]['required']>
> &
> &
ObjType<p['properties'], NonNullable<p['required']>>
: never
: ObjType<p['properties'], NonNullable<p['required']>>
Expand Down
6 changes: 3 additions & 3 deletions packages/backend/src/models/DriveFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class MiDriveFile {
public storedInternal: boolean;

@Column('varchar', {
length: 512,
length: 1024,
comment: 'The URL of the DriveFile.',
})
public url: string;
Expand Down Expand Up @@ -124,13 +124,13 @@ export class MiDriveFile {

@Index()
@Column('varchar', {
length: 512, nullable: true,
length: 1024, nullable: true,
comment: 'The URI of the DriveFile. it will be null when the DriveFile is local.',
})
public uri: string | null;

@Column('varchar', {
length: 512, nullable: true,
length: 1024, nullable: true,
})
public src: string | null;

Expand Down
23 changes: 21 additions & 2 deletions packages/backend/src/models/json-schema/emoji-log.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
const emojiChangeInfoData = [
{
type: 'array',
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,
},
},
{
type: 'string',
optional: false, nullable: false,
},
{
type: 'boolean',
optional: false, nullable: false,
},
] as const;

export const packedEmojiChangeInfoSchema = {
type: 'object',
properties: {
before: {
type: 'any',
oneOf: emojiChangeInfoData,
optional: false, nullable: false,
},
after: {
type: 'any',
oneOf: emojiChangeInfoData,
optional: false, nullable: false,
},
},
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/models/json-schema/role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ export const packedRolePoliciesSchema = {
type: 'boolean',
optional: false, nullable: false,
},
canEditNote: {
type: 'boolean',
optional: false, nullable: false,
},
mentionLimit: {
type: 'integer',
optional: false, nullable: false,
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/queue/QueueProcessorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,4 +363,4 @@ export class QueueProcessorService implements OnApplicationShutdown {
public async onApplicationShutdown(signal?: string | undefined): Promise<void> {
await this.stop();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ export class DeleteAccountProcessorService {
},
});

if (emojis.length !== 0)
if (emojis.length !== 0) {
await this.customEmojiService.deleteBulk(emojis.map(v => v.id));
}
}

{ // Delete files
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
let emojiLicense = '';
if (emoji.license != null && emoji.license.trim().length !== 0) {
emojiLicense = emoji.license;
}
else {
} else {
emojiLicense = `Import by ${emoji.host}`;
}

Expand Down
6 changes: 2 additions & 4 deletions packages/backend/src/server/api/endpoints/admin/emoji/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
emojis = emojis.filter(emoji =>
queryarry.includes(`:${emoji.name}:`),
);
}
else if (queryuser) {
} else if (queryuser) {
emojis = await q.innerJoinAndSelect('emoji.user', 'user').getMany();
const users = queryuser.map(v => v.replace('@', '').toLowerCase());
emojis = emojis.filter((emoji) =>
users.includes(emoji.user?.username.toLowerCase() ?? '')
);
}
else {
} else {
emojis = await q.getMany();
emojis = emojis.filter(emoji =>
emoji.name.includes(ps.query!) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const isEmojiModerator = await this.roleService.isEmojiModerator(me);

if (ps.userId && oldEmoji.userId !== ps.userId) {
if (!isEmojiModerator)
if (!isEmojiModerator) {
throw new ApiError(meta.errors.rolePermissionDenied);
}

if (await this.usersRepository.countBy({ id: ps.userId }) === 0)
if (await this.usersRepository.countBy({ id: ps.userId }) === 0) {
throw new ApiError(meta.errors.noSuchUser);
}
}

if (oldEmoji.license !== ps.license && (ps.license == null || ps.license.trim().length === 0)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
for (const folder of innerFolders) {
this.globalEventService.publishDriveStream(me.id, 'folderDeleted', folder.id);
}
}
else {
} else {
await this.driveFoldersRepository.delete(folder.id);

// Publish folderCreated event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
throw new ApiError(meta.errors.rtlDisabled);
}


//#region Construct query
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'),
ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
Expand Down
16 changes: 8 additions & 8 deletions packages/backend/src/server/api/endpoints/roles/unassign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,21 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
}

const assignedCount = await this.roleAssignmentsRepository.createQueryBuilder('assign')
.where('assign.roleId = :roleId', { roleId: role.id })
.andWhere(new Brackets(qb => { qb
.where('assign.expiresAt IS NULL')
.orWhere('assign.expiresAt > :now', { now: new Date() });
}))
.getCount();
.where('assign.roleId = :roleId', { roleId: role.id })
.andWhere(new Brackets(qb => {
qb
.where('assign.expiresAt IS NULL')
.orWhere('assign.expiresAt > :now', { now: new Date() });
}))
.getCount();

if (assignedCount === 1) {
// 自動削除
await this.rolesRepository.delete({
id: ps.roleId,
});
this.globalEventService.publishInternalEvent('roleDeleted', role);
}
else {
} else {
await this.roleService.unassign(me.id, role.id);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
bg: v.bg,
frame: v.frame,
title: v.title,
description: me.id === ps.userId ? v.description : '???',
flavor: me.id === ps.userId ? v.flavor : ''
description: me?.id === ps.userId ? v.description : '???',
flavor: me?.id === ps.userId ? v.flavor : '',
}));
}
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
Expand Down
Loading
Loading