diff --git a/packages/backend/src/misc/prelude/array.ts b/packages/backend/src/misc/prelude/array.ts index b2f29bcec..8438b6480 100644 --- a/packages/backend/src/misc/prelude/array.ts +++ b/packages/backend/src/misc/prelude/array.ts @@ -142,3 +142,7 @@ export function toArray(x: T | T[] | undefined): T[] { export function toSingle(x: T | T[] | undefined): T | undefined { return Array.isArray(x) ? x[0] : x; } + +export function toSingleLast(x: T | T[] | undefined): T | undefined { + return Array.isArray(x) ? x.at(-1) : x; +} diff --git a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts index efc2302f3..0bfa1a39f 100644 --- a/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts +++ b/packages/backend/src/server/api/mastodon/MastodonApiServerService.ts @@ -3,16 +3,18 @@ import megalodon, { Entity, MegalodonInterface } from 'megalodon'; import querystring from 'querystring'; import { IsNull } from 'typeorm'; import multer from 'fastify-multer'; -import type { NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; +import type { AccessTokensRepository, NoteEditRepository, NotesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; -import { convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; +import { convertAnnouncement, convertFilter, convertAttachment, convertFeaturedTag, convertList, MastoConverters } from './converters.js'; import { getInstance } from './endpoints/meta.js'; import { ApiAuthMastodon, ApiAccountMastodon, ApiFilterMastodon, ApiNotifyMastodon, ApiSearchMastodon, ApiTimelineMastodon, ApiStatusMastodon } from './endpoints.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { DriveService } from '@/core/DriveService.js'; +import { toSingleLast } from '@/misc/prelude/array.js'; export function getClient(BASE_URL: string, authorization: string | undefined): MegalodonInterface { const accessTokenArr = authorization?.split(' ') ?? [null]; @@ -33,10 +35,13 @@ export class MastodonApiServerService { private userProfilesRepository: UserProfilesRepository, @Inject(DI.noteEditRepository) private noteEditRepository: NoteEditRepository, + @Inject(DI.accessTokensRepository) + private accessTokensRepository: AccessTokensRepository, @Inject(DI.config) private config: Config, private metaService: MetaService, private userEntityService: UserEntityService, + private driveService: DriveService, private mastoConverter: MastoConverters, ) { } @@ -245,16 +250,46 @@ export class MastodonApiServerService { } }); - fastify.patch('/v1/accounts/update_credentials', { preHandler: upload.none() }, async (_request, reply) => { + fastify.patch('/v1/accounts/update_credentials', { preHandler: upload.any() }, async (_request, reply) => { const BASE_URL = `${_request.protocol}://${_request.hostname}`; const accessTokens = _request.headers.authorization; const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt // displayed without being logged in try { + if (_request.files.length > 0) { + const tokeninfo = await this.accessTokensRepository.findOneBy({ token: accessTokens }); + console.error(tokeninfo); + if (tokeninfo && (_request.files as any)['avatar']) { + const file = toSingleLast((_request.files as any)['avatar']); + const user = await this.usersRepository.findOneBy({ id: tokeninfo.userId }); + const upload = await this.driveService.addFile({ + user: { id: tokeninfo.userId, host: user ? user.host : null }, + path: file.path, + name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, + sensitive: false, + }); + if (upload.type.startsWith('image/')) { + (_request.body as any).avatar = upload.id; + } + } + if (tokeninfo && (_request.files as any)['header']) { + const file = toSingleLast((_request.files as any)['header']); + const user = await this.usersRepository.findOneBy({ id: tokeninfo.userId }); + const upload = await this.driveService.addFile({ + user: { id: tokeninfo.userId, host: user ? user.host : null }, + path: file.path, + name: file.originalname !== null && file.originalname !== 'file' ? file.originalname : undefined, + sensitive: false, + }); + if (upload.type.startsWith('image/')) { + (_request.body as any).header = upload.id; + } + } + } const data = await client.updateCredentials(_request.body!); reply.send(await this.mastoConverter.convertAccount(data.data)); } catch (e: any) { - /* console.error(e); */ + //console.error(e); reply.code(401).send(e.response.data); } }); diff --git a/packages/megalodon/src/misskey.ts b/packages/megalodon/src/misskey.ts index 69a8972d6..b81fb77a6 100644 --- a/packages/megalodon/src/misskey.ts +++ b/packages/megalodon/src/misskey.ts @@ -238,6 +238,16 @@ export default class Misskey implements MegalodonInterface { description: options.note }) } + if (options.avatar) { + params = Object.assign(params, { + avatarId: options.avatar + }) + } + if (options.header) { + params = Object.assign(params, { + bannerId: options.header + }) + } if (options.locked !== undefined) { params = Object.assign(params, { isLocked: options.locked.toString() === 'true' ? true : false