Fixed 267U.pre2
This commit is contained in:
@@ -0,0 +1,349 @@
|
||||
import RE2 from "re2";
|
||||
import { updateUserProfileData } from "../../../../services/i/update.js";
|
||||
import { Users, DriveFiles, UserProfiles, Pages } from "../../../../models/index.js";
|
||||
import { notificationTypes } from "../../../../types.js";
|
||||
import { langmap } from "../../../../misc/langmap.js";
|
||||
import { verifyLink } from "../../../../services/fetch-rel-me.js";
|
||||
import { ApiError } from "../../error.js";
|
||||
import define from "../../define.js";
|
||||
export const meta = {
|
||||
tags: [
|
||||
"account"
|
||||
],
|
||||
requireCredential: true,
|
||||
kind: "write:account",
|
||||
errors: {
|
||||
noSuchAvatar: {
|
||||
message: "No such avatar file.",
|
||||
code: "NO_SUCH_AVATAR",
|
||||
id: "539f3a45-f215-4f81-a9a8-31293640207f"
|
||||
},
|
||||
noSuchBanner: {
|
||||
message: "No such banner file.",
|
||||
code: "NO_SUCH_BANNER",
|
||||
id: "0d8f5629-f210-41c2-9433-735831a58595"
|
||||
},
|
||||
avatarNotAnImage: {
|
||||
message: "The file specified as an avatar is not an image.",
|
||||
code: "AVATAR_NOT_AN_IMAGE",
|
||||
id: "f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191"
|
||||
},
|
||||
bannerNotAnImage: {
|
||||
message: "The file specified as a banner is not an image.",
|
||||
code: "BANNER_NOT_AN_IMAGE",
|
||||
id: "75aedb19-2afd-4e6d-87fc-67941256fa60"
|
||||
},
|
||||
noSuchPage: {
|
||||
message: "No such page.",
|
||||
code: "NO_SUCH_PAGE",
|
||||
id: "8e01b590-7eb9-431b-a239-860e086c408e"
|
||||
},
|
||||
invalidRegexp: {
|
||||
message: "Invalid Regular Expression.",
|
||||
code: "INVALID_REGEXP",
|
||||
id: "0d786918-10df-41cd-8f33-8dec7d9a89a5"
|
||||
},
|
||||
invalidFieldName: {
|
||||
message: "Invalid field name.",
|
||||
code: "INVALID_FIELD_NAME",
|
||||
id: "8f81972e-8b53-4d30-b0d2-efb026dda673"
|
||||
},
|
||||
invalidFieldValue: {
|
||||
message: "Invalid field value.",
|
||||
code: "INVALID_FIELD_VALUE",
|
||||
id: "aede7444-244b-11ee-be56-0242ac120002"
|
||||
}
|
||||
},
|
||||
res: {
|
||||
type: "object",
|
||||
optional: false,
|
||||
nullable: false,
|
||||
ref: "MeDetailed"
|
||||
}
|
||||
};
|
||||
export const paramDef = {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: {
|
||||
...Users.nameSchema,
|
||||
nullable: true
|
||||
},
|
||||
description: {
|
||||
...Users.descriptionSchema,
|
||||
nullable: true
|
||||
},
|
||||
location: {
|
||||
...Users.locationSchema,
|
||||
nullable: true
|
||||
},
|
||||
birthday: {
|
||||
...Users.birthdaySchema,
|
||||
nullable: true
|
||||
},
|
||||
lang: {
|
||||
type: "string",
|
||||
enum: [
|
||||
null,
|
||||
...Object.keys(langmap)
|
||||
],
|
||||
nullable: true
|
||||
},
|
||||
avatarId: {
|
||||
type: "string",
|
||||
format: "misskey:id",
|
||||
nullable: true
|
||||
},
|
||||
bannerId: {
|
||||
type: "string",
|
||||
format: "misskey:id",
|
||||
nullable: true
|
||||
},
|
||||
fields: {
|
||||
type: "array",
|
||||
minItems: 0,
|
||||
maxItems: 16,
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: {
|
||||
type: "string"
|
||||
},
|
||||
value: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
required: [
|
||||
"name",
|
||||
"value"
|
||||
]
|
||||
}
|
||||
},
|
||||
isLocked: {
|
||||
type: "boolean"
|
||||
},
|
||||
isExplorable: {
|
||||
type: "boolean"
|
||||
},
|
||||
hideOnlineStatus: {
|
||||
type: "boolean"
|
||||
},
|
||||
publicReactions: {
|
||||
type: "boolean"
|
||||
},
|
||||
allowCalls: {
|
||||
type: "boolean"
|
||||
},
|
||||
symbolFileId: {
|
||||
type: "string",
|
||||
format: "misskey:id",
|
||||
nullable: true
|
||||
},
|
||||
carefulBot: {
|
||||
type: "boolean"
|
||||
},
|
||||
autoAcceptFollowed: {
|
||||
type: "boolean"
|
||||
},
|
||||
noCrawle: {
|
||||
type: "boolean"
|
||||
},
|
||||
preventAiLearning: {
|
||||
type: "boolean"
|
||||
},
|
||||
isBot: {
|
||||
type: "boolean"
|
||||
},
|
||||
isCat: {
|
||||
type: "boolean"
|
||||
},
|
||||
speakAsCat: {
|
||||
type: "boolean"
|
||||
},
|
||||
minorBadges: {
|
||||
type: "array",
|
||||
uniqueItems: true,
|
||||
maxItems: 1,
|
||||
items: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"K",
|
||||
"T",
|
||||
"E"
|
||||
]
|
||||
}
|
||||
},
|
||||
injectFeaturedNote: {
|
||||
type: "boolean"
|
||||
},
|
||||
receiveAnnouncementEmail: {
|
||||
type: "boolean"
|
||||
},
|
||||
alwaysMarkNsfw: {
|
||||
type: "boolean"
|
||||
},
|
||||
ffVisibility: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"public",
|
||||
"followers",
|
||||
"private"
|
||||
]
|
||||
},
|
||||
pinnedPageId: {
|
||||
type: "string",
|
||||
format: "misskey:id",
|
||||
nullable: true
|
||||
},
|
||||
mutedWords: {
|
||||
type: "array"
|
||||
},
|
||||
mutedInstances: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
mutingNotificationTypes: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
enum: notificationTypes
|
||||
}
|
||||
},
|
||||
emailNotificationTypes: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
pronouns: {
|
||||
type: "object",
|
||||
nullable: true
|
||||
},
|
||||
canBite: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"anyone",
|
||||
"followers",
|
||||
"nobody"
|
||||
],
|
||||
nullable: true
|
||||
}
|
||||
}
|
||||
};
|
||||
export default define(meta, paramDef, async (ps, _user, token)=>{
|
||||
const user = await Users.findOneByOrFail({
|
||||
id: _user.id
|
||||
});
|
||||
const isSecure = token == null;
|
||||
const updates = {};
|
||||
const profileUpdates = {};
|
||||
const profile = await UserProfiles.findOneByOrFail({
|
||||
userId: user.id
|
||||
});
|
||||
if (ps.name !== undefined) updates.name = ps.name;
|
||||
if (ps.description !== undefined) profileUpdates.description = ps.description;
|
||||
if (ps.lang !== undefined) profileUpdates.lang = ps.lang;
|
||||
if (ps.location !== undefined) profileUpdates.location = ps.location;
|
||||
if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday;
|
||||
if (ps.ffVisibility !== undefined) profileUpdates.ffVisibility = ps.ffVisibility;
|
||||
if (ps.avatarId !== undefined) updates.avatarId = ps.avatarId;
|
||||
if (ps.bannerId !== undefined) updates.bannerId = ps.bannerId;
|
||||
if (ps.mutedWords !== undefined) {
|
||||
// validate regular expression syntax
|
||||
ps.mutedWords.filter((x)=>!Array.isArray(x)).forEach((x)=>{
|
||||
const regexp = x.match(/^\/(.+)\/(.*)$/);
|
||||
if (!regexp) throw new ApiError(meta.errors.invalidRegexp);
|
||||
try {
|
||||
new RE2(regexp[1], regexp[2]);
|
||||
} catch (err) {
|
||||
throw new ApiError(meta.errors.invalidRegexp);
|
||||
}
|
||||
});
|
||||
profileUpdates.mutedWords = ps.mutedWords;
|
||||
profileUpdates.enableWordMute = ps.mutedWords.length > 0;
|
||||
}
|
||||
if (ps.mutedInstances !== undefined) profileUpdates.mutedInstances = ps.mutedInstances;
|
||||
if (ps.mutingNotificationTypes !== undefined) profileUpdates.mutingNotificationTypes = ps.mutingNotificationTypes;
|
||||
if (typeof ps.isLocked === "boolean") updates.isLocked = ps.isLocked;
|
||||
if (typeof ps.isExplorable === "boolean") updates.isExplorable = ps.isExplorable;
|
||||
if (typeof ps.hideOnlineStatus === "boolean") updates.hideOnlineStatus = ps.hideOnlineStatus;
|
||||
if (typeof ps.publicReactions === "boolean") profileUpdates.publicReactions = ps.publicReactions;
|
||||
if (typeof ps.allowCalls === "boolean") profileUpdates.allowCalls = ps.allowCalls;
|
||||
if (ps.symbolFileId !== undefined) profileUpdates.symbolFileId = ps.symbolFileId;
|
||||
if (typeof ps.isBot === "boolean") updates.isBot = ps.isBot;
|
||||
if (ps.minorBadges !== undefined) updates.minorBadges = ps.minorBadges.slice(0, 1);
|
||||
if (typeof ps.carefulBot === "boolean") profileUpdates.carefulBot = ps.carefulBot;
|
||||
if (typeof ps.autoAcceptFollowed === "boolean") profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed;
|
||||
if (typeof ps.noCrawle === "boolean") profileUpdates.noCrawle = ps.noCrawle;
|
||||
if (typeof ps.preventAiLearning === "boolean") profileUpdates.preventAiLearning = ps.preventAiLearning;
|
||||
if (typeof ps.isCat === "boolean") updates.isCat = ps.isCat;
|
||||
if (typeof ps.speakAsCat === "boolean") updates.speakAsCat = ps.speakAsCat;
|
||||
if (typeof ps.injectFeaturedNote === "boolean") profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
||||
if (typeof ps.receiveAnnouncementEmail === "boolean") profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
|
||||
if (typeof ps.alwaysMarkNsfw === "boolean") profileUpdates.alwaysMarkNsfw = ps.alwaysMarkNsfw;
|
||||
if (ps.emailNotificationTypes !== undefined) profileUpdates.emailNotificationTypes = ps.emailNotificationTypes;
|
||||
if (typeof ps.pronouns === "object") {
|
||||
if (ps.pronouns === null) ps.pronouns = {};
|
||||
for (const key of Object.keys(ps.pronouns)){
|
||||
if (key.length !== 2 || typeof ps.pronouns[key] !== "string" || ps.pronouns[key].length === 0) {
|
||||
delete ps.pronouns[key];
|
||||
}
|
||||
}
|
||||
profileUpdates.pronouns = ps.pronouns;
|
||||
}
|
||||
const avatar = ps.avatarId ? await DriveFiles.findOneBy({
|
||||
id: ps.avatarId
|
||||
}) : null;
|
||||
const banner = ps.bannerId ? await DriveFiles.findOneBy({
|
||||
id: ps.bannerId
|
||||
}) : null;
|
||||
if (ps.avatarId) {
|
||||
if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar);
|
||||
if (!avatar.type.startsWith("image/")) throw new ApiError(meta.errors.avatarNotAnImage);
|
||||
updates.avatarUrl = DriveFiles.getDatabasePrefetchUrl(avatar, true);
|
||||
updates.avatarBlurhash = avatar.blurhash;
|
||||
}
|
||||
if (ps.bannerId) {
|
||||
if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner);
|
||||
if (!banner.type.startsWith("image/")) throw new ApiError(meta.errors.bannerNotAnImage);
|
||||
updates.bannerUrl = DriveFiles.getDatabasePrefetchUrl(banner, false);
|
||||
updates.bannerBlurhash = banner.blurhash;
|
||||
}
|
||||
if (ps.pinnedPageId) {
|
||||
const page = await Pages.findOneBy({
|
||||
id: ps.pinnedPageId
|
||||
});
|
||||
if (page == null || page.userId !== user.id) throw new ApiError(meta.errors.noSuchPage);
|
||||
profileUpdates.pinnedPageId = page.id;
|
||||
} else if (ps.pinnedPageId === null) {
|
||||
profileUpdates.pinnedPageId = null;
|
||||
}
|
||||
if (ps.fields) {
|
||||
for (const field of ps.fields){
|
||||
if (!field || field.name === "" || field.value === "") {
|
||||
continue;
|
||||
}
|
||||
if (typeof field.name !== "string" || field.name === "") {
|
||||
throw new ApiError(meta.errors.invalidFieldName);
|
||||
}
|
||||
if (typeof field.value !== "string" || field.value === "") {
|
||||
throw new ApiError(meta.errors.invalidFieldValue);
|
||||
}
|
||||
if (field.value.startsWith("http")) {
|
||||
field.verified = await verifyLink(field.value, user.username);
|
||||
}
|
||||
}
|
||||
profileUpdates.fields = ps.fields.filter((x)=>Object.keys(x).length !== 0).map((x)=>{
|
||||
return {
|
||||
name: x.name,
|
||||
value: x.value,
|
||||
verified: x.verified
|
||||
};
|
||||
});
|
||||
}
|
||||
if (ps.canBite) {
|
||||
updates.canBite = ps.canBite;
|
||||
}
|
||||
return updateUserProfileData(user, profile, updates, profileUpdates, isSecure);
|
||||
});
|
||||
Reference in New Issue
Block a user