@things-factory/gallery 10.1.233 → 10.1.236

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.
Files changed (62) hide show
  1. package/client/bootstrap.ts +12 -0
  2. package/client/components/gallery-forms.ts +1 -1
  3. package/client/components/gallery-saver-setting-let.ts +78 -0
  4. package/client/components/gallery-show.ts +312 -0
  5. package/client/components/gallery-uploader.ts +35 -5
  6. package/client/components/gallery-viewer.ts +17 -4
  7. package/client/pages/gallery-page.ts +18 -16
  8. package/client/utils/gallery-api.ts +4 -2
  9. package/client/utils/gallery-saver.ts +72 -0
  10. package/dist-client/bootstrap.d.ts +1 -0
  11. package/dist-client/bootstrap.js +10 -0
  12. package/dist-client/bootstrap.js.map +1 -1
  13. package/dist-client/components/gallery-forms.js +1 -1
  14. package/dist-client/components/gallery-forms.js.map +1 -1
  15. package/dist-client/components/gallery-saver-setting-let.d.ts +11 -0
  16. package/dist-client/components/gallery-saver-setting-let.js +81 -0
  17. package/dist-client/components/gallery-saver-setting-let.js.map +1 -0
  18. package/dist-client/components/gallery-show.d.ts +46 -0
  19. package/dist-client/components/gallery-show.js +316 -0
  20. package/dist-client/components/gallery-show.js.map +1 -0
  21. package/dist-client/components/gallery-uploader.d.ts +5 -0
  22. package/dist-client/components/gallery-uploader.js +43 -4
  23. package/dist-client/components/gallery-uploader.js.map +1 -1
  24. package/dist-client/components/gallery-viewer.d.ts +2 -2
  25. package/dist-client/components/gallery-viewer.js +16 -3
  26. package/dist-client/components/gallery-viewer.js.map +1 -1
  27. package/dist-client/pages/gallery-page.d.ts +0 -1
  28. package/dist-client/pages/gallery-page.js +20 -16
  29. package/dist-client/pages/gallery-page.js.map +1 -1
  30. package/dist-client/tsconfig.tsbuildinfo +1 -1
  31. package/dist-client/utils/gallery-api.d.ts +4 -0
  32. package/dist-client/utils/gallery-api.js +1 -1
  33. package/dist-client/utils/gallery-api.js.map +1 -1
  34. package/dist-client/utils/gallery-saver.d.ts +6 -0
  35. package/dist-client/utils/gallery-saver.js +69 -0
  36. package/dist-client/utils/gallery-saver.js.map +1 -0
  37. package/dist-server/service/gallery/gallery-resolver.js +13 -2
  38. package/dist-server/service/gallery/gallery-resolver.js.map +1 -1
  39. package/dist-server/service/gallery/gallery-rules.d.ts +4 -2
  40. package/dist-server/service/gallery/gallery-rules.js +4 -3
  41. package/dist-server/service/gallery/gallery-rules.js.map +1 -1
  42. package/dist-server/service/gallery/gallery-types.d.ts +3 -0
  43. package/dist-server/service/gallery/gallery-types.js +12 -0
  44. package/dist-server/service/gallery/gallery-types.js.map +1 -1
  45. package/dist-server/service/gallery/gallery.d.ts +2 -1
  46. package/dist-server/service/gallery/gallery.js +7 -2
  47. package/dist-server/service/gallery/gallery.js.map +1 -1
  48. package/dist-server/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +10 -9
  50. package/server/service/gallery/gallery-resolver.ts +13 -4
  51. package/server/service/gallery/gallery-rules.ts +5 -4
  52. package/server/service/gallery/gallery-types.ts +9 -0
  53. package/server/service/gallery/gallery.ts +7 -2
  54. package/test/gallery-persistence.test.ts +24 -3
  55. package/test/gallery-rules.test.ts +10 -4
  56. package/test/refusals-and-bounds.test.ts +28 -0
  57. package/translations/en.json +16 -2
  58. package/translations/es.json +16 -2
  59. package/translations/ja.json +16 -2
  60. package/translations/ko.json +16 -2
  61. package/translations/ms.json +16 -2
  62. package/translations/zh.json +16 -2
@@ -23,6 +23,7 @@ export type EventChoice = EventFacts & {
23
23
  export interface Post {
24
24
  id: string;
25
25
  space: Space;
26
+ shared: boolean;
26
27
  caption?: string | null;
27
28
  takenAt: string;
28
29
  tags?: string[] | null;
@@ -42,6 +43,7 @@ export interface Post {
42
43
  }
43
44
  export interface PostInput {
44
45
  space?: Space;
46
+ shared?: boolean;
45
47
  caption?: string;
46
48
  takenAt?: string;
47
49
  tags?: string[];
@@ -52,6 +54,8 @@ export type Filter = {
52
54
  eventId?: string;
53
55
  tag?: string;
54
56
  authorId?: string;
57
+ mine?: boolean;
58
+ everyone?: boolean;
55
59
  };
56
60
  /** Tells the open gallery and the menu's count that a post came, changed or went. */
57
61
  export declare const galleryChanged: () => boolean;
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import gql from 'graphql-tag';
5
5
  import { client, uploadContext } from '@operato/graphql';
6
- const POST_FIELDS = `id space caption takenAt tags likeCount liked editable moderatable hiddenAt hiddenReason createdAt
6
+ const POST_FIELDS = `id space shared caption takenAt tags likeCount liked editable moderatable hiddenAt hiddenReason createdAt
7
7
  creator { id name } event { id name startAt endAt location } photos { id name thumbnail fullpath mimetype }`;
8
8
  const EVENT_FIELDS = 'id name startAt endAt location';
9
9
  function answer(response, field) {
@@ -1 +1 @@
1
- {"version":3,"file":"gallery-api.js","sourceRoot":"","sources":["../../client/utils/gallery-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAoCxD,MAAM,WAAW,GAAG;8GAC0F,CAAA;AAC9G,MAAM,YAAY,GAAG,gCAAgC,CAAA;AAErD,SAAS,MAAM,CAAI,QAAa,EAAE,KAAa;IAC7C,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IACxG,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAM,CAAA;AACpC,CAAC;AAED,KAAK,UAAU,GAAG,CAAI,KAAa,EAAE,SAAkC,EAAE,KAAa;IACpF,OAAO,MAAM,CAAI,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;AAC5G,CAAC;AAED,KAAK,UAAU,MAAM,CACnB,QAAgB,EAChB,SAAkC,EAClC,KAAa,EACb,SAAsC;IAEtC,OAAO,MAAM,CACX,MAAM,MAAM,CAAC,MAAM,CAAC;QAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC;QACvB,SAAS;QACT,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAC,EACF,KAAK,CACN,CAAA;AACH,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5F,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE,CAAC,MAAc,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,CAC7C,GAAG,CACD,8HAA8H,WAAW,cAAc,EACvJ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EACtB,cAAc,CACf;IACH,IAAI,EAAE,CAAC,EAAU,EAAE,EAAE,CACnB,GAAG,CAAc,iDAAiD,WAAW,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,aAAa,CAAC;IAC7G,MAAM,EAAE,CAAC,EAAU,EAAE,EAAE,CACrB,GAAG,CACD,6DAA6D,EAC7D,EAAE,EAAE,EAAE,EACN,eAAe,CAChB;IACH,IAAI,EAAE,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,CAClB,GAAG,CACD,kEAAkE,EAClE,EAAE,IAAI,EAAE,EACR,aAAa,CACd;IACH,MAAM,EAAE,GAAG,EAAE,CACX,GAAG,CACD,2BAA2B,YAAY,gDAAgD,EACvF,EAAE,EACF,eAAe,CAChB;IACH,YAAY,EAAE,CAAC,OAAgB,EAAE,EAAE,CACjC,GAAG,CACD,4EAA4E,YAAY,WAAW,EACnG,EAAE,OAAO,EAAE,EACX,qBAAqB,CACtB;IACH,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAoB,oCAAoC,EAAE,EAAE,EAAE,gBAAgB,CAAC;IACjG,MAAM,EAAE,CAAC,KAAgB,EAAE,MAAc,EAAE,SAAsC,EAAE,EAAE,CACnF,MAAM,CACJ,mHAAmH,WAAW,MAAM,EACpI,EAAE,KAAK,EAAE,MAAM,EAAE,EACjB,mBAAmB,EACnB,SAAS,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CACxB;IACH,MAAM,EAAE,CAAC,EAAU,EAAE,KAAgB,EAAE,MAAc,EAAE,MAAgB,EAAE,SAAsC,EAAE,EAAE,CACjH,MAAM,CACJ;wFACkF,WAAW;QAC3F,EACF,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAC7B,mBAAmB,EACnB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CACtD;IACH,MAAM,EAAE,CAAC,EAAU,EAAE,EAAE,CACrB,MAAM,CAAU,wDAAwD,EAAE,EAAE,EAAE,EAAE,EAAE,mBAAmB,CAAC;IACxG,IAAI,EAAE,CAAC,EAAU,EAAE,IAAa,EAAE,EAAE,CAClC,MAAM,CACJ,2GAA2G,EAC3G,EAAE,EAAE,EAAE,IAAI,EAAE,EACZ,iBAAiB,CAClB;IACH,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAU,2BAA2B,EAAE,EAAE,EAAE,cAAc,CAAC;IAC7E,IAAI,EAAE,CAAC,EAAU,EAAE,MAAc,EAAE,EAAE,CACnC,MAAM,CACJ,2FAA2F,WAAW,MAAM,EAC5G,EAAE,EAAE,EAAE,MAAM,EAAE,EACd,iBAAiB,CAClB;IACH,MAAM,EAAE,CAAC,EAAU,EAAE,EAAE,CACrB,MAAM,CACJ,0DAA0D,WAAW,MAAM,EAC3E,EAAE,EAAE,EAAE,EACN,mBAAmB,CACpB;IACH,SAAS,EAAE,CAAC,IAAY,EAAE,EAAU,EAAE,EAAE,CACtC,MAAM,CACJ,oFAAoF,EACpF,EAAE,IAAI,EAAE,EAAE,EAAE,EACZ,kBAAkB,CACnB;IACH,WAAW,EAAE,CAAC,KAA0E,EAAE,EAAE,CAC1F,MAAM,CACJ,+EAA+E,YAAY,gBAAgB,EAC3G,EAAE,KAAK,EAAE,EACT,oBAAoB,CACrB;CACJ,CAAA","sourcesContent":["/*\n * The gallery doors as the screens call them (ADR-0165). Every call throws the server's words when it is refused.\n */\nimport gql from 'graphql-tag'\n\nimport { client, uploadContext } from '@operato/graphql'\n\nexport type Space = 'COMPANY' | 'PERSONAL'\nexport type Photo = { id: string; name?: string; thumbnail?: string | null; fullpath: string; mimetype?: string }\nexport type EventFacts = { id: string; name: string; startAt: string; endAt: string; location?: string | null }\nexport type EventCard = EventFacts & { postCount: number; cover?: Photo | null }\nexport type EventChoice = EventFacts & { near: boolean }\n\nexport interface Post {\n id: string\n space: Space\n caption?: string | null\n takenAt: string\n tags?: string[] | null\n likeCount: number\n liked: boolean\n editable: boolean\n moderatable: boolean\n hiddenAt?: string | null\n hiddenReason?: string | null\n createdAt: string\n creator?: { id: string; name?: string } | null\n event?: EventFacts | null\n photos: Photo[]\n}\n\nexport interface PostInput {\n space?: Space\n caption?: string\n takenAt?: string\n tags?: string[]\n eventId?: string | null\n}\n\nexport type Filter = { space?: Space; eventId?: string; tag?: string; authorId?: string }\n\nconst POST_FIELDS = `id space caption takenAt tags likeCount liked editable moderatable hiddenAt hiddenReason createdAt\n creator { id name } event { id name startAt endAt location } photos { id name thumbnail fullpath mimetype }`\nconst EVENT_FIELDS = 'id name startAt endAt location'\n\nfunction answer<T>(response: any, field: string): T {\n if (response.errors?.length) throw new Error(response.errors.map((one: any) => one.message).join(' · '))\n return response.data?.[field] as T\n}\n\nasync function ask<T>(query: string, variables: Record<string, unknown>, field: string): Promise<T> {\n return answer<T>(await client.query({ query: gql(query), variables, fetchPolicy: 'network-only' }), field)\n}\n\nasync function change<T>(\n mutation: string,\n variables: Record<string, unknown>,\n field: string,\n uploading?: (fraction: number) => void\n): Promise<T> {\n return answer<T>(\n await client.mutate({\n mutation: gql(mutation),\n variables,\n ...(uploading ? { context: uploadContext(uploading) } : {})\n }),\n field\n )\n}\n\n/** Tells the open gallery and the menu's count that a post came, changed or went. */\nexport const galleryChanged = () => window.dispatchEvent(new CustomEvent('gallery-changed'))\n\nexport const galleryApi = {\n posts: (filter: Filter, skip = 0, take = 30) =>\n ask<{ items: Post[]; total: number }>(\n `query ($filter: GalleryFilter, $skip: Int, $take: Int) { galleryPosts(filter: $filter, skip: $skip, take: $take) { items { ${POST_FIELDS} } total } }`,\n { filter, skip, take },\n 'galleryPosts'\n ),\n post: (id: string) =>\n ask<Post | null>(`query ($id: String!) { galleryPost(id: $id) { ${POST_FIELDS} } }`, { id }, 'galleryPost'),\n likers: (id: string) =>\n ask<{ id: string; name?: string }[]>(\n `query ($id: String!) { galleryLikers(id: $id) { id name } }`,\n { id },\n 'galleryLikers'\n ),\n tags: (text = '') =>\n ask<{ tag: string; count: number }[]>(\n `query ($text: String) { galleryTags(text: $text) { tag count } }`,\n { text },\n 'galleryTags'\n ),\n events: () =>\n ask<EventCard[]>(\n `query { galleryEvents { ${EVENT_FIELDS} postCount cover { id thumbnail fullpath } } }`,\n {},\n 'galleryEvents'\n ),\n eventChoices: (takenAt?: string) =>\n ask<EventChoice[]>(\n `query ($takenAt: DateTimeISO) { galleryEventChoices(takenAt: $takenAt) { ${EVENT_FIELDS} near } }`,\n { takenAt },\n 'galleryEventChoices'\n ),\n summary: () => ask<{ fresh: number }>(`query { gallerySummary { fresh } }`, {}, 'gallerySummary'),\n create: (input: PostInput, photos: File[], uploading?: (fraction: number) => void) =>\n change<Post>(\n `mutation ($input: GalleryPostInput!, $photos: [Upload!]!) { createGalleryPost(input: $input, photos: $photos) { ${POST_FIELDS} } }`,\n { input, photos },\n 'createGalleryPost',\n uploading ?? (() => {})\n ),\n update: (id: string, input: PostInput, attach: File[], remove: string[], uploading?: (fraction: number) => void) =>\n change<Post>(\n `mutation ($id: String!, $input: GalleryPostInput!, $attach: [Upload!], $remove: [String!]) {\n updateGalleryPost(id: $id, input: $input, attach: $attach, remove: $remove) { ${POST_FIELDS} }\n }`,\n { id, input, attach, remove },\n 'updateGalleryPost',\n attach.length ? (uploading ?? (() => {})) : undefined\n ),\n remove: (id: string) =>\n change<boolean>(`mutation ($id: String!) { deleteGalleryPost(id: $id) }`, { id }, 'deleteGalleryPost'),\n like: (id: string, like: boolean) =>\n change<{ id: string; likeCount: number; liked: boolean }>(\n `mutation ($id: String!, $like: Boolean!) { likeGalleryPost(id: $id, like: $like) { id likeCount liked } }`,\n { id, like },\n 'likeGalleryPost'\n ),\n visit: () => change<boolean>(`mutation { visitGallery }`, {}, 'visitGallery'),\n hide: (id: string, reason: string) =>\n change<Post>(\n `mutation ($id: String!, $reason: String!) { hideGalleryPost(id: $id, reason: $reason) { ${POST_FIELDS} } }`,\n { id, reason },\n 'hideGalleryPost'\n ),\n unhide: (id: string) =>\n change<Post>(\n `mutation ($id: String!) { unhideGalleryPost(id: $id) { ${POST_FIELDS} } }`,\n { id },\n 'unhideGalleryPost'\n ),\n renameTag: (from: string, to: string) =>\n change<number>(\n `mutation ($from: String!, $to: String!) { renameGalleryTag(from: $from, to: $to) }`,\n { from, to },\n 'renameGalleryTag'\n ),\n createEvent: (input: { name: string; startAt: string; endAt: string; location?: string }) =>\n change<EventCard>(\n `mutation ($input: GalleryEventInput!) { createGalleryEvent(input: $input) { ${EVENT_FIELDS} postCount } }`,\n { input },\n 'createGalleryEvent'\n )\n}\n"]}
1
+ {"version":3,"file":"gallery-api.js","sourceRoot":"","sources":["../../client/utils/gallery-api.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The gallery doors as the screens call them (ADR-0165). Every call throws the server's words when it is refused.\n */\nimport gql from 'graphql-tag'\n\nimport { client, uploadContext } from '@operato/graphql'\n\nexport type Space = 'COMPANY' | 'PERSONAL'\nexport type Photo = { id: string; name?: string; thumbnail?: string | null; fullpath: string; mimetype?: string }\nexport type EventFacts = { id: string; name: string; startAt: string; endAt: string; location?: string | null }\nexport type EventCard = EventFacts & { postCount: number; cover?: Photo | null }\nexport type EventChoice = EventFacts & { near: boolean }\n\nexport interface Post {\n id: string\n space: Space\n shared: boolean\n caption?: string | null\n takenAt: string\n tags?: string[] | null\n likeCount: number\n liked: boolean\n editable: boolean\n moderatable: boolean\n hiddenAt?: string | null\n hiddenReason?: string | null\n createdAt: string\n creator?: { id: string; name?: string } | null\n event?: EventFacts | null\n photos: Photo[]\n}\n\nexport interface PostInput {\n space?: Space\n shared?: boolean\n caption?: string\n takenAt?: string\n tags?: string[]\n eventId?: string | null\n}\n\nexport type Filter = { space?: Space; eventId?: string; tag?: string; authorId?: string; mine?: boolean; everyone?: boolean }\n\nconst POST_FIELDS = `id space shared caption takenAt tags likeCount liked editable moderatable hiddenAt hiddenReason createdAt\n creator { id name } event { id name startAt endAt location } photos { id name thumbnail fullpath mimetype }`\nconst EVENT_FIELDS = 'id name startAt endAt location'\n\nfunction answer<T>(response: any, field: string): T {\n if (response.errors?.length) throw new Error(response.errors.map((one: any) => one.message).join(' · '))\n return response.data?.[field] as T\n}\n\nasync function ask<T>(query: string, variables: Record<string, unknown>, field: string): Promise<T> {\n return answer<T>(await client.query({ query: gql(query), variables, fetchPolicy: 'network-only' }), field)\n}\n\nasync function change<T>(\n mutation: string,\n variables: Record<string, unknown>,\n field: string,\n uploading?: (fraction: number) => void\n): Promise<T> {\n return answer<T>(\n await client.mutate({\n mutation: gql(mutation),\n variables,\n ...(uploading ? { context: uploadContext(uploading) } : {})\n }),\n field\n )\n}\n\n/** Tells the open gallery and the menu's count that a post came, changed or went. */\nexport const galleryChanged = () => window.dispatchEvent(new CustomEvent('gallery-changed'))\n\nexport const galleryApi = {\n posts: (filter: Filter, skip = 0, take = 30) =>\n ask<{ items: Post[]; total: number }>(\n `query ($filter: GalleryFilter, $skip: Int, $take: Int) { galleryPosts(filter: $filter, skip: $skip, take: $take) { items { ${POST_FIELDS} } total } }`,\n { filter, skip, take },\n 'galleryPosts'\n ),\n post: (id: string) =>\n ask<Post | null>(`query ($id: String!) { galleryPost(id: $id) { ${POST_FIELDS} } }`, { id }, 'galleryPost'),\n likers: (id: string) =>\n ask<{ id: string; name?: string }[]>(\n `query ($id: String!) { galleryLikers(id: $id) { id name } }`,\n { id },\n 'galleryLikers'\n ),\n tags: (text = '') =>\n ask<{ tag: string; count: number }[]>(\n `query ($text: String) { galleryTags(text: $text) { tag count } }`,\n { text },\n 'galleryTags'\n ),\n events: () =>\n ask<EventCard[]>(\n `query { galleryEvents { ${EVENT_FIELDS} postCount cover { id thumbnail fullpath } } }`,\n {},\n 'galleryEvents'\n ),\n eventChoices: (takenAt?: string) =>\n ask<EventChoice[]>(\n `query ($takenAt: DateTimeISO) { galleryEventChoices(takenAt: $takenAt) { ${EVENT_FIELDS} near } }`,\n { takenAt },\n 'galleryEventChoices'\n ),\n summary: () => ask<{ fresh: number }>(`query { gallerySummary { fresh } }`, {}, 'gallerySummary'),\n create: (input: PostInput, photos: File[], uploading?: (fraction: number) => void) =>\n change<Post>(\n `mutation ($input: GalleryPostInput!, $photos: [Upload!]!) { createGalleryPost(input: $input, photos: $photos) { ${POST_FIELDS} } }`,\n { input, photos },\n 'createGalleryPost',\n uploading ?? (() => {})\n ),\n update: (id: string, input: PostInput, attach: File[], remove: string[], uploading?: (fraction: number) => void) =>\n change<Post>(\n `mutation ($id: String!, $input: GalleryPostInput!, $attach: [Upload!], $remove: [String!]) {\n updateGalleryPost(id: $id, input: $input, attach: $attach, remove: $remove) { ${POST_FIELDS} }\n }`,\n { id, input, attach, remove },\n 'updateGalleryPost',\n attach.length ? (uploading ?? (() => {})) : undefined\n ),\n remove: (id: string) =>\n change<boolean>(`mutation ($id: String!) { deleteGalleryPost(id: $id) }`, { id }, 'deleteGalleryPost'),\n like: (id: string, like: boolean) =>\n change<{ id: string; likeCount: number; liked: boolean }>(\n `mutation ($id: String!, $like: Boolean!) { likeGalleryPost(id: $id, like: $like) { id likeCount liked } }`,\n { id, like },\n 'likeGalleryPost'\n ),\n visit: () => change<boolean>(`mutation { visitGallery }`, {}, 'visitGallery'),\n hide: (id: string, reason: string) =>\n change<Post>(\n `mutation ($id: String!, $reason: String!) { hideGalleryPost(id: $id, reason: $reason) { ${POST_FIELDS} } }`,\n { id, reason },\n 'hideGalleryPost'\n ),\n unhide: (id: string) =>\n change<Post>(\n `mutation ($id: String!) { unhideGalleryPost(id: $id) { ${POST_FIELDS} } }`,\n { id },\n 'unhideGalleryPost'\n ),\n renameTag: (from: string, to: string) =>\n change<number>(\n `mutation ($from: String!, $to: String!) { renameGalleryTag(from: $from, to: $to) }`,\n { from, to },\n 'renameGalleryTag'\n ),\n createEvent: (input: { name: string; startAt: string; endAt: string; location?: string }) =>\n change<EventCard>(\n `mutation ($input: GalleryEventInput!) { createGalleryEvent(input: $input) { ${EVENT_FIELDS} postCount } }`,\n { input },\n 'createGalleryEvent'\n )\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /** The waits the setting offers, in minutes; 0 is off. */
2
+ export declare const SAVER_MINUTES: number[];
3
+ export declare function saverMinutes(): Promise<number>;
4
+ export declare function setSaverMinutes(minutes: number): Promise<void>;
5
+ /** Watches for the quiet stretch, once per application. */
6
+ export declare function watchForSaver(): void;
@@ -0,0 +1,69 @@
1
+ /*
2
+ * The gallery as the screen saver (ADR-0165 decision 9): after the minutes set on this device with no press, move or
3
+ * key, the gallery everyone sees - the company's and the shared own photos - plays over the window until the person
4
+ * comes back. Kept on the device (`clientSettingStore`),
5
+ * since it is the screen that is left - a meeting room's display, not the person - and off until it is turned on.
6
+ */
7
+ import { clientSettingStore } from '@operato/shell';
8
+ import { auth } from '@things-factory/auth-base/dist-client';
9
+ import { GalleryShow } from '../components/gallery-show.js';
10
+ const KEY = 'gallery-saver';
11
+ /** The waits the setting offers, in minutes; 0 is off. */
12
+ export const SAVER_MINUTES = [0, 5, 10, 30];
13
+ /** What says the person is here. */
14
+ const PRESENCE = ['pointermove', 'pointerdown', 'keydown', 'wheel', 'touchstart'];
15
+ export async function saverMinutes() {
16
+ try {
17
+ const minutes = Number((await clientSettingStore.get(KEY))?.value?.minutes);
18
+ return SAVER_MINUTES.includes(minutes) ? minutes : 0;
19
+ }
20
+ catch {
21
+ return 0;
22
+ }
23
+ }
24
+ export async function setSaverMinutes(minutes) {
25
+ await clientSettingStore.put({ key: KEY, value: { minutes } });
26
+ window.dispatchEvent(new CustomEvent('gallery-saver-changed'));
27
+ }
28
+ let minutes = 0;
29
+ let timer;
30
+ let signedIn = false;
31
+ let showing;
32
+ function wait() {
33
+ clearTimeout(timer);
34
+ if (!minutes || !signedIn || showing)
35
+ return;
36
+ timer = setTimeout(start, minutes * 60_000);
37
+ }
38
+ function start() {
39
+ /* A hidden tab is not looked at; it waits for the next quiet stretch after it is shown. */
40
+ if (document.visibilityState !== 'visible' || document.querySelector('gallery-show'))
41
+ return wait();
42
+ /* What everyone sees - never the photos the device's person keeps to themselves. */
43
+ showing = GalleryShow.open({ filter: { everyone: true }, saver: true });
44
+ showing.addEventListener('closed', () => {
45
+ showing = undefined;
46
+ wait();
47
+ });
48
+ }
49
+ /** Watches for the quiet stretch, once per application. */
50
+ export function watchForSaver() {
51
+ const read = async () => {
52
+ minutes = await saverMinutes();
53
+ wait();
54
+ };
55
+ for (const name of PRESENCE)
56
+ window.addEventListener(name, () => !showing && wait(), { passive: true, capture: true });
57
+ document.addEventListener('visibilitychange', () => document.visibilityState === 'visible' && wait());
58
+ window.addEventListener('gallery-saver-changed', read);
59
+ auth.on('profile', () => {
60
+ signedIn = true;
61
+ read();
62
+ });
63
+ auth.on('signout', () => {
64
+ signedIn = false;
65
+ clearTimeout(timer);
66
+ showing?.close();
67
+ });
68
+ }
69
+ //# sourceMappingURL=gallery-saver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gallery-saver.js","sourceRoot":"","sources":["../../client/utils/gallery-saver.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The gallery as the screen saver (ADR-0165 decision 9): after the minutes set on this device with no press, move or\n * key, the gallery everyone sees - the company's and the shared own photos - plays over the window until the person\n * comes back. Kept on the device (`clientSettingStore`),\n * since it is the screen that is left - a meeting room's display, not the person - and off until it is turned on.\n */\nimport { clientSettingStore } from '@operato/shell'\nimport { auth } from '@things-factory/auth-base/dist-client'\n\nimport { GalleryShow } from '../components/gallery-show.js'\n\nconst KEY = 'gallery-saver'\n/** The waits the setting offers, in minutes; 0 is off. */\nexport const SAVER_MINUTES = [0, 5, 10, 30]\n/** What says the person is here. */\nconst PRESENCE = ['pointermove', 'pointerdown', 'keydown', 'wheel', 'touchstart']\n\nexport async function saverMinutes(): Promise<number> {\n try {\n const minutes = Number((await clientSettingStore.get(KEY))?.value?.minutes)\n return SAVER_MINUTES.includes(minutes) ? minutes : 0\n } catch {\n return 0\n }\n}\n\nexport async function setSaverMinutes(minutes: number) {\n await clientSettingStore.put({ key: KEY, value: { minutes } })\n window.dispatchEvent(new CustomEvent('gallery-saver-changed'))\n}\n\nlet minutes = 0\nlet timer: ReturnType<typeof setTimeout> | undefined\nlet signedIn = false\nlet showing: GalleryShow | undefined\n\nfunction wait() {\n clearTimeout(timer)\n if (!minutes || !signedIn || showing) return\n timer = setTimeout(start, minutes * 60_000)\n}\n\nfunction start() {\n /* A hidden tab is not looked at; it waits for the next quiet stretch after it is shown. */\n if (document.visibilityState !== 'visible' || document.querySelector('gallery-show')) return wait()\n /* What everyone sees - never the photos the device's person keeps to themselves. */\n showing = GalleryShow.open({ filter: { everyone: true }, saver: true })\n showing.addEventListener('closed', () => {\n showing = undefined\n wait()\n })\n}\n\n/** Watches for the quiet stretch, once per application. */\nexport function watchForSaver() {\n const read = async () => {\n minutes = await saverMinutes()\n wait()\n }\n for (const name of PRESENCE) window.addEventListener(name, () => !showing && wait(), { passive: true, capture: true })\n document.addEventListener('visibilitychange', () => document.visibilityState === 'visible' && wait())\n window.addEventListener('gallery-saver-changed', read)\n auth.on('profile', () => {\n signedIn = true\n read()\n })\n auth.on('signout', () => {\n signedIn = false\n clearTimeout(timer)\n showing?.close()\n })\n}\n"]}
@@ -83,16 +83,18 @@ async function seenPosts(context) {
83
83
  if (!viewer.moderator)
84
84
  qb.andWhere('(P.hiddenAt IS NULL OR P.creator = :me)', { me: user.id });
85
85
  const active = [...viewer.activePeople];
86
- /* The own gallery of someone who left is no longer shown (decision 5). */
86
+ /* The own gallery is its owner's until shared (decision 2), and no longer shown when they left (decision 5). */
87
87
  qb.andWhere(active.length
88
- ? '(P.space != :personal OR P.creator = :me OR P.creator IN (:...active))'
88
+ ? '(P.space != :personal OR P.creator = :me OR (P.shared = :shared AND P.creator IN (:...active)))'
89
89
  : '(P.space != :personal OR P.creator = :me)', {
90
90
  personal: gallery_1.GallerySpace.PERSONAL,
91
+ shared: true,
91
92
  me: user.id,
92
93
  active
93
94
  });
94
95
  return qb;
95
96
  }
97
+ /* Calendar's refusals (createGalleryEvent calls its createEvent) are spoken in the reader's language only through this. */
96
98
  let GalleryResolver = class GalleryResolver {
97
99
  /* ---------------------------------------------------------------- looking */
98
100
  async galleryPosts(filter, skip, take, context) {
@@ -103,6 +105,12 @@ let GalleryResolver = class GalleryResolver {
103
105
  qb.andWhere('P.event = :event', { event: filter.eventId });
104
106
  if (filter?.authorId)
105
107
  qb.andWhere('P.creator = :author', { author: filter.authorId });
108
+ /* The own gallery is the asker's, known here - the client's profile carries no user id (2026-10-31). */
109
+ if (filter?.mine)
110
+ qb.andWhere('P.creator = :me', { me: context.state.user.id });
111
+ /* What a shared screen may show - the screen saver (decision 9): never one's own unshared photos. */
112
+ if (filter?.everyone)
113
+ qb.andWhere('(P.space != :personal OR P.shared = :shared)', { personal: gallery_1.GallerySpace.PERSONAL, shared: true });
106
114
  const tag = (0, gallery_rules_1.tagOf)(filter?.tag ?? '');
107
115
  /* Tags are kept as a JSON list: the quotes bound the word, so 「워크숍」 does not find 「워크숍2026」. */
108
116
  if (tag)
@@ -188,6 +196,7 @@ let GalleryResolver = class GalleryResolver {
188
196
  const post = await (0, shell_1.getRepository)(gallery_1.GalleryPost, tx).save({
189
197
  domain,
190
198
  space: eventId ? gallery_1.GallerySpace.COMPANY : (input.space ?? gallery_1.GallerySpace.COMPANY),
199
+ shared: !!input.shared,
191
200
  caption: input.caption?.trim() || null,
192
201
  takenAt: input.takenAt ?? new Date(),
193
202
  tags: (0, gallery_rules_1.tagsOf)(input.tags),
@@ -219,6 +228,7 @@ let GalleryResolver = class GalleryResolver {
219
228
  : null;
220
229
  await (0, shell_1.getRepository)(gallery_1.GalleryPost, tx).update(post.id, {
221
230
  space: eventId ? gallery_1.GallerySpace.COMPANY : (input.space ?? post.space),
231
+ shared: input.shared ?? post.shared,
222
232
  caption: input.caption?.trim() || null,
223
233
  takenAt: input.takenAt ?? post.takenAt,
224
234
  tags: (0, gallery_rules_1.tagsOf)(input.tags),
@@ -597,6 +607,7 @@ tslib_1.__decorate([
597
607
  tslib_1.__metadata("design:returntype", Promise)
598
608
  ], GalleryResolver.prototype, "hiddenReason", null);
599
609
  exports.GalleryResolver = GalleryResolver = tslib_1.__decorate([
610
+ (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals),
600
611
  (0, type_graphql_1.Resolver)(gallery_1.GalleryPost)
601
612
  ], GalleryResolver);
602
613
  //# sourceMappingURL=gallery-resolver.js.map
@@ -1 +1 @@
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 } 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 } 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 of someone who left is no longer shown (decision 5). */\n qb.andWhere(\n active.length\n ? '(P.space != :personal OR P.creator = :me OR P.creator IN (:...active))'\n : '(P.space != :personal OR P.creator = :me)',\n {\n personal: GallerySpace.PERSONAL,\n me: user.id,\n active\n }\n )\n return qb\n}\n\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 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 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 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
+ {"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"]}
@@ -36,12 +36,14 @@ export type Viewer = {
36
36
  };
37
37
  export type SeenPost = {
38
38
  space: string;
39
+ shared?: boolean | null;
39
40
  creatorId?: string | null;
40
41
  hiddenAt?: Date | string | null;
41
42
  };
42
43
  /**
43
- * Whether the viewer sees the post. Everyone of the domain sees every post (decision 2), except a hidden one - its
44
- * owner and the moderators see that - and the own gallery of someone who left (decision 5).
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).
45
47
  */
46
48
  export declare function seesPost(post: SeenPost, viewer: Viewer): boolean;
47
49
  /** Whether a photo taken at `takenAt` is near the event - from a day before it starts to a day after it ends. */
@@ -106,14 +106,15 @@ function tagCounts(lists, text = '', limit = 20) {
106
106
  .slice(0, limit);
107
107
  }
108
108
  /**
109
- * Whether the viewer sees the post. Everyone of the domain sees every post (decision 2), except a hidden one - its
110
- * owner and the moderators see that - and the own gallery of someone who left (decision 5).
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).
111
112
  */
112
113
  function seesPost(post, viewer) {
113
114
  const own = !!post.creatorId && post.creatorId === viewer.userId;
114
115
  if (post.hiddenAt && !own && !viewer.moderator)
115
116
  return false;
116
- if (post.space === 'PERSONAL' && !own && !viewer.activePeople.has(post.creatorId ?? ''))
117
+ if (post.space === 'PERSONAL' && !own && !(post.shared && viewer.activePeople.has(post.creatorId ?? '')))
117
118
  return false;
118
119
  return true;
119
120
  }
@@ -1 +1 @@
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; creatorId?: string | null; hiddenAt?: Date | string | null }\n\n/**\n * Whether the viewer sees the post. Everyone of the domain sees every post (decision 2), except a hidden one - its\n * owner and the moderators see that - and the own gallery of someone who left (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 && !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
+ {"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"]}
@@ -43,6 +43,7 @@ export declare class GalleryLikeState {
43
43
  }
44
44
  export declare class GalleryPostInput {
45
45
  space?: GallerySpace;
46
+ shared?: boolean;
46
47
  caption?: string;
47
48
  takenAt?: Date;
48
49
  tags?: string[];
@@ -53,6 +54,8 @@ export declare class GalleryFilter {
53
54
  eventId?: string;
54
55
  tag?: string;
55
56
  authorId?: string;
57
+ mine?: boolean;
58
+ everyone?: boolean;
56
59
  }
57
60
  export declare class GalleryEventInput {
58
61
  name: string;