feat: follow-me

This commit is contained in:
老周部落 2024-04-25 20:45:41 +08:00
parent af109b45ef
commit 22b52ac3d3
No known key found for this signature in database
GPG key ID: C72181CD85C6B738
5 changed files with 107 additions and 3 deletions

View file

@ -1011,6 +1011,8 @@ isSystemAccount: "This account is created and automatically operated by the syst
Please do not moderate, edit, delete, or otherwise tamper with this account, or Please do not moderate, edit, delete, or otherwise tamper with this account, or
it may break your server." it may break your server."
typeToConfirm: "Please enter {x} to confirm" typeToConfirm: "Please enter {x} to confirm"
useThisAccountConfirm: "Do you want to continue with this account?"
inputAccountId: "Please input your account (e.g., @firefish@info.firefish.dev )"
deleteAccount: "Delete account" deleteAccount: "Delete account"
document: "Documentation" document: "Documentation"
numberOfPageCache: "Number of cached pages" numberOfPageCache: "Number of cached pages"
@ -1158,6 +1160,8 @@ confirm: "Confirm"
importZip: "Import ZIP" importZip: "Import ZIP"
exportZip: "Export ZIP" exportZip: "Export ZIP"
getQrCode: "Get QR code" getQrCode: "Get QR code"
remoteFollow: "Remote Follow"
remoteFollowUrl: "Remote Follow URL"
emojiPackCreator: "Emoji pack creator" emojiPackCreator: "Emoji pack creator"
indexable: "Indexable" indexable: "Indexable"
indexableDescription: "Allow built-in search to show your public posts" indexableDescription: "Allow built-in search to show your public posts"

View file

@ -879,6 +879,8 @@ driveCapOverrideCaption: "输入 0 或以下的值将容量重置为默认值。
requireAdminForView: "您需要使用管理员账号登录才能查看。" requireAdminForView: "您需要使用管理员账号登录才能查看。"
isSystemAccount: "该账号由系统自动创建。请不要修改、编辑、删除或以其它方式篡改这个账号,否则可能会破坏您的服务器。" isSystemAccount: "该账号由系统自动创建。请不要修改、编辑、删除或以其它方式篡改这个账号,否则可能会破坏您的服务器。"
typeToConfirm: "输入 {x} 以确认操作" typeToConfirm: "输入 {x} 以确认操作"
useThisAccountConfirm: "您想使用此帐户继续执行此操作吗?"
inputAccountId: "请输入您的帐户(例如 @firefish@info.firefish.dev "
deleteAccount: "删除账号" deleteAccount: "删除账号"
document: "文档" document: "文档"
numberOfPageCache: "缓存页数" numberOfPageCache: "缓存页数"
@ -1975,6 +1977,8 @@ confirm: 确认
importZip: 导入 ZIP importZip: 导入 ZIP
exportZip: 导出 ZIP exportZip: 导出 ZIP
getQrCode: "获取二维码" getQrCode: "获取二维码"
remoteFollow: "远程关注"
remoteFollowUrl: "远程关注 URL"
emojiPackCreator: 表情包创建工具 emojiPackCreator: 表情包创建工具
objectStorageS3ForcePathStyleDesc: 打开此选项可构建格式为 "s3.amazonaws.com/<bucket>/" 而非 "<bucket>.s3.amazonaws.com" objectStorageS3ForcePathStyleDesc: 打开此选项可构建格式为 "s3.amazonaws.com/<bucket>/" 而非 "<bucket>.s3.amazonaws.com"
的端点 URL。 的端点 URL。

View file

@ -0,0 +1,78 @@
<template>
<div class="mk-follow-page"></div>
</template>
<script lang="ts" setup>
import { acct } from "firefish-js";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { host as hostRaw } from "@/config";
import { isSignedIn, me } from "@/me";
import { waiting } from "@/os";
const acctUri = new URL(location.href).searchParams.get("acct");
if (acctUri == null) {
throw new Error("acct required");
}
let useThisAccount = isSignedIn(me) ? true : false;
// If the user is already logged in, ask whether to follow using the current account.
if (useThisAccount) {
const { canceled } = await os.confirm({
type: "question",
text: i18n.ts.useThisAccountConfirm,
});
if (!canceled) {
waiting();
window.location.href = `/authorize-follow?acct=${acctUri}`;
} else {
useThisAccount = false;
}
}
if (!useThisAccount) {
// Ask the user what the account ID is
const remoteAccountId = await os.inputText({
text: i18n.ts.inputAccountId,
});
// If the user do not want enter uri, the user will be redirected to the user page.
if (!remoteAccountId.result) {
waiting();
window.location.href = `/@${acctUri}`;
} else {
const remoteAcctInfo = acct.parse(remoteAccountId.result);
// If the user on this server, redirect directly
if (remoteAcctInfo.host === hostRaw || remoteAcctInfo.host === null) {
waiting();
window.location.href = `/authorize-follow?acct=${acctUri}`;
} else {
waiting();
// If not, find the interaction url through webfinger interface
fetch(
`https://${remoteAcctInfo.host}/.well-known/webfinger?resource=${remoteAcctInfo.username}@${remoteAcctInfo.host}`,
{
method: "GET",
},
)
.then((response) => response.json())
.then((data) => {
const subscribeUri = data.links.find(
(link) => link.rel === "http://ostatus.org/schema/1.0/subscribe",
).template;
window.location.href = subscribeUri.replace(
"{uri}",
acctUri.includes("@") ? acctUri : `${acctUri}@${hostRaw}`,
);
})
.catch((e) => {
// TODO: It would be better to provide more information, but the priority of
// waiting component is too high and the pop-up window will be blocked.
window.location.href = `/@${acctUri}`;
});
}
}
}
</script>

View file

@ -325,6 +325,10 @@ export const routes: RouteDef[] = [
component: page(() => import("./pages/follow.vue")), component: page(() => import("./pages/follow.vue")),
loginRequired: true, loginRequired: true,
}, },
{
path: "/follow-me",
component: page(() => import("./pages/follow-me.vue")),
},
{ {
path: "/authorize_interaction", path: "/authorize_interaction",
component: page(() => import("./pages/authorize_interaction.vue")), component: page(() => import("./pages/authorize_interaction.vue")),

View file

@ -281,6 +281,13 @@ export function getUserMenu(user, router: Router = mainRouter) {
copyToClipboard(`https://${host}/@${user.username}.json`); copyToClipboard(`https://${host}/@${user.username}.json`);
}, },
}, },
{
icon: `${icon("ph-hand-waving")}`,
text: i18n.ts.remoteFollowUrl,
action: () => {
copyToClipboard(`https://${host}/follow-me?acct=${user.username}`);
},
},
], ],
}, },
{ {
@ -290,13 +297,20 @@ export function getUserMenu(user, router: Router = mainRouter) {
os.post({ specified: user }); os.post({ specified: user });
}, },
}, },
!isSignedIn(me)
? {
icon: `${icon("ph-hand-waving")}`,
text: i18n.ts.remoteFollow,
action: () => {
router.push(`/follow-me?acct=${user.username}`);
},
}
: undefined,
{ {
icon: "ph-qr-code ph-bold ph-lg", icon: "ph-qr-code ph-bold ph-lg",
text: i18n.ts.getQrCode, text: i18n.ts.getQrCode,
action: () => { action: () => {
os.displayQrCode( os.displayQrCode(`https://${host}/follow-me?acct=${user.username}`);
`https://${host}/authorize-follow?acct=${user.username}`,
);
}, },
}, },
isSignedIn(me) && me.id !== user.id isSignedIn(me) && me.id !== user.id