@things-factory/gallery 10.1.246 → 10.1.248
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -10
- package/dist-client/bootstrap.d.ts +0 -2
- package/dist-client/bootstrap.js +0 -26
- package/dist-client/bootstrap.js.map +0 -1
- package/dist-client/components/gallery-forms.d.ts +0 -31
- package/dist-client/components/gallery-forms.js +0 -223
- package/dist-client/components/gallery-forms.js.map +0 -1
- package/dist-client/components/gallery-saver-setting-let.d.ts +0 -11
- package/dist-client/components/gallery-saver-setting-let.js +0 -81
- package/dist-client/components/gallery-saver-setting-let.js.map +0 -1
- package/dist-client/components/gallery-show.d.ts +0 -46
- package/dist-client/components/gallery-show.js +0 -316
- package/dist-client/components/gallery-show.js.map +0 -1
- package/dist-client/components/gallery-uploader.d.ts +0 -57
- package/dist-client/components/gallery-uploader.js +0 -624
- package/dist-client/components/gallery-uploader.js.map +0 -1
- package/dist-client/components/gallery-viewer.d.ts +0 -30
- package/dist-client/components/gallery-viewer.js +0 -429
- package/dist-client/components/gallery-viewer.js.map +0 -1
- package/dist-client/index.d.ts +0 -1
- package/dist-client/index.js +0 -2
- package/dist-client/index.js.map +0 -1
- package/dist-client/pages/gallery-page.d.ts +0 -54
- package/dist-client/pages/gallery-page.js +0 -590
- package/dist-client/pages/gallery-page.js.map +0 -1
- package/dist-client/route.d.ts +0 -1
- package/dist-client/route.js +0 -9
- package/dist-client/route.js.map +0 -1
- package/dist-client/tsconfig.tsbuildinfo +0 -1
- package/dist-client/utils/gallery-api.d.ts +0 -99
- package/dist-client/utils/gallery-api.js +0 -46
- package/dist-client/utils/gallery-api.js.map +0 -1
- package/dist-client/utils/gallery-badge.d.ts +0 -4
- package/dist-client/utils/gallery-badge.js +0 -45
- package/dist-client/utils/gallery-badge.js.map +0 -1
- package/dist-client/utils/gallery-saver.d.ts +0 -6
- package/dist-client/utils/gallery-saver.js +0 -69
- package/dist-client/utils/gallery-saver.js.map +0 -1
- package/dist-client/utils/gallery-words.d.ts +0 -7
- package/dist-client/utils/gallery-words.js +0 -20
- package/dist-client/utils/gallery-words.js.map +0 -1
- package/dist-client/utils/photo-prep.d.ts +0 -10
- package/dist-client/utils/photo-prep.js +0 -102
- package/dist-client/utils/photo-prep.js.map +0 -1
- package/dist-server/attachment-reader.d.ts +0 -1
- package/dist-server/attachment-reader.js +0 -13
- package/dist-server/attachment-reader.js.map +0 -1
- package/dist-server/index.d.ts +0 -1
- package/dist-server/index.js +0 -11
- package/dist-server/index.js.map +0 -1
- package/dist-server/role-tasks.d.ts +0 -2
- package/dist-server/role-tasks.js +0 -15
- package/dist-server/role-tasks.js.map +0 -1
- package/dist-server/service/gallery/gallery-resolver.d.ts +0 -29
- package/dist-server/service/gallery/gallery-resolver.js +0 -613
- package/dist-server/service/gallery/gallery-resolver.js.map +0 -1
- package/dist-server/service/gallery/gallery-rules.d.ts +0 -90
- package/dist-server/service/gallery/gallery-rules.js +0 -182
- package/dist-server/service/gallery/gallery-rules.js.map +0 -1
- package/dist-server/service/gallery/gallery-service.d.ts +0 -37
- package/dist-server/service/gallery/gallery-service.js +0 -234
- package/dist-server/service/gallery/gallery-service.js.map +0 -1
- package/dist-server/service/gallery/gallery-types.d.ts +0 -65
- package/dist-server/service/gallery/gallery-types.js +0 -239
- package/dist-server/service/gallery/gallery-types.js.map +0 -1
- package/dist-server/service/gallery/gallery.d.ts +0 -84
- package/dist-server/service/gallery/gallery.js +0 -335
- package/dist-server/service/gallery/gallery.js.map +0 -1
- package/dist-server/service/gallery/index.d.ts +0 -4
- package/dist-server/service/gallery/index.js +0 -8
- package/dist-server/service/gallery/index.js.map +0 -1
- package/dist-server/service/index.d.ts +0 -7
- package/dist-server/service/index.js +0 -23
- package/dist-server/service/index.js.map +0 -1
- package/dist-server/tsconfig.tsbuildinfo +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gallery-resolver.js","sourceRoot":"","sources":["../../../server/service/gallery/gallery-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The doors of the gallery (ADR-0165 decisions 3-7).\n *\n * Looking, posting and liking are no privilege: everyone of the domain sees every post (decision 2), so those doors are\n * open to anyone signed in to the domain and each asks the post itself (gallery-service.ts). Changing or deleting a\n * post is its owner's. Hiding, tidying tags and making an event are `gallery:mutation` - the task `gallery.moderation`.\n */\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport { Arg, Ctx, Directive, FieldResolver, Int, Mutation, Query, Resolver, Root, UseMiddleware } from 'type-graphql'\nimport { In, IsNull, Not } from 'typeorm'\n\nimport { Attachment, createAttachment, deleteAttachment, deleteAttachmentsByRef } from '@things-factory/attachment-base'\nimport { User } from '@things-factory/auth-base'\nimport { createEvent, Event } from '@things-factory/calendar'\nimport { getRepository, SpeakRefusals } from '@things-factory/shell'\n\nimport { GalleryEvent, GalleryLike, GalleryPost, GallerySpace, GalleryVisit } from './gallery'\nimport {\n inputRefusal,\n isPhoto,\n MAX_TAG,\n orderChoices,\n photoCountRefusal,\n renamedTags,\n hasTag,\n tagCounts,\n tagOf,\n tagsOf\n} from './gallery-rules'\nimport {\n decorate,\n eventsSeenBetween,\n GALLERY_REF_TYPE,\n isModerator,\n maySeeEvent,\n openEvent,\n photosOf,\n tellFirstPhoto,\n tellHidden,\n viewerOf,\n visiblePost\n} from './gallery-service'\nimport {\n GalleryEventCard,\n GalleryEventChoice,\n GalleryEventFacts,\n GalleryEventInput,\n GalleryFilter,\n GalleryLikeState,\n GalleryPerson,\n GalleryPhoto,\n GalleryPostInput,\n GalleryPostList,\n GallerySummary,\n GalleryTagCount\n} from './gallery-types'\n\nconst MODERATE = '@privilege(category: \"gallery\", privilege: \"mutation\", domainOwnerGranted: true)'\nconst DAY = 24 * 60 * 60 * 1000\n/* A person who never opened the gallery hears of the last week's posts. */\nconst FIRST_LOOK = 7 * DAY\n\n/** A refusal said in the reader's words, with a code the screen may read. */\nfunction refuse(context: ResolverContext, code: string, fallback: string): never {\n const message = context.t ? String(context.t(`gallery.refusal.${code}`, { defaultValue: fallback })) : fallback\n const error: any = new Error(message)\n error.extensions = { code: `gallery.${code}` }\n throw error\n}\n\nconst NOT_FOUND = 'there is no such post.'\n\nasync function visibleOrRefuse(id: string, context: ResolverContext): Promise<GalleryPost> {\n const post = await visiblePost(id, context, context.state.tx)\n if (!post) refuse(context, 'unknown-post', NOT_FOUND)\n return post\n}\n\nasync function ownedOrRefuse(id: string, context: ResolverContext): Promise<GalleryPost> {\n const post = await visibleOrRefuse(id, context)\n if (post.creatorId !== context.state.user.id)\n refuse(context, 'not-yours', 'only the one who posted it changes or deletes it.')\n return post\n}\n\nfunction checkInput(input: GalleryPostInput, context: ResolverContext): void {\n const refusal = inputRefusal(input)\n if (refusal) refuse(context, refusal, `the post cannot be kept (${refusal}).`)\n}\n\n/** The uploads, each checked to be a photo before anything is stored. */\nasync function photoUploads(files: FileUpload[] | undefined, context: ResolverContext): Promise<FileUpload[]> {\n const out: FileUpload[] = []\n for (const file of files ?? []) {\n const upload = await file\n if (!isPhoto(upload?.mimetype)) refuse(context, 'not-a-photo', 'only photos go in the gallery.')\n out.push(file)\n }\n return out\n}\n\n/** The event a post may hang on - one the person may post to - opened for everyone; refused otherwise. */\nasync function eventOrRefuse(eventId: string, context: ResolverContext): Promise<string> {\n const event = await maySeeEvent(eventId, context, context.state.tx)\n if (!event) refuse(context, 'unknown-event', 'there is no such event to post to.')\n await openEvent(event.id, context, context.state.tx)\n return event.id\n}\n\nconst factsOf = (event: Event): GalleryEventFacts => ({\n id: event.id,\n name: event.name,\n startAt: event.startAt,\n endAt: event.endAt,\n location: event.location ?? undefined\n})\n\nconst photoOf = (one: Attachment): GalleryPhoto => ({\n id: one.id,\n name: one.name,\n thumbnail: one.thumbnail ?? undefined,\n fullpath: one.fullpath,\n mimetype: one.mimetype ?? undefined\n})\n\n/** The posts the request's person sees, as a query to narrow further. */\nasync function seenPosts(context: ResolverContext) {\n const { domain, user } = context.state\n const viewer = await viewerOf(context)\n const qb = getRepository(GalleryPost).createQueryBuilder('P').where('P.domain = :domain', { domain: domain.id })\n if (!viewer.moderator) qb.andWhere('(P.hiddenAt IS NULL OR P.creator = :me)', { me: user.id })\n const active = [...viewer.activePeople]\n /* The own gallery is its owner's until shared (decision 2), and no longer shown when they left (decision 5). */\n qb.andWhere(\n active.length\n ? '(P.space != :personal OR P.creator = :me OR (P.shared = :shared AND P.creator IN (:...active)))'\n : '(P.space != :personal OR P.creator = :me)',\n {\n personal: GallerySpace.PERSONAL,\n shared: true,\n me: user.id,\n active\n }\n )\n return qb\n}\n\n/* Calendar's refusals (createGalleryEvent calls its createEvent) are spoken in the reader's language only through this. */\n@UseMiddleware(SpeakRefusals)\n@Resolver(GalleryPost)\nexport class GalleryResolver {\n /* ---------------------------------------------------------------- looking */\n\n @Query(returns => GalleryPostList, {\n description: 'The posts the person sees, newest first - narrowed by space, event, tag or person.'\n })\n async galleryPosts(\n @Arg('filter', type => GalleryFilter, { nullable: true }) filter: GalleryFilter | undefined,\n @Arg('skip', type => Int, { nullable: true }) skip: number | undefined,\n @Arg('take', type => Int, { nullable: true }) take: number | undefined,\n @Ctx() context: ResolverContext\n ): Promise<GalleryPostList> {\n const qb = await seenPosts(context)\n if (filter?.space) qb.andWhere('P.space = :space', { space: filter.space })\n if (filter?.eventId) qb.andWhere('P.event = :event', { event: filter.eventId })\n if (filter?.authorId) qb.andWhere('P.creator = :author', { author: filter.authorId })\n /* The own gallery is the asker's, known here - the client's profile carries no user id (2026-10-31). */\n if (filter?.mine) qb.andWhere('P.creator = :me', { me: context.state.user.id })\n /* What a shared screen may show - the screen saver (decision 9): never one's own unshared photos. */\n if (filter?.everyone) qb.andWhere('(P.space != :personal OR P.shared = :shared)', { personal: GallerySpace.PERSONAL, shared: true })\n const tag = tagOf(filter?.tag ?? '')\n /* Tags are kept as a JSON list: the quotes bound the word, so 「워크숍」 does not find 「워크숍2026」. */\n if (tag) qb.andWhere('LOWER(P.tags) LIKE :tag', { tag: `%${JSON.stringify(tag.toLowerCase())}%` })\n qb.orderBy('P.createdAt', 'DESC')\n .skip(Math.max(0, skip ?? 0))\n .take(Math.min(60, Math.max(1, take ?? 30)))\n const [items, total] = await qb.getManyAndCount()\n return { items: await decorate(items, context), total }\n }\n\n @Query(returns => GalleryPost, { nullable: true, description: 'One post, when the person sees it.' })\n async galleryPost(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<GalleryPost | undefined> {\n const post = await visiblePost(id, context)\n return post ? (await decorate([post], context))[0] : undefined\n }\n\n @Query(returns => [GalleryPerson], { description: 'Who likes the post, the latest first.' })\n async galleryLikers(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<GalleryPerson[]> {\n const post = await visibleOrRefuse(id, context)\n const likes = await getRepository(GalleryLike).find({\n where: { post: { id: post.id } } as any,\n relations: ['user'],\n order: { createdAt: 'DESC' } as any\n })\n return likes.map(one => ({ id: one.userId!, name: one.user?.name }))\n }\n\n @Query(returns => [GalleryTagCount], {\n description: 'The tags of the domain the most used first - those holding `text` when given.'\n })\n async galleryTags(\n @Arg('text', { nullable: true }) text: string | undefined,\n @Ctx() context: ResolverContext\n ): Promise<GalleryTagCount[]> {\n const rows = await getRepository(GalleryPost).find({\n where: { domain: { id: context.state.domain.id }, hiddenAt: IsNull() } as any,\n select: ['id', 'tags'] as any\n })\n return tagCounts(\n rows.map(one => one.tags),\n text ?? ''\n )\n }\n\n @Query(returns => [GalleryEventCard], {\n description: 'The events whose gallery is open, the latest first, each with its posts counted and a photo shown.'\n })\n async galleryEvents(@Ctx() context: ResolverContext): Promise<GalleryEventCard[]> {\n const { domain } = context.state\n const open = await getRepository(GalleryEvent).find({ where: { domain: { id: domain.id } } as any })\n if (!open.length) return []\n const events = await getRepository(Event).find({\n where: { id: In(open.map(one => one.eventId)), domain: { id: domain.id } } as any,\n order: { startAt: 'DESC' } as any\n })\n if (!events.length) return []\n const posts = await (\n await seenPosts(context)\n )\n .andWhere('P.event IN (:...events)', { events: events.map(one => one.id) })\n .orderBy('P.likeCount', 'DESC')\n .addOrderBy('P.createdAt', 'DESC')\n .getMany()\n const byEvent = new Map<string, GalleryPost[]>()\n for (const one of posts) byEvent.set(one.eventId!, [...(byEvent.get(one.eventId!) ?? []), one])\n const covers = await photosOf(\n [...byEvent.values()].map(list => list[0].id),\n domain.id\n )\n return events.map(event => {\n const list = byEvent.get(event.id) ?? []\n const cover = list.length ? covers.get(list[0].id)?.[0] : undefined\n return { ...factsOf(event), postCount: list.length, cover: cover ? photoOf(cover) : undefined }\n })\n }\n\n @Query(returns => [GalleryEventChoice], {\n description:\n 'The events the person may post photos to - those near when the photo was taken first. Their own events, the open ones, and every event for whoever reads the calendar.'\n })\n async galleryEventChoices(\n @Arg('takenAt', { nullable: true }) takenAt: Date | undefined,\n @Ctx() context: ResolverContext\n ): Promise<GalleryEventChoice[]> {\n const at = takenAt && !isNaN(new Date(takenAt).getTime()) ? new Date(takenAt) : new Date()\n const events = await eventsSeenBetween(context, new Date(at.getTime() - 45 * DAY), new Date(at.getTime() + 3 * DAY))\n return orderChoices(events.map(factsOf), at)\n }\n\n @Query(returns => GallerySummary, {\n description: 'How many posts others made since the person last opened the gallery.'\n })\n async gallerySummary(@Ctx() context: ResolverContext): Promise<GallerySummary> {\n const { domain, user } = context.state\n const visit = await getRepository(GalleryVisit).findOne({\n where: { domain: { id: domain.id }, user: { id: user.id } } as any\n })\n const since = visit?.seenAt ?? new Date(Date.now() - FIRST_LOOK)\n const fresh = await (\n await seenPosts(context)\n )\n .andWhere('P.createdAt > :since', { since })\n .andWhere('P.creator != :me', { me: user.id })\n .getCount()\n return { fresh }\n }\n\n /* ---------------------------------------------------------------- posting */\n\n @Directive('@transaction')\n @Mutation(returns => GalleryPost, {\n description: 'Posts photos - at least one - with a caption, tags and an event when given.'\n })\n async createGalleryPost(\n @Arg('input', type => GalleryPostInput) input: GalleryPostInput,\n @Arg('photos', type => [GraphQLUpload]) photos: FileUpload[],\n @Ctx() context: ResolverContext\n ): Promise<GalleryPost> {\n const { domain, user, tx } = context.state as any\n checkInput(input, context)\n const countRefusal = photoCountRefusal(photos?.length ?? 0)\n if (countRefusal) refuse(context, countRefusal, `a post holds 1 to 20 photos (${countRefusal}).`)\n const uploads = await photoUploads(photos, context)\n const eventId = input.eventId ? await eventOrRefuse(input.eventId, context) : null\n const post = await getRepository(GalleryPost, tx).save({\n domain,\n space: eventId ? GallerySpace.COMPANY : (input.space ?? GallerySpace.COMPANY),\n shared: !!input.shared,\n caption: input.caption?.trim() || null,\n takenAt: input.takenAt ?? new Date(),\n tags: tagsOf(input.tags),\n event: eventId ? { id: eventId } : null,\n likeCount: 0,\n creator: user,\n updater: user\n } as any)\n for (const file of uploads)\n await createAttachment(null, { attachment: { file, refType: GALLERY_REF_TYPE, refBy: post.id } } as any, context)\n if (eventId) await tellFirstPhoto(context, post, eventId)\n return (await decorate([await getRepository(GalleryPost, tx).findOneBy({ id: post.id })], context))[0]\n }\n\n @Directive('@transaction')\n @Mutation(returns => GalleryPost, {\n description: \"Changes one's own post - its caption, tags, space, event and photos; at least one photo stays.\"\n })\n async updateGalleryPost(\n @Arg('id') id: string,\n @Arg('input', type => GalleryPostInput) input: GalleryPostInput,\n @Arg('attach', type => [GraphQLUpload], { nullable: true }) attach: FileUpload[] | undefined,\n @Arg('remove', type => [String], { nullable: true }) remove: string[] | undefined,\n @Ctx() context: ResolverContext\n ): Promise<GalleryPost> {\n const { domain, user, tx } = context.state as any\n const post = await ownedOrRefuse(id, context)\n checkInput(input, context)\n const current = (await photosOf([post.id], domain.id, tx)).get(post.id) ?? []\n const removing = current.filter(one => (remove ?? []).includes(one.id))\n const countRefusal = photoCountRefusal(current.length - removing.length + (attach?.length ?? 0))\n if (countRefusal) refuse(context, countRefusal, `a post holds 1 to 20 photos (${countRefusal}).`)\n const uploads = await photoUploads(attach, context)\n const eventId = input.eventId\n ? input.eventId === post.eventId\n ? post.eventId\n : await eventOrRefuse(input.eventId, context)\n : null\n await getRepository(GalleryPost, tx).update(post.id, {\n space: eventId ? GallerySpace.COMPANY : (input.space ?? post.space),\n shared: input.shared ?? post.shared,\n caption: input.caption?.trim() || null,\n takenAt: input.takenAt ?? post.takenAt,\n tags: tagsOf(input.tags),\n event: eventId ? { id: eventId } : null,\n updater: user\n } as any)\n for (const one of removing) await deleteAttachment(null, { id: one.id }, context)\n for (const file of uploads)\n await createAttachment(null, { attachment: { file, refType: GALLERY_REF_TYPE, refBy: post.id } } as any, context)\n if (eventId && eventId !== post.eventId) await tellFirstPhoto(context, post, eventId)\n return (await decorate([await getRepository(GalleryPost, tx).findOneBy({ id: post.id })], context))[0]\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, { description: \"Deletes one's own post with its photos.\" })\n async deleteGalleryPost(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { tx, user } = context.state as any\n const post = await ownedOrRefuse(id, context)\n await deleteAttachmentsByRef(null, { refBys: [post.id], refType: GALLERY_REF_TYPE }, context)\n await getRepository(GalleryLike, tx).softDelete({ post: { id: post.id } } as any)\n await getRepository(GalleryPost, tx).update(post.id, { updater: user } as any)\n await getRepository(GalleryPost, tx).softDelete(post.id)\n return true\n }\n\n @Directive('@transaction')\n @Mutation(returns => GalleryLikeState, {\n description: 'Likes a post, or takes the like back - liking it twice changes nothing.'\n })\n async likeGalleryPost(\n @Arg('id') id: string,\n @Arg('like') like: boolean,\n @Ctx() context: ResolverContext\n ): Promise<GalleryLikeState> {\n const { domain, user, tx } = context.state as any\n const post = await visibleOrRefuse(id, context)\n const repository = getRepository(GalleryLike, tx)\n const mine = await repository.findOne({ where: { post: { id: post.id }, user: { id: user.id } } as any })\n if (like && !mine)\n await repository.save({\n domain,\n post: { id: post.id },\n user: { id: user.id },\n creator: user,\n updater: user\n } as any)\n if (!like && mine) await repository.softDelete(mine.id)\n const likeCount = await repository.count({ where: { post: { id: post.id } } as any })\n await getRepository(GalleryPost, tx).update(post.id, { likeCount } as any)\n return { id: post.id, likeCount, liked: like }\n }\n\n @Directive('@transaction')\n @Mutation(returns => Boolean, {\n description: 'Records that the person opened the gallery - the menu counts the posts after it.'\n })\n async visitGallery(@Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, user, tx } = context.state as any\n const repository = getRepository(GalleryVisit, tx)\n const visit = await repository.findOne({ where: { domain: { id: domain.id }, user: { id: user.id } } as any })\n if (visit) await repository.update(visit.id, { seenAt: new Date(), updater: user } as any)\n else\n await repository.save({ domain, user: { id: user.id }, seenAt: new Date(), creator: user, updater: user } as any)\n return true\n }\n\n /* ---------------------------------------------------------------- moderating */\n\n @Directive(MODERATE)\n @Directive('@transaction')\n @Mutation(returns => GalleryPost, {\n description:\n 'Hides a post with the reason - its owner is told, and still sees it marked hidden. Undone by unhideGalleryPost.'\n })\n async hideGalleryPost(\n @Arg('id') id: string,\n @Arg('reason') reason: string,\n @Ctx() context: ResolverContext\n ): Promise<GalleryPost> {\n const { user, tx } = context.state as any\n const post = await visibleOrRefuse(id, context)\n const why = (reason ?? '').trim()\n if (!why) refuse(context, 'reason-required', 'give the reason it is hidden.')\n if (why.length > 200) refuse(context, 'reason-too-long', 'the reason is at most 200 characters.')\n await getRepository(GalleryPost, tx).update(post.id, {\n hiddenAt: new Date(),\n hiddenReason: why,\n hiddenBy: user,\n updater: user\n } as any)\n await tellHidden(context, post, why)\n return (await decorate([await getRepository(GalleryPost, tx).findOneBy({ id: post.id })], context))[0]\n }\n\n @Directive(MODERATE)\n @Directive('@transaction')\n @Mutation(returns => GalleryPost, { description: 'Shows a hidden post again.' })\n async unhideGalleryPost(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<GalleryPost> {\n const { user, tx } = context.state as any\n const post = await visibleOrRefuse(id, context)\n await getRepository(GalleryPost, tx).update(post.id, {\n hiddenAt: null,\n hiddenReason: null,\n hiddenBy: null,\n updater: user\n } as any)\n return (await decorate([await getRepository(GalleryPost, tx).findOneBy({ id: post.id })], context))[0]\n }\n\n @Directive(MODERATE)\n @Directive('@transaction')\n @Mutation(returns => Int, {\n description:\n 'Renames a tag on every post of the domain - into a tag already there, the two become one. Answers how many posts changed.'\n })\n async renameGalleryTag(\n @Arg('from') from: string,\n @Arg('to') to: string,\n @Ctx() context: ResolverContext\n ): Promise<number> {\n const { domain, user, tx } = context.state as any\n const target = tagOf(to)\n if (!tagOf(from) || !target) refuse(context, 'tag-required', 'give the tag and its new name.')\n if (target.length > MAX_TAG) refuse(context, 'tag-too-long', 'a tag is at most 30 characters.')\n const repository = getRepository(GalleryPost, tx)\n const rows = await repository.find({\n where: { domain: { id: domain.id }, tags: Not(IsNull()) } as any,\n select: ['id', 'tags'] as any\n })\n let changed = 0\n for (const one of rows) {\n if (!hasTag(one.tags, from)) continue\n await repository.update(one.id, { tags: renamedTags(one.tags, from, target), updater: user } as any)\n changed++\n }\n return changed\n }\n\n @Directive(MODERATE)\n @Directive('@transaction')\n @Mutation(returns => GalleryEventCard, {\n description:\n 'Makes a company event on the calendar and opens its gallery - for the events nobody put on the calendar yet.'\n })\n async createGalleryEvent(\n @Arg('input', type => GalleryEventInput) input: GalleryEventInput,\n @Ctx() context: ResolverContext\n ): Promise<GalleryEventCard> {\n const { domain, user, tx } = context.state as any\n const event = await createEvent(tx, domain, user, {\n name: input.name,\n startAt: input.startAt,\n endAt: input.endAt,\n location: input.location\n } as any)\n await openEvent(event.id, context, tx)\n return { ...factsOf(event), postCount: 0 }\n }\n\n /* ---------------------------------------------------------------- a post's fields */\n\n @FieldResolver(type => [GalleryPhoto], { description: 'The photos, in the order they were added.' })\n async photos(@Root() post: GalleryPost, @Ctx() context: ResolverContext): Promise<GalleryPhoto[]> {\n const rows = (post as any).__photos ?? (await photosOf([post.id], context.state.domain.id)).get(post.id) ?? []\n return rows.map(photoOf)\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who posted it - the owner.' })\n async creator(@Root() post: GalleryPost): Promise<User | undefined> {\n if ((post as any).__creator !== undefined) return (post as any).__creator ?? undefined\n return post.creatorId ? await getRepository(User).findOneBy({ id: post.creatorId }) : undefined\n }\n\n @FieldResolver(type => GalleryEventFacts, {\n nullable: true,\n description: 'The event the photos are of - its name, time and place.'\n })\n async event(@Root() post: GalleryPost): Promise<GalleryEventFacts | undefined> {\n const event =\n (post as any).__event ?? (post.eventId ? await getRepository(Event).findOneBy({ id: post.eventId }) : null)\n return event ? factsOf(event) : undefined\n }\n\n @FieldResolver(type => Boolean, { description: 'Whether the person likes it.' })\n async liked(@Root() post: GalleryPost, @Ctx() context: ResolverContext): Promise<boolean> {\n if ((post as any).__liked !== undefined) return (post as any).__liked\n return !!(await getRepository(GalleryLike).findOne({\n where: { post: { id: post.id }, user: { id: context.state.user.id } } as any\n }))\n }\n\n @FieldResolver(type => Boolean, { description: \"Whether it is the person's own - they change and delete it.\" })\n editable(@Root() post: GalleryPost, @Ctx() context: ResolverContext): boolean {\n return post.creatorId === context.state.user?.id\n }\n\n @FieldResolver(type => Boolean, { description: 'Whether the person may hide it or show it again.' })\n async moderatable(@Ctx() context: ResolverContext): Promise<boolean> {\n return await isModerator(context)\n }\n\n @FieldResolver(type => String, {\n nullable: true,\n description: 'Why it was hidden - for its owner and the moderators.'\n })\n async hiddenReason(@Root() post: GalleryPost, @Ctx() context: ResolverContext): Promise<string | undefined> {\n if (!post.hiddenAt) return undefined\n return post.creatorId === context.state.user?.id || (await isModerator(context)) ? post.hiddenReason : undefined\n }\n}\n"]}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
export declare const SPACES: string[];
|
|
2
|
-
/** At most this many photos in one post, and at least one. */
|
|
3
|
-
export declare const MAX_PHOTOS = 20;
|
|
4
|
-
export declare const MAX_CAPTION = 500;
|
|
5
|
-
export declare const MAX_TAGS = 10;
|
|
6
|
-
export declare const MAX_TAG = 30;
|
|
7
|
-
/** A tag as it is kept: no `#` in front, inner spaces as one, nothing around. */
|
|
8
|
-
export declare function tagOf(raw: string): string;
|
|
9
|
-
/** The tags as they are kept - each once (the same word whatever its case), in the order given. */
|
|
10
|
-
export declare function tagsOf(raw: string[] | null | undefined): string[];
|
|
11
|
-
export type PostInput = {
|
|
12
|
-
space?: string | null;
|
|
13
|
-
caption?: string | null;
|
|
14
|
-
tags?: string[] | null;
|
|
15
|
-
eventId?: string | null;
|
|
16
|
-
};
|
|
17
|
-
/** Why the input cannot be kept, or nothing. */
|
|
18
|
-
export declare function inputRefusal(input: PostInput): string | undefined;
|
|
19
|
-
/** Why a post would hold this many photos wrongly, or nothing. */
|
|
20
|
-
export declare function photoCountRefusal(count: number): string | undefined;
|
|
21
|
-
/** A photo is an image - the gallery takes nothing else. */
|
|
22
|
-
export declare function isPhoto(mimetype?: string | null): boolean;
|
|
23
|
-
/** The tags with `from` renamed to `to` - a rename into a tag already there merges the two. */
|
|
24
|
-
export declare function renamedTags(tags: string[] | null | undefined, from: string, to: string): string[];
|
|
25
|
-
/** Whether a post holds the tag, whatever its case. */
|
|
26
|
-
export declare function hasTag(tags: string[] | null | undefined, tag: string): boolean;
|
|
27
|
-
/** The tags of the domain with how many posts hold each, the most used first - narrowed to those that hold `text`. */
|
|
28
|
-
export declare function tagCounts(lists: (string[] | null | undefined)[], text?: string, limit?: number): {
|
|
29
|
-
tag: string;
|
|
30
|
-
count: number;
|
|
31
|
-
}[];
|
|
32
|
-
export type Viewer = {
|
|
33
|
-
userId: string;
|
|
34
|
-
moderator: boolean;
|
|
35
|
-
activePeople: ReadonlySet<string>;
|
|
36
|
-
};
|
|
37
|
-
export type SeenPost = {
|
|
38
|
-
space: string;
|
|
39
|
-
shared?: boolean | null;
|
|
40
|
-
creatorId?: string | null;
|
|
41
|
-
hiddenAt?: Date | string | null;
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* Whether the viewer sees the post. Everyone of the domain sees the company's posts (decision 2) and the own-gallery
|
|
45
|
-
* posts their owner shared (decision 2, 2026-10-31) - a moderator sees no unshared one either. A hidden post is seen by
|
|
46
|
-
* its owner and the moderators; the own gallery of someone who left, by no one else (decision 5).
|
|
47
|
-
*/
|
|
48
|
-
export declare function seesPost(post: SeenPost, viewer: Viewer): boolean;
|
|
49
|
-
/** Whether a photo taken at `takenAt` is near the event - from a day before it starts to a day after it ends. */
|
|
50
|
-
export declare function nearEvent(event: {
|
|
51
|
-
startAt: Date | string;
|
|
52
|
-
endAt: Date | string;
|
|
53
|
-
}, takenAt: Date | string): boolean;
|
|
54
|
-
/** The events offered for a photo: those near when it was taken first - the closest start first - then the newest. */
|
|
55
|
-
export declare function orderChoices<T extends {
|
|
56
|
-
id: string;
|
|
57
|
-
startAt: Date | string;
|
|
58
|
-
endAt: Date | string;
|
|
59
|
-
}>(events: T[], takenAt: Date | string): (T & {
|
|
60
|
-
near: boolean;
|
|
61
|
-
})[];
|
|
62
|
-
/**
|
|
63
|
-
* Who hears that an event's first photo is up: the people named on it, or everyone of the domain when it names nobody
|
|
64
|
-
* (an event made from the gallery). Never the one who posted it.
|
|
65
|
-
*/
|
|
66
|
-
export declare function firstPhotoReceivers(attendeeIds: string[], memberIds: string[], posterId: string): string[];
|
|
67
|
-
/** The page a notice opens - the gallery, narrowed to the event or the post. */
|
|
68
|
-
export declare function galleryAddressOf(where: {
|
|
69
|
-
eventId?: string | null;
|
|
70
|
-
postId?: string | null;
|
|
71
|
-
}): string;
|
|
72
|
-
export type Say = (key: string, english: string, params?: Record<string, unknown>) => string;
|
|
73
|
-
/** The words of the notice that an event's first photo is up. */
|
|
74
|
-
export declare function firstPhotoWords(event: {
|
|
75
|
-
name: string;
|
|
76
|
-
}, poster: string, caption: string | null | undefined, say: Say): {
|
|
77
|
-
subject: string;
|
|
78
|
-
summary: string;
|
|
79
|
-
body: string;
|
|
80
|
-
action: string;
|
|
81
|
-
note: string;
|
|
82
|
-
};
|
|
83
|
-
/** The words of the notice that a moderator hid one's post. */
|
|
84
|
-
export declare function hiddenWords(reason: string, say: Say): {
|
|
85
|
-
subject: string;
|
|
86
|
-
summary: string;
|
|
87
|
-
body: string;
|
|
88
|
-
action: string;
|
|
89
|
-
note: string;
|
|
90
|
-
};
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* The gallery's rules that need no database (ADR-0165): what a post may hold, how tags are kept, who sees a post, which
|
|
4
|
-
* events are offered for a photo, and who hears of an event's first photo. Pure, so the tests read them directly.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.MAX_TAG = exports.MAX_TAGS = exports.MAX_CAPTION = exports.MAX_PHOTOS = exports.SPACES = void 0;
|
|
8
|
-
exports.tagOf = tagOf;
|
|
9
|
-
exports.tagsOf = tagsOf;
|
|
10
|
-
exports.inputRefusal = inputRefusal;
|
|
11
|
-
exports.photoCountRefusal = photoCountRefusal;
|
|
12
|
-
exports.isPhoto = isPhoto;
|
|
13
|
-
exports.renamedTags = renamedTags;
|
|
14
|
-
exports.hasTag = hasTag;
|
|
15
|
-
exports.tagCounts = tagCounts;
|
|
16
|
-
exports.seesPost = seesPost;
|
|
17
|
-
exports.nearEvent = nearEvent;
|
|
18
|
-
exports.orderChoices = orderChoices;
|
|
19
|
-
exports.firstPhotoReceivers = firstPhotoReceivers;
|
|
20
|
-
exports.galleryAddressOf = galleryAddressOf;
|
|
21
|
-
exports.firstPhotoWords = firstPhotoWords;
|
|
22
|
-
exports.hiddenWords = hiddenWords;
|
|
23
|
-
exports.SPACES = ['COMPANY', 'PERSONAL'];
|
|
24
|
-
/** At most this many photos in one post, and at least one. */
|
|
25
|
-
exports.MAX_PHOTOS = 20;
|
|
26
|
-
exports.MAX_CAPTION = 500;
|
|
27
|
-
exports.MAX_TAGS = 10;
|
|
28
|
-
exports.MAX_TAG = 30;
|
|
29
|
-
/** A tag as it is kept: no `#` in front, inner spaces as one, nothing around. */
|
|
30
|
-
function tagOf(raw) {
|
|
31
|
-
return String(raw ?? '')
|
|
32
|
-
.trim()
|
|
33
|
-
.replace(/^#+/, '')
|
|
34
|
-
.replace(/\s+/g, ' ')
|
|
35
|
-
.trim();
|
|
36
|
-
}
|
|
37
|
-
/** The tags as they are kept - each once (the same word whatever its case), in the order given. */
|
|
38
|
-
function tagsOf(raw) {
|
|
39
|
-
const seen = new Set();
|
|
40
|
-
const out = [];
|
|
41
|
-
for (const one of raw ?? []) {
|
|
42
|
-
const tag = tagOf(one);
|
|
43
|
-
const key = tag.toLowerCase();
|
|
44
|
-
if (!tag || seen.has(key))
|
|
45
|
-
continue;
|
|
46
|
-
seen.add(key);
|
|
47
|
-
out.push(tag);
|
|
48
|
-
}
|
|
49
|
-
return out;
|
|
50
|
-
}
|
|
51
|
-
/** Why the input cannot be kept, or nothing. */
|
|
52
|
-
function inputRefusal(input) {
|
|
53
|
-
if (input.space && !exports.SPACES.includes(input.space))
|
|
54
|
-
return 'unknown-space';
|
|
55
|
-
if ((input.caption ?? '').length > exports.MAX_CAPTION)
|
|
56
|
-
return 'caption-too-long';
|
|
57
|
-
const tags = tagsOf(input.tags);
|
|
58
|
-
if (tags.length > exports.MAX_TAGS)
|
|
59
|
-
return 'too-many-tags';
|
|
60
|
-
if (tags.some(tag => tag.length > exports.MAX_TAG))
|
|
61
|
-
return 'tag-too-long';
|
|
62
|
-
/* An event is the company's: a person's own gallery holds their days, not the company's events (decision 2). */
|
|
63
|
-
if (input.eventId && input.space === 'PERSONAL')
|
|
64
|
-
return 'event-in-personal';
|
|
65
|
-
return undefined;
|
|
66
|
-
}
|
|
67
|
-
/** Why a post would hold this many photos wrongly, or nothing. */
|
|
68
|
-
function photoCountRefusal(count) {
|
|
69
|
-
if (count < 1)
|
|
70
|
-
return 'no-photo';
|
|
71
|
-
if (count > exports.MAX_PHOTOS)
|
|
72
|
-
return 'too-many-photos';
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
/** A photo is an image - the gallery takes nothing else. */
|
|
76
|
-
function isPhoto(mimetype) {
|
|
77
|
-
return /^image\//i.test(mimetype ?? '');
|
|
78
|
-
}
|
|
79
|
-
/** The tags with `from` renamed to `to` - a rename into a tag already there merges the two. */
|
|
80
|
-
function renamedTags(tags, from, to) {
|
|
81
|
-
const source = tagOf(from).toLowerCase();
|
|
82
|
-
return tagsOf((tags ?? []).map(tag => (tagOf(tag).toLowerCase() === source ? to : tag)));
|
|
83
|
-
}
|
|
84
|
-
/** Whether a post holds the tag, whatever its case. */
|
|
85
|
-
function hasTag(tags, tag) {
|
|
86
|
-
const key = tagOf(tag).toLowerCase();
|
|
87
|
-
return !!key && (tags ?? []).some(one => tagOf(one).toLowerCase() === key);
|
|
88
|
-
}
|
|
89
|
-
/** The tags of the domain with how many posts hold each, the most used first - narrowed to those that hold `text`. */
|
|
90
|
-
function tagCounts(lists, text = '', limit = 20) {
|
|
91
|
-
const counts = new Map();
|
|
92
|
-
for (const list of lists) {
|
|
93
|
-
for (const tag of tagsOf(list)) {
|
|
94
|
-
const key = tag.toLowerCase();
|
|
95
|
-
const one = counts.get(key);
|
|
96
|
-
if (one)
|
|
97
|
-
one.count++;
|
|
98
|
-
else
|
|
99
|
-
counts.set(key, { tag, count: 1 });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
const wanted = tagOf(text).toLowerCase();
|
|
103
|
-
return [...counts.values()]
|
|
104
|
-
.filter(one => !wanted || one.tag.toLowerCase().includes(wanted))
|
|
105
|
-
.sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag))
|
|
106
|
-
.slice(0, limit);
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Whether the viewer sees the post. Everyone of the domain sees the company's posts (decision 2) and the own-gallery
|
|
110
|
-
* posts their owner shared (decision 2, 2026-10-31) - a moderator sees no unshared one either. A hidden post is seen by
|
|
111
|
-
* its owner and the moderators; the own gallery of someone who left, by no one else (decision 5).
|
|
112
|
-
*/
|
|
113
|
-
function seesPost(post, viewer) {
|
|
114
|
-
const own = !!post.creatorId && post.creatorId === viewer.userId;
|
|
115
|
-
if (post.hiddenAt && !own && !viewer.moderator)
|
|
116
|
-
return false;
|
|
117
|
-
if (post.space === 'PERSONAL' && !own && !(post.shared && viewer.activePeople.has(post.creatorId ?? '')))
|
|
118
|
-
return false;
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
const DAY = 24 * 60 * 60 * 1000;
|
|
122
|
-
/** Whether a photo taken at `takenAt` is near the event - from a day before it starts to a day after it ends. */
|
|
123
|
-
function nearEvent(event, takenAt) {
|
|
124
|
-
const at = new Date(takenAt).getTime();
|
|
125
|
-
return new Date(event.startAt).getTime() - DAY <= at && at <= new Date(event.endAt).getTime() + DAY;
|
|
126
|
-
}
|
|
127
|
-
/** The events offered for a photo: those near when it was taken first - the closest start first - then the newest. */
|
|
128
|
-
function orderChoices(events, takenAt) {
|
|
129
|
-
const at = new Date(takenAt).getTime();
|
|
130
|
-
const unique = [...new Map(events.map(one => [one.id, one])).values()];
|
|
131
|
-
return unique
|
|
132
|
-
.map(one => ({ ...one, near: nearEvent(one, takenAt) }))
|
|
133
|
-
.sort((a, b) => a.near !== b.near
|
|
134
|
-
? Number(b.near) - Number(a.near)
|
|
135
|
-
: a.near
|
|
136
|
-
? Math.abs(new Date(a.startAt).getTime() - at) - Math.abs(new Date(b.startAt).getTime() - at)
|
|
137
|
-
: new Date(b.startAt).getTime() - new Date(a.startAt).getTime());
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Who hears that an event's first photo is up: the people named on it, or everyone of the domain when it names nobody
|
|
141
|
-
* (an event made from the gallery). Never the one who posted it.
|
|
142
|
-
*/
|
|
143
|
-
function firstPhotoReceivers(attendeeIds, memberIds, posterId) {
|
|
144
|
-
const base = attendeeIds.length ? attendeeIds : memberIds;
|
|
145
|
-
return [...new Set(base)].filter(id => id && id !== posterId);
|
|
146
|
-
}
|
|
147
|
-
/** The page a notice opens - the gallery, narrowed to the event or the post. */
|
|
148
|
-
function galleryAddressOf(where) {
|
|
149
|
-
if (where.postId)
|
|
150
|
-
return `gallery-page?post=${where.postId}`;
|
|
151
|
-
if (where.eventId)
|
|
152
|
-
return `gallery-page?event=${where.eventId}`;
|
|
153
|
-
return 'gallery-page';
|
|
154
|
-
}
|
|
155
|
-
/** The words of the notice that an event's first photo is up. */
|
|
156
|
-
function firstPhotoWords(event, poster, caption, say) {
|
|
157
|
-
const subject = say('gallery.notice.first-photo-subject', 'Photos of {event} are up', { event: event.name });
|
|
158
|
-
const body = say('gallery.notice.first-photo-body', '{poster} posted the first photos of {event}.', {
|
|
159
|
-
poster,
|
|
160
|
-
event: event.name
|
|
161
|
-
});
|
|
162
|
-
return {
|
|
163
|
-
subject,
|
|
164
|
-
summary: body,
|
|
165
|
-
body: caption ? `${body}\n\n${caption}` : body,
|
|
166
|
-
action: say('gallery.notice.action', 'Open the gallery'),
|
|
167
|
-
note: say('gallery.notice.note', 'Open Gallery in the application to see them.')
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
/** The words of the notice that a moderator hid one's post. */
|
|
171
|
-
function hiddenWords(reason, say) {
|
|
172
|
-
const subject = say('gallery.notice.hidden-subject', 'Your gallery post was hidden');
|
|
173
|
-
const body = say('gallery.notice.hidden-body', 'Reason: {reason}', { reason });
|
|
174
|
-
return {
|
|
175
|
-
subject,
|
|
176
|
-
summary: body,
|
|
177
|
-
body,
|
|
178
|
-
action: say('gallery.notice.action', 'Open the gallery'),
|
|
179
|
-
note: say('gallery.notice.note', 'Open Gallery in the application to see them.')
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
//# sourceMappingURL=gallery-rules.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"gallery-rules.js","sourceRoot":"","sources":["../../../server/service/gallery/gallery-rules.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The gallery's rules that need no database (ADR-0165): what a post may hold, how tags are kept, who sees a post, which\n * events are offered for a photo, and who hears of an event's first photo. Pure, so the tests read them directly.\n */\n\nexport const SPACES = ['COMPANY', 'PERSONAL']\n\n/** At most this many photos in one post, and at least one. */\nexport const MAX_PHOTOS = 20\nexport const MAX_CAPTION = 500\nexport const MAX_TAGS = 10\nexport const MAX_TAG = 30\n\n/** A tag as it is kept: no `#` in front, inner spaces as one, nothing around. */\nexport function tagOf(raw: string): string {\n return String(raw ?? '')\n .trim()\n .replace(/^#+/, '')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\n/** The tags as they are kept - each once (the same word whatever its case), in the order given. */\nexport function tagsOf(raw: string[] | null | undefined): string[] {\n const seen = new Set<string>()\n const out: string[] = []\n for (const one of raw ?? []) {\n const tag = tagOf(one)\n const key = tag.toLowerCase()\n if (!tag || seen.has(key)) continue\n seen.add(key)\n out.push(tag)\n }\n return out\n}\n\nexport type PostInput = {\n space?: string | null\n caption?: string | null\n tags?: string[] | null\n eventId?: string | null\n}\n\n/** Why the input cannot be kept, or nothing. */\nexport function inputRefusal(input: PostInput): string | undefined {\n if (input.space && !SPACES.includes(input.space)) return 'unknown-space'\n if ((input.caption ?? '').length > MAX_CAPTION) return 'caption-too-long'\n const tags = tagsOf(input.tags)\n if (tags.length > MAX_TAGS) return 'too-many-tags'\n if (tags.some(tag => tag.length > MAX_TAG)) return 'tag-too-long'\n /* An event is the company's: a person's own gallery holds their days, not the company's events (decision 2). */\n if (input.eventId && input.space === 'PERSONAL') return 'event-in-personal'\n return undefined\n}\n\n/** Why a post would hold this many photos wrongly, or nothing. */\nexport function photoCountRefusal(count: number): string | undefined {\n if (count < 1) return 'no-photo'\n if (count > MAX_PHOTOS) return 'too-many-photos'\n return undefined\n}\n\n/** A photo is an image - the gallery takes nothing else. */\nexport function isPhoto(mimetype?: string | null): boolean {\n return /^image\\//i.test(mimetype ?? '')\n}\n\n/** The tags with `from` renamed to `to` - a rename into a tag already there merges the two. */\nexport function renamedTags(tags: string[] | null | undefined, from: string, to: string): string[] {\n const source = tagOf(from).toLowerCase()\n return tagsOf((tags ?? []).map(tag => (tagOf(tag).toLowerCase() === source ? to : tag)))\n}\n\n/** Whether a post holds the tag, whatever its case. */\nexport function hasTag(tags: string[] | null | undefined, tag: string): boolean {\n const key = tagOf(tag).toLowerCase()\n return !!key && (tags ?? []).some(one => tagOf(one).toLowerCase() === key)\n}\n\n/** The tags of the domain with how many posts hold each, the most used first - narrowed to those that hold `text`. */\nexport function tagCounts(\n lists: (string[] | null | undefined)[],\n text = '',\n limit = 20\n): { tag: string; count: number }[] {\n const counts = new Map<string, { tag: string; count: number }>()\n for (const list of lists) {\n for (const tag of tagsOf(list)) {\n const key = tag.toLowerCase()\n const one = counts.get(key)\n if (one) one.count++\n else counts.set(key, { tag, count: 1 })\n }\n }\n const wanted = tagOf(text).toLowerCase()\n return [...counts.values()]\n .filter(one => !wanted || one.tag.toLowerCase().includes(wanted))\n .sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag))\n .slice(0, limit)\n}\n\nexport type Viewer = { userId: string; moderator: boolean; activePeople: ReadonlySet<string> }\nexport type SeenPost = { space: string; shared?: boolean | null; creatorId?: string | null; hiddenAt?: Date | string | null }\n\n/**\n * Whether the viewer sees the post. Everyone of the domain sees the company's posts (decision 2) and the own-gallery\n * posts their owner shared (decision 2, 2026-10-31) - a moderator sees no unshared one either. A hidden post is seen by\n * its owner and the moderators; the own gallery of someone who left, by no one else (decision 5).\n */\nexport function seesPost(post: SeenPost, viewer: Viewer): boolean {\n const own = !!post.creatorId && post.creatorId === viewer.userId\n if (post.hiddenAt && !own && !viewer.moderator) return false\n if (post.space === 'PERSONAL' && !own && !(post.shared && viewer.activePeople.has(post.creatorId ?? ''))) return false\n return true\n}\n\nconst DAY = 24 * 60 * 60 * 1000\n\n/** Whether a photo taken at `takenAt` is near the event - from a day before it starts to a day after it ends. */\nexport function nearEvent(event: { startAt: Date | string; endAt: Date | string }, takenAt: Date | string): boolean {\n const at = new Date(takenAt).getTime()\n return new Date(event.startAt).getTime() - DAY <= at && at <= new Date(event.endAt).getTime() + DAY\n}\n\n/** The events offered for a photo: those near when it was taken first - the closest start first - then the newest. */\nexport function orderChoices<T extends { id: string; startAt: Date | string; endAt: Date | string }>(\n events: T[],\n takenAt: Date | string\n): (T & { near: boolean })[] {\n const at = new Date(takenAt).getTime()\n const unique = [...new Map(events.map(one => [one.id, one])).values()]\n return unique\n .map(one => ({ ...one, near: nearEvent(one, takenAt) }))\n .sort((a, b) =>\n a.near !== b.near\n ? Number(b.near) - Number(a.near)\n : a.near\n ? Math.abs(new Date(a.startAt).getTime() - at) - Math.abs(new Date(b.startAt).getTime() - at)\n : new Date(b.startAt).getTime() - new Date(a.startAt).getTime()\n )\n}\n\n/**\n * Who hears that an event's first photo is up: the people named on it, or everyone of the domain when it names nobody\n * (an event made from the gallery). Never the one who posted it.\n */\nexport function firstPhotoReceivers(attendeeIds: string[], memberIds: string[], posterId: string): string[] {\n const base = attendeeIds.length ? attendeeIds : memberIds\n return [...new Set(base)].filter(id => id && id !== posterId)\n}\n\n/** The page a notice opens - the gallery, narrowed to the event or the post. */\nexport function galleryAddressOf(where: { eventId?: string | null; postId?: string | null }): string {\n if (where.postId) return `gallery-page?post=${where.postId}`\n if (where.eventId) return `gallery-page?event=${where.eventId}`\n return 'gallery-page'\n}\n\nexport type Say = (key: string, english: string, params?: Record<string, unknown>) => string\n\n/** The words of the notice that an event's first photo is up. */\nexport function firstPhotoWords(event: { name: string }, poster: string, caption: string | null | undefined, say: Say) {\n const subject = say('gallery.notice.first-photo-subject', 'Photos of {event} are up', { event: event.name })\n const body = say('gallery.notice.first-photo-body', '{poster} posted the first photos of {event}.', {\n poster,\n event: event.name\n })\n return {\n subject,\n summary: body,\n body: caption ? `${body}\\n\\n${caption}` : body,\n action: say('gallery.notice.action', 'Open the gallery'),\n note: say('gallery.notice.note', 'Open Gallery in the application to see them.')\n }\n}\n\n/** The words of the notice that a moderator hid one's post. */\nexport function hiddenWords(reason: string, say: Say) {\n const subject = say('gallery.notice.hidden-subject', 'Your gallery post was hidden')\n const body = say('gallery.notice.hidden-body', 'Reason: {reason}', { reason })\n return {\n subject,\n summary: body,\n body,\n action: say('gallery.notice.action', 'Open the gallery'),\n note: say('gallery.notice.note', 'Open Gallery in the application to see them.')\n }\n}\n"]}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { EntityManager } from 'typeorm';
|
|
2
|
-
import { Attachment } from '@things-factory/attachment-base';
|
|
3
|
-
import { Event } from '@things-factory/calendar';
|
|
4
|
-
import { GalleryPost } from './gallery';
|
|
5
|
-
import { type Viewer } from './gallery-rules';
|
|
6
|
-
/** The photos of a post hang on it under this `refType` (attachment-base). */
|
|
7
|
-
export declare const GALLERY_REF_TYPE = "Gallery Post";
|
|
8
|
-
/** Whether the request moderates the gallery - the module's one task, `gallery.moderation`. */
|
|
9
|
-
export declare const isModerator: (context: any) => Promise<boolean>;
|
|
10
|
-
/** The request's person as a post's viewer - asked once per request. */
|
|
11
|
-
export declare function viewerOf(context: any): Promise<Viewer>;
|
|
12
|
-
/** The post as the request may see it, or nothing - one answer for "none" and "not for you". */
|
|
13
|
-
export declare function visiblePost(id: string, context: any, tx?: EntityManager): Promise<GalleryPost | undefined>;
|
|
14
|
-
/** The photos of each post, in the order they were added. */
|
|
15
|
-
export declare function photosOf(postIds: string[], domainId: string, tx?: EntityManager): Promise<Map<string, Attachment[]>>;
|
|
16
|
-
/** The name, time and place of each event. */
|
|
17
|
-
export declare function eventsOf(eventIds: string[], domainId: string, tx?: EntityManager): Promise<Map<string, Event>>;
|
|
18
|
-
/** Puts on each post what its fields answer from - who posted it, its photos, its event and whether the request's person likes it. */
|
|
19
|
-
export declare function decorate(posts: GalleryPost[], context: any): Promise<GalleryPost[]>;
|
|
20
|
-
/** Whether the event's gallery is open. */
|
|
21
|
-
export declare function isOpenEvent(eventId: string, domainId: string, tx?: EntityManager): Promise<boolean>;
|
|
22
|
-
/**
|
|
23
|
-
* Whether the request's person may post to the event: its gallery is open, or they see the event - they are named on
|
|
24
|
-
* it or responsible for it, or they read the whole calendar. An event they cannot see takes no photo (판정 1).
|
|
25
|
-
*/
|
|
26
|
-
export declare function maySeeEvent(eventId: string, context: any, tx?: EntityManager): Promise<Event | undefined>;
|
|
27
|
-
/** The events the person may post to that overlap [from, to): their own, the open ones, and all when they read the calendar. */
|
|
28
|
-
export declare function eventsSeenBetween(context: any, from: Date, to: Date, tx?: EntityManager): Promise<Event[]>;
|
|
29
|
-
/** Opens the event's gallery, once. */
|
|
30
|
-
export declare function openEvent(eventId: string, context: any, tx: EntityManager): Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* When the post is the event's first, tells the people named on the event - everyone of the domain when it names
|
|
33
|
-
* nobody - that its photos are up (decision 6). Once per event: a later post is not the first.
|
|
34
|
-
*/
|
|
35
|
-
export declare function tellFirstPhoto(context: any, post: GalleryPost, eventId: string): Promise<void>;
|
|
36
|
-
/** Tells the owner that a moderator hid their post, and why (decision 5). */
|
|
37
|
-
export declare function tellHidden(context: any, post: GalleryPost, reason: string): Promise<void>;
|