New PATCH /api/members/me/community-connections endpoint following peer-support.patch.js pattern (requireAuth, validateBody, dot-notation $set, Slack user lookup when offerPeerSupport+slackHandle set, logActivity). Profile endpoint updated with craftTags handling, craftTagsPrivacy and communityConnectionsPrivacy in privacy fields, and craftTags in response.
124 lines
3.2 KiB
JavaScript
124 lines
3.2 KiB
JavaScript
import Member from "../../models/member.js";
|
|
import { requireAuth } from "../../utils/auth.js";
|
|
import { validateBody } from "../../utils/validateBody.js";
|
|
import { memberProfileUpdateSchema } from "../../utils/schemas.js";
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const authedMember = await requireAuth(event);
|
|
const memberId = authedMember._id;
|
|
|
|
const body = await validateBody(event, memberProfileUpdateSchema);
|
|
|
|
// Profile fields from validated body
|
|
const profileFields = [
|
|
"pronouns",
|
|
"timeZone",
|
|
"avatar",
|
|
"studio",
|
|
"bio",
|
|
"location",
|
|
"socialLinks",
|
|
"showInDirectory",
|
|
"notifications",
|
|
];
|
|
|
|
// Privacy fields from validated body
|
|
const privacyFields = [
|
|
"pronounsPrivacy",
|
|
"timeZonePrivacy",
|
|
"avatarPrivacy",
|
|
"studioPrivacy",
|
|
"bioPrivacy",
|
|
"locationPrivacy",
|
|
"socialLinksPrivacy",
|
|
"offeringPrivacy",
|
|
"lookingForPrivacy",
|
|
"craftTagsPrivacy",
|
|
"communityConnectionsPrivacy",
|
|
];
|
|
|
|
// Build update object from validated data
|
|
const updateData = {};
|
|
|
|
profileFields.forEach((field) => {
|
|
if (body[field] !== undefined) {
|
|
updateData[field] = body[field];
|
|
}
|
|
});
|
|
|
|
// Handle craftTags (simple array)
|
|
if (body.craftTags !== undefined) {
|
|
updateData.craftTags = body.craftTags;
|
|
}
|
|
|
|
// Handle offering and lookingFor separately (nested objects)
|
|
if (body.offering !== undefined) {
|
|
updateData.offering = {
|
|
text: body.offering.text || "",
|
|
tags: body.offering.tags || [],
|
|
};
|
|
}
|
|
if (body.lookingFor !== undefined) {
|
|
updateData.lookingFor = {
|
|
text: body.lookingFor.text || "",
|
|
tags: body.lookingFor.tags || [],
|
|
};
|
|
}
|
|
|
|
// Handle privacy settings
|
|
privacyFields.forEach((privacyField) => {
|
|
if (body[privacyField] !== undefined) {
|
|
const baseField = privacyField.replace("Privacy", "");
|
|
updateData[`privacy.${baseField}`] = body[privacyField];
|
|
}
|
|
});
|
|
|
|
try {
|
|
const member = await Member.findByIdAndUpdate(
|
|
memberId,
|
|
{ $set: updateData },
|
|
{ new: true, runValidators: true },
|
|
);
|
|
|
|
if (!member) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: "Member not found",
|
|
});
|
|
}
|
|
|
|
// Log which fields were updated
|
|
const changedFields = Object.keys(body).filter(k => body[k] !== undefined && !k.endsWith('Privacy'))
|
|
if (changedFields.length) {
|
|
logActivity(memberId, 'profile_updated', { fields: changedFields })
|
|
}
|
|
|
|
// Return sanitized member data
|
|
return {
|
|
id: member._id,
|
|
email: member.email,
|
|
name: member.name,
|
|
circle: member.circle,
|
|
contributionTier: member.contributionTier,
|
|
pronouns: member.pronouns,
|
|
timeZone: member.timeZone,
|
|
avatar: member.avatar,
|
|
studio: member.studio,
|
|
bio: member.bio,
|
|
location: member.location,
|
|
socialLinks: member.socialLinks,
|
|
offering: member.offering,
|
|
lookingFor: member.lookingFor,
|
|
craftTags: member.craftTags,
|
|
showInDirectory: member.showInDirectory,
|
|
notifications: member.notifications,
|
|
};
|
|
} catch (error) {
|
|
if (error.statusCode) throw error;
|
|
console.error("Profile update error:", error);
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: "Failed to update profile",
|
|
});
|
|
}
|
|
});
|