diff --git a/index.js b/index.js index a7a92cb..ec2bfde 100644 --- a/index.js +++ b/index.js @@ -178,7 +178,7 @@ export default class ActivityPubEndpoint { router.get("/admin/followers", followersController(mp)); router.get("/admin/following", followingController(mp)); router.get("/admin/activities", activitiesController(mp)); - router.get("/admin/migrate", migrateGetController(mp)); + router.get("/admin/migrate", migrateGetController(mp, this.options)); router.post("/admin/migrate", migratePostController(mp, this.options)); return router; diff --git a/lib/controllers/migrate.js b/lib/controllers/migrate.js index f3c97c8..f4fb2c9 100644 --- a/lib/controllers/migrate.js +++ b/lib/controllers/migrate.js @@ -12,12 +12,13 @@ import { bulkImportFollowers, } from "../migration.js"; -export function migrateGetController(mountPath) { +export function migrateGetController(mountPath, pluginOptions) { return async (request, response, next) => { try { response.render("activitypub-migrate", { title: response.locals.__("activitypub.migrate.title"), mountPath, + currentAlias: pluginOptions.alsoKnownAs || "", result: null, }); } catch (error) { @@ -94,6 +95,7 @@ export function migratePostController(mountPath, pluginOptions) { response.render("activitypub-migrate", { title: response.locals.__("activitypub.migrate.title"), mountPath, + currentAlias: pluginOptions.alsoKnownAs || "", result, }); } catch (error) { diff --git a/locales/en.json b/locales/en.json index 4f25669..fdd3396 100644 --- a/locales/en.json +++ b/locales/en.json @@ -21,23 +21,28 @@ "directionOutbound": "Sent", "migrate": { "title": "Mastodon migration", - "step1Title": "Step 1 — Configure actor alias", - "step1Desc": "Link your old Mastodon account to this actor so the fediverse knows they are the same person.", - "aliasLabel": "Your old Mastodon account URL", - "aliasHint": "e.g. https://mstdn.social/users/rmdes — sets alsoKnownAs on your actor", + "intro": "This guide walks you through moving your Mastodon identity to your IndieWeb site. Complete each step in order — your existing followers will be notified and can re-follow you automatically.", + "step1Title": "Step 1 — Link your old account", + "step1Desc": "Tell the fediverse that your old Mastodon account and this site belong to the same person. This sets the alsoKnownAs property on your ActivityPub actor, which Mastodon checks before allowing a Move.", + "aliasLabel": "Old Mastodon account URL", + "aliasHint": "The full URL of your Mastodon profile, e.g. https://mstdn.social/users/rmdes", "aliasSave": "Save alias", - "step2Title": "Step 2 — Import followers/following", - "step2Desc": "Upload your Mastodon data export CSV to import your social graph.", - "importLabel": "Import followers and following", - "fileLabel": "Mastodon export CSV", - "fileHint": "Upload following_accounts.csv from your Mastodon data export", + "aliasCurrent": "Current alias", + "aliasNone": "No alias configured yet.", + "step2Title": "Step 2 — Import your social graph", + "step2Desc": "Upload the CSV files from your Mastodon data export to bring over your connections. Go to your Mastodon instance → Preferences → Import and export → Data export to download them.", + "importLegend": "What to import", + "fileLabel": "CSV file", + "fileHint": "Select a CSV file from your Mastodon data export (e.g. following_accounts.csv or followers.csv)", "importButton": "Import", - "importFollowing": "Import following list", - "importFollowers": "Import followers list (pending until they re-follow after Move)", - "step3Title": "Step 3 — Trigger Move on Mastodon", - "step3Desc": "Go to your Mastodon instance → Preferences → Account → Move to a different account. Enter your new handle and confirm. After the Move, followers will automatically re-follow you here.", + "importFollowing": "Following list", + "importFollowingHint": "Accounts you follow — they will appear in your Following list immediately", + "importFollowers": "Followers list", + "importFollowersHint": "Your current followers — they will be recorded as pending until they re-follow you after the Move in step 3", + "step3Title": "Step 3 — Move your account", + "step3Desc": "Once you have saved your alias and imported your data, go to your Mastodon instance → Preferences → Account → Move to a different account. Enter your new fediverse handle and confirm. Mastodon will notify all your followers, and those whose servers support it will automatically re-follow you here. This step is irreversible — your old account will become a redirect.", "success": "Imported %d following, %d followers (%d failed).", - "aliasSuccess": "Actor alias updated." + "aliasSuccess": "Alias saved — your actor document now includes this account as alsoKnownAs." } } } diff --git a/package.json b/package.json index 9ee52a5..819698e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rmdes/indiekit-endpoint-activitypub", - "version": "0.1.5", + "version": "0.1.6", "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.", "keywords": [ "indiekit", diff --git a/views/activitypub-migrate.njk b/views/activitypub-migrate.njk index 2cc7c8e..ce8f59a 100644 --- a/views/activitypub-migrate.njk +++ b/views/activitypub-migrate.njk @@ -5,9 +5,9 @@ {% from "button/macro.njk" import button with context %} {% from "checkboxes/macro.njk" import checkboxes with context %} {% from "file-input/macro.njk" import fileInput with context %} -{% from "details/macro.njk" import details with context %} {% from "notification-banner/macro.njk" import notificationBanner with context %} {% from "prose/macro.njk" import prose with context %} +{% from "badge/macro.njk" import badge with context %} {% block content %} {{ heading({ text: title, level: 1, parent: { text: __("activitypub.title"), href: mountPath } }) }} @@ -16,16 +16,28 @@ {{ notificationBanner({ type: result.type, text: result.text }) }} {% endif %} + {{ prose({ text: __("activitypub.migrate.intro") }) }} + {# Step 1 — Actor alias #} {{ heading({ text: __("activitypub.migrate.step1Title"), level: 2 }) }} {{ prose({ text: __("activitypub.migrate.step1Desc") }) }} + {% if currentAlias %} +

+ {{ __("activitypub.migrate.aliasCurrent") }}: + {{ currentAlias }} +

+ {% else %} +

{{ __("activitypub.migrate.aliasNone") }}

+ {% endif %} +
{{ input({ name: "aliasUrl", label: __("activitypub.migrate.aliasLabel"), hint: __("activitypub.migrate.aliasHint"), + value: currentAlias, type: "url" }) }} {{ button({ text: __("activitypub.migrate.aliasSave") }) }} @@ -42,9 +54,20 @@ {{ checkboxes({ name: "importTypes", + fieldset: { + legend: __("activitypub.migrate.importLegend") + }, items: [ - { value: "following", text: __("activitypub.migrate.importFollowing") }, - { value: "followers", text: __("activitypub.migrate.importFollowers") } + { + label: __("activitypub.migrate.importFollowing"), + value: "following", + hint: __("activitypub.migrate.importFollowingHint") + }, + { + label: __("activitypub.migrate.importFollowers"), + value: "followers", + hint: __("activitypub.migrate.importFollowersHint") + } ], values: ["following"] }) }}