mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
- Add express.urlencoded({ limit: '5mb' }) to migration POST route
to handle large CSV files (default 100KB was too small)
- Add per-handle progress logging to console for monitoring imports
- Log failed handles with reasons (WebFinger failure, no AP link, etc.)
- Show failed handles in the UI result notification
- Use error notification type when all imports fail
127 lines
3.9 KiB
JavaScript
127 lines
3.9 KiB
JavaScript
/**
|
|
* Migration controller — handles Mastodon account migration UI.
|
|
*
|
|
* GET: shows the 3-step migration page
|
|
* POST: processes alias update or CSV file import
|
|
*/
|
|
|
|
import {
|
|
parseMastodonFollowingCsv,
|
|
parseMastodonFollowersList,
|
|
bulkImportFollowing,
|
|
bulkImportFollowers,
|
|
} from "../migration.js";
|
|
|
|
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) {
|
|
next(error);
|
|
}
|
|
};
|
|
}
|
|
|
|
export function migratePostController(mountPath, pluginOptions) {
|
|
return async (request, response, next) => {
|
|
try {
|
|
const { application } = request.app.locals;
|
|
const action = request.body.action;
|
|
let result = null;
|
|
|
|
if (action === "alias") {
|
|
// Update alsoKnownAs on the actor config
|
|
const aliasUrl = request.body.aliasUrl?.trim();
|
|
if (aliasUrl) {
|
|
pluginOptions.alsoKnownAs = aliasUrl;
|
|
result = {
|
|
type: "success",
|
|
text: response.locals.__("activitypub.migrate.aliasSuccess"),
|
|
};
|
|
}
|
|
}
|
|
|
|
if (action === "import") {
|
|
const followingCollection =
|
|
application?.collections?.get("ap_following");
|
|
const followersCollection =
|
|
application?.collections?.get("ap_followers");
|
|
|
|
const importFollowing = request.body.importTypes?.includes("following");
|
|
const importFollowers = request.body.importTypes?.includes("followers");
|
|
|
|
// Read file content (submitted as text via client-side FileReader)
|
|
const fileContent = request.body.csvContent?.trim();
|
|
if (!fileContent) {
|
|
result = {
|
|
type: "error",
|
|
text: response.locals.__("activitypub.migrate.errorNoFile"),
|
|
};
|
|
} else {
|
|
let followingResult = { imported: 0, failed: 0, errors: [] };
|
|
let followersResult = { imported: 0, failed: 0, errors: [] };
|
|
|
|
if (importFollowing && followingCollection) {
|
|
const handles = parseMastodonFollowingCsv(fileContent);
|
|
console.log(`[ActivityPub] Migration: parsed ${handles.length} following handles from CSV`);
|
|
followingResult = await bulkImportFollowing(
|
|
handles,
|
|
followingCollection,
|
|
);
|
|
}
|
|
|
|
if (importFollowers && followersCollection) {
|
|
const entries = parseMastodonFollowersList(fileContent);
|
|
console.log(`[ActivityPub] Migration: parsed ${entries.length} follower entries from CSV`);
|
|
followersResult = await bulkImportFollowers(
|
|
entries,
|
|
followersCollection,
|
|
);
|
|
}
|
|
|
|
const totalFailed =
|
|
followingResult.failed + followersResult.failed;
|
|
const allErrors = [
|
|
...followingResult.errors,
|
|
...followersResult.errors,
|
|
];
|
|
|
|
let text = response.locals
|
|
.__("activitypub.migrate.success")
|
|
.replace("%d", followingResult.imported)
|
|
.replace("%d", followersResult.imported)
|
|
.replace("%d", totalFailed);
|
|
|
|
if (allErrors.length > 0) {
|
|
text += " " + response.locals
|
|
.__("activitypub.migrate.failedList")
|
|
.replace("%s", allErrors.join(", "));
|
|
}
|
|
|
|
result = {
|
|
type: totalFailed > 0 && followingResult.imported + followersResult.imported === 0
|
|
? "error"
|
|
: "success",
|
|
text,
|
|
};
|
|
}
|
|
}
|
|
|
|
response.render("activitypub-migrate", {
|
|
title: response.locals.__("activitypub.migrate.title"),
|
|
mountPath,
|
|
currentAlias: pluginOptions.alsoKnownAs || "",
|
|
result,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
}
|
|
|