From 79d038c7249d600c8eb388bcb640769fc3d90830 Mon Sep 17 00:00:00 2001 From: Jennie Robinson Faber Date: Sun, 5 Apr 2026 16:15:29 +0100 Subject: [PATCH] feat: add Tags API endpoints and validation schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GET /api/tags — public, filterable by ?pool=craft|cooperative, active only, sorted by label - POST /api/tags/suggest — auth-required, creates TagSuggestion doc - Add tagSuggestionSchema and communityConnectionsUpdateSchema to schemas.js - Extend memberProfileUpdateSchema with craftTags, craftTagsPrivacy, communityConnectionsPrivacy --- server/api/tags/index.get.js | 16 ++++++++++++++++ server/api/tags/suggest.post.js | 17 +++++++++++++++++ server/utils/schemas.js | 24 +++++++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 server/api/tags/index.get.js create mode 100644 server/api/tags/suggest.post.js diff --git a/server/api/tags/index.get.js b/server/api/tags/index.get.js new file mode 100644 index 0000000..43387f0 --- /dev/null +++ b/server/api/tags/index.get.js @@ -0,0 +1,16 @@ +import Tag from '../../models/tag.js' + +export default defineEventHandler(async (event) => { + await connectDB() + + const query = getQuery(event) + const filter = { active: true } + + if (query.pool) { + filter.pool = query.pool + } + + const tags = await Tag.find(filter).sort({ label: 1 }).lean() + + return { tags } +}) diff --git a/server/api/tags/suggest.post.js b/server/api/tags/suggest.post.js new file mode 100644 index 0000000..c71fbee --- /dev/null +++ b/server/api/tags/suggest.post.js @@ -0,0 +1,17 @@ +import TagSuggestion from '../../models/tagSuggestion.js' +import { tagSuggestionSchema } from '../../utils/schemas.js' + +export default defineEventHandler(async (event) => { + await connectDB() + + const member = await requireAuth(event) + const body = await validateBody(event, tagSuggestionSchema) + + await TagSuggestion.create({ + label: body.label, + pool: body.pool, + suggestedBy: member._id + }) + + return { success: true } +}) diff --git a/server/utils/schemas.js b/server/utils/schemas.js index 44f51d5..74f290b 100644 --- a/server/utils/schemas.js +++ b/server/utils/schemas.js @@ -48,7 +48,10 @@ export const memberProfileUpdateSchema = z.object({ locationPrivacy: privacyEnum.optional(), socialLinksPrivacy: privacyEnum.optional(), offeringPrivacy: privacyEnum.optional(), - lookingForPrivacy: privacyEnum.optional() + lookingForPrivacy: privacyEnum.optional(), + craftTags: z.array(z.string().max(100)).max(16).optional(), + craftTagsPrivacy: privacyEnum.optional(), + communityConnectionsPrivacy: privacyEnum.optional() }) export const eventRegistrationSchema = z.object({ @@ -346,3 +349,22 @@ export const memberInviteSchema = z.object({ memberIds: z.array(z.string().min(1)).min(1).max(100), emailTemplate: z.string().min(1).max(10000) }) + +// --- Tag schemas --- + +export const tagSuggestionSchema = z.object({ + label: z.string().min(1).max(100), + pool: z.enum(['craft', 'cooperative']) +}) + +export const communityConnectionsUpdateSchema = z.object({ + topics: z.array(z.object({ + tagSlug: z.string().min(1).max(100), + state: z.enum(['help', 'interested', 'seeking']) + })).max(20).optional(), + offerPeerSupport: z.boolean().optional(), + availability: z.string().max(500).optional(), + slackHandle: z.string().max(200).optional(), + personalMessage: z.string().max(2000).optional(), + details: z.string().max(300).optional() +})