summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2020-02-01 07:16:52 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2020-02-01 07:16:52 +0900
commit7ed3448e13847f3ba807be1354e90c912fbefd9a (patch)
treea9d91176e5a95f90e2af570ae900641f651e77aa /src
parentUpdate gulpfile.ts (diff)
downloadsharkey-7ed3448e13847f3ba807be1354e90c912fbefd9a.tar.gz
sharkey-7ed3448e13847f3ba807be1354e90c912fbefd9a.tar.bz2
sharkey-7ed3448e13847f3ba807be1354e90c912fbefd9a.zip
Resolve #1669
Diffstat (limited to 'src')
-rw-r--r--src/client/pages/settings/integration.vue27
-rw-r--r--src/models/entities/user-profile.ts83
-rw-r--r--src/models/repositories/user.ts14
-rw-r--r--src/remote/activitypub/models/person.ts9
-rw-r--r--src/remote/activitypub/renderer/person.ts39
-rw-r--r--src/server/api/endpoints/i/2fa/done.ts2
-rw-r--r--src/server/api/endpoints/i/2fa/register.ts2
-rw-r--r--src/server/api/endpoints/i/2fa/unregister.ts2
-rw-r--r--src/server/api/endpoints/i/change-password.ts2
-rw-r--r--src/server/api/endpoints/i/update-email.ts4
-rw-r--r--src/server/api/endpoints/i/update.ts2
-rw-r--r--src/server/api/endpoints/room/show.ts6
-rw-r--r--src/server/api/endpoints/room/update.ts2
-rw-r--r--src/server/api/service/discord.ts58
-rw-r--r--src/server/api/service/github.ts31
-rw-r--r--src/server/api/service/twitter.ts34
16 files changed, 102 insertions, 215 deletions
diff --git a/src/client/pages/settings/integration.vue b/src/client/pages/settings/integration.vue
index bb0346d1c9..74efe3941c 100644
--- a/src/client/pages/settings/integration.vue
+++ b/src/client/pages/settings/integration.vue
@@ -1,24 +1,25 @@
<template>
<section class="_card" v-if="enableTwitterIntegration || enableDiscordIntegration || enableGithubIntegration">
<div class="_title"><fa :icon="faShareAlt"/> {{ $t('integration') }}</div>
+
<div class="_content" v-if="enableTwitterIntegration">
<header><fa :icon="faTwitter"/> Twitter</header>
- <p v-if="$store.state.i.twitter">{{ $t('connectedTo') }}: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
- <mk-button v-if="$store.state.i.twitter" @click="disconnectTwitter">{{ $t('disconnectSerice') }}</mk-button>
+ <p v-if="integrations.twitter">{{ $t('connectedTo') }}: <a :href="`https://twitter.com/${integrations.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ integrations.twitter.screenName }}</a></p>
+ <mk-button v-if="integrations.twitter" @click="disconnectTwitter">{{ $t('disconnectSerice') }}</mk-button>
<mk-button v-else @click="connectTwitter">{{ $t('connectSerice') }}</mk-button>
</div>
<div class="_content" v-if="enableDiscordIntegration">
<header><fa :icon="faDiscord"/> Discord</header>
- <p v-if="$store.state.i.discord">{{ $t('connectedTo') }}: <a :href="`https://discordapp.com/users/${$store.state.i.discord.id}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.discord.username }}#{{ $store.state.i.discord.discriminator }}</a></p>
- <mk-button v-if="$store.state.i.discord" @click="disconnectDiscord">{{ $t('disconnectSerice') }}</mk-button>
+ <p v-if="integrations.discord">{{ $t('connectedTo') }}: <a :href="`https://discordapp.com/users/${integrations.discord.id}`" rel="nofollow noopener" target="_blank">@{{ integrations.discord.username }}#{{ integrations.discord.discriminator }}</a></p>
+ <mk-button v-if="integrations.discord" @click="disconnectDiscord">{{ $t('disconnectSerice') }}</mk-button>
<mk-button v-else @click="connectDiscord">{{ $t('connectSerice') }}</mk-button>
</div>
<div class="_content" v-if="enableGithubIntegration">
<header><fa :icon="faGithub"/> GitHub</header>
- <p v-if="$store.state.i.github">{{ $t('connectedTo') }}: <a :href="`https://github.com/${$store.state.i.github.login}`" rel="nofollow noopener" target="_blank">@{{ $store.state.i.github.login }}</a></p>
- <mk-button v-if="$store.state.i.github" @click="disconnectGithub">{{ $t('disconnectSerice') }}</mk-button>
+ <p v-if="integrations.github">{{ $t('connectedTo') }}: <a :href="`https://github.com/${integrations.github.login}`" rel="nofollow noopener" target="_blank">@{{ integrations.github.login }}</a></p>
+ <mk-button v-if="integrations.github" @click="disconnectGithub">{{ $t('disconnectSerice') }}</mk-button>
<mk-button v-else @click="connectGithub">{{ $t('connectSerice') }}</mk-button>
</div>
</section>
@@ -52,6 +53,12 @@ export default Vue.extend({
};
},
+ computed: {
+ integrations() {
+ return this.$store.state.i.integrations;
+ }
+ },
+
created() {
this.$root.getMeta().then(meta => {
this.enableTwitterIntegration = meta.enableTwitterIntegration;
@@ -66,14 +73,14 @@ export default Vue.extend({
` domain=${document.location.hostname}; max-age=31536000;` +
(document.location.protocol.startsWith('https') ? ' secure' : '');
}
- this.$watch('$store.state.i', () => {
- if (this.$store.state.i.twitter) {
+ this.$watch('integrations', () => {
+ if (this.integrations.twitter) {
if (this.twitterForm) this.twitterForm.close();
}
- if (this.$store.state.i.discord) {
+ if (this.integrations.discord) {
if (this.discordForm) this.discordForm.close();
}
- if (this.$store.state.i.github) {
+ if (this.integrations.github) {
if (this.githubForm) this.githubForm.close();
}
}, {
diff --git a/src/models/entities/user-profile.ts b/src/models/entities/user-profile.ts
index 1244fa4390..278e8ce815 100644
--- a/src/models/entities/user-profile.ts
+++ b/src/models/entities/user-profile.ts
@@ -137,87 +137,10 @@ export class UserProfile {
@JoinColumn()
public pinnedPage: Page | null;
- //#region Linking
- @Column('boolean', {
- default: false,
- })
- public twitter: boolean;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public twitterAccessToken: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public twitterAccessTokenSecret: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public twitterUserId: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public twitterScreenName: string | null;
-
- @Column('boolean', {
- default: false,
- })
- public github: boolean;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public githubAccessToken: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public githubId: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public githubLogin: string | null;
-
- @Column('boolean', {
- default: false,
- })
- public discord: boolean;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public discordAccessToken: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public discordRefreshToken: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public discordExpiresDate: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public discordId: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
- })
- public discordUsername: string | null;
-
- @Column('varchar', {
- length: 64, nullable: true, default: null,
+ @Column('jsonb', {
+ default: {}
})
- public discordDiscriminator: string | null;
- //#endregion
+ public integrations: Record<string, any>;
//#region Denormalized fields
@Index()
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index 3b3ed6b793..25ce00cdc4 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -213,19 +213,6 @@ export class UserRepository extends Repository<User> {
userId: user.id
}).then(result => result >= 1)
: false,
- twitter: profile!.twitter ? {
- id: profile!.twitterUserId,
- screenName: profile!.twitterScreenName
- } : null,
- github: profile!.github ? {
- id: profile!.githubId,
- login: profile!.githubLogin
- } : null,
- discord: profile!.discord ? {
- id: profile!.discordId,
- username: profile!.discordUsername,
- discriminator: profile!.discordDiscriminator
- } : null,
} : {}),
...(opts.detail && meId === user.id ? {
@@ -242,6 +229,7 @@ export class UserRepository extends Repository<User> {
pendingReceivedFollowRequestsCount: FollowRequests.count({
followeeId: user.id
}),
+ integrations: profile?.integrations,
} : {}),
...(opts.includeSecrets ? {
diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index 6fad553c91..f9ffa4d77a 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -306,7 +306,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
const emojiNames = emojis.map(emoji => emoji.name);
- const { fields, services } = analyzeAttachments(person.attachment || []);
+ const { fields } = analyzeAttachments(person.attachment || []);
const tags = extractHashtags(person.tag).map(tag => tag.toLowerCase()).splice(0, 32);
@@ -347,13 +347,6 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
url: person.url,
fields,
description: person.summary ? fromHtml(person.summary) : null,
- twitterUserId: services.twitter ? services.twitter.userId : null,
- twitterScreenName: services.twitter ? services.twitter.screenName : null,
- githubId: services.github ? services.github.id : null,
- githubLogin: services.github ? services.github.login : null,
- discordId: services.discord ? services.discord.id : null,
- discordUsername: services.discord ? services.discord.username : null,
- discordDiscriminator: services.discord ? services.discord.discriminator : null,
});
// ハッシュタグ更新
diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts
index 07a0eeed42..af0e446ac1 100644
--- a/src/remote/activitypub/renderer/person.ts
+++ b/src/remote/activitypub/renderer/person.ts
@@ -39,45 +39,6 @@ export async function renderPerson(user: ILocalUser) {
}
}
- if (profile.twitter) {
- attachment.push({
- type: 'PropertyValue',
- name: 'Twitter',
- value: `<a href="https://twitter.com/intent/user?user_id=${profile.twitterUserId}" rel="me nofollow noopener" target="_blank"><span>@${profile.twitterScreenName}</span></a>`,
- identifier: {
- type: 'PropertyValue',
- name: 'misskey:authentication:twitter',
- value: `${profile.twitterUserId}@${profile.twitterScreenName}`
- }
- });
- }
-
- if (profile.github) {
- attachment.push({
- type: 'PropertyValue',
- name: 'GitHub',
- value: `<a href="https://github.com/${profile.githubLogin}" rel="me nofollow noopener" target="_blank"><span>@${profile.githubLogin}</span></a>`,
- identifier: {
- type: 'PropertyValue',
- name: 'misskey:authentication:github',
- value: `${profile.githubId}@${profile.githubLogin}`
- }
- });
- }
-
- if (profile.discord) {
- attachment.push({
- type: 'PropertyValue',
- name: 'Discord',
- value: `<a href="https://discordapp.com/users/${profile.discordId}" rel="me nofollow noopener" target="_blank"><span>${profile.discordUsername}#${profile.discordDiscriminator}</span></a>`,
- identifier: {
- type: 'PropertyValue',
- name: 'misskey:authentication:discord',
- value: `${profile.discordId}@${profile.discordUsername}#${profile.discordDiscriminator}`
- }
- });
- }
-
const emojis = await getEmojis(user.emojis);
const apemojis = emojis.map(emoji => renderEmoji(emoji));
diff --git a/src/server/api/endpoints/i/2fa/done.ts b/src/server/api/endpoints/i/2fa/done.ts
index c134e1b226..3420bc3f64 100644
--- a/src/server/api/endpoints/i/2fa/done.ts
+++ b/src/server/api/endpoints/i/2fa/done.ts
@@ -35,7 +35,7 @@ export default define(meta, async (ps, user) => {
throw new Error('not verified');
}
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
twoFactorSecret: profile.twoFactorTempSecret,
twoFactorEnabled: true
});
diff --git a/src/server/api/endpoints/i/2fa/register.ts b/src/server/api/endpoints/i/2fa/register.ts
index bd46b7c68c..112cdd6b7c 100644
--- a/src/server/api/endpoints/i/2fa/register.ts
+++ b/src/server/api/endpoints/i/2fa/register.ts
@@ -34,7 +34,7 @@ export default define(meta, async (ps, user) => {
length: 32
});
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
twoFactorTempSecret: secret.base32
});
diff --git a/src/server/api/endpoints/i/2fa/unregister.ts b/src/server/api/endpoints/i/2fa/unregister.ts
index 99483143cc..8fda128095 100644
--- a/src/server/api/endpoints/i/2fa/unregister.ts
+++ b/src/server/api/endpoints/i/2fa/unregister.ts
@@ -26,7 +26,7 @@ export default define(meta, async (ps, user) => {
throw new Error('incorrect password');
}
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
twoFactorSecret: null,
twoFactorEnabled: false
});
diff --git a/src/server/api/endpoints/i/change-password.ts b/src/server/api/endpoints/i/change-password.ts
index 07d2d864d2..0f44bbf826 100644
--- a/src/server/api/endpoints/i/change-password.ts
+++ b/src/server/api/endpoints/i/change-password.ts
@@ -34,7 +34,7 @@ export default define(meta, async (ps, user) => {
const salt = await bcrypt.genSalt(8);
const hash = await bcrypt.hash(ps.newPassword, salt);
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
password: hash
});
});
diff --git a/src/server/api/endpoints/i/update-email.ts b/src/server/api/endpoints/i/update-email.ts
index ca95e612a3..92ac3d79eb 100644
--- a/src/server/api/endpoints/i/update-email.ts
+++ b/src/server/api/endpoints/i/update-email.ts
@@ -49,7 +49,7 @@ export default define(meta, async (ps, user) => {
throw new ApiError(meta.errors.incorrectPassword);
}
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
email: ps.email,
emailVerified: false,
emailVerifyCode: null
@@ -66,7 +66,7 @@ export default define(meta, async (ps, user) => {
if (ps.email != null) {
const code = rndstr('a-z0-9', 16);
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
emailVerifyCode: code
});
diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts
index f7f03e84a3..14ed27fe5a 100644
--- a/src/server/api/endpoints/i/update.ts
+++ b/src/server/api/endpoints/i/update.ts
@@ -268,7 +268,7 @@ export default define(meta, async (ps, user, app) => {
//#endregion
if (Object.keys(updates).length > 0) await Users.update(user.id, updates);
- if (Object.keys(profileUpdates).length > 0) await UserProfiles.update({ userId: user.id }, profileUpdates);
+ if (Object.keys(profileUpdates).length > 0) await UserProfiles.update(user.id, profileUpdates);
const iObj = await Users.pack(user.id, user, {
detail: true,
diff --git a/src/server/api/endpoints/room/show.ts b/src/server/api/endpoints/room/show.ts
index 17634834ac..2dc69210a0 100644
--- a/src/server/api/endpoints/room/show.ts
+++ b/src/server/api/endpoints/room/show.ts
@@ -54,7 +54,7 @@ export default define(meta, async (ps, me) => {
const profile = await UserProfiles.findOne(user.id).then(ensure);
if (profile.room.furnitures == null) {
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
room: {
furnitures: [],
...profile.room
@@ -66,7 +66,7 @@ export default define(meta, async (ps, me) => {
if (profile.room.roomType == null) {
const initialType = 'default';
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
room: {
roomType: initialType as any,
...profile.room
@@ -78,7 +78,7 @@ export default define(meta, async (ps, me) => {
if (profile.room.carpetColor == null) {
const initialColor = '#85CAF0';
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
room: {
carpetColor: initialColor as any,
...profile.room
diff --git a/src/server/api/endpoints/room/update.ts b/src/server/api/endpoints/room/update.ts
index 897f65f2d2..97586eb6f3 100644
--- a/src/server/api/endpoints/room/update.ts
+++ b/src/server/api/endpoints/room/update.ts
@@ -32,7 +32,7 @@ export const meta = {
};
export default define(meta, async (ps, user) => {
- await UserProfiles.update({ userId: user.id }, {
+ await UserProfiles.update(user.id, {
room: ps.room as any
});
diff --git a/src/server/api/service/discord.ts b/src/server/api/service/discord.ts
index d5ca05577c..f9f3026aa8 100644
--- a/src/server/api/service/discord.ts
+++ b/src/server/api/service/discord.ts
@@ -46,16 +46,12 @@ router.get('/disconnect/discord', async ctx => {
token: userToken
}).then(ensure);
- await UserProfiles.update({
- userId: user.id
- }, {
- discord: false,
- discordAccessToken: null,
- discordRefreshToken: null,
- discordExpiresDate: null,
- discordId: null,
- discordUsername: null,
- discordDiscriminator: null,
+ const profile = await UserProfiles.findOne(user.id).then(ensure);
+
+ delete profile.integrations.discord;
+
+ await UserProfiles.update(user.id, {
+ integrations: profile.integrations,
});
ctx.body = `Discordの連携を解除しました :v:`;
@@ -203,7 +199,7 @@ router.get('/dc/cb', async ctx => {
}
const profile = await UserProfiles.createQueryBuilder()
- .where('"discordId" = :id', { id: id })
+ .where('"integrations"->"discord"->"id" = :id', { id: id })
.andWhere('"userHost" IS NULL')
.getOne();
@@ -212,13 +208,17 @@ router.get('/dc/cb', async ctx => {
return;
}
- await UserProfiles.update({ userId: profile.userId }, {
- discord: true,
- discordAccessToken: accessToken,
- discordRefreshToken: refreshToken,
- discordExpiresDate: expiresDate,
- discordUsername: username,
- discordDiscriminator: discriminator
+ await UserProfiles.update(profile.userId, {
+ integrations: {
+ ...profile.integrations,
+ discord: {
+ accessToken: accessToken,
+ refreshToken: refreshToken,
+ expiresDate: expiresDate,
+ username: username,
+ discriminator: discriminator
+ }
+ },
});
signin(ctx, await Users.findOne(profile.userId) as ILocalUser, true);
@@ -284,14 +284,20 @@ router.get('/dc/cb', async ctx => {
token: userToken
}).then(ensure);
- await UserProfiles.update({ userId: user.id }, {
- discord: true,
- discordAccessToken: accessToken,
- discordRefreshToken: refreshToken,
- discordExpiresDate: expiresDate,
- discordId: id,
- discordUsername: username,
- discordDiscriminator: discriminator
+ const profile = await UserProfiles.findOne(user.id).then(ensure);
+
+ await UserProfiles.update(user.id, {
+ integrations: {
+ ...profile.integrations,
+ discord: {
+ accessToken: accessToken,
+ refreshToken: refreshToken,
+ expiresDate: expiresDate,
+ id: id,
+ username: username,
+ discriminator: discriminator
+ }
+ }
});
ctx.body = `Discord: @${username}#${discriminator} を、Misskey: @${user.username} に接続しました!`;
diff --git a/src/server/api/service/github.ts b/src/server/api/service/github.ts
index 071b4a96d1..ec9cce7ad8 100644
--- a/src/server/api/service/github.ts
+++ b/src/server/api/service/github.ts
@@ -46,13 +46,12 @@ router.get('/disconnect/github', async ctx => {
token: userToken
}).then(ensure);
- await UserProfiles.update({
- userId: user.id
- }, {
- github: false,
- githubAccessToken: null,
- githubId: null,
- githubLogin: null,
+ const profile = await UserProfiles.findOne(user.id).then(ensure);
+
+ delete profile.integrations.github;
+
+ await UserProfiles.update(user.id, {
+ integrations: profile.integrations,
});
ctx.body = `GitHubの連携を解除しました :v:`;
@@ -193,7 +192,7 @@ router.get('/gh/cb', async ctx => {
}
const link = await UserProfiles.createQueryBuilder()
- .where('"githubId" = :id', { id: id })
+ .where('"integrations"->"github"->"id" = :id', { id: id })
.andWhere('"userHost" IS NULL')
.getOne();
@@ -260,11 +259,17 @@ router.get('/gh/cb', async ctx => {
token: userToken
}).then(ensure);
- await UserProfiles.update({ userId: user.id }, {
- github: true,
- githubAccessToken: accessToken,
- githubId: id,
- githubLogin: login,
+ const profile = await UserProfiles.findOne(user.id).then(ensure);
+
+ await UserProfiles.update(user.id, {
+ integrations: {
+ ...profile.integrations,
+ github: {
+ accessToken: accessToken,
+ id: id,
+ login: login,
+ }
+ }
});
ctx.body = `GitHub: @${login} を、Misskey: @${user.username} に接続しました!`;
diff --git a/src/server/api/service/twitter.ts b/src/server/api/service/twitter.ts
index dc6c593201..881915b58f 100644
--- a/src/server/api/service/twitter.ts
+++ b/src/server/api/service/twitter.ts
@@ -45,14 +45,12 @@ router.get('/disconnect/twitter', async ctx => {
token: userToken
}).then(ensure);
- await UserProfiles.update({
- userId: user.id
- }, {
- twitter: false,
- twitterAccessToken: null,
- twitterAccessTokenSecret: null,
- twitterUserId: null,
- twitterScreenName: null,
+ const profile = await UserProfiles.findOne(user.id).then(ensure);
+
+ delete profile.integrations.twitter;
+
+ await UserProfiles.update(user.id, {
+ integrations: profile.integrations,
});
ctx.body = `Twitterの連携を解除しました :v:`;
@@ -141,7 +139,7 @@ router.get('/tw/cb', async ctx => {
const result = await twAuth!.done(JSON.parse(twCtx), ctx.query.oauth_verifier);
const link = await UserProfiles.createQueryBuilder()
- .where('"twitterUserId" = :id', { id: result.userId })
+ .where('"integrations"->"twitter"->"userId" = :id', { id: result.userId })
.andWhere('"userHost" IS NULL')
.getOne();
@@ -174,12 +172,18 @@ router.get('/tw/cb', async ctx => {
token: userToken
}).then(ensure);
- await UserProfiles.update({ userId: user.id }, {
- twitter: true,
- twitterAccessToken: result.accessToken,
- twitterAccessTokenSecret: result.accessTokenSecret,
- twitterUserId: result.userId,
- twitterScreenName: result.screenName,
+ const profile = await UserProfiles.findOne(user.id).then(ensure);
+
+ await UserProfiles.update(user.id, {
+ integrations: {
+ ...profile.integrations,
+ twitter: {
+ accessToken: result.accessToken,
+ accessTokenSecret: result.accessTokenSecret,
+ userId: result.userId,
+ screenName: result.screenName,
+ }
+ },
});
ctx.body = `Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`;