Compare commits

...

235 Commits

Author SHA1 Message Date
0bf724f0c0
fix(webapp): fix & improve map substantially (#9481) 2026-04-02 18:59:49 +00:00
4c539406bc
fix(webapp): fix mobile invites, settings & global page paddings (#9478) 2026-04-02 02:07:49 +00:00
192104664d
chore(other): temporary filter some files for coderabbit (#9480) 2026-04-02 00:56:34 +00:00
9cba88cb68
fix(package/ui): fix package ui regression target on icons (#9479) 2026-04-02 00:16:54 +00:00
2cd07950c6
refactor(backend): improve map performance (#9476) 2026-04-01 17:44:24 +00:00
Wolfgang Huß
b07830769d
feat(webapp): replace language switch logo (#9475) 2026-04-01 18:55:25 +02:00
7431c4685c
fix(maintenance): fix maintenance image build (#9473) 2026-04-01 03:03:26 +00:00
cd866f55c2
fix(maintenance): fix branded maintenance (#9472) 2026-04-01 02:34:07 +00:00
e931d6e03b
feat(webapp): group chat (#9439) 2026-04-01 00:48:28 +00:00
dependabot[bot]
1be90b4976
build(deps): bump nodemailer from 8.0.3 to 8.0.4 in /backend (#9451)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 02:07:58 +00:00
202c869515
feat(package/ui): os-counter-icon (#9471) 2026-03-30 01:28:55 +00:00
e144170cf0
feat(package/ui): actionButton + labledButton (#9470) 2026-03-30 00:16:21 +00:00
8849db6cbf
refactor(webapp): extract password form into its own component (#9469) 2026-03-29 15:27:12 +00:00
dependabot[bot]
da95664285
build(deps): bump nginx from 1.29.6-alpine to 1.29.7-alpine in /maintenance (#9467)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 16:25:52 +02:00
dependabot[bot]
bbff1b81a2
build(deps): bump node from 25.8.1-alpine to 25.8.2-alpine in /maintenance (#9468)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 13:28:00 +00:00
01a951e77b
feat(maintenance): new maintenance page (#9445) 2026-03-29 05:27:02 +00:00
dependabot[bot]
602fa0c26e
build(deps): bump node from 25.8.1-alpine to 25.8.2-alpine in /webapp (#9448)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 04:22:41 +02:00
dependabot[bot]
d9e0192aea
build(deps): bump node from 25.8.1-alpine to 25.8.2-alpine in /backend (#9447)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 01:25:10 +00:00
dependabot[bot]
e756c11ff8
build(deps): bump nginx from 1.29.6-alpine to 1.29.7-alpine in /webapp (#9446)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 00:52:04 +00:00
dependabot[bot]
2b188dfa09
build(deps): bump graphql from 16.13.1 to 16.13.2 in /backend (#9456)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-29 00:40:44 +01:00
dependabot[bot]
8680477839
build(deps): bump ws from 8.19.0 to 8.20.0 in /backend (#9458)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 23:14:19 +00:00
dependabot[bot]
81ac3303db
build(deps-dev): bump the vitest group in /packages/ui with 2 updates (#9460)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 23:44:47 +01:00
dependabot[bot]
e75ae18e2b
build(deps-dev): bump @storybook/vue3-vite from 10.3.1 to 10.3.3 in /packages/ui (#9463)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 22:12:23 +00:00
dependabot[bot]
c446e58bbc
build(deps): bump peter-evans/repository-dispatch from 11446b25a5fd252975d4bdf43d8989a5ac4f16c5 to 1a91c28090489a711dd89a2424bb13d72a56e2e4 (#9459)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 22:45:55 +01:00
dependabot[bot]
14e0566800
build(deps-dev): bump eslint-plugin-jsdoc from 62.8.0 to 62.8.1 in /packages/ui (#9464)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 17:15:31 +00:00
dependabot[bot]
61267d4bf7
build(deps-dev): bump eslint-plugin-storybook from 10.2.19 to 10.3.3 in /packages/ui (#9466)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 16:44:55 +00:00
dependabot[bot]
ec1af07374
build(deps-dev): bump storybook from 10.3.1 to 10.3.3 in /packages/ui (#9465)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-28 11:52:25 +00:00
b088ec9e62
refactor(backend): remove content excerpt (#9441) 2026-03-27 13:38:46 +00:00
33f522ed16
fix(webapp): properly bind css from lokal package-ui to avoid outdated build files (#9444) 2026-03-27 13:17:24 +00:00
4407eab8e3
fix(webapp): fix post teaser icon positioning (#9442) 2026-03-27 12:41:48 +01:00
b0b755d6bd
fix(webapp): fix svgs in chat (#9440) 2026-03-26 19:28:09 +00:00
779841a711
fix(webapp): fix error in chat when message is undefined or null (#9438) 2026-03-26 10:02:47 +00:00
b629307f4e
chore(release): v3.15.1 (#9437) 2026-03-24 13:15:01 +00:00
0257cf8ee6
fix(webapp): fix dependency problem - async-validator required in production (#9436) 2026-03-24 12:51:37 +00:00
dab7c8dfeb
chore(release): v3.15.0 (#9434) 2026-03-24 11:08:52 +00:00
53a13c2173
fix(backend): fix flaky backend tests (#9433) 2026-03-24 01:38:16 +00:00
fa5c225138
refactor(webapp): remove styleguide (#9432) 2026-03-24 01:02:33 +00:00
75c1232860
feat(package/ui): os-menu (#9431) 2026-03-23 21:32:50 +00:00
cadd0d0286
refactor(webapp): migrate ds-select to OcelotSelect (#9430) 2026-03-23 16:57:02 +00:00
d62abc524b
refactor(webapp): replace ds-icon with OsIcon and add missing svgs (#9429) 2026-03-23 15:13:16 +00:00
7eb1bbdb3f
refactor(webapp): migrate ds-input to OcelotInput (#9428) 2026-03-23 14:12:57 +00:00
dependabot[bot]
9a92e2209f
build(deps): bump graphql from 16.13.0 to 16.13.1 in /backend (#9354)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-23 00:05:10 +00:00
dependabot[bot]
b94f869d3f
build(deps): bump sanitize-html from 2.17.1 to 2.17.2 in /backend (#9420)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 21:52:33 +00:00
dependabot[bot]
6859e7c65e
build(deps-dev): bump jsdom from 28.1.0 to 29.0.1 in /packages/ui (#9413)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 22:17:49 +01:00
dependabot[bot]
4359b3da80
build(deps): bump actions/cache from 5.0.3 to 5.0.4 (#9410)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 19:53:16 +00:00
dependabot[bot]
5e40ab0df1
build(deps-dev): bump @tailwindcss/vite from 4.2.1 to 4.2.2 in /packages/ui (#9419)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 17:15:45 +00:00
dependabot[bot]
53a52e7ada
build(deps-dev): bump @storybook/vue3-vite from 10.2.19 to 10.3.1 in /packages/ui (#9418)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 17:44:47 +01:00
dependabot[bot]
70ab1cf003
build(deps): bump ioredis from 5.10.0 to 5.10.1 in /backend (#9425)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 12:35:14 +00:00
dependabot[bot]
4ca66d755b
build(deps-dev): bump @tailwindcss/cli from 4.2.1 to 4.2.2 in /packages/ui (#9421)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 12:05:19 +00:00
dependabot[bot]
0ecb8e576e
build(deps-dev): bump tailwindcss from 4.2.1 to 4.2.2 in /packages/ui (#9422)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 12:12:32 +01:00
dependabot[bot]
41d40405d9
build(deps-dev): bump eslint-plugin-playwright from 2.9.0 to 2.10.1 in /packages/ui (#9424)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-21 21:54:30 +00:00
dependabot[bot]
b88df05280
build(deps): bump node from 25.8.0-alpine to 25.8.1-alpine in /backend (#9377)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-21 21:10:36 +00:00
dependabot[bot]
d291b56992
build(deps): bump node from 25.8.0-alpine to 25.8.1-alpine in /webapp (#9378)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-21 01:27:48 +00:00
dependabot[bot]
f67bb0319d
build(deps): bump the metascraper group in /backend with 12 updates (#9384)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-21 00:54:38 +00:00
dependabot[bot]
86aec37ec5
build(deps): bump dorny/paths-filter from 3.0.2 to 4.0.1 (#9380)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-21 00:25:59 +00:00
dependabot[bot]
6f7e800644
build(deps): bump nodemailer from 8.0.1 to 8.0.2 in /backend (#9388)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 23:54:29 +00:00
dependabot[bot]
75844940a6
build(deps-dev): bump @types/node from 25.4.0 to 25.5.0 in /backend (#9391)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 22:00:50 +01:00
dependabot[bot]
4283c997d6
build(deps): bump pug from 3.0.3 to 3.0.4 in /backend (#9385)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 20:13:26 +00:00
dependabot[bot]
c1810dcd6f
build(deps): bump nginx from 1.29.5-alpine to 1.29.6-alpine in /webapp (#9379)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 19:41:31 +00:00
194fc53ade
fix(package/ui): override active hover effect of disabled button to not create visual glitches when button state changes (#9408) 2026-03-20 19:02:57 +00:00
906ac801be
refactor(webapp): vue 3 migration - ds-form (#9407) 2026-03-20 17:14:59 +00:00
dependabot[bot]
16c4f03d3f
build(deps): bump slugify from 1.6.6 to 1.6.8 in /backend (#9390)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-18 04:17:19 +01:00
dependabot[bot]
484489b685
build(deps-dev): bump the vitest group in /packages/ui with 2 updates (#9394)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 21:34:43 +00:00
dependabot[bot]
3ec0d111f9
build(deps-dev): bump @types/node from 25.3.5 to 25.5.0 in /packages/ui (#9396)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 19:51:13 +00:00
dependabot[bot]
8a5ead9724
build(deps-dev): bump jest from 30.2.0 to 30.3.0 in /backend (#9398)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 18:59:36 +00:00
dependabot[bot]
35f2934570
build(deps-dev): bump eslint-plugin-jsdoc from 62.7.1 to 62.8.0 in /packages/ui (#9399)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 18:14:50 +00:00
dependabot[bot]
21a599d739
build(deps-dev): bump @storybook/vue3-vite from 10.2.17 to 10.2.19 in /packages/ui (#9400)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 18:26:26 +01:00
dependabot[bot]
0828645c9c
build(deps-dev): bump eslint-plugin-storybook from 10.2.17 to 10.2.19 in /packages/ui (#9401)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-17 17:48:04 +01:00
3fdb77fe2e
fix(webapp): fix flaky e2e test (#9404) 2026-03-15 16:37:28 +00:00
4727eb6eb4
refactor(webapp): ds-radio -> html (#9403) 2026-03-14 17:35:54 +00:00
83df85001d
fix(webapp): fix search + search e2e (#9376) 2026-03-13 19:10:38 +00:00
237798b0f0
feat(package/ui): os-modal & webapp integration (#9375) 2026-03-13 02:30:54 +00:00
f5b5c6d306
refactor(webapp): pin and unpin network-wide clarification (#9374) 2026-03-12 18:39:30 +00:00
9fa4d6a95e
feat(backend): translate all emails into missing languages (#9372) 2026-03-12 16:11:16 +00:00
0a8f09c4d4
fix(webapp): fix distance of spinner in feed (#9373) 2026-03-12 15:39:16 +00:00
9d048b67f9
feat(webapp): ukrainian language translation (#9371) 2026-03-12 15:09:23 +00:00
0df685f372
fix(webapp): fix date select language crash (#9370) 2026-03-11 15:45:11 +00:00
3af5601132
fix(webapp): fix user teaser group name color (now grey) (#9367)
Co-authored-by: Wolfgang Huß <wolle.huss@pjannto.com>
2026-03-11 14:54:01 +00:00
5ad0689dda
fix(package/ui): update eslint-config-it4c & fix lint errors (#9368) 2026-03-11 13:57:24 +00:00
dependabot[bot]
021143eac4
build(deps): bump docker/login-action from 3.7.0 to 4.0.0 (#9349)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 05:01:16 +01:00
dependabot[bot]
43b8655451
build(deps): bump crazy-max/ghaction-github-pages from 4.2.0 to 5.0.0 (#9347)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 02:23:02 +00:00
dependabot[bot]
f93c80b4ee
build(deps): bump docker/metadata-action from 5.10.0 to 6.0.0 (#9345)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 03:00:56 +01:00
dependabot[bot]
90c8c1cb5a
build(deps): bump node from 25.7.0-alpine to 25.8.0-alpine in /backend (#9343)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 01:48:51 +01:00
dependabot[bot]
051698656e
build(deps): bump node from 25.7.0-alpine to 25.8.0-alpine in /webapp (#9344)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 18:37:05 +01:00
dependabot[bot]
d57ff0c7c7
build(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0 (#9348)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 16:38:10 +00:00
dependabot[bot]
a370a949cf
build(deps): bump peter-evans/repository-dispatch from f49a8ac5751834a0666df77deb0289abbe2b3a78 to 11446b25a5fd252975d4bdf43d8989a5ac4f16c5 (#9346)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 15:51:00 +00:00
dependabot[bot]
097949af48
build(deps): bump docker/build-push-action from 6.19.2 to 7.0.0 (#9350)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 15:04:27 +00:00
dependabot[bot]
1255f32221
build(deps-dev): bump webpack from 5.105.3 to 5.105.4 (#9351)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 11:09:45 +00:00
dependabot[bot]
17db0530c9
build(deps-dev): bump @types/node from 25.3.2 to 25.3.5 in /backend (#9352)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-10 11:45:19 +01:00
dependabot[bot]
4282c033f1
build(deps-dev): bump eslint-plugin-playwright from 2.8.0 to 2.9.0 in /packages/ui (#9358)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 22:57:24 +00:00
dependabot[bot]
7872532597
build(deps): bump @aws-sdk/client-s3 from 3.1000.0 to 3.1004.0 in /backend (#9356)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 22:30:07 +00:00
dependabot[bot]
f44ddd91c0
build(deps-dev): bump @size-limit/file from 12.0.0 to 12.0.1 in /packages/ui (#9359)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 21:43:56 +00:00
dependabot[bot]
f530dc7bf2
build(deps-dev): bump eslint-plugin-storybook from 10.2.13 to 10.2.16 in /packages/ui (#9360)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 20:59:45 +00:00
dependabot[bot]
65dbfc74f6
build(deps-dev): bump @storybook/vue3-vite from 10.2.13 to 10.2.16 in /packages/ui (#9361)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 18:29:40 +00:00
dependabot[bot]
8f87075a99
build(deps-dev): bump storybook from 10.2.13 to 10.2.16 in /packages/ui (#9362)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 17:13:06 +00:00
207640bc7f
refactor(docker): mount styleguide and packages/ui in docker-compose.override.yml (#9342) 2026-03-09 17:26:34 +01:00
dependabot[bot]
6d42a2f04f
build(deps-dev): bump publint from 0.3.17 to 0.3.18 in /packages/ui (#9364)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 12:13:55 +00:00
dependabot[bot]
c61fb02396
build(deps-dev): bump @types/node from 25.3.2 to 25.3.5 in /packages/ui (#9366)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 12:14:47 +01:00
dependabot[bot]
c0a5a84ef5
build(deps): bump node from 25.6.1-alpine to 25.7.0-alpine in /backend (#9304)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-04 08:53:48 +00:00
dependabot[bot]
c018a6fa74
build(deps): bump node from 25.6.1-alpine to 25.7.0-alpine in /webapp (#9305)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-03 00:15:03 +01:00
dependabot[bot]
603cbc5420
build(deps): bump actions/download-artifact from 4 to 8 (#9306)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 23:21:53 +01:00
71a00f55ca
fix(backend): ensure req.body exists with global parser setup (#9340) 2026-03-02 12:34:49 +00:00
Moriz Wahl
ac228ebdfc
fix(webapp): remove flags from locales (#9341) 2026-03-02 12:11:26 +00:00
dependabot[bot]
bfb765a4af
build(deps): bump actions/upload-artifact from 6 to 7 (#9307)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 09:41:30 +00:00
fa604de702
refactor(e2e): remove e2e relics (#9336) 2026-03-02 09:17:59 +00:00
2bb9d793a5
feat(backend): smtp - new config variable to allow ignoring tls errors (#9339) 2026-03-02 00:56:15 +00:00
dependabot[bot]
1f7e7c95ac
build(deps): bump ioredis from 5.9.3 to 5.10.0 in /backend (#9308)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 18:57:13 +00:00
2ca5fe20aa
fix(webapp): meta - description (#9338) 2026-03-01 11:39:30 +00:00
d543c192a8
fix(webapp): fix lang query location (#9337) 2026-03-01 10:00:37 +00:00
4b0470310e
feat(webapp): metadata for link preview (#9335) 2026-03-01 07:06:50 +00:00
dependabot[bot]
3a56878899
build(deps-dev): bump the cypress group with 2 updates (#9309)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 06:42:48 +00:00
dependabot[bot]
762037c7b8
build(deps-dev): bump webpack from 5.105.2 to 5.105.3 (#9311)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 06:09:53 +00:00
dependabot[bot]
c10b2e1af7
build(deps): bump minimatch from 10.2.2 to 10.2.4 in /backend (#9313)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 05:45:18 +00:00
dependabot[bot]
6e53c53f38
build(deps-dev): bump @types/lodash from 4.17.23 to 4.17.24 in /backend (#9314)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 05:18:55 +00:00
dependabot[bot]
8690adf895
build(deps-dev): bump the vue group in /packages/ui with 2 updates (#9315)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 05:21:10 +01:00
dependabot[bot]
8216db5925
build(deps): bump @aws-sdk/lib-storage from 3.990.0 to 3.995.0 in /backend (#9316)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 03:27:24 +00:00
dependabot[bot]
9f71ac2ece
build(deps-dev): bump @storybook/vue3-vite from 10.2.10 to 10.2.13 in /packages/ui (#9318)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 03:59:15 +01:00
dependabot[bot]
f4bea134a2
build(deps-dev): bump eslint-plugin-jsdoc from 62.7.0 to 62.7.1 in /packages/ui (#9320)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 03:18:04 +01:00
dependabot[bot]
fb4830c0b0
build(deps-dev): bump @types/node from 25.3.0 to 25.3.2 in /backend (#9323)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 17:41:41 +01:00
dependabot[bot]
07ff56ccb3
build(deps-dev): bump @tailwindcss/vite from 4.2.0 to 4.2.1 in /packages/ui (#9325)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 13:50:31 +00:00
dependabot[bot]
73dfda12da
build(deps): bump graphql from 16.12.0 to 16.13.0 in /backend (#9324)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 14:25:56 +01:00
dependabot[bot]
907d9abcb6
build(deps-dev): bump @types/node from 25.3.0 to 25.3.2 in /packages/ui (#9328)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 12:14:26 +00:00
dependabot[bot]
272a6a4b0a
build(deps-dev): bump eslint-plugin-playwright from 2.7.0 to 2.8.0 in /packages/ui (#9329)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 10:19:25 +00:00
dependabot[bot]
c910931fc1
build(deps-dev): bump eslint-plugin-storybook from 10.2.10 to 10.2.13 in /packages/ui (#9330)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 09:38:32 +00:00
dependabot[bot]
9f742ffbde
build(deps): bump @aws-sdk/client-s3 from 3.995.0 to 3.1000.0 in /backend (#9331)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 08:57:51 +00:00
dependabot[bot]
85efb3b161
build(deps-dev): bump @tailwindcss/cli from 4.2.0 to 4.2.1 in /packages/ui (#9332)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 09:34:16 +01:00
dependabot[bot]
76362570de
build(deps-dev): bump tailwindcss from 4.2.0 to 4.2.1 in /packages/ui (#9333)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 07:49:13 +00:00
0f1504fb8a
fix(workflow): ensure cucumber-json-formatter (#9300) 2026-02-27 01:17:48 +00:00
795881e5b4
feat(e2e): e2e - chat notification (#9303) 2026-02-27 01:39:26 +01:00
d0348545ad
feat(webapp): complete translations + Albanian (#9301) 2026-02-26 23:47:15 +00:00
732ac9a2ad
fix(webapp): downgrade graphql - socket not working (#9302) 2026-02-26 23:01:19 +00:00
8feb34a41a
fix(webapp): fix landscape image distances (#9299) 2026-02-25 15:43:34 +00:00
dependabot[bot]
f40398ec66
build(deps): bump graphql from 14.7.0 to 16.12.0 in /webapp (#9045)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-25 14:59:51 +00:00
114a25025f
feat(webapp): first draft of landscape mode (#9298) 2026-02-25 14:34:20 +00:00
1174cf9a03
fix(webapp): fix time display in user teaser (#9297) 2026-02-25 14:06:39 +00:00
6b77839fb4
fix(webapp): fix embed in non-editor-mode (#9296) 2026-02-25 13:16:08 +00:00
dependabot[bot]
587559a97a
build(deps): bump body-parser from 1.20.3 to 2.2.2 in /backend (#9101)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 12:15:22 +01:00
fc5d3aca8e
refactor(workflow): use docker cache (#9294) 2026-02-23 09:46:14 +00:00
dependabot[bot]
b72a7c29dd
build(deps-dev): bump @badeball/cypress-cucumber-preprocessor from 24.0.0 to 24.0.1 in the cypress group (#9256)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 08:43:04 +00:00
b4db6dc8d8
refactor(backend): graphql lint + query gql files (#9293) 2026-02-23 08:09:50 +00:00
dependabot[bot]
cef1cceea4
build(deps-dev): bump @tailwindcss/vite from 4.1.18 to 4.2.0 in /packages/ui (#9257)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 08:41:59 +01:00
dependabot[bot]
e31e9f6259
build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 in /packages/ui (#9258)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 05:48:12 +00:00
dependabot[bot]
5005f53e00
build(deps-dev): bump @storybook/vue3-vite from 10.2.8 to 10.2.10 in /packages/ui (#9259)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 05:16:03 +00:00
dependabot[bot]
a0cb0f437b
build(deps-dev): bump @types/node from 25.2.3 to 25.3.0 in /packages/ui (#9261)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 04:35:37 +00:00
dependabot[bot]
15d3c27fb6
build(deps): bump the metascraper group in /backend with 12 updates (#9262)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 05:06:12 +01:00
dependabot[bot]
470889c252
build(deps-dev): bump nodemon from 3.1.11 to 3.1.14 in /backend (#9265)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-23 03:24:00 +00:00
9decd998cc
refactor(backend): update apollo (#9292) 2026-02-23 03:45:32 +01:00
dependabot[bot]
ad1cc13650
build(deps-dev): bump @tailwindcss/cli from 4.1.18 to 4.2.0 in /packages/ui (#9263)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 22:54:53 +00:00
dependabot[bot]
20169005cd
build(deps-dev): bump jsdom from 28.0.0 to 28.1.0 in /packages/ui (#9267)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 22:28:28 +00:00
fc4e15c217
refactor(backend): use eslint config it4c (#9290) 2026-02-22 21:52:14 +00:00
dependabot[bot]
703cbbc1dc
build(deps-dev): bump eslint-plugin-jsdoc from 62.5.4 to 62.7.0 in /packages/ui (#9271)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 21:23:41 +00:00
dependabot[bot]
d3be3ccac4
build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.0 in /packages/ui (#9269)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 20:52:21 +00:00
dependabot[bot]
eec866072a
build(deps-dev): bump eslint-plugin-playwright from 2.5.1 to 2.7.0 in /packages/ui (#9264)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 21:17:55 +01:00
dependabot[bot]
b9fbb92aae
build(deps-dev): bump glob from 13.0.3 to 13.0.6 in /packages/ui (#9272)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 18:49:48 +00:00
dependabot[bot]
3293f268dd
build(deps-dev): bump eslint-plugin-storybook from 10.2.8 to 10.2.10 in /packages/ui (#9274)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 18:17:34 +00:00
dependabot[bot]
34f6443981
build(deps): bump @aws-sdk/client-s3 from 3.990.0 to 3.995.0 in /backend (#9275)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 17:48:31 +00:00
c79a5db39e
fix(other): fix image cache (#9289) 2026-02-22 16:56:30 +00:00
dependabot[bot]
0861dc8f7c
build(deps): bump sanitize-html from 2.17.0 to 2.17.1 in /backend (#9276)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 16:12:34 +00:00
dependabot[bot]
617846f61b
build(deps): bump @aws-sdk/lib-storage from 3.985.0 to 3.990.0 in /backend (#9277)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-22 15:45:36 +00:00
dependabot[bot]
7b6234356d
build(deps-dev): bump @types/node from 25.2.3 to 25.3.0 in /backend (#9278)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-21 22:13:58 +00:00
9ff74b4219
fix(webapp): fix badge select + drag&drop for badges on desktop devices (#9287) 2026-02-21 19:42:44 +00:00
ccf10610c8
feat(webapp): feed view mode (#9285) 2026-02-21 18:48:41 +00:00
1b2c5e68b6
fix(webapp): flex layout und spacing in profile und group pages (#9286) 2026-02-21 17:59:01 +00:00
dependabot[bot]
8b14759782
build(deps): bump minimatch from 10.2.0 to 10.2.2 in /backend (#9279)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-21 15:53:04 +00:00
dependabot[bot]
03d0c52a66
build(deps-dev): bump eslint-plugin-jest from 29.14.0 to 29.15.0 in /backend (#9280)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-21 16:17:50 +01:00
6b6e77c2a5
fix(webapp): optimize masonry grid rendering and add SSR compatibility (#9284) 2026-02-21 12:39:12 +00:00
e3a41cb828
fix(webapp): add responsive masonry layout and skeleton loading UI (#9282) 2026-02-21 11:01:59 +00:00
64594a3235
fix(webapp): user teaser (#9283) 2026-02-21 08:52:23 +00:00
9548ad6e31
fix(webapp): add responsive mobile menu with locale switching and filter support (#9281) 2026-02-21 07:47:14 +00:00
30d88e9b41
fix(webapp): tab navigation (#9255) 2026-02-21 05:07:48 +00:00
bbad57bbc7
feat(package/ui): os-number (#9254) 2026-02-21 04:13:42 +00:00
518ed8af89
refactor(webapp): webapp test - no more skipped, no more todos (#9252) 2026-02-20 23:15:56 +00:00
7bb8c95770
refactor(webapp): ds-text equivalent css (#9253) 2026-02-20 20:41:25 +00:00
cdf2d12e69
refactor(webapp): ds-table to plain html (#9251) 2026-02-20 19:29:47 +00:00
951a24f100
feat(package/ui): os-badge (#9250) 2026-02-20 04:49:02 +00:00
0e23f4ec4e
refactor(webapp): improve webapp build (#9249) 2026-02-20 00:27:15 +00:00
c269e971f2
refactor(webapp): ds-grid (#9248) 2026-02-19 23:57:58 +00:00
5ef4fecf99
refactor(webapp): ds html (#9247) 2026-02-19 21:44:50 +00:00
4f4f2e4696
refactor(package/ui): os-card (#9246) 2026-02-19 08:06:48 +00:00
daafde24b0
refactor(package/ui): os-spinner (#9245) 2026-02-19 01:51:05 +00:00
c3a65a410e
fix(backend): fix memory leaks (#9239) 2026-02-19 00:00:42 +00:00
c0a7965d24
feat(webapp): more button icons, more loading states (#9243) 2026-02-18 02:59:10 +00:00
82d2a2b1f3
fix(webapp): properly autohide dropdown menu (#9244) 2026-02-18 02:19:08 +00:00
282d4a33eb
feat(package/ui): os-button suffix slot (#9242) 2026-02-18 01:56:21 +00:00
0cbdfea5a1
feat(webapp): push to top indicator (#9237) 2026-02-18 00:10:18 +00:00
77a1e0964b
refactor(webapp): migrate icons (#9238) 2026-02-17 22:40:51 +00:00
dependabot[bot]
4c4763f62a
build(deps-dev): bump multiple-cucumber-html-reporter from 3.9.3 to 3.10.0 in the cypress group (#9217)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 21:35:32 +00:00
1141514e39
fix(workflow): disable docstring (#9236) 2026-02-15 21:09:10 +00:00
fc714a5f30
feat(package/ui): os-icon (#9234) 2026-02-15 20:31:00 +00:00
b60e270f4c
refactor(webapp): vue3 migration os button as prop, remove obsolete buttons & inline single user buttons (#9214) 2026-02-15 19:30:02 +00:00
dependabot[bot]
8b22235b30
build(deps): bump node from 25.6.0-alpine to 25.6.1-alpine in /webapp (#9215)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 19:04:27 +00:00
dependabot[bot]
cb186ceb91
build(deps): bump node from 25.6.0-alpine to 25.6.1-alpine in /backend (#9216)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 18:16:22 +00:00
dependabot[bot]
018d386b3c
build(deps-dev): bump webpack from 5.105.0 to 5.105.2 (#9218)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 18:45:55 +01:00
c82af3487d
fix(docker): fix some broken compose vars (#9235) 2026-02-15 16:54:52 +00:00
dependabot[bot]
7781c5032d
build(deps-dev): bump dotenv from 17.2.4 to 17.3.1 (#9219)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 17:24:24 +01:00
dependabot[bot]
2145a3bb53
build(deps-dev): bump eslint-plugin-jest from 29.13.0 to 29.14.0 in /backend (#9221)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 03:12:39 +00:00
dependabot[bot]
a527fd902b
build(deps): bump minimatch from 10.1.2 to 10.2.0 in /backend (#9222)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 02:32:09 +00:00
dependabot[bot]
49577328f4
build(deps): bump ioredis from 5.9.2 to 5.9.3 in /backend (#9223)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 01:18:31 +00:00
dependabot[bot]
55e8746833
build(deps-dev): bump vite-tsconfig-paths from 6.1.0 to 6.1.1 in /packages/ui in the vite group (#9225)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-15 00:25:34 +00:00
dependabot[bot]
0a6e47008e
build(deps-dev): bump @storybook/vue3-vite from 10.2.7 to 10.2.8 in /packages/ui (#9229)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-14 23:59:51 +00:00
179bf6983c
chore(release): v3.14.1 (#9213) 2026-02-14 23:24:28 +00:00
36e9ad6f80
refactor(package/ui): eslint config it4c update (#9233) 2026-02-14 22:43:38 +00:00
dependabot[bot]
72714f58a6
build(deps): bump @aws-sdk/client-s3 from 3.985.0 to 3.990.0 in /backend (#9224)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-14 15:33:24 +01:00
dependabot[bot]
29277341b2
build(deps-dev): bump eslint-plugin-vuejs-accessibility from 2.4.1 to 2.5.0 in /packages/ui (#9226)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-14 13:58:12 +00:00
dependabot[bot]
1908332279
build(deps-dev): bump eslint-plugin-storybook from 10.2.7 to 10.2.8 in /packages/ui (#9228)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-14 13:34:33 +00:00
dependabot[bot]
231473644d
build(deps-dev): bump glob from 13.0.1 to 13.0.3 in /packages/ui (#9230)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-14 12:54:47 +00:00
dependabot[bot]
6024e63308
build(deps-dev): bump @types/node from 25.2.2 to 25.2.3 in /packages/ui (#9232)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-14 13:29:45 +01:00
f4fe8553de
fix(package/ui): os-button class to ensure branding compatibility (#9211) 2026-02-14 00:02:43 +01:00
794b4dabfa
refactor(webapp): vue3 migration - button - icon + circle + loading (#9208) 2026-02-13 16:27:33 +00:00
91fac6f7c6
fix(workflow): fix workflow not to double build the webapp image when running unit test (#9210) 2026-02-13 16:04:17 +00:00
dependabot[bot]
93309bf4f3
build(deps-dev): bump the babel group with 3 updates (#9109)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-12 00:52:16 +01:00
dependabot[bot]
21036c5391
build(deps): bump email-templates from 12.0.3 to 13.0.1 in /backend (#9091)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-12 00:15:18 +01:00
dependabot[bot]
d38bd9de65
build(deps-dev): bump eslint-plugin-jest from 29.12.2 to 29.13.0 in /backend (#9186)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-11 22:06:06 +00:00
5d204e0254
fix(backend): fix categories filter (#9209) 2026-02-11 19:58:22 +00:00
dependabot[bot]
3cb643754d
build(deps-dev): bump eslint-plugin-jsonc from 2.21.0 to 2.21.1 in /backend (#9188)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-11 17:15:07 +01:00
dependabot[bot]
c993b2862b
build(deps-dev): bump dotenv from 17.2.3 to 17.2.4 (#9166)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-11 13:49:47 +01:00
dependabot[bot]
5ec508b33c
build(deps): bump actions/setup-node from 4 to 6 (#9184)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-11 12:57:21 +01:00
dependabot[bot]
b7c09eee7f
build(deps): bump actions/checkout from 4 to 6 (#9185)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-11 12:01:24 +01:00
dependabot[bot]
5dfb000f45
build(deps): bump actions/upload-artifact from 4 to 6 (#9182)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-11 04:14:45 +00:00
761305e333
feat(webapp): correct version + commits (#9203) 2026-02-11 03:42:03 +00:00
604de30fa2
fix(workflow): rename ui compatibility test (#9207) 2026-02-11 02:51:27 +00:00
07cf1eacc9
refactor(workflow): cache packages (#9206) 2026-02-11 00:46:04 +00:00
9b6d2bbbba
refactor(workflow): all e2e are running in parallel (#9205) 2026-02-11 01:17:26 +01:00
0d617c46c6
fix(workflow): ensure ui workflows always run, but be skipped if not needed (#9204) 2026-02-10 23:09:37 +00:00
dependabot[bot]
c32ea0f43b
build(deps-dev): bump @types/node from 25.2.1 to 25.2.2 in /backend (#9187)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-10 22:36:17 +00:00
eaac170a60
fix(webapp): properly switch language on static pages (#9202) 2026-02-10 22:05:57 +00:00
7b3c907cf6
fix(webapp): make static pages available when logged out (#9201) 2026-02-10 21:32:12 +00:00
9b98dcae9a
refactor(webapp): vue3 migration - phase 3 - integration (#9180) 2026-02-10 20:56:32 +00:00
f2e77595b2
fix(backend): ensure a pinned post is accessible even tho the user was muted (#9200) 2026-02-10 18:55:33 +00:00
04effaa506
fix(backend): fix structure of unit test reports (#9199) 2026-02-10 17:13:07 +01:00
75e36abbc6
refactor(package/ui): extract rules to eslint config it4c & update package (#9198) 2026-02-10 14:44:51 +00:00
080923a0e4
refactor(workflow): remove auto-approve workflow (#9197) 2026-02-10 14:10:56 +00:00
901fc01ca6
refactor(workflow): add a new scope for PRs: package/ui (#9196) 2026-02-10 13:47:45 +00:00
dependabot[bot]
accb62d8ae
build(deps-dev): bump @types/node from 25.2.1 to 25.2.2 in /packages/ui (#9193)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-10 03:34:45 +00:00
dependabot[bot]
3da25b6519
build(deps-dev): bump vue from 3.5.27 to 3.5.28 in /packages/ui in the vue group (#9191)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-10 03:14:31 +00:00
1341 changed files with 77042 additions and 29074 deletions

View File

@ -4,6 +4,10 @@
language: de
reviews:
pre_merge_checks:
docstrings:
mode: "off"
# Automatisches Review für alle PRs
auto_review:
enabled: true
@ -29,6 +33,7 @@ reviews:
- "!**/package-lock.json"
- "!**/yarn.lock"
- "!**/*.snap"
- "!**/*.png"
- "!**/coverage/**"
- "!**/dist/**"
- "!**/node_modules/**"

View File

@ -127,6 +127,43 @@ updates:
timezone: "Europe/Berlin"
time: "03:00"
# maintenance
- package-ecosystem: docker
open-pull-requests-limit: 99
directory: "/maintenance"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"
- package-ecosystem: npm
open-pull-requests-limit: 99
directory: "/maintenance"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"
groups:
nuxt:
applies-to: version-updates
patterns:
- "nuxt*"
- "@nuxt*"
- "@nuxtjs*"
vitest:
applies-to: version-updates
patterns:
- "vitest*"
- "@vitest*"
tailwind:
applies-to: version-updates
patterns:
- "tailwindcss*"
- "@tailwindcss*"
# ui library
- package-ecosystem: npm
open-pull-requests-limit: 99

View File

@ -1,5 +1,14 @@
# These file filter patterns are used by the action https://github.com/dorny/paths-filter
ui: &ui
- '.github/workflows/ui-*.yml'
- 'packages/ui/**/*'
maintenance: &maintenance
- '.github/workflows/maintenance-*.yml'
- 'maintenance/**/*'
- *ui
backend: &backend
- '.github/workflows/test-backend.yml'
- 'backend/**/*'
@ -14,6 +23,7 @@ webapp: &webapp
- 'webapp/**/*'
- 'styleguide/**/*'
- 'package.json'
- *ui
docs-check: &docs-check
- '.github/workflows/check-documentation.yml'

View File

@ -1,17 +0,0 @@
name: Auto Approve after CodeRabbit
on:
pull_request_review:
types: [submitted]
permissions:
pull-requests: write
jobs:
auto-approve:
if: >
github.event.review.state == 'approved' &&
github.event.review.user.login == 'coderabbitai[bot]'
runs-on: ubuntu-latest
steps:
- uses: hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363 # v4.0.0

View File

@ -11,10 +11,10 @@ jobs:
documentation: ${{ steps.changes.outputs.documentation }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for markdown file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
@ -28,7 +28,7 @@ jobs:
if: needs.files-changed.outputs.markdown == 'true'
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Remove uncheckable documentation files
run: rm -rf ./CHANGELOG.md # workaround until https://github.com/gaurav-nelson/github-action-markdown-link-check/pull/183 has been done
@ -51,10 +51,10 @@ jobs:
if: needs.files-changed.outputs.documentation == 'true'
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node 20
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: '20'

View File

@ -13,10 +13,10 @@ jobs:
documentation: ${{ steps.changes.outputs.documentation }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
@ -27,10 +27,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node 20
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 20
@ -38,7 +38,7 @@ jobs:
run: npm install && npm run docs:build
- name: Deploy Vuepress to Github Pages
uses: crazy-max/ghaction-github-pages@df5cc2bfa78282ded844b354faee141f06b41865 # v4.0.0
uses: crazy-max/ghaction-github-pages@1d6ee9b181a81033a16bd707a1401afa978daab4 # v4.0.0
with:
target_branch: gh-pages
build_dir: .vuepress/dist

View File

@ -37,15 +37,15 @@ jobs:
target: production
- name: maintenance-base
context: .
file: webapp/Dockerfile.maintenance
target: base
file: maintenance/Dockerfile
target: production
- name: maintenance-build
context: .
file: webapp/Dockerfile.maintenance
file: maintenance/Dockerfile
target: build
- name: maintenance
context: .
file: webapp/Dockerfile.maintenance
file: maintenance/Dockerfile
target: production
runs-on: ubuntu-latest
env:
@ -59,16 +59,18 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to the Container registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
@ -81,7 +83,7 @@ jobs:
type=sha
- name: Build and push Docker images
id: push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: ${{ matrix.app.context }}
target: ${{ matrix.app.target }}
@ -89,3 +91,5 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.app.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.app.name }}

77
.github/workflows/maintenance-build.yml vendored Normal file
View File

@ -0,0 +1,77 @@
name: Maintenance Build
on:
push:
branches: [master]
pull_request:
branches: [master]
defaults:
run:
working-directory: maintenance
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
maintenance: ${{ steps.changes.outputs.maintenance }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build:
name: Build
if: needs.files-changed.outputs.maintenance == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'maintenance/.tool-versions'
cache: 'npm'
cache-dependency-path: maintenance/package-lock.json
- name: Build UI library
working-directory: packages/ui
run: npm ci && npm run build
- name: Install dependencies
run: npm ci
- name: Generate static site
run: npx nuxt generate
- name: Verify build output
run: |
if [ ! -d ".output/public" ]; then
echo "::error::.output/public directory not found"
exit 1
fi
if [ ! -f ".output/public/index.html" ]; then
echo "::error::index.html not found in build output"
exit 1
fi
echo "Build output verified!"
ls -la .output/public/
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: maintenance-site
path: maintenance/.output/public/
retention-days: 7

View File

@ -0,0 +1,59 @@
name: Maintenance Docker
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
maintenance: ${{ steps.changes.outputs.maintenance }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build:
name: Build Docker Image
if: needs.files-changed.outputs.maintenance == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Build development image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: .
file: ./maintenance/Dockerfile
target: development
push: false
tags: ocelot-social/maintenance:development
cache-from: type=gha,scope=maintenance-development
cache-to: type=gha,mode=max,scope=maintenance-development
- name: Build production image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: .
file: ./maintenance/Dockerfile
target: production
push: false
tags: ocelot-social/maintenance:latest
cache-from: type=gha,scope=maintenance-production
cache-to: type=gha,mode=max,scope=maintenance-production

58
.github/workflows/maintenance-lint.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: Maintenance Lint
on:
push:
branches: [master]
pull_request:
branches: [master]
defaults:
run:
working-directory: maintenance
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
maintenance: ${{ steps.changes.outputs.maintenance }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
lint:
name: ESLint
if: needs.files-changed.outputs.maintenance == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'maintenance/.tool-versions'
cache: 'npm'
cache-dependency-path: maintenance/package-lock.json
- name: Build UI library
working-directory: packages/ui
run: npm ci && npm run build
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run TypeScript type check
run: npx nuxi typecheck

63
.github/workflows/maintenance-test.yml vendored Normal file
View File

@ -0,0 +1,63 @@
name: Maintenance Test
on:
push:
branches: [master]
pull_request:
branches: [master]
defaults:
run:
working-directory: maintenance
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
maintenance: ${{ steps.changes.outputs.maintenance }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
test:
name: Unit Tests
if: needs.files-changed.outputs.maintenance == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'maintenance/.tool-versions'
cache: 'npm'
cache-dependency-path: maintenance/package-lock.json
- name: Build UI library
working-directory: packages/ui
run: npm ci && npm run build
- name: Install dependencies
run: npm ci
- name: Run tests with coverage
run: npx vitest run --coverage
- name: Upload coverage report
uses: actions/upload-artifact@v7
if: always()
with:
name: maintenance-coverage-report
path: maintenance/coverage/
retention-days: 7

View File

@ -14,11 +14,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Fetch full History for changelog
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: '.nvmrc'
- name: Setup env
@ -58,11 +58,11 @@ jobs:
needs: [github_tag]
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Fetch full History for changelog
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: '.nvmrc'
- name: Setup env
@ -72,7 +72,7 @@ jobs:
echo "BUILD_COMMIT=${GITHUB_SHA}" >> $GITHUB_ENV
- run: echo "BUILD_VERSION=${VERSION}-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
#- name: Repository Dispatch
# uses: peter-evans/repository-dispatch@f49a8ac5751834a0666df77deb0289abbe2b3a78 # v3.0.0
# uses: peter-evans/repository-dispatch@1a91c28090489a711dd89a2424bb13d72a56e2e4 # v3.0.0
# with:
# token: ${{ github.token }}
# event-type: trigger-ocelot-build-success
@ -80,7 +80,7 @@ jobs:
# client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "VERSION": "${VERSION}", "BUILD_DATE": "${BUILD_DATE}", "BUILD_COMMIT": "${BUILD_COMMIT}", "BUILD_VERSION": "${BUILD_VERSION}"}'
- name: Repository Dispatch stage.ocelot.social
uses: peter-evans/repository-dispatch@f49a8ac5751834a0666df77deb0289abbe2b3a78 # v3.0.0
uses: peter-evans/repository-dispatch@1a91c28090489a711dd89a2424bb13d72a56e2e4 # v3.0.0
with:
token: ${{ secrets.OCELOT_PUBLISH_EVENT_PAT }} # this token is required to access the other repository
event-type: trigger-ocelot-build-success
@ -88,7 +88,7 @@ jobs:
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}", "GITHUB_RUN_NUMBER": "${{ env.GITHUB_RUN_NUMBER }}", "VERSION": "${VERSION}", "BUILD_DATE": "${BUILD_DATE}", "BUILD_COMMIT": "${BUILD_COMMIT}", "BUILD_VERSION": "${BUILD_VERSION}"}'
- name: Repository Dispatch stage.yunite.me
uses: peter-evans/repository-dispatch@f49a8ac5751834a0666df77deb0289abbe2b3a78 # v3.0.0
uses: peter-evans/repository-dispatch@1a91c28090489a711dd89a2424bb13d72a56e2e4 # v3.0.0
with:
token: ${{ secrets.OCELOT_PUBLISH_EVENT_PAT }} # this token is required to access the other repository
event-type: trigger-ocelot-build-success

View File

@ -11,10 +11,10 @@ jobs:
backend: ${{ steps.changes.outputs.backend }}
docker: ${{ steps.changes.outputs.docker }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for backend file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
@ -28,16 +28,28 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Neo4J | Build 'community' image
run: |
docker compose -f docker-compose.yml -f docker-compose.test.yml build neo4j
docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: neo4j
file: neo4j/Dockerfile
target: community
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/neo4j:community
cache-from: type=gha,scope=neo4j
cache-to: type=gha,mode=max,scope=neo4j
- name: Save image for test job
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar
- name: Cache docker images
id: cache-neo4j
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/neo4j.tar
key: ${{ github.run_id }}-backend-neo4j-cache
@ -49,16 +61,28 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: backend | Build 'test' image
run: |
docker compose -f docker-compose.yml -f docker-compose.test.yml build backend
docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: backend
file: backend/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/backend:test
cache-from: type=gha,scope=backend-test
cache-to: type=gha,mode=max,scope=backend-test
- name: Save image for test job
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar
- name: Cache docker images
id: cache-backend
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/backend.tar
key: ${{ github.run_id }}-backend-cache
@ -70,15 +94,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: 'backend/.nvmrc'
cache: 'yarn'
cache-dependency-path: 'backend/yarn.lock'
- name: backend | Lint
run: cd backend && yarn && yarn run lint
run: cd backend && yarn --frozen-lockfile && yarn run lint
unit_test_backend:
name: Unit tests - Backend
@ -89,17 +115,17 @@ jobs:
checks: write
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Restore Neo4J cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/neo4j.tar
key: ${{ github.run_id }}-backend-neo4j-cache
fail-on-cache-miss: true
- name: Restore Backend cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/backend.tar
key: ${{ github.run_id }}-backend-cache

View File

@ -8,30 +8,54 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Copy backend env file
run: |
cp backend/.env.test_e2e backend/.env
cp webapp/.env.template webapp/.env
- name: Build backend and dependencies
run: |
# Build and start all required images for backend
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach neo4j backend --build
- name: Neo4J | Build image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: neo4j
file: neo4j/Dockerfile
target: community
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/neo4j:community
cache-from: type=gha,scope=neo4j
cache-to: type=gha,mode=max,scope=neo4j
# Save the build images
- name: Backend | Build image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: backend
file: backend/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/backend:test
cache-from: type=gha,scope=backend-test
cache-to: type=gha,mode=max,scope=backend-test
- name: Pull third-party images
run: |
docker pull quay.io/minio/minio:latest
docker pull quay.io/minio/mc:latest
docker pull maildev/maildev:latest
- name: Save all images
run: |
docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar
docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar
docker save "quay.io/minio/minio:latest" > /tmp/minio.tar
docker save "quay.io/minio/mc:latest" > /tmp/minio-mc.tar
docker save "maildev/maildev:latest" > /tmp/mailserver.tar
# Stop the containers
docker compose -f docker-compose.yml -f docker-compose.test.yml down
- name: Cache docker images
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: |
/tmp/backend.tar
@ -46,20 +70,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Copy backend env file
run: |
cp backend/.env.test_e2e backend/.env
cp webapp/.env.template webapp/.env
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Build docker image
run: |
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach webapp --build --no-deps
docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
- name: Webapp | Build 'test' image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: .
file: webapp/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/webapp:test
cache-from: type=gha,scope=webapp-test
cache-to: type=gha,mode=max,scope=webapp-test
- name: Save image for test jobs
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
- name: Cache docker image
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/webapp.tar
key: ${{ github.run_id }}-e2e-webapp-cache
@ -72,10 +103,10 @@ jobs:
run: rm -rf /opt/hostedtoolcache
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.4.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: 'backend/.nvmrc'
cache: 'yarn'
@ -87,7 +118,8 @@ jobs:
- name: Install cypress requirements
run: |
sudo wget --no-verbose -O /opt/cucumber-json-formatter "https://github.com/cucumber/json-formatter/releases/download/v19.0.0/cucumber-json-formatter-linux-386"
sudo wget --no-verbose -O /opt/cucumber-json-formatter "https://github.com/cucumber/json-formatter/releases/download/v19.0.0/cucumber-json-formatter-linux-amd64"
echo "66a2ef158866c3ecb3d8e49a7189814a485bddca43e133e4ca5735b8d3951bf7 /opt/cucumber-json-formatter" | sha256sum -c -
sudo chmod +x /opt/cucumber-json-formatter
cd backend
yarn install
@ -97,7 +129,7 @@ jobs:
- name: Cache docker image
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: |
/opt/cucumber-json-formatter
@ -105,32 +137,45 @@ jobs:
/home/runner/work/Ocelot-Social/Ocelot-Social
key: ${{ github.run_id }}-e2e-cypress
fullstack_tests:
name: Fullstack | tests
if: success()
needs: [prepare_backend_environment, prepare_webapp_image, prepare_cypress]
list_features:
name: List Feature Files
runs-on: ubuntu-latest
outputs:
features: ${{ steps.list.outputs.features }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: List feature files
id: list
run: |
FEATURES=$(cd cypress && find e2e/ -name "*.feature" -printf '%P\n' | sort | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "features=$FEATURES" >> $GITHUB_OUTPUT
fullstack_tests:
name: E2E | ${{ matrix.feature }}
if: success()
needs: [prepare_backend_environment, prepare_webapp_image, prepare_cypress, list_features]
runs-on: ubuntu-latest
env:
jobs: 8
strategy:
fail-fast: false
matrix:
# run copies of the current job in parallel
job: [1, 2, 3, 4, 5, 6, 7, 8]
feature: ${{ fromJson(needs.list_features.outputs.features) }}
steps:
- name: Delete huge unnecessary tools folder
run: rm -rf /opt/hostedtoolcache
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.4.0
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: 'backend/.nvmrc'
cache: 'yarn'
- name: Restore cypress cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: |
/opt/cucumber-json-formatter
@ -140,7 +185,7 @@ jobs:
restore-keys: ${{ github.run_id }}-e2e-cypress
- name: Restore backend environment cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: |
/tmp/backend.tar
@ -151,15 +196,27 @@ jobs:
key: ${{ github.run_id }}-e2e-backend-environment-cache
- name: Restore webapp cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/webapp.tar
key: ${{ github.run_id }}-e2e-webapp-cache
- name: Copy env files
run: |
cp webapp/.env.template webapp/.env
cp backend/.env.test_e2e backend/.env
- name: Ensure cucumber-json-formatter exists
run: |
if [ ! -f /opt/cucumber-json-formatter ]; then
sudo wget --no-verbose -O /opt/cucumber-json-formatter "https://github.com/cucumber/json-formatter/releases/download/v19.0.0/cucumber-json-formatter-linux-amd64"
echo "66a2ef158866c3ecb3d8e49a7189814a485bddca43e133e4ca5735b8d3951bf7 /opt/cucumber-json-formatter" | sha256sum -c -
fi
sudo chmod +x /opt/cucumber-json-formatter
sudo ln -fs /opt/cucumber-json-formatter /usr/bin/cucumber-json-formatter
- name: Boot up test system | docker compose
run: |
chmod +x /opt/cucumber-json-formatter
sudo ln -fs /opt/cucumber-json-formatter /usr/bin/cucumber-json-formatter
docker load < /tmp/neo4j.tar
docker load < /tmp/backend.tar
docker load < /tmp/minio.tar
@ -167,11 +224,24 @@ jobs:
docker load < /tmp/mailserver.tar
docker load < /tmp/webapp.tar
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach backend mailserver webapp
sleep 90s
echo "Waiting for backend (max 120s)..."
timeout 120 bash -c 'until curl -sf -X POST -H "Content-Type: application/json" -d "{\"query\":\"{__typename}\"}" http://localhost:4000 > /dev/null 2>&1; do sleep 5; done'
echo "Backend is ready."
echo "Waiting for webapp (max 120s)..."
timeout 120 bash -c 'until curl -sf http://localhost:3000 > /dev/null 2>&1; do sleep 5; done'
echo "Webapp is ready."
- name: Initialize database
run: docker compose -f docker-compose.yml -f docker-compose.test.yml exec -T backend yarn db:migrate init
- name: Migrate database
run: docker compose -f docker-compose.yml -f docker-compose.test.yml exec -T backend yarn db:migrate up
- name: Full stack tests | run tests
id: e2e-tests
run: yarn run cypress:run --spec $(cypress/parallel-features.sh ${{ matrix.job }} ${{ env.jobs }} )
run: yarn run cypress:run --spec "cypress/e2e/${{ matrix.feature }}"
- name: Full stack tests | if tests failed, compile html report
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
@ -179,11 +249,29 @@ jobs:
cd cypress/
node create-cucumber-html-report.js
- name: Full stack tests | if tests failed, compute artifact name
id: artifact-name
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
run: echo "name=e2e-report-$(echo '${{ matrix.feature }}' | tr '/' '-')" >> $GITHUB_OUTPUT
- name: Full stack tests | if tests failed, upload report
id: e2e-report
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: ocelot-e2e-test-report-pr${{ needs.docker_preparation.outputs.pr-number }}
name: ${{ steps.artifact-name.outputs.name }}
path: /home/runner/work/Ocelot-Social/Ocelot-Social/cypress/reports/cucumber_html_report
e2e_status:
name: E2E | Status
if: always()
needs: [fullstack_tests]
runs-on: ubuntu-latest
steps:
- name: Check E2E results
run: |
if [ "${{ needs.fullstack_tests.result }}" != "success" ]; then
echo "E2E tests failed or were cancelled (result: ${{ needs.fullstack_tests.result }})"
exit 1
fi

View File

@ -11,10 +11,10 @@ jobs:
docker: ${{ steps.changes.outputs.docker }}
webapp: ${{ steps.changes.outputs.webapp }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for frontend file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
@ -28,10 +28,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: 'webapp/.nvmrc'
@ -43,19 +43,31 @@ jobs:
build_test_webapp:
name: Docker Build Test - Webapp
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.webapp == 'true'
needs: [files-changed, prepare]
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Webapp | Build 'test' image
run: |
docker build --target test -f webapp/Dockerfile -t "ocelotsocialnetwork/webapp:test" .
docker save "ocelotsocialnetwork/webapp:test" > /tmp/webapp.tar
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: .
file: webapp/Dockerfile
target: test
load: true
tags: ghcr.io/ocelot-social-community/ocelot-social/webapp:test
cache-from: type=gha,scope=webapp-test
cache-to: type=gha,mode=max,scope=webapp-test
- name: Save image for test job
run: docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar
- name: Cache docker image
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/webapp.tar
key: ${{ github.run_id }}-webapp-cache
@ -67,15 +79,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version-file: 'webapp/.nvmrc'
cache: 'yarn'
cache-dependency-path: 'webapp/yarn.lock'
- name: webapp | Lint
run: cd webapp && yarn && yarn run lint
run: cd webapp && yarn --frozen-lockfile && yarn run lint
unit_test_webapp:
name: Unit Tests - Webapp
@ -86,10 +100,10 @@ jobs:
checks: write
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Restore webapp cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4.0.2
with:
path: /tmp/webapp.tar
key: ${{ github.run_id }}-webapp-cache
@ -102,9 +116,8 @@ jobs:
cp webapp/.env.template webapp/.env
cp backend/.env.template backend/.env
- name: backend | docker compose
# doesn't work without the --build flag - this either means we should not load the cached images or cache the correct image
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp --build
- name: Start webapp container
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp
- name: webapp | Unit tests incl. coverage check
run: docker compose exec -T webapp yarn test

View File

@ -29,6 +29,7 @@ jobs:
# Configure which scopes are allowed (newline delimited).
scopes: |
backend
package/ui
webapp
maintenance
database

View File

@ -3,28 +3,42 @@ name: UI Build
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build:
name: Build
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
@ -74,7 +88,7 @@ jobs:
run: npm run validate
- name: Upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: dist
path: packages/ui/dist/

View File

@ -3,16 +3,30 @@ name: UI Compatibility
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build-library:
name: Build Library
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
defaults:
run:
@ -20,10 +34,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
@ -36,15 +50,16 @@ jobs:
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: ui-dist
path: packages/ui/dist/
retention-days: 1
test-compatibility:
name: Test ${{ matrix.example }}
needs: build-library
name: Test Compatibility
if: needs.files-changed.outputs.ui == 'true'
needs: [files-changed, build-library]
runs-on: ubuntu-latest
strategy:
fail-fast: false
@ -60,16 +75,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Download build artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: ui-dist
path: packages/ui/dist/
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
@ -86,3 +101,21 @@ jobs:
- name: Build example app
run: npm run build
compatibility-result:
name: Compatibility Result
if: always()
needs: [files-changed, test-compatibility]
runs-on: ubuntu-latest
steps:
- name: Skip if no UI changes
if: needs.files-changed.outputs.ui != 'true'
run: echo "No UI changes detected, skipping."
- name: Check matrix results
if: needs.files-changed.outputs.ui == 'true'
run: |
if [ "${{ needs.test-compatibility.result }}" != "success" ]; then
echo "Compatibility tests failed"
exit 1
fi

View File

@ -3,43 +3,57 @@ name: UI Docker
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build:
name: Build Docker Image
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Build development image
uses: docker/build-push-action@v6
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: ./packages/ui
file: ./packages/ui/Dockerfile
target: development
push: false
tags: ocelot-social/ui:development
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: type=gha,scope=ui-development
cache-to: type=gha,mode=max,scope=ui-development
- name: Build production image
uses: docker/build-push-action@v6
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: ./packages/ui
file: ./packages/ui/Dockerfile
target: production
push: false
tags: ocelot-social/ui:latest
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: type=gha,scope=ui-production
cache-to: type=gha,mode=max,scope=ui-production

View File

@ -3,28 +3,42 @@ name: UI Lint
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
lint:
name: ESLint
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'

View File

@ -40,10 +40,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
registry-url: 'https://registry.npmjs.org'

View File

@ -3,28 +3,42 @@ name: UI Size
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
size:
name: Bundle Size Check
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'

View File

@ -3,28 +3,42 @@ name: UI Storybook
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
build:
name: Build Storybook
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
@ -53,7 +67,7 @@ jobs:
echo "✓ Storybook build verified!"
- name: Upload Storybook artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: storybook-static
path: packages/ui/storybook-static/

View File

@ -3,28 +3,42 @@ name: UI Test
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
test:
name: Unit Tests
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
@ -37,7 +51,7 @@ jobs:
run: npm run test:coverage
- name: Upload coverage report
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
if: always()
with:
name: coverage-report

View File

@ -3,28 +3,42 @@ name: UI Verify
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
verify:
name: Completeness Check
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'

View File

@ -3,28 +3,42 @@ name: UI Visual
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
pull_request:
branches: [master]
paths:
- 'packages/ui/**'
defaults:
run:
working-directory: packages/ui
jobs:
files-changed:
name: Detect File Changes
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.changes.outputs.ui }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check for file changes
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: changes
with:
token: ${{ github.token }}
filters: .github/file-filters.yml
visual:
name: Visual Regression
if: needs.files-changed.outputs.ui == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
@ -40,7 +54,7 @@ jobs:
run: npm run test:visual
- name: Upload test results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
if: failure()
with:
name: visual-test-results

View File

@ -4,8 +4,229 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [3.15.1](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.15.0...3.15.1)
- fix(webapp): fix dependency problem - async-validator required in production [`#9436`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9436)
#### [3.15.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.14.1...3.15.0)
> 24 March 2026
- chore(release): v3.15.0 [`#9434`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9434)
- fix(backend): fix flaky backend tests [`#9433`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9433)
- refactor(webapp): remove styleguide [`#9432`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9432)
- feat(package/ui): os-menu [`#9431`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9431)
- refactor(webapp): migrate ds-select to OcelotSelect [`#9430`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9430)
- refactor(webapp): replace ds-icon with OsIcon and add missing svgs [`#9429`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9429)
- refactor(webapp): migrate ds-input to OcelotInput [`#9428`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9428)
- build(deps): bump graphql from 16.13.0 to 16.13.1 in /backend [`#9354`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9354)
- build(deps): bump sanitize-html from 2.17.1 to 2.17.2 in /backend [`#9420`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9420)
- build(deps-dev): bump jsdom from 28.1.0 to 29.0.1 in /packages/ui [`#9413`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9413)
- build(deps): bump actions/cache from 5.0.3 to 5.0.4 [`#9410`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9410)
- build(deps-dev): bump @tailwindcss/vite from 4.2.1 to 4.2.2 in /packages/ui [`#9419`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9419)
- build(deps-dev): bump @storybook/vue3-vite from 10.2.19 to 10.3.1 in /packages/ui [`#9418`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9418)
- build(deps): bump ioredis from 5.10.0 to 5.10.1 in /backend [`#9425`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9425)
- build(deps-dev): bump @tailwindcss/cli from 4.2.1 to 4.2.2 in /packages/ui [`#9421`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9421)
- build(deps-dev): bump tailwindcss from 4.2.1 to 4.2.2 in /packages/ui [`#9422`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9422)
- build(deps-dev): bump eslint-plugin-playwright from 2.9.0 to 2.10.1 in /packages/ui [`#9424`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9424)
- build(deps): bump node from 25.8.0-alpine to 25.8.1-alpine in /backend [`#9377`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9377)
- build(deps): bump node from 25.8.0-alpine to 25.8.1-alpine in /webapp [`#9378`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9378)
- build(deps): bump the metascraper group in /backend with 12 updates [`#9384`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9384)
- build(deps): bump dorny/paths-filter from 3.0.2 to 4.0.1 [`#9380`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9380)
- build(deps): bump nodemailer from 8.0.1 to 8.0.2 in /backend [`#9388`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9388)
- build(deps-dev): bump @types/node from 25.4.0 to 25.5.0 in /backend [`#9391`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9391)
- build(deps): bump pug from 3.0.3 to 3.0.4 in /backend [`#9385`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9385)
- build(deps): bump nginx from 1.29.5-alpine to 1.29.6-alpine in /webapp [`#9379`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9379)
- fix(package/ui): override active hover effect of disabled button to not create visual glitches when button state changes [`#9408`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9408)
- refactor(webapp): vue 3 migration - ds-form [`#9407`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9407)
- build(deps): bump slugify from 1.6.6 to 1.6.8 in /backend [`#9390`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9390)
- build(deps-dev): bump the vitest group in /packages/ui with 2 updates [`#9394`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9394)
- build(deps-dev): bump @types/node from 25.3.5 to 25.5.0 in /packages/ui [`#9396`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9396)
- build(deps-dev): bump jest from 30.2.0 to 30.3.0 in /backend [`#9398`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9398)
- build(deps-dev): bump eslint-plugin-jsdoc from 62.7.1 to 62.8.0 in /packages/ui [`#9399`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9399)
- build(deps-dev): bump @storybook/vue3-vite from 10.2.17 to 10.2.19 in /packages/ui [`#9400`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9400)
- build(deps-dev): bump eslint-plugin-storybook from 10.2.17 to 10.2.19 in /packages/ui [`#9401`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9401)
- fix(webapp): fix flaky e2e test [`#9404`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9404)
- refactor(webapp): ds-radio -&gt; html [`#9403`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9403)
- fix(webapp): fix search + search e2e [`#9376`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9376)
- feat(package/ui): os-modal & webapp integration [`#9375`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9375)
- refactor(webapp): pin and unpin network-wide clarification [`#9374`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9374)
- feat(backend): translate all emails into missing languages [`#9372`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9372)
- fix(webapp): fix distance of spinner in feed [`#9373`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9373)
- feat(webapp): ukrainian language translation [`#9371`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9371)
- fix(webapp): fix date select language crash [`#9370`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9370)
- fix(webapp): fix user teaser group name color (now grey) [`#9367`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9367)
- fix(package/ui): update eslint-config-it4c & fix lint errors [`#9368`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9368)
- build(deps): bump docker/login-action from 3.7.0 to 4.0.0 [`#9349`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9349)
- build(deps): bump crazy-max/ghaction-github-pages from 4.2.0 to 5.0.0 [`#9347`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9347)
- build(deps): bump docker/metadata-action from 5.10.0 to 6.0.0 [`#9345`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9345)
- build(deps): bump node from 25.7.0-alpine to 25.8.0-alpine in /backend [`#9343`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9343)
- build(deps): bump node from 25.7.0-alpine to 25.8.0-alpine in /webapp [`#9344`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9344)
- build(deps): bump docker/setup-buildx-action from 3.12.0 to 4.0.0 [`#9348`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9348)
- build(deps): bump peter-evans/repository-dispatch from f49a8ac5751834a0666df77deb0289abbe2b3a78 to 11446b25a5fd252975d4bdf43d8989a5ac4f16c5 [`#9346`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9346)
- build(deps): bump docker/build-push-action from 6.19.2 to 7.0.0 [`#9350`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9350)
- build(deps-dev): bump webpack from 5.105.3 to 5.105.4 [`#9351`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9351)
- build(deps-dev): bump @types/node from 25.3.2 to 25.3.5 in /backend [`#9352`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9352)
- build(deps-dev): bump eslint-plugin-playwright from 2.8.0 to 2.9.0 in /packages/ui [`#9358`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9358)
- build(deps): bump @aws-sdk/client-s3 from 3.1000.0 to 3.1004.0 in /backend [`#9356`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9356)
- build(deps-dev): bump @size-limit/file from 12.0.0 to 12.0.1 in /packages/ui [`#9359`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9359)
- build(deps-dev): bump eslint-plugin-storybook from 10.2.13 to 10.2.16 in /packages/ui [`#9360`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9360)
- build(deps-dev): bump @storybook/vue3-vite from 10.2.13 to 10.2.16 in /packages/ui [`#9361`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9361)
- build(deps-dev): bump storybook from 10.2.13 to 10.2.16 in /packages/ui [`#9362`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9362)
- refactor(docker): mount styleguide and packages/ui in docker-compose.override.yml [`#9342`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9342)
- build(deps-dev): bump publint from 0.3.17 to 0.3.18 in /packages/ui [`#9364`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9364)
- build(deps-dev): bump @types/node from 25.3.2 to 25.3.5 in /packages/ui [`#9366`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9366)
- build(deps): bump node from 25.6.1-alpine to 25.7.0-alpine in /backend [`#9304`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9304)
- build(deps): bump node from 25.6.1-alpine to 25.7.0-alpine in /webapp [`#9305`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9305)
- build(deps): bump actions/download-artifact from 4 to 8 [`#9306`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9306)
- fix(backend): ensure req.body exists with global parser setup [`#9340`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9340)
- fix(webapp): remove flags from locales [`#9341`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9341)
- build(deps): bump actions/upload-artifact from 6 to 7 [`#9307`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9307)
- refactor(e2e): remove e2e relics [`#9336`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9336)
- feat(backend): smtp - new config variable to allow ignoring tls errors [`#9339`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9339)
- build(deps): bump ioredis from 5.9.3 to 5.10.0 in /backend [`#9308`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9308)
- fix(webapp): meta - description [`#9338`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9338)
- fix(webapp): fix lang query location [`#9337`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9337)
- feat(webapp): metadata for link preview [`#9335`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9335)
- build(deps-dev): bump the cypress group with 2 updates [`#9309`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9309)
- build(deps-dev): bump webpack from 5.105.2 to 5.105.3 [`#9311`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9311)
- build(deps): bump minimatch from 10.2.2 to 10.2.4 in /backend [`#9313`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9313)
- build(deps-dev): bump @types/lodash from 4.17.23 to 4.17.24 in /backend [`#9314`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9314)
- build(deps-dev): bump the vue group in /packages/ui with 2 updates [`#9315`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9315)
- build(deps): bump @aws-sdk/lib-storage from 3.990.0 to 3.995.0 in /backend [`#9316`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9316)
- build(deps-dev): bump @storybook/vue3-vite from 10.2.10 to 10.2.13 in /packages/ui [`#9318`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9318)
- build(deps-dev): bump eslint-plugin-jsdoc from 62.7.0 to 62.7.1 in /packages/ui [`#9320`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9320)
- build(deps-dev): bump @types/node from 25.3.0 to 25.3.2 in /backend [`#9323`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9323)
- build(deps-dev): bump @tailwindcss/vite from 4.2.0 to 4.2.1 in /packages/ui [`#9325`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9325)
- build(deps): bump graphql from 16.12.0 to 16.13.0 in /backend [`#9324`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9324)
- build(deps-dev): bump @types/node from 25.3.0 to 25.3.2 in /packages/ui [`#9328`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9328)
- build(deps-dev): bump eslint-plugin-playwright from 2.7.0 to 2.8.0 in /packages/ui [`#9329`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9329)
- build(deps-dev): bump eslint-plugin-storybook from 10.2.10 to 10.2.13 in /packages/ui [`#9330`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9330)
- build(deps): bump @aws-sdk/client-s3 from 3.995.0 to 3.1000.0 in /backend [`#9331`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9331)
- build(deps-dev): bump @tailwindcss/cli from 4.2.0 to 4.2.1 in /packages/ui [`#9332`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9332)
- build(deps-dev): bump tailwindcss from 4.2.0 to 4.2.1 in /packages/ui [`#9333`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9333)
- fix(workflow): ensure cucumber-json-formatter [`#9300`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9300)
- feat(e2e): e2e - chat notification [`#9303`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9303)
- feat(webapp): complete translations + Albanian [`#9301`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9301)
- fix(webapp): downgrade graphql - socket not working [`#9302`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9302)
- fix(webapp): fix landscape image distances [`#9299`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9299)
- build(deps): bump graphql from 14.7.0 to 16.12.0 in /webapp [`#9045`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9045)
- feat(webapp): first draft of landscape mode [`#9298`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9298)
- fix(webapp): fix time display in user teaser [`#9297`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9297)
- fix(webapp): fix embed in non-editor-mode [`#9296`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9296)
- build(deps): bump body-parser from 1.20.3 to 2.2.2 in /backend [`#9101`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9101)
- refactor(workflow): use docker cache [`#9294`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9294)
- build(deps-dev): bump @badeball/cypress-cucumber-preprocessor from 24.0.0 to 24.0.1 in the cypress group [`#9256`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9256)
- refactor(backend): graphql lint + query gql files [`#9293`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9293)
- build(deps-dev): bump @tailwindcss/vite from 4.1.18 to 4.2.0 in /packages/ui [`#9257`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9257)
- build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 in /packages/ui [`#9258`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9258)
- build(deps-dev): bump @storybook/vue3-vite from 10.2.8 to 10.2.10 in /packages/ui [`#9259`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9259)
- build(deps-dev): bump @types/node from 25.2.3 to 25.3.0 in /packages/ui [`#9261`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9261)
- build(deps): bump the metascraper group in /backend with 12 updates [`#9262`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9262)
- build(deps-dev): bump nodemon from 3.1.11 to 3.1.14 in /backend [`#9265`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9265)
- refactor(backend): update apollo [`#9292`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9292)
- build(deps-dev): bump @tailwindcss/cli from 4.1.18 to 4.2.0 in /packages/ui [`#9263`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9263)
- build(deps-dev): bump jsdom from 28.0.0 to 28.1.0 in /packages/ui [`#9267`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9267)
- refactor(backend): use eslint config it4c [`#9290`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9290)
- build(deps-dev): bump eslint-plugin-jsdoc from 62.5.4 to 62.7.0 in /packages/ui [`#9271`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9271)
- build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.0 in /packages/ui [`#9269`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9269)
- build(deps-dev): bump eslint-plugin-playwright from 2.5.1 to 2.7.0 in /packages/ui [`#9264`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9264)
- build(deps-dev): bump glob from 13.0.3 to 13.0.6 in /packages/ui [`#9272`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9272)
- build(deps-dev): bump eslint-plugin-storybook from 10.2.8 to 10.2.10 in /packages/ui [`#9274`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9274)
- build(deps): bump @aws-sdk/client-s3 from 3.990.0 to 3.995.0 in /backend [`#9275`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9275)
- fix(other): fix image cache [`#9289`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9289)
- build(deps): bump sanitize-html from 2.17.0 to 2.17.1 in /backend [`#9276`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9276)
- build(deps): bump @aws-sdk/lib-storage from 3.985.0 to 3.990.0 in /backend [`#9277`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9277)
- build(deps-dev): bump @types/node from 25.2.3 to 25.3.0 in /backend [`#9278`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9278)
- fix(webapp): fix badge select + drag&drop for badges on desktop devices [`#9287`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9287)
- feat(webapp): feed view mode [`#9285`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9285)
- fix(webapp): flex layout und spacing in profile und group pages [`#9286`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9286)
- build(deps): bump minimatch from 10.2.0 to 10.2.2 in /backend [`#9279`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9279)
- build(deps-dev): bump eslint-plugin-jest from 29.14.0 to 29.15.0 in /backend [`#9280`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9280)
- fix(webapp): optimize masonry grid rendering and add SSR compatibility [`#9284`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9284)
- fix(webapp): add responsive masonry layout and skeleton loading UI [`#9282`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9282)
- fix(webapp): user teaser [`#9283`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9283)
- fix(webapp): add responsive mobile menu with locale switching and filter support [`#9281`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9281)
- fix(webapp): tab navigation [`#9255`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9255)
- feat(package/ui): os-number [`#9254`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9254)
- refactor(webapp): webapp test - no more skipped, no more todos [`#9252`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9252)
- refactor(webapp): ds-text equivalent css [`#9253`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9253)
- refactor(webapp): ds-table to plain html [`#9251`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9251)
- feat(package/ui): os-badge [`#9250`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9250)
- refactor(webapp): improve webapp build [`#9249`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9249)
- refactor(webapp): ds-grid [`#9248`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9248)
- refactor(webapp): ds html [`#9247`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9247)
- refactor(package/ui): os-card [`#9246`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9246)
- refactor(package/ui): os-spinner [`#9245`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9245)
- fix(backend): fix memory leaks [`#9239`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9239)
- feat(webapp): more button icons, more loading states [`#9243`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9243)
- fix(webapp): properly autohide dropdown menu [`#9244`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9244)
- feat(package/ui): os-button suffix slot [`#9242`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9242)
- feat(webapp): push to top indicator [`#9237`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9237)
- refactor(webapp): migrate icons [`#9238`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9238)
- build(deps-dev): bump multiple-cucumber-html-reporter from 3.9.3 to 3.10.0 in the cypress group [`#9217`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9217)
- fix(workflow): disable docstring [`#9236`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9236)
- feat(package/ui): os-icon [`#9234`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9234)
- refactor(webapp): vue3 migration os button as prop, remove obsolete buttons & inline single user buttons [`#9214`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9214)
- build(deps): bump node from 25.6.0-alpine to 25.6.1-alpine in /webapp [`#9215`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9215)
- build(deps): bump node from 25.6.0-alpine to 25.6.1-alpine in /backend [`#9216`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9216)
- build(deps-dev): bump webpack from 5.105.0 to 5.105.2 [`#9218`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9218)
- fix(docker): fix some broken compose vars [`#9235`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9235)
- build(deps-dev): bump dotenv from 17.2.4 to 17.3.1 [`#9219`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9219)
- build(deps-dev): bump eslint-plugin-jest from 29.13.0 to 29.14.0 in /backend [`#9221`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9221)
- build(deps): bump minimatch from 10.1.2 to 10.2.0 in /backend [`#9222`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9222)
- build(deps): bump ioredis from 5.9.2 to 5.9.3 in /backend [`#9223`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9223)
- build(deps-dev): bump vite-tsconfig-paths from 6.1.0 to 6.1.1 in /packages/ui in the vite group [`#9225`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9225)
- build(deps-dev): bump @storybook/vue3-vite from 10.2.7 to 10.2.8 in /packages/ui [`#9229`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9229)
#### [3.14.1](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.14.0...3.14.1)
> 14 February 2026
- chore(release): v3.14.1 [`#9213`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9213)
- refactor(package/ui): eslint config it4c update [`#9233`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9233)
- build(deps): bump @aws-sdk/client-s3 from 3.985.0 to 3.990.0 in /backend [`#9224`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9224)
- build(deps-dev): bump eslint-plugin-vuejs-accessibility from 2.4.1 to 2.5.0 in /packages/ui [`#9226`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9226)
- build(deps-dev): bump eslint-plugin-storybook from 10.2.7 to 10.2.8 in /packages/ui [`#9228`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9228)
- build(deps-dev): bump glob from 13.0.1 to 13.0.3 in /packages/ui [`#9230`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9230)
- build(deps-dev): bump @types/node from 25.2.2 to 25.2.3 in /packages/ui [`#9232`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9232)
- fix(package/ui): os-button class to ensure branding compatibility [`#9211`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9211)
- refactor(webapp): vue3 migration - button - icon + circle + loading [`#9208`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9208)
- fix(workflow): fix workflow not to double build the webapp image when running unit test [`#9210`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9210)
- build(deps-dev): bump the babel group with 3 updates [`#9109`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9109)
- build(deps): bump email-templates from 12.0.3 to 13.0.1 in /backend [`#9091`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9091)
- build(deps-dev): bump eslint-plugin-jest from 29.12.2 to 29.13.0 in /backend [`#9186`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9186)
- fix(backend): fix categories filter [`#9209`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9209)
- build(deps-dev): bump eslint-plugin-jsonc from 2.21.0 to 2.21.1 in /backend [`#9188`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9188)
- build(deps-dev): bump dotenv from 17.2.3 to 17.2.4 [`#9166`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9166)
- build(deps): bump actions/setup-node from 4 to 6 [`#9184`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9184)
- build(deps): bump actions/checkout from 4 to 6 [`#9185`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9185)
- build(deps): bump actions/upload-artifact from 4 to 6 [`#9182`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9182)
- feat(webapp): correct version + commits [`#9203`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9203)
- fix(workflow): rename ui compatibility test [`#9207`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9207)
- refactor(workflow): cache packages [`#9206`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9206)
- refactor(workflow): all e2e are running in parallel [`#9205`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9205)
- fix(workflow): ensure ui workflows always run, but be skipped if not needed [`#9204`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9204)
- build(deps-dev): bump @types/node from 25.2.1 to 25.2.2 in /backend [`#9187`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9187)
- fix(webapp): properly switch language on static pages [`#9202`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9202)
- fix(webapp): make static pages available when logged out [`#9201`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9201)
- refactor(webapp): vue3 migration - phase 3 - integration [`#9180`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9180)
- fix(backend): ensure a pinned post is accessible even tho the user was muted [`#9200`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9200)
- fix(backend): fix structure of unit test reports [`#9199`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9199)
- refactor(package/ui): extract rules to eslint config it4c & update package [`#9198`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9198)
- refactor(workflow): remove auto-approve workflow [`#9197`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9197)
- refactor(workflow): add a new scope for PRs: package/ui [`#9196`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9196)
- build(deps-dev): bump @types/node from 25.2.1 to 25.2.2 in /packages/ui [`#9193`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9193)
- build(deps-dev): bump vue from 3.5.27 to 3.5.28 in /packages/ui in the vue group [`#9191`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9191)
- refactor(backend): reports query parameterization and resolver cleanup with test coverage [`#9156`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9156)
- fix(workflow): allow code rabbit to approve PRs [`#9195`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9195)
- feat(workflow): coderabbit [`#9194`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9194)
#### [3.14.0](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.13.1...3.14.0)
> 9 February 2026
- chore(release): v3.14.0 [`#9181`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9181)
- refactor(webapp): vue3 migration - phase 2 - setup [`#9161`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9161)
- build(deps): bump nginx from 1.29.4-alpine to 1.29.5-alpine in /webapp [`#9162`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9162)
- build(deps): bump node from 25.5.0-alpine to 25.6.0-alpine in /backend [`#9163`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9163)

View File

@ -1,3 +0,0 @@
node_modules/
build/
coverage/

View File

@ -1,263 +0,0 @@
// eslint-disable-next-line import/no-commonjs
module.exports = {
root: true,
env: {
node: true,
},
parser: '@typescript-eslint/parser',
plugins: ['prettier', '@typescript-eslint', 'import', 'n', 'promise', 'security', 'no-catch-all'],
extends: [
'standard',
'eslint:recommended',
'plugin:n/recommended',
'plugin:prettier/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'plugin:promise/recommended',
'plugin:@eslint-community/eslint-comments/recommended',
'prettier',
],
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
'import/resolver': {
typescript: {
project: ['./tsconfig.json', './backend/tsconfig.json'],
},
node: true,
},
},
rules: {
'no-catch-all/no-catch-all': 'error',
'no-console': 'error',
camelcase: 'error',
'no-debugger': 'error',
'prettier/prettier': [
'error',
{
htmlWhitespaceSensitivity: 'ignore',
},
],
// import
'import/export': 'error',
// 'import/no-deprecated': 'error',
'import/no-empty-named-blocks': 'error',
'import/no-extraneous-dependencies': 'error',
'import/no-mutable-exports': 'error',
'import/no-unused-modules': 'error',
'import/no-named-as-default': 'error',
'import/no-named-as-default-member': 'error',
'import/no-amd': 'error',
'import/no-commonjs': 'error',
'import/no-import-module-exports': 'error',
'import/no-nodejs-modules': 'off',
'import/unambiguous': 'off', // not compatible with .eslintrc.cjs
'import/default': 'error',
'import/named': 'off', // has false positives
'import/namespace': 'error',
'import/no-absolute-path': 'error',
'import/no-cycle': 'error',
'import/no-dynamic-require': 'error',
'import/no-internal-modules': 'off',
'import/no-relative-packages': 'error',
'import/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
'import/no-self-import': 'error',
'import/no-unresolved': 'error',
'import/no-useless-path-segments': 'error',
'import/no-webpack-loader-syntax': 'error',
'import/consistent-type-specifier-style': 'error',
'import/exports-last': 'off',
'import/extensions': 'error',
'import/first': 'error',
'import/group-exports': 'off',
'import/newline-after-import': 'error',
'import/no-anonymous-default-export': 'off', // not compatible with neode
'import/no-default-export': 'off', // not compatible with neode
'import/no-duplicates': 'error',
'import/no-named-default': 'error',
'import/no-namespace': 'error',
'import/no-unassigned-import': 'error',
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
'newlines-between': 'always',
pathGroups: [
{
pattern: '@?*/**',
group: 'external',
position: 'after',
},
{
pattern: '@/**',
group: 'external',
position: 'after',
},
],
alphabetize: {
order: 'asc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
caseInsensitive: true /* ignore case. Options: [true, false] */,
},
distinctGroup: true,
},
],
'import/prefer-default-export': 'off',
// n
// 'n/callback-return': 'error',
'n/exports-style': 'error',
'n/file-extension-in-import': ['error', 'never'],
'n/global-require': 'error',
'n/handle-callback-err': 'error',
// 'n/hashbang': 'error', // part of n/recommended
'n/no-callback-literal': 'error',
// 'n/no-deprecated-api': 'error', // part of n/recommended
// 'n/no-exports-assign': 'error', // part of n/recommended
'n/no-extraneous-import': 'off', // duplicate of import/no-extraneous-dependencies // part of n/recommended
// 'n/no-extraneous-require': 'error', // part of n/recommended
'n/no-hide-core-modules': 'error',
'n/no-missing-import': 'off', // not compatible with typescript // part of n/recommended
// 'n/no-missing-require': 'error', // part of n/recommended
'n/no-mixed-requires': 'error',
'n/no-new-require': 'error',
'n/no-path-concat': 'error',
'n/no-process-env': 'error',
// 'n/no-process-exit': 'error', // part of n/recommended
'n/no-restricted-import': 'error',
'n/no-restricted-require': 'error',
'n/no-sync': 'error',
// 'n/no-unpublished-bin': 'error', // part of n/recommended
'n/no-unpublished-import': [
'error',
{ allowModules: ['apollo-server-testing', 'rosie', '@faker-js/faker', 'ts-jest'] },
], // part of n/recommended
'n/no-unpublished-require': ['error', { allowModules: ['ts-jest', 'require-json5'] }], // part of n/recommended
// 'n/no-unsupported-features/es-builtins': 'error', // part of n/recommended
// 'n/no-unsupported-features/es-syntax': 'error', // part of n/recommended
// 'n/no-unsupported-features/node-builtins': 'error', // part of n/recommended
'n/prefer-global/buffer': 'error',
'n/prefer-global/console': 'error',
'n/prefer-global/process': 'error',
'n/prefer-global/text-decoder': 'error',
'n/prefer-global/text-encoder': 'error',
'n/prefer-global/url': 'error',
'n/prefer-global/url-search-params': 'error',
'n/prefer-node-protocol': 'error',
'n/prefer-promises/dns': 'error',
'n/prefer-promises/fs': 'error',
// 'n/process-exit-as-throw': 'error', // part of n/recommended
'n/shebang': 'error',
// promise
// 'promise/always-return': 'error', // part of promise/recommended
'promise/avoid-new': 'error',
// 'promise/catch-or-return': 'error', // part of promise/recommended
// 'promise/no-callback-in-promise': 'warn', // part of promise/recommended
'promise/no-multiple-resolved': 'error',
'promise/no-native': 'off', // ES5 only
// 'promise/no-nesting': 'warn', // part of promise/recommended
// 'promise/no-new-statics': 'error', // part of promise/recommended
// 'promise/no-promise-in-callback': 'warn', // part of promise/recommended
// 'promise/no-return-in-finally': 'warn', // part of promise/recommended
// 'promise/no-return-wrap': 'error', // part of promise/recommended
// 'promise/param-names': 'error', // part of promise/recommended
'promise/prefer-await-to-callbacks': 'error',
'promise/prefer-catch': 'error',
'promise/spec-only': 'error',
// 'promise/valid-params': 'error', // part of promise/recommended
// eslint comments
'@eslint-community/eslint-comments/disable-enable-pair': ['error', { allowWholeFile: true }],
'@eslint-community/eslint-comments/no-restricted-disable': 'error',
'@eslint-community/eslint-comments/no-use': 'off',
'@eslint-community/eslint-comments/require-description': 'off',
},
overrides: [
{
files: ['*.js', '*.cjs', '*.ts', '*.tsx'],
extends: ['plugin:security/recommended-legacy'],
},
// only for ts files
{
files: ['*.ts', '*.tsx'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:@typescript-eslint/strict',
'prettier',
],
rules: {
// allow explicitly defined dangling promises
// '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
'no-void': ['error', { allowAsStatement: true }],
// ignore prefer-regexp-exec rule to allow string.match(regex)
'@typescript-eslint/prefer-regexp-exec': 'off',
// this should not run on ts files: https://github.com/import-js/eslint-plugin-import/issues/2215#issuecomment-911245486
'import/unambiguous': 'off',
// this is not compatible with typeorm, due to joined tables can be null, but are not defined as nullable
'@typescript-eslint/no-unnecessary-condition': 'off',
// respect underscore as acceptable unused variable
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
// this is to properly reference the referenced project database without requirement of compiling it
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
},
},
{
files: ['*.spec.ts'],
plugins: ['jest'],
env: {
jest: true,
},
rules: {
'jest/no-disabled-tests': 'error',
'jest/no-focused-tests': 'error',
'jest/no-identical-title': 'error',
'jest/prefer-to-have-length': 'error',
'jest/valid-expect': 'error',
'@typescript-eslint/unbound-method': 'off',
'jest/unbound-method': 'error',
},
},
{
extends: ['plugin:jsonc/recommended-with-jsonc'],
files: ['*.json', '*.json5', '*.jsonc'],
parser: 'jsonc-eslint-parser',
},
{
files: ['*.graphql', '*.gql'],
parser: '@graphql-eslint/eslint-plugin',
plugins: ['@graphql-eslint'],
extends: ['plugin:@graphql-eslint/schema-recommended'],
rules: {
'@graphql-eslint/description-style': ['error', { style: 'inline' }],
'@graphql-eslint/require-description': 'off',
'@graphql-eslint/naming-convention': 'off',
'@graphql-eslint/strict-id-in-types': 'off',
'@graphql-eslint/no-typename-prefix': 'off',
// incompatible: `depends on a GraphQL validation rule "XXX" but it's not available in the "graphql" version you are using. Skipping…`
'@graphql-eslint/known-directives': 'off',
'@graphql-eslint/known-argument-names': 'off',
'@graphql-eslint/known-type-names': 'off',
'@graphql-eslint/lone-schema-definition': 'off',
'@graphql-eslint/provided-required-arguments': 'off',
'@graphql-eslint/unique-directive-names': 'off',
'@graphql-eslint/unique-directive-names-per-location': 'off',
'@graphql-eslint/unique-field-definition-names': 'off',
'@graphql-eslint/unique-operation-types': 'off',
'@graphql-eslint/unique-type-names': 'off',
},
parserOptions: {
schema: './src/graphql/types/**/*.gql',
assumeValid: true,
},
},
],
}

View File

@ -1,9 +0,0 @@
module.exports = {
semi: false,
printWidth: 100,
singleQuote: true,
trailingComma: "all",
tabWidth: 2,
bracketSpacing: true
};

View File

@ -1,4 +1,5 @@
FROM node:25.6.0-alpine AS base
# syntax=docker/dockerfile:1
FROM node:25.8.2-alpine AS base
LABEL org.label-schema.name="ocelot.social:backend"
LABEL org.label-schema.description="Backend of the Social Network Software ocelot.social"
LABEL org.label-schema.usage="https://github.com/Ocelot-Social-Community/Ocelot-Social/blob/master/README.md"
@ -28,13 +29,15 @@ ONBUILD COPY ./branding/email/ src/middleware/helpers/email/
ONBUILD COPY ./branding/middlewares/ src/middleware/branding/
ONBUILD COPY ./branding/data/ src/db/data
ONBUILD COPY ./branding/public/ public/
ONBUILD RUN yarn install --production=false --frozen-lockfile --non-interactive
ONBUILD RUN --mount=type=cache,target=/yarn-cache,sharing=locked \
yarn install --production=false --frozen-lockfile --non-interactive --cache-folder /yarn-cache
ONBUILD RUN yarn run build
ONBUILD RUN mkdir /build
ONBUILD RUN cp -r ./build /build
ONBUILD RUN cp -r ./public /build
ONBUILD RUN cp -r ./package.json yarn.lock /build
ONBUILD RUN cd /build && yarn install --production=true --frozen-lockfile --non-interactive
ONBUILD RUN --mount=type=cache,target=/yarn-cache,sharing=locked \
cd /build && yarn install --production=true --frozen-lockfile --non-interactive --cache-folder /yarn-cache
FROM build AS test
# required for the migrations

89
backend/eslint.config.ts Normal file
View File

@ -0,0 +1,89 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-return */
import config from 'eslint-config-it4c'
import graphql from 'eslint-config-it4c/modules/graphql'
import jest from 'eslint-config-it4c/modules/jest'
export default [
{
ignores: ['node_modules/', 'build/', 'coverage/'],
},
...config,
...jest,
// GraphQL schema linting (extend file pattern to include .gql)
...graphql.map((c) => ({
...c,
files: ['**/*.graphql', '**/*.gql'],
})),
{
files: ['**/*.graphql', '**/*.gql'],
// TODO: Parser must be set explicitly because the it4c module only provides
// plugins and rules, not languageOptions. Without this, ESLint uses the JS
// parser for .gql files. Remove when fixed in eslint-config-it4c.
languageOptions: {
parser: graphql[0].plugins['@graphql-eslint'].parser,
parserOptions: {
graphQLConfig: {
schema: './src/graphql/types/**/*.gql',
documents: './src/graphql/queries/**/*.gql',
},
},
},
rules: {
// Would require descriptions on every type/field/input — too noisy for now
'@graphql-eslint/require-description': 'off',
// camelCase operation names and _id/_ne underscores conflict with existing schema
'@graphql-eslint/naming-convention': 'off',
// Many types (Image, File, InviteCode, etc.) intentionally lack id: ID!
'@graphql-eslint/strict-id-in-types': 'off',
// Fields like groupType, queryLocations match parent type name by coincidence
'@graphql-eslint/no-typename-prefix': 'off',
// neo4j-graphql-js adds arguments (first, offset) at runtime not present in static schema
'@graphql-eslint/known-argument-names': 'off',
// TODO: operations-recommended rules must be disabled because the it4c
// graphql module bundles both schema and operations configs together.
// Remove when eslint-config-it4c exports them separately (e.g. graphql/schema).
'@graphql-eslint/executable-definitions': 'off',
// neo4j-graphql-js adds fields at runtime (_id, relations) not present in static schema
'@graphql-eslint/fields-on-correct-type': 'off',
},
},
{
// Backend-specific TypeScript overrides
files: ['**/*.ts'],
languageOptions: {
parserOptions: {
projectService: {
allowDefaultProject: ['eslint.config.ts', 'jest.config.ts', 'prettier.config.ts'],
},
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// TypeORM compatibility: joined tables can be null but are not defined as nullable
'@typescript-eslint/no-unnecessary-condition': 'off',
// Allow string.match(regex) instead of regex.exec(string)
'@typescript-eslint/prefer-regexp-exec': 'off',
// TODO: gradually add return types to exported functions, then remove this override
'@typescript-eslint/explicit-module-boundary-types': 'off',
// Allow @/* path aliases in relative parent imports
'import-x/no-relative-parent-imports': ['error', { ignore: ['@/*'] }],
},
},
{
// Jest test file overrides
files: ['**/*.spec.ts'],
rules: {
'@typescript-eslint/unbound-method': 'off',
},
},
{
// Config files: allow require() of devDependencies
files: ['*.config.{js,mjs,cjs,ts,mts,cts}'],
rules: {
'n/no-unpublished-require': 'off',
},
},
]

View File

@ -1,27 +0,0 @@
/* eslint-disable import/no-commonjs */
const requireJSON5 = require('require-json5')
const { pathsToModuleNameMapper } = require('ts-jest')
const { compilerOptions } = requireJSON5('./tsconfig.json')
module.exports = {
verbose: true,
preset: 'ts-jest',
collectCoverage: true,
collectCoverageFrom: [
'**/*.ts',
'!**/node_modules/**',
'!**/test/**',
'!**/build/**',
'!**/src/**/?(*.)+(spec|test).ts?(x)',
'!**/src/db/**',
],
coverageThreshold: {
global: {
lines: 93,
},
},
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' }),
}

40
backend/jest.config.ts Normal file
View File

@ -0,0 +1,40 @@
import { readFileSync } from 'node:fs'
import { pathsToModuleNameMapper } from 'ts-jest'
import { parseConfigFileTextToJson } from 'typescript'
// eslint-disable-next-line n/no-sync -- config files are synchronous by nature
const tsconfigText = readFileSync('./tsconfig.json', 'utf-8')
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- parseConfigFileTextToJson returns untyped config
const { config } = parseConfigFileTextToJson('tsconfig.json', tsconfigText)
const paths = (config as { compilerOptions: { paths: Record<string, string[]> } }).compilerOptions
.paths
export default {
verbose: true,
preset: 'ts-jest',
collectCoverage: true,
collectCoverageFrom: [
'**/*.ts',
'!**/node_modules/**',
'!**/test/**',
'!**/build/**',
'!**/src/**/?(*.)+(spec|test).ts?(x)',
'!**/src/db/**',
'!*.config.ts',
'!**/*.d.ts',
'!**/gql-register.ts',
],
coverageThreshold: {
global: {
lines: 93,
},
},
testMatch: ['**/src/**/?(*.)+(spec|test).ts?(x)'],
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
transform: {
'\\.gql$': '<rootDir>/test/graphqlTransform.ts',
'\\.tsx?$': 'ts-jest',
},
moduleNameMapper: pathsToModuleNameMapper(paths, { prefix: '<rootDir>/' }),
}

View File

@ -1,6 +1,6 @@
{
"name": "ocelot-social-backend",
"version": "3.14.0",
"version": "3.15.1",
"description": "GraphQL Backend for ocelot.social",
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
"author": "ocelot.social Community",
@ -10,20 +10,20 @@
"scripts": {
"start": "node build/src/",
"build": "tsc && tsc-alias && ./scripts/build.copy.files.sh",
"dev": "nodemon --exec ts-node --require tsconfig-paths/register src/index.ts -e js,ts,gql",
"dev": "nodemon --exec tsx src/index.ts -e js,ts,gql",
"dev:debug": "nodemon --exec node --inspect=0.0.0.0:9229 build/src/index.js -e js,ts,gql",
"lint": "eslint --max-warnings=0 --report-unused-disable-directives --ext .js,.ts,.cjs,.json,.json5,.jsonc,.graphql,.gql .",
"lint": "eslint --max-warnings 0 .",
"test": "cross-env NODE_ENV=test NODE_OPTIONS=--max-old-space-size=8192 jest --runInBand --coverage --forceExit --detectOpenHandles",
"db:reset": "ts-node --require tsconfig-paths/register src/db/reset.ts",
"db:reset:withmigrations": "ts-node --require tsconfig-paths/register src/db/reset-with-migrations.ts",
"db:seed": "ts-node --require tsconfig-paths/register src/db/seed.ts",
"db:data:admin": "ts-node --require tsconfig-paths/register src/db/admin.ts",
"db:data:badges": "ts-node --require tsconfig-paths/register src/db/badges.ts",
"db:data:branding": "ts-node --require tsconfig-paths/register src/db/data-branding.ts",
"db:data:categories": "ts-node --require tsconfig-paths/register src/db/categories.ts",
"db:reset": "tsx src/db/reset.ts",
"db:reset:withmigrations": "tsx src/db/reset-with-migrations.ts",
"db:seed": "tsx --require ./src/graphql/gql-register.ts src/db/seed.ts",
"db:data:admin": "tsx src/db/admin.ts",
"db:data:badges": "tsx src/db/badges.ts",
"db:data:branding": "tsx src/db/data-branding.ts",
"db:data:categories": "tsx src/db/categories.ts",
"db:migrate": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --store ./src/db/migrate/store.ts",
"db:migrate:create": "migrate --compiler 'ts:./src/db/compiler.ts' --migrations-dir ./src/db/migrations --template-file ./src/db/migrate/template.ts --date-format 'yyyymmddHHmmss' create",
"db:func:disable:notifications": "ts-node --require tsconfig-paths/register src/db/disable-notifications.ts",
"db:func:disable:notifications": "tsx src/db/disable-notifications.ts",
"prod:migrate": "migrate --migrations-dir ./build/src/db/migrations --store ./build/src/db/migrate/store.js",
"prod:db:data:branding": "node build/src/db/data-branding.js",
"prod:db:data:categories": "node build/src/db/categories.js",
@ -31,105 +31,90 @@
"prod:db:func:disable:notifications": "node build/src/db/disable-notifications.js"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.985.0",
"@aws-sdk/lib-storage": "^3.985.0",
"@apollo/server": "^4.11.3",
"@aws-sdk/client-s3": "^3.1005.0",
"@aws-sdk/lib-storage": "^3.1000.0",
"@graphql-tools/load-files": "^7.0.0",
"@graphql-tools/merge": "^9.0.0",
"@sentry/node": "^5.30.0",
"@types/mime-types": "^3.0.1",
"apollo-server": "~2.14.2",
"apollo-server-express": "^2.14.2",
"bcryptjs": "~3.0.3",
"body-parser": "^1.20.3",
"body-parser": "^2.2.2",
"cheerio": "~1.2.0",
"cross-env": "~10.1.0",
"dotenv": "~17.0.1",
"email-templates": "^12.0.3",
"email-templates": "^13.0.1",
"express": "^4.22.1",
"graphql": "^14.6.0",
"graphql": "^16.13.2",
"graphql-middleware": "~6.1.35",
"graphql-middleware-sentry": "^3.2.1",
"graphql-redis-subscriptions": "^2.7.0",
"graphql-shield": "~7.2.2",
"graphql-subscriptions": "^1.1.0",
"graphql-tag": "~2.10.3",
"graphql-shield": "^7.6.5",
"graphql-subscriptions": "^2.0.0",
"graphql-upload": "^13.0.0",
"graphql-ws": "^5.16.2",
"helmet": "~8.1.0",
"ioredis": "^5.9.2",
"ioredis": "^5.10.1",
"jsonwebtoken": "~8.5.1",
"languagedetect": "^2.0.0",
"linkify-html": "^4.3.2",
"linkifyjs": "^4.3.2",
"lodash": "~4.17.23",
"merge-graphql-schemas": "^1.7.8",
"metascraper": "^5.49.19",
"metascraper-author": "^5.49.19",
"metascraper-date": "^5.49.19",
"metascraper-description": "^5.49.19",
"metascraper-image": "^5.49.19",
"metascraper-lang": "^5.49.19",
"metascraper": "^5.50.0",
"metascraper-author": "^5.50.0",
"metascraper-date": "^5.50.0",
"metascraper-description": "^5.50.0",
"metascraper-image": "^5.50.0",
"metascraper-lang": "^5.50.0",
"metascraper-lang-detector": "^4.10.2",
"metascraper-logo": "^5.49.19",
"metascraper-publisher": "^5.49.19",
"metascraper-logo": "^5.50.0",
"metascraper-publisher": "^5.50.0",
"metascraper-soundcloud": "^5.34.4",
"metascraper-title": "^5.49.19",
"metascraper-url": "^5.49.19",
"metascraper-video": "^5.49.19",
"metascraper-youtube": "^5.49.20",
"metascraper-title": "^5.50.0",
"metascraper-url": "^5.50.0",
"metascraper-video": "^5.50.0",
"metascraper-youtube": "^5.50.0",
"migrate": "^2.1.0",
"mime-types": "^3.0.2",
"minimatch": "^10.1.2",
"minimatch": "^10.2.4",
"mustache": "^4.2.0",
"neo4j-driver": "^4.4.11",
"neo4j-graphql-js": "2.11.5",
"neode": "^0.4.9",
"node-fetch": "^2.7.0",
"nodemailer": "^8.0.1",
"nodemailer": "^8.0.4",
"nodemailer-html-to-text": "^3.2.0",
"preview-email": "^3.1.1",
"pug": "^3.0.3",
"sanitize-html": "~2.17.0",
"slugify": "^1.6.6",
"pug": "^3.0.4",
"sanitize-html": "~2.17.2",
"slugify": "^1.6.8",
"subscriptions-transport-ws": "^0.11.0",
"trunc-html": "~1.1.2",
"tslog": "^4.10.2",
"uuid": "~9.0.1",
"validator": "^13.15.26",
"ws": "^8.20.0",
"xregexp": "^5.1.2"
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "^4.6.0",
"@faker-js/faker": "9.9.0",
"@graphql-eslint/eslint-plugin": "^3.20.1",
"@types/email-templates": "^10.0.4",
"@types/jest": "^30.0.0",
"@types/jsonwebtoken": "~8.5.1",
"@types/lodash": "^4.17.23",
"@types/node": "^25.2.1",
"@types/lodash": "^4.17.24",
"@types/node": "^25.5.0",
"@types/request": "^2.48.13",
"@types/slug": "^5.0.9",
"@types/uuid": "~9.0.1",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"apollo-server-testing": "~2.11.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.1.8",
"eslint-config-standard": "^17.1.0",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^29.12.2",
"eslint-plugin-jsonc": "^2.21.0",
"eslint-plugin-n": "^17.23.2",
"eslint-plugin-no-catch-all": "^1.1.0",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-security": "^3.0.1",
"jest": "^30.2.0",
"nodemon": "~3.1.11",
"@types/ws": "^8.18.1",
"eslint": "^9.27.0",
"eslint-config-it4c": "^0.12.0",
"jest": "^30.3.0",
"nodemon": "~3.1.14",
"prettier": "^3.8.1",
"require-json5": "^1.3.0",
"rosie": "^2.1.1",
"ts-jest": "^29.4.6",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.16",
"tsconfig-paths": "^4.2.0",
"tsx": "^4.21.0",
"typescript": "^5.8.3"
},
"resolutions": {
@ -139,7 +124,9 @@
"**/string-width": "4.2.0",
"**/wrap-ansi": "7.0.0",
"**/jwa": "^2.0.1",
"**/@types/express": "4.17.25"
"**/@types/express": "4.17.25",
"neo4j-graphql-js/graphql": "^16.11.0",
"graphql-upload/graphql": "^16.11.0"
},
"engines": {
"node": ">=20.12.1"

View File

@ -0,0 +1 @@
export { default } from 'eslint-config-it4c/prettier'

View File

@ -1,14 +1,17 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable import-x/no-namespace */
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
/* eslint-disable n/no-process-env */
import { config } from 'dotenv'
// eslint-disable-next-line import/no-namespace
import * as SMTPTransport from 'nodemailer/lib/smtp-pool'
import emails from './emails'
import metadata from './metadata'
import type * as SMTPTransport from 'nodemailer/lib/smtp-pool'
// Load env file
config()
@ -51,6 +54,7 @@ const SMTP_DKIM_KEYSELECTOR = env.SMTP_DKIM_KEYSELECTOR
const SMTP_DKIM_PRIVATEKEY = env.SMTP_DKIM_PRIVATEKEY?.replace(/\\n/g, '\n') // replace all "\n" in .env string by real line break
const SMTP_MAX_CONNECTIONS = (env.SMTP_MAX_CONNECTIONS && parseInt(env.SMTP_MAX_CONNECTIONS)) || 5
const SMTP_MAX_MESSAGES = (env.SMTP_MAX_MESSAGES && parseInt(env.SMTP_MAX_MESSAGES)) || 100
const SMTP_REJECT_UNAUTHORIZED = env.SMTP_REJECT_UNAUTHORIZED !== 'false' // default = true
const nodemailerTransportOptions: SMTPTransport.Options = {
host: SMTP_HOST,
@ -60,6 +64,9 @@ const nodemailerTransportOptions: SMTPTransport.Options = {
pool: true,
maxConnections: SMTP_MAX_CONNECTIONS,
maxMessages: SMTP_MAX_MESSAGES,
tls: {
rejectUnauthorized: SMTP_REJECT_UNAUTHORIZED,
},
}
if (SMTP_USERNAME && SMTP_PASSWORD) {
nodemailerTransportOptions.auth = {

View File

@ -1,3 +1,4 @@
export const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED'
export const CHAT_MESSAGE_ADDED = 'CHAT_MESSAGE_ADDED'
export const CHAT_MESSAGE_STATUS_UPDATED = 'CHAT_MESSAGE_STATUS_UPDATED'
export const ROOM_COUNT_UPDATED = 'ROOM_COUNT_UPDATED'

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-shadow */
import { getDriver, getNeode } from '@db/neo4j'
import type { Driver } from 'neo4j-driver'

View File

@ -1,14 +1,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import databaseContext from '@context/database'
import pubsubContext from '@context/pubsub'
import CONFIG from '@src/config'
import type { DecodedUser } from '@src/jwt/decode'
import { decode } from '@src/jwt/decode'
import ocelotLogger from '@src/logger'
import type OcelotLogger from '@src/logger'
import type { ApolloServerExpressConfig } from 'apollo-server-express'
import type { DecodedUser } from '@src/jwt/decode'
const serverDatabase = databaseContext()
const serverPubsub = pubsubContext()
@ -18,14 +14,14 @@ export const getContext =
database?: ReturnType<typeof databaseContext>
pubsub?: ReturnType<typeof pubsubContext>
authenticatedUser: DecodedUser | null | undefined
logger?: typeof OcelotLogger
logger?: typeof ocelotLogger
config: typeof CONFIG
}) =>
async (req: { headers: { authorization?: string } }) => {
const {
database = serverDatabase,
pubsub = serverPubsub,
authenticatedUser = undefined,
authenticatedUser,
logger = ocelotLogger,
config = CONFIG,
} = opts ?? {}
@ -44,18 +40,11 @@ export const getContext =
req,
cypherParams: {
currentUserId: user ? user.id : null,
languageDefault: config.LANGUAGE_DEFAULT.toUpperCase(),
},
config,
}
return result
}
export const context: ApolloServerExpressConfig['context'] = async (options) => {
const { connection, req } = options
if (connection) {
return connection.context
} else {
return getContext()(req)
}
}
export type Context = Awaited<ReturnType<ReturnType<typeof getContext>>>

View File

@ -2,7 +2,7 @@
import { getNeode } from './neo4j'
import { trophies, verification } from './seed/badges'
// eslint-disable-next-line import/newline-after-import
// eslint-disable-next-line import-x/newline-after-import
;(async function () {
const neode = getNeode()
try {

View File

@ -1,9 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable import/no-commonjs */
// eslint-disable-next-line n/no-unpublished-require, @typescript-eslint/no-var-requires
const tsNode = require('ts-node')
// eslint-disable-next-line import/no-unassigned-import, n/no-unpublished-require
require('tsconfig-paths/register')
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-require-imports */
/* eslint-disable import-x/no-commonjs */
// eslint-disable-next-line n/no-unpublished-require
const tsx = require('tsx/cjs/api')
module.exports = tsNode.register
module.exports = tsx.register

View File

@ -2,6 +2,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/await-thenable */
import { readdir } from 'node:fs/promises'
import path from 'node:path'

View File

@ -6,7 +6,7 @@ const run = async () => {
if (args.length !== 1) {
// eslint-disable-next-line no-console
console.error('Usage: yarn run db:func:disable-notifications <email>')
// eslint-disable-next-line n/no-process-exit
process.exit(1)
}
@ -16,7 +16,7 @@ const run = async () => {
if (!emailRegex.test(email)) {
// eslint-disable-next-line no-console
console.error('Error: Invalid email address format')
// eslint-disable-next-line n/no-process-exit
process.exit(1)
}
@ -46,13 +46,13 @@ const run = async () => {
if (result !== '1') {
// eslint-disable-next-line no-console
console.error(`User with email address ${email} not found`)
// eslint-disable-next-line n/no-process-exit
process.exit(1)
}
// eslint-disable-next-line no-console
console.log(`Notifications for User with email address ${email} disabled`)
// eslint-disable-next-line n/no-process-exit
process.exit(0)
}

View File

@ -4,6 +4,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable n/no-unpublished-import */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { faker } from '@faker-js/faker'
import { hashSync } from 'bcryptjs'
import { Factory } from 'rosie'
@ -13,10 +15,11 @@ import { v4 as uuid } from 'uuid'
import { generateInviteCode } from '@graphql/resolvers/inviteCodes'
import { isUniqueFor } from '@middleware/sluggifyMiddleware'
import uniqueSlug from '@middleware/slugify/uniqueSlug'
import { Context } from '@src/context'
import { getDriver, getNeode } from './neo4j'
import type { Context } from '@src/context'
const neode = getNeode()
const uniqueImageUrl = (imageUrl) => {
@ -49,14 +52,14 @@ Factory.define('category')
.attr('id', uuid)
.attr('icon', 'globe')
.attr('name', 'Global Peace & Nonviolence')
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('Category', buildObject)
})
Factory.define('badge')
.attr('type', 'crowdfunding')
.attr('status', 'permanent')
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('Badge', buildObject)
})
@ -67,7 +70,7 @@ Factory.define('image')
.attr('alt', faker.lorem.sentence)
.attr('type', 'image/jpeg')
.attr('url', null)
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
if (!buildObject.url) {
buildObject.url = faker.image.urlPicsumPhotos({
width: buildObject.width,
@ -84,7 +87,7 @@ Factory.define('file')
.attr('name', faker.lorem.slug)
.attr('type', 'image/jpeg')
.attr('url', null)
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
if (!buildObject.url) {
buildObject.url = faker.image.urlPicsumPhotos()
}
@ -171,8 +174,8 @@ Factory.define('post')
return Promise.all([Factory.build('category')])
}) */
.option('tagIds', [])
.option('tags', ['tagIds'], (tagIds) => {
return Promise.all(tagIds.map((id) => neode.find('Tag', id)))
.option('tags', ['tagIds'], async (tagIds) => {
return Promise.all(tagIds.map(async (id) => neode.find('Tag', id)))
})
.option('authorId', null)
.option('author', ['authorId'], (authorId) => {
@ -196,9 +199,6 @@ Factory.define('post')
// Convert false to null
return pinned || null
})
.attr('contentExcerpt', ['contentExcerpt', 'content'], (contentExcerpt, content) => {
return contentExcerpt || content
})
.attr('slug', ['slug', 'title'], (slug, title) => {
return slug || slugify(title, { lower: true })
})
@ -227,6 +227,55 @@ Factory.define('post')
return post
})
Factory.define('group')
.option('ownerId', null)
.option('owner', ['ownerId'], (ownerId) => {
if (ownerId) return neode.find('User', ownerId)
return Factory.build('user')
})
.attrs({
id: uuid,
name: faker.company.name,
about: faker.lorem.sentence,
description: faker.lorem.paragraphs,
groupType: 'public',
actionRadius: 'regional',
deleted: false,
disabled: false,
})
.attr('slug', ['slug', 'name'], (slug, name) => {
return slug || slugify(name, { lower: true })
})
.attr(
'descriptionExcerpt',
['descriptionExcerpt', 'description'],
(descriptionExcerpt, description) => {
return descriptionExcerpt || description
},
)
.after(async (buildObject, options) => {
const [group, owner] = await Promise.all([neode.create('Group', buildObject), options.owner])
const session = driver.session()
try {
await session.writeTransaction((txc) =>
txc.run(
`
MATCH (owner:User {id: $ownerId}), (group:Group {id: $groupId})
MERGE (owner)-[:CREATED]->(group)
MERGE (owner)-[membership:MEMBER_OF]->(group)
SET membership.createdAt = toString(datetime()),
membership.updatedAt = toString(datetime()),
membership.role = 'owner'
`,
{ ownerId: owner.get('id'), groupId: buildObject.id },
),
)
} finally {
await session.close()
}
return group
})
Factory.define('comment')
.option('postId', null)
.option('post', ['postId'], (postId) => {
@ -242,9 +291,6 @@ Factory.define('comment')
id: uuid,
content: faker.lorem.sentence,
})
.attr('contentExcerpt', ['contentExcerpt', 'content'], (contentExcerpt, content) => {
return contentExcerpt || content
})
.after(async (buildObject, options) => {
const [comment, author, post] = await Promise.all([
neode.create('Comment', buildObject),
@ -264,7 +310,7 @@ Factory.define('donations')
.attr('showDonations', true)
.attr('goal', 15000)
.attr('progress', 7000)
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('Donations', buildObject)
})
@ -275,13 +321,13 @@ const emailDefaults = {
Factory.define('emailAddress')
.attrs(emailDefaults)
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('EmailAddress', buildObject)
})
Factory.define('unverifiedEmailAddress')
.attr(emailDefaults)
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('UnverifiedEmailAddress', buildObject)
})
@ -294,7 +340,7 @@ const inviteCodeDefaults = {
Factory.define('inviteCode')
.attrs(inviteCodeDefaults)
.option('groupId', null)
.option('group', ['groupId'], (groupId) => {
.option('group', ['groupId'], async (groupId) => {
if (groupId) {
return neode.find('Group', groupId)
}
@ -331,11 +377,11 @@ Factory.define('location')
id: 'country.10743216036480410',
type: 'country',
})
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('Location', buildObject)
})
Factory.define('report').after((buildObject, _options) => {
Factory.define('report').after(async (buildObject, _options) => {
return neode.create('Report', buildObject)
})
@ -343,7 +389,7 @@ Factory.define('tag')
.attrs({
name: '#human-connection',
})
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('Tag', buildObject)
})
@ -351,7 +397,7 @@ Factory.define('socialMedia')
.attrs({
url: 'https://mastodon.social/@Gargron',
})
.after((buildObject, _options) => {
.after(async (buildObject, _options) => {
return neode.create('SocialMedia', buildObject)
})

View File

@ -2,6 +2,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-confusing-void-expression */
import { getDriver, getNeode } from '@db/neo4j'
class Store {
@ -83,7 +84,7 @@ class Store {
const driver = getDriver()
const session = driver.session()
const { migrations } = set
const writeTxResultPromise = session.writeTransaction((txc) => {
const writeTxResultPromise = session.writeTransaction(async (txc) => {
return Promise.all(
migrations.map(async (migration) => {
const { title, description, timestamp } = migration

View File

@ -4,8 +4,9 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import-x/no-extraneous-dependencies */
/* eslint-disable promise/prefer-await-to-callbacks */
/* eslint-disable import-x/no-deprecated */
import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError, filter } from 'rxjs/operators'
@ -71,7 +72,7 @@ export function up(next) {
),
)
.subscribe({
next: ({ user, email, _oldUser, oldEmail }) =>
next: ({ user, email, _oldUser, oldEmail }) => {
// eslint-disable-next-line no-console
console.log(`
Merged:
@ -79,7 +80,8 @@ export function up(next) {
userId: ${user.id}
email: ${oldEmail} => ${email.email}
=============================
`),
`)
},
complete: () => {
// eslint-disable-next-line no-console
console.log('Merging of duplicate users completed')

View File

@ -4,8 +4,9 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import-x/no-extraneous-dependencies */
/* eslint-disable promise/prefer-await-to-callbacks */
/* eslint-disable import-x/no-deprecated */
import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError } from 'rxjs/operators'
@ -65,7 +66,7 @@ export function up(next) {
),
)
.subscribe({
next: ({ updatedLocation, location }) =>
next: ({ updatedLocation, location }) => {
// eslint-disable-next-line no-console
console.log(`
Merged:
@ -73,7 +74,8 @@ export function up(next) {
locationId: ${location.id}
updatedLocation: ${location.id} => ${updatedLocation.id}
=============================
`),
`)
},
complete: () => {
// eslint-disable-next-line no-console
console.log('Merging of duplicate locations completed')

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-empty-function */
'use strict'
export async function up(_next) {}

View File

@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/await-thenable */
import { open } from 'node:fs/promises'
import path from 'node:path'

View File

@ -0,0 +1,75 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { getDriver } from '@db/neo4j'
export const description =
'Replace global message.seen flag with per-user HAS_NOT_SEEN relationships'
export async function up(_next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
try {
// Create HAS_NOT_SEEN relationships for unseen messages
// For each message with seen=false, create a relationship for each room member
// who is not the sender
await transaction.run(`
MATCH (message:Message { seen: false })-[:INSIDE]->(room:Room)<-[:CHATS_IN]-(user:User)
WHERE NOT (user)-[:CREATED]->(message)
CREATE (user)-[:HAS_NOT_SEEN]->(message)
`)
// Remove the seen property from all messages
await transaction.run(`
MATCH (m:Message)
REMOVE m.seen
`)
await transaction.commit()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
throw new Error(error)
} finally {
await session.close()
}
}
export async function down(_next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
try {
// Re-add seen property: messages with HAS_NOT_SEEN are unseen, rest are seen
await transaction.run(`
MATCH (m:Message)
SET m.seen = true
`)
await transaction.run(`
MATCH ()-[:HAS_NOT_SEEN]->(m:Message)
SET m.seen = false
`)
// Remove all HAS_NOT_SEEN relationships
await transaction.run(`
MATCH ()-[r:HAS_NOT_SEEN]->(:Message)
DELETE r
`)
await transaction.commit()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
throw new Error(error)
} finally {
await session.close()
}
}

View File

@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { getDriver } from '@db/neo4j'
export const description =
'Delete empty DM rooms (no messages) that were created by the old CreateRoom mutation'
export async function up(_next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
try {
await transaction.run(`
MATCH (room:Room)
WHERE NOT (room)-[:ROOM_FOR]->(:Group)
AND NOT (room)<-[:INSIDE]-(:Message)
DETACH DELETE room
`)
await transaction.commit()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
throw new Error(error)
} finally {
await session.close()
}
}
export async function down(_next) {
// Cannot restore deleted rooms
}

View File

@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { getDriver } from '@db/neo4j'
export const description = 'Remove contentExcerpt property from Post and Comment nodes'
export async function up(_next) {
const driver = getDriver()
const session = driver.session()
const transaction = session.beginTransaction()
try {
await transaction.run(`
MATCH (n)
WHERE n:Post OR n:Comment
REMOVE n.contentExcerpt
`)
await transaction.commit()
} catch (error) {
// eslint-disable-next-line no-console
console.log(error)
await transaction.rollback()
// eslint-disable-next-line no-console
console.log('rolled back')
throw new Error(error)
} finally {
await session.close()
}
}
export function down(_next) {
throw new Error(
'Irreversible migration: contentExcerpt was removed and cannot be restored without regenerating from content',
)
}

View File

@ -10,7 +10,6 @@ export default {
default: () => new Date().toISOString(),
},
content: { type: 'string', disallow: [null], min: 3 },
contentExcerpt: { type: 'string', allow: [null] },
deleted: { type: 'boolean', default: false },
disabled: { type: 'boolean', default: false },
post: {

View File

@ -13,6 +13,7 @@ export default {
nameNL: { type: 'string' },
namePL: { type: 'string' },
nameRU: { type: 'string' },
nameSQ: { type: 'string' },
isIn: {
type: 'relationship',
relationship: 'IS_IN',

View File

@ -19,7 +19,6 @@ export default {
title: { type: 'string', disallow: [null], min: 3 },
slug: { type: 'string', allow: [null], unique: 'true' },
content: { type: 'string', disallow: [null], required: true, min: 3 },
contentExcerpt: { type: 'string', allow: [null] },
deleted: { type: 'boolean', default: false },
disabled: { type: 'boolean', default: false },
clickedCount: { type: 'int', default: 0 },

View File

@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable jest/valid-title */
import { cleanDatabase } from '@db/factories'
import { getNeode, getDriver } from '@db/neo4j'
@ -65,8 +66,8 @@ describe('slug', () => {
})
describe('characters', () => {
const createUser = (attrs) => {
return neode.create('User', attrs).then((user) => user.toJson())
const createUser = async (attrs) => {
return neode.create('User', attrs).then(async (user) => user.toJson())
}
it('-', async () => {
@ -81,7 +82,7 @@ describe('slug', () => {
})
})
it(' ', async () => {
it('', async () => {
await expect(createUser({ slug: 'matt rider' })).rejects.toThrow('ERROR_VALIDATION')
})

View File

@ -1,10 +1,12 @@
/* eslint-disable import/no-named-as-default-member */
import neo4j, { Driver } from 'neo4j-driver'
/* eslint-disable import-x/no-named-as-default-member */
import neo4j from 'neo4j-driver'
import Neode from 'neode'
import CONFIG from '@config/index'
import models from '@db/models/index'
import type { Driver } from 'neo4j-driver'
let driver: Driver
const defaultOptions = {
uri: CONFIG.NEO4J_URI,

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable n/no-process-exit */
import CONFIG from '@config/index'
import { cleanDatabase } from './factories'

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable n/no-process-exit */
import CONFIG from '@config/index'
import { cleanDatabase } from './factories'

View File

@ -2,19 +2,22 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable n/no-process-exit */
/* eslint-disable n/no-unpublished-import */
/* eslint-disable @typescript-eslint/restrict-template-expressions */
/* eslint-disable @typescript-eslint/no-confusing-void-expression */
import { faker } from '@faker-js/faker'
import sample from 'lodash/sample'
import CONFIG from '@config/index'
import { categories } from '@constants/categories'
import { ChangeGroupMemberRole } from '@graphql/queries/ChangeGroupMemberRole'
import { CreateComment } from '@graphql/queries/CreateComment'
import { CreateGroup } from '@graphql/queries/CreateGroup'
import { CreateMessage } from '@graphql/queries/CreateMessage'
import { CreatePost } from '@graphql/queries/CreatePost'
import { CreateRoom } from '@graphql/queries/CreateRoom'
import { JoinGroup } from '@graphql/queries/JoinGroup'
import CreateComment from '@graphql/queries/comments/CreateComment.gql'
import ChangeGroupMemberRole from '@graphql/queries/groups/ChangeGroupMemberRole.gql'
import CreateGroup from '@graphql/queries/groups/CreateGroup.gql'
import JoinGroup from '@graphql/queries/groups/JoinGroup.gql'
import CreateGroupRoom from '@graphql/queries/messaging/CreateGroupRoom.gql'
import CreateMessage from '@graphql/queries/messaging/CreateMessage.gql'
import CreatePost from '@graphql/queries/posts/CreatePost.gql'
import { createApolloTestSetup } from '@root/test/helpers'
import Factory from './factories'
@ -39,7 +42,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
authenticatedUser,
config: CONFIG,
})
const apolloSetup = createApolloTestSetup({ context })
const apolloSetup = await createApolloTestSetup({ context })
const { mutate, server, database } = apolloSetup
const { neode } = database
@ -827,15 +830,103 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
// eslint-disable-next-line no-console
console.log('seed', 'invitecodes')
// Peter invited the core users: Jenny, Bob, Huey
await Factory.build(
'inviteCode',
{
code: 'ABCDEF',
},
{
generatedBy: jennyRostock,
},
{ code: 'PETER1', comment: 'For Jenny' },
{ generatedBy: peterLustig },
)
await Factory.build(
'inviteCode',
{ code: 'PETER2', comment: 'For Bob' },
{ generatedBy: peterLustig },
)
await Factory.build(
'inviteCode',
{ code: 'PETER3', comment: 'For Huey' },
{ generatedBy: peterLustig },
)
// Jenny invited Dewey, Louie, Dagobert
await Factory.build(
'inviteCode',
{ code: 'JENNY1', comment: 'For Dewey' },
{ generatedBy: jennyRostock },
)
await Factory.build(
'inviteCode',
{ code: 'JENNY2', comment: 'For Louie' },
{ generatedBy: jennyRostock },
)
await Factory.build(
'inviteCode',
{ code: 'JENNY3', comment: 'For Dagobert' },
{ generatedBy: jennyRostock },
)
// Jenny's shared code (used by additional users)
await Factory.build(
'inviteCode',
{ code: 'ABCDEF', comment: 'Share link' },
{ generatedBy: jennyRostock },
)
// Jenny's unused code (still active)
await Factory.build('inviteCode', { code: 'JNEW01' }, { generatedBy: jennyRostock })
// Jenny's invalidated code (was used once, then deactivated)
await Factory.build(
'inviteCode',
{ code: 'JENNY0', comment: 'Old link', expiresAt: new Date().toISOString() },
{ generatedBy: jennyRostock },
)
// Jenny total: JENNY1, JENNY2, JENNY3, ABCDEF, JNEW01 (5 active) + JENNY0 (1 expired) = 6 codes
// Create REDEEMED and INVITED relationships via Cypher
const inviteSession = database.driver.session()
try {
await inviteSession.writeTransaction((txc) =>
txc.run(`
// Peter's invitations
MATCH (jenny:User {id: 'u3'}), (code1:InviteCode {code: 'PETER1'}), (peter:User {id: 'u1'})
MERGE (jenny)-[:REDEEMED {createdAt: toString(datetime())}]->(code1)
MERGE (peter)-[:INVITED {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(peter)
MERGE (peter)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
WITH 1 AS dummy
MATCH (bob:User {id: 'u2'}), (code2:InviteCode {code: 'PETER2'}), (peter:User {id: 'u1'})
MERGE (bob)-[:REDEEMED {createdAt: toString(datetime())}]->(code2)
MERGE (peter)-[:INVITED {createdAt: toString(datetime())}]->(bob)
MERGE (bob)-[:FOLLOWS {createdAt: toString(datetime())}]->(peter)
MERGE (peter)-[:FOLLOWS {createdAt: toString(datetime())}]->(bob)
WITH 1 AS dummy
MATCH (huey:User {id: 'u4'}), (code3:InviteCode {code: 'PETER3'}), (peter:User {id: 'u1'})
MERGE (huey)-[:REDEEMED {createdAt: toString(datetime())}]->(code3)
MERGE (peter)-[:INVITED {createdAt: toString(datetime())}]->(huey)
MERGE (huey)-[:FOLLOWS {createdAt: toString(datetime())}]->(peter)
MERGE (peter)-[:FOLLOWS {createdAt: toString(datetime())}]->(huey)
WITH 1 AS dummy
// Jenny's invitations
MATCH (dewey:User {id: 'u5'}), (code4:InviteCode {code: 'JENNY1'}), (jenny:User {id: 'u3'})
MERGE (dewey)-[:REDEEMED {createdAt: toString(datetime())}]->(code4)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(dewey)
MERGE (dewey)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(dewey)
WITH 1 AS dummy
MATCH (louie:User {id: 'u6'}), (code5:InviteCode {code: 'JENNY2'}), (jenny:User {id: 'u3'})
MERGE (louie)-[:REDEEMED {createdAt: toString(datetime())}]->(code5)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(louie)
MERGE (louie)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(louie)
WITH 1 AS dummy
MATCH (dagobert:User {id: 'u7'}), (code6:InviteCode {code: 'JENNY3'}), (jenny:User {id: 'u3'})
MERGE (dagobert)-[:REDEEMED {createdAt: toString(datetime())}]->(code6)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(dagobert)
MERGE (dagobert)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(dagobert)
`),
)
} finally {
await inviteSession.close()
}
authenticatedUser = await louie.toJson()
const mention1 =
@ -1210,13 +1301,123 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
})
// eslint-disable-next-line no-console
console.log('seed', 'users additional')
console.log('seed', 'users additional with map locations around Zwingenberg')
// Region Hessen (Mapbox-compatible hierarchy: place -> region -> country)
const Hessen = await Factory.build('location', {
id: 'region.8967011281068080',
name: 'Hessen',
type: 'region',
lng: 8.6528,
lat: 50.6521,
nameDE: 'Hessen',
nameEN: 'Hesse',
nameES: 'Hesse',
nameFR: 'Hesse',
nameIT: 'Assia',
namePT: 'Hessen',
nameNL: 'Hessen',
namePL: 'Hesja',
nameRU: 'Гессен',
})
await Hessen.relateTo(Germany, 'isIn')
// 50 villages around Zwingenberg (64673), Zwingenberg excluded
// Mapbox-compatible: type 'place', realistic IDs
const zwingenbergVillages = [
// Bergstraße (west)
{ id: 'place.8652241', name: 'Alsbach-Hähnlein', lat: 49.7389, lng: 8.6331 },
{ id: 'place.8652242', name: 'Bickenbach', lat: 49.7567, lng: 8.6178 },
{ id: 'place.8652243', name: 'Seeheim-Jugenheim', lat: 49.7631, lng: 8.6506 },
{ id: 'place.8652244', name: 'Bensheim', lat: 49.6812, lng: 8.6167 },
{ id: 'place.8652245', name: 'Auerbach', lat: 49.7053, lng: 8.6389 },
{ id: 'place.8652246', name: 'Heppenheim', lat: 49.6428, lng: 8.6392 },
{ id: 'place.8652247', name: 'Lorsch', lat: 49.6539, lng: 8.5678 },
{ id: 'place.8652248', name: 'Einhausen', lat: 49.6775, lng: 8.5578 },
{ id: 'place.8652249', name: 'Gernsheim', lat: 49.7528, lng: 8.4906 },
{ id: 'place.8652250', name: 'Pfungstadt', lat: 49.8056, lng: 8.6042 },
// Odenwald (east)
{ id: 'place.8652251', name: 'Reichenbach', lat: 49.725, lng: 8.67 },
{ id: 'place.8652252', name: 'Lautertal', lat: 49.7253, lng: 8.6914 },
{ id: 'place.8652253', name: 'Lindenfels', lat: 49.6836, lng: 8.7781 },
{ id: 'place.8652254', name: 'Modautal', lat: 49.7736, lng: 8.7258 },
{ id: 'place.8652255', name: 'Mühltal', lat: 49.8003, lng: 8.6917 },
{ id: 'place.8652256', name: 'Ober-Ramstadt', lat: 49.8306, lng: 8.7486 },
{ id: 'place.8652257', name: 'Reinheim', lat: 49.8289, lng: 8.8356 },
{ id: 'place.8652258', name: 'Groß-Bieberau', lat: 49.7906, lng: 8.8281 },
{ id: 'place.8652259', name: 'Fränkisch-Crumbach', lat: 49.745, lng: 8.8444 },
{ id: 'place.8652260', name: 'Brensbach', lat: 49.7742, lng: 8.8819 },
// Ried (west/southwest)
{ id: 'place.8652261', name: 'Bürstadt', lat: 49.6433, lng: 8.4506 },
{ id: 'place.8652262', name: 'Lampertheim', lat: 49.5978, lng: 8.47 },
{ id: 'place.8652263', name: 'Biblis', lat: 49.6878, lng: 8.4531 },
{ id: 'place.8652264', name: 'Groß-Rohrheim', lat: 49.7228, lng: 8.4822 },
{ id: 'place.8652265', name: 'Riedstadt', lat: 49.835, lng: 8.4944 },
{ id: 'place.8652266', name: 'Stockstadt am Rhein', lat: 49.8094, lng: 8.4656 },
{ id: 'place.8652267', name: 'Biebesheim', lat: 49.7806, lng: 8.4672 },
{ id: 'place.8652268', name: 'Trebur', lat: 49.9211, lng: 8.4081 },
{ id: 'place.8652269', name: 'Nauheim', lat: 49.9456, lng: 8.4494 },
{ id: 'place.8652270', name: 'Griesheim', lat: 49.8619, lng: 8.5722 },
// Darmstadt area (north)
{ id: 'place.8652271', name: 'Roßdorf', lat: 49.8572, lng: 8.7578 },
{ id: 'place.8652272', name: 'Messel', lat: 49.9333, lng: 8.75 },
{ id: 'place.8652273', name: 'Eppertshausen', lat: 49.95, lng: 8.85 },
{ id: 'place.8652274', name: 'Münster', lat: 49.9253, lng: 8.8653 },
{ id: 'place.8652275', name: 'Dieburg', lat: 49.8983, lng: 8.8467 },
{ id: 'place.8652276', name: 'Babenhausen', lat: 49.965, lng: 8.9511 },
{ id: 'place.8652277', name: 'Schaafheim', lat: 49.9244, lng: 8.9703 },
{ id: 'place.8652278', name: 'Groß-Umstadt', lat: 49.8667, lng: 8.9333 },
{ id: 'place.8652279', name: 'Otzberg', lat: 49.82, lng: 8.91 },
{ id: 'place.8652280', name: 'Höchst im Odenwald', lat: 49.7994, lng: 8.9986 },
// Further south
{ id: 'place.8652281', name: 'Mörlenbach', lat: 49.5969, lng: 8.7378 },
{ id: 'place.8652282', name: 'Rimbach', lat: 49.6256, lng: 8.7611 },
{ id: 'place.8652283', name: 'Fürth', lat: 49.6522, lng: 8.7789 },
{ id: 'place.8652284', name: 'Grasellenbach', lat: 49.6353, lng: 8.8531 },
{ id: 'place.8652285', name: 'Wald-Michelbach', lat: 49.57, lng: 8.83 },
{ id: 'place.8652286', name: 'Abtsteinach', lat: 49.5536, lng: 8.78 },
{ id: 'place.8652287', name: 'Gorxheimertal', lat: 49.5322, lng: 8.7322 },
{ id: 'place.8652288', name: 'Viernheim', lat: 49.5403, lng: 8.5783 },
{ id: 'place.8652289', name: 'Weinheim', lat: 49.5489, lng: 8.6639 },
{ id: 'place.8652290', name: 'Hemsbach', lat: 49.59, lng: 8.65 },
]
// Create village location nodes (one per village, shared by all users in that village)
const villageLocationNodes: (typeof Hamburg)[] = []
for (const village of zwingenbergVillages) {
const location = await Factory.build('location', {
id: village.id,
name: village.name,
type: 'place',
lng: village.lng,
lat: village.lat,
nameDE: village.name,
nameEN: village.name,
nameES: village.name,
nameFR: village.name,
nameIT: village.name,
namePT: village.name,
nameNL: village.name,
namePL: village.name,
nameRU: village.name,
})
await location.relateTo(Hessen, 'isIn')
villageLocationNodes.push(location)
}
// Create 1000 additional users with locations assigned during creation
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const additionalUsers: any[] = []
for (let i = 0; i < 1000; i++) {
if (i % 100 === 0) {
// eslint-disable-next-line no-console
console.log('seed', `additional users ${i}/1000`)
}
const user = await Factory.build('user')
await jennyRostock.relateTo(user, 'following')
await user.relateTo(jennyRostock, 'following')
// Assign village location (round-robin across 50 villages = ~20 users per village)
await user.relateTo(villageLocationNodes[i % villageLocationNodes.length], 'isIn')
additionalUsers.push(user)
const userObj = await user.toJson()
@ -1230,6 +1431,34 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
},
})
}
// eslint-disable-next-line no-console
console.log('seed', 'additional users 1000/1000 done')
// Jenny's first 99 additional users all redeemed code ABCDEF
// eslint-disable-next-line no-console
console.log('seed', 'invite redemptions for additional users')
const jennyInviteSession = database.driver.session()
try {
for (let i = 0; i < Math.min(99, additionalUsers.length); i++) {
// eslint-disable-next-line security/detect-object-injection
const userObj = await additionalUsers[i].toJson()
const userId = userObj.id as string
await jennyInviteSession.writeTransaction((txc) =>
txc.run(
`
MATCH (user:User {id: $userId}), (inviteCode:InviteCode {code: 'ABCDEF'}), (jenny:User {id: 'u3'})
MERGE (user)-[:REDEEMED {createdAt: toString(datetime())}]->(inviteCode)
MERGE (jenny)-[:INVITED {createdAt: toString(datetime())}]->(user)
MERGE (user)-[:FOLLOWS {createdAt: toString(datetime())}]->(jenny)
MERGE (jenny)-[:FOLLOWS {createdAt: toString(datetime())}]->(user)
`,
{ userId },
),
)
}
} finally {
await jennyInviteSession.close()
}
// Jenny users
for (let i = 0; i < 30; i++) {
@ -1528,87 +1757,139 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
// eslint-disable-next-line no-console
console.log('seed', 'chat')
// DM chat: Huey <-> Peter (first message creates room via userId)
authenticatedUser = await huey.toJson()
const { data: roomHueyPeter } = await mutate({
mutation: CreateRoom,
const { data: firstMsgHueyPeter } = await mutate({
mutation: CreateMessage,
variables: {
userId: (await peterLustig.toJson()).id,
content: faker.lorem.sentence(),
},
})
const roomIdHueyPeter = firstMsgHueyPeter?.CreateMessage.room.id
for (let i = 0; i < 30; i++) {
authenticatedUser = await huey.toJson()
await mutate({
mutation: CreateMessage,
variables: {
roomId: roomHueyPeter?.CreateRoom.id,
content: faker.lorem.sentence(),
},
})
for (let i = 0; i < 29; i++) {
authenticatedUser = await peterLustig.toJson()
await mutate({
mutation: CreateMessage,
variables: {
roomId: roomHueyPeter?.CreateRoom.id,
content: faker.lorem.sentence(),
},
variables: { roomId: roomIdHueyPeter, content: faker.lorem.sentence() },
})
}
authenticatedUser = await huey.toJson()
const { data: roomHueyJenny } = await mutate({
mutation: CreateRoom,
variables: {
userId: (await jennyRostock.toJson()).id,
},
})
for (let i = 0; i < 1000; i++) {
authenticatedUser = await huey.toJson()
await mutate({
mutation: CreateMessage,
variables: {
roomId: roomHueyJenny?.CreateRoom.id,
content: faker.lorem.sentence(),
},
variables: { roomId: roomIdHueyPeter, content: faker.lorem.sentence() },
})
}
// DM chat: Huey <-> Jenny (first message creates room via userId)
authenticatedUser = await huey.toJson()
const { data: firstMsgHueyJenny } = await mutate({
mutation: CreateMessage,
variables: {
userId: (await jennyRostock.toJson()).id,
content: faker.lorem.sentence(),
},
})
const roomIdHueyJenny = firstMsgHueyJenny?.CreateMessage.room.id
for (let i = 0; i < 999; i++) {
authenticatedUser = await jennyRostock.toJson()
await mutate({
mutation: CreateMessage,
variables: { roomId: roomIdHueyJenny, content: faker.lorem.sentence() },
})
authenticatedUser = await huey.toJson()
await mutate({
mutation: CreateMessage,
variables: { roomId: roomIdHueyJenny, content: faker.lorem.sentence() },
})
}
// DM chats: Jenny <-> additionalUsers
for (const user of additionalUsers.slice(0, 99)) {
authenticatedUser = await jennyRostock.toJson()
const { data: firstMsg } = await mutate({
mutation: CreateMessage,
variables: {
roomId: roomHueyJenny?.CreateRoom.id,
userId: (await user.toJson()).id,
content: faker.lorem.sentence(),
},
})
const dmRoomId = firstMsg?.CreateMessage.room.id
for (let i = 0; i < 28; i++) {
authenticatedUser = await user.toJson()
await mutate({
mutation: CreateMessage,
variables: { roomId: dmRoomId, content: faker.lorem.sentence() },
})
authenticatedUser = await jennyRostock.toJson()
await mutate({
mutation: CreateMessage,
variables: { roomId: dmRoomId, content: faker.lorem.sentence() },
})
}
}
// eslint-disable-next-line no-console
console.log('seed', 'group chat')
// Group g1 (School For Citizens) - active members: Jenny(owner/creator), Peter(usual), Bob(usual), Dewey(admin), Louie(owner), Dagobert(usual)
// Create group room as Jenny (creator of g1)
authenticatedUser = await jennyRostock.toJson()
const { data: roomG1 } = await mutate({
mutation: CreateGroupRoom,
variables: { groupId: 'g1' },
})
const g1RoomId = roomG1?.CreateGroupRoom.id
// Members have a conversation
const g1Members = [
{ user: jennyRostock, name: 'Jenny' },
{ user: peterLustig, name: 'Peter' },
{ user: dewey, name: 'Dewey' },
{ user: louie, name: 'Louie' },
]
for (let i = 0; i < 20; i++) {
const member = g1Members[i % g1Members.length]
authenticatedUser = await member.user.toJson()
await mutate({
mutation: CreateMessage,
variables: {
roomId: g1RoomId,
content: faker.lorem.sentence(),
},
})
}
for (const user of additionalUsers.slice(0, 99)) {
authenticatedUser = await jennyRostock.toJson()
const { data: room } = await mutate({
mutation: CreateRoom,
// Group g2 (Yoga Practice) - active members: Bob(owner/creator), Jenny(usual), Dewey(admin), Louie(usual), Dagobert(usual) - Huey is pending
authenticatedUser = await bobDerBaumeister.toJson()
const { data: roomG2 } = await mutate({
mutation: CreateGroupRoom,
variables: { groupId: 'g2' },
})
const g2RoomId = roomG2?.CreateGroupRoom.id
const g2Members = [
{ user: bobDerBaumeister, name: 'Bob' },
{ user: jennyRostock, name: 'Jenny' },
{ user: dewey, name: 'Dewey' },
{ user: louie, name: 'Louie' },
{ user: dagobert, name: 'Dagobert' },
]
for (let i = 0; i < 25; i++) {
const member = g2Members[i % g2Members.length]
authenticatedUser = await member.user.toJson()
await mutate({
mutation: CreateMessage,
variables: {
userId: (await user.toJson()).id,
roomId: g2RoomId,
content: faker.lorem.sentence(),
},
})
for (let i = 0; i < 29; i++) {
authenticatedUser = await jennyRostock.toJson()
await mutate({
mutation: CreateMessage,
variables: {
roomId: room?.CreateRoom.id,
content: faker.lorem.sentence(),
},
})
authenticatedUser = await user.toJson()
await mutate({
mutation: CreateMessage,
variables: {
roomId: room?.CreateRoom.id,
content: faker.lorem.sentence(),
},
})
}
}
// Group g0 (Investigative Journalism) - intentionally NO chat seeded
} catch (err) {
/* eslint-disable-next-line no-console */
console.error(err)

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface CategoryDbProperties {
createdAt: string

View File

@ -1,8 +1,7 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface CommentDbProperties {
content: string
contentExcerpt: string
createdAt: string
deleted: boolean
disabled: boolean

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface EmailAddressDbProperties {
createdAt: string

View File

@ -1,6 +1,5 @@
import { Integer, Node } from 'neo4j-driver'
import { PostDbProperties } from './Post'
import type { PostDbProperties } from './Post'
import type { Integer, Node } from 'neo4j-driver'
export interface EventDbProperties extends PostDbProperties {
eventIsOnline: boolean

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface GroupDbProperties {
about: string

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface ImageDbProperties {
alt: string

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface InviteCodeDbProperties {
code: string

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface LocationDbProperties {
id: string
@ -14,6 +14,7 @@ export interface LocationDbProperties {
namePL: string
namePT: string
nameRU: string
nameSQ: string
type: string
}

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface MessageDbProperties {
content: string
@ -7,7 +7,6 @@ export interface MessageDbProperties {
id: string
indexId: number
saved: boolean
seen: boolean
}
export type Message = Node<Integer, MessageDbProperties>

View File

@ -1,9 +1,8 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface PostDbProperties {
clickedCount: number
content: string
contentExcerpt: string
createdAt: string
deleted: boolean
disabled: boolean

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface ReportDbProperties {
closed: boolean

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface TagDbProperties {
deleted: boolean

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver'
import type { Integer, Node } from 'neo4j-driver'
export interface UserDbProperties {
allowEmbedIframes: boolean

View File

@ -0,0 +1,71 @@
{
"notification": "Notificación",
"subjects": {
"changedGroupMemberRole": "Rol en el grupo cambiado",
"chatMessage": "Nuevo mensaje de chat",
"commentedOnPost": "Nuevo comentario en una publicación",
"followedUserPosted": "Nueva publicación de un usuario seguido",
"mentionedInComment": "Mencionado en un comentario",
"mentionedInPost": "Mencionado en una publicación",
"newEmail": "Nueva dirección de correo electrónico",
"removedUserFromGroup": "Eliminado del grupo",
"postInGroup": "Nueva publicación en el grupo",
"resetPassword": "Restablecer contraseña",
"userJoinedGroup": "Un usuario se unió al grupo",
"userLeftGroup": "Un usuario abandonó el grupo",
"wrongEmail": "¿Correo electrónico incorrecto?"
},
"registration": {
"introduction": "Gracias por registrarte nos alegra tenerte con nosotros. Solo falta un pequeño paso antes de que podamos cambiar el mundo juntos … Por favor, confirma tu dirección de correo electrónico haciendo clic en el botón de abajo:",
"codeHint": "Si el botón de arriba no funciona, también puedes copiar el siguiente código en la ventana de tu navegador: ",
"codeHintException": "Sin embargo, esto solo funciona si te has registrado a través de nuestro sitio web.",
"notYouStart": "Si no te has registrado en ",
"notYouEnd": " te recomendamos que lo visites. Es una red social de personas para personas que quieren conectarse y cambiar el mundo juntas.",
"ps": "PD: Si ignoras este correo electrónico, no crearemos una cuenta para ti. ;)"
},
"emailVerification": {
"codeHint": "Si el botón de arriba no funciona, también puedes copiar el siguiente código en la ventana de tu navegador: ",
"introduction": "¿Quieres cambiar tu dirección de correo electrónico? ¡No hay problema! Simplemente haz clic en el botón de abajo para verificar tu nueva dirección:",
"doNotChange": "Si no quieres cambiar tu dirección de correo electrónico, simplemente ignora este mensaje. "
},
"support": "Si tienes preguntas o problemas, no dudes en contactar con nuestro soporte: ",
"buttons": {
"confirmEmail": "Confirma tu dirección de correo electrónico",
"resetPassword": "Restablecer contraseña",
"tryAgain": "Probar con otro correo electrónico",
"verifyEmail": "Verificar dirección de correo electrónico",
"viewChat": "Ver chat",
"viewComment": "Ver comentario",
"viewGroup": "Ver grupo",
"viewPost": "Ver publicación"
},
"general": {
"greeting": "Hola",
"seeYou": "¡Hasta pronto en ",
"yourTeam": " El equipo de {team}",
"settingsHint": "PD: Si no quieres recibir más correos electrónicos, cambia tu ",
"settingsName": "configuración de notificaciones",
"welcome": "Bienvenido a"
},
"resetPassword": {
"codeHint": "Si el botón de arriba no funciona, también puedes copiar el siguiente código en la ventana de tu navegador: ",
"ignore": "Si no has solicitado una nueva contraseña, simplemente ignora este correo electrónico.",
"introduction": "¿Has olvidado tu contraseña? ¡No hay problema! Simplemente haz clic en el botón de abajo para restablecerla en las próximas 24 horas:"
},
"wrongEmail": {
"ignoreEnd": " o si no querías restablecer tu contraseña, simplemente ignora este correo electrónico.",
"ignoreStart": "Si no tienes una cuenta en ",
"introduction": "Has solicitado un restablecimiento de contraseña, pero lamentablemente no hemos encontrado ninguna cuenta asociada a tu dirección de correo electrónico. ¿Te registraste quizás con otra dirección?"
},
"changedGroupMemberRole": "tu rol en el grupo «{groupName}» ha sido cambiado. Haz clic en el botón para ver este grupo:",
"chatMessageStart": "has recibido un nuevo mensaje de chat de ",
"chatMessageEnd": ".",
"commentedOnPost": " ha comentado en una publicación que sigues con el título «{postTitle}». Haz clic en el botón para ver este comentario:",
"followedUserPosted": ", un usuario al que sigues, ha escrito una nueva publicación con el título «{postTitle}». Haz clic en el botón para ver esta publicación:",
"mentionedInComment": " te ha mencionado en un comentario de la publicación con el título «{postTitle}». Haz clic en el botón para ver este comentario:",
"mentionedInPost": " te ha mencionado en una publicación con el título «{postTitle}». Haz clic en el botón para ver esta publicación:",
"removedUserFromGroup": "has sido eliminado del grupo «{groupName}».",
"postInGroup": "alguien ha escrito una nueva publicación con el título «{postTitle}» en uno de tus grupos. Haz clic en el botón para ver esta publicación:",
"userJoinedGroup": " se ha unido al grupo «{groupName}». Haz clic en el botón para ver este grupo:",
"userLeftGroup": " ha abandonado el grupo «{groupName}». Haz clic en el botón para ver este grupo:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Notification",
"subjects": {
"changedGroupMemberRole": "Rôle dans le groupe modifié",
"chatMessage": "Nouveau message de chat",
"commentedOnPost": "Nouveau commentaire sur une publication",
"followedUserPosted": "Nouvelle publication d'un utilisateur suivi",
"mentionedInComment": "Mentionné dans un commentaire",
"mentionedInPost": "Mentionné dans une publication",
"newEmail": "Nouvelle adresse e-mail",
"removedUserFromGroup": "Retiré du groupe",
"postInGroup": "Nouvelle publication dans le groupe",
"resetPassword": "Réinitialiser le mot de passe",
"userJoinedGroup": "Un utilisateur a rejoint le groupe",
"userLeftGroup": "Un utilisateur a quitté le groupe",
"wrongEmail": "Mauvaise adresse e-mail ?"
},
"registration": {
"introduction": "Merci de nous avoir rejoints nous sommes ravis de vous compter parmi nous. Il ne reste plus qu'une petite étape avant de pouvoir changer le monde ensemble … Veuillez confirmer votre adresse e-mail en cliquant sur le bouton ci-dessous :",
"codeHint": "Si le bouton ci-dessus ne fonctionne pas, vous pouvez aussi copier le code suivant dans votre navigateur : ",
"codeHintException": "Cependant, cela ne fonctionne que si vous vous êtes inscrit via notre site web.",
"notYouStart": "Si vous ne vous êtes pas inscrit sur ",
"notYouEnd": " nous vous recommandons d'y jeter un œil ! C'est un réseau social de personnes pour des personnes qui veulent se connecter et changer le monde ensemble.",
"ps": "PS : Si vous ignorez cet e-mail, nous ne créerons pas de compte pour vous. ;)"
},
"emailVerification": {
"codeHint": "Si le bouton ci-dessus ne fonctionne pas, vous pouvez aussi copier le code suivant dans votre navigateur : ",
"introduction": "Vous souhaitez changer votre adresse e-mail ? Pas de problème ! Cliquez simplement sur le bouton ci-dessous pour vérifier votre nouvelle adresse :",
"doNotChange": "Si vous ne souhaitez pas changer votre adresse e-mail, n'hésitez pas à ignorer ce message. "
},
"support": "Si vous avez des questions ou des problèmes, n'hésitez pas à contacter notre support : ",
"buttons": {
"confirmEmail": "Confirmer votre adresse e-mail",
"resetPassword": "Réinitialiser le mot de passe",
"tryAgain": "Essayer une autre adresse e-mail",
"verifyEmail": "Vérifier l'adresse e-mail",
"viewChat": "Voir le chat",
"viewComment": "Voir le commentaire",
"viewGroup": "Voir le groupe",
"viewPost": "Voir la publication"
},
"general": {
"greeting": "Bonjour",
"seeYou": "À bientôt sur ",
"yourTeam": " L'équipe {team}",
"settingsHint": "PS : Si vous ne souhaitez plus recevoir d'e-mails, modifiez vos ",
"settingsName": "paramètres de notification",
"welcome": "Bienvenue sur"
},
"resetPassword": {
"codeHint": "Si le bouton ci-dessus ne fonctionne pas, vous pouvez aussi copier le code suivant dans votre navigateur : ",
"ignore": "Si vous n'avez pas demandé de nouveau mot de passe, n'hésitez pas à ignorer cet e-mail.",
"introduction": "Vous avez oublié votre mot de passe ? Pas de problème ! Cliquez simplement sur le bouton ci-dessous pour le réinitialiser dans les 24 prochaines heures :"
},
"wrongEmail": {
"ignoreEnd": " ou si vous ne souhaitiez pas réinitialiser votre mot de passe, veuillez ignorer cet e-mail.",
"ignoreStart": "Si vous n'avez pas de compte sur ",
"introduction": "Vous avez demandé une réinitialisation de mot de passe, mais malheureusement nous n'avons trouvé aucun compte associé à votre adresse e-mail. Vous êtes-vous peut-être inscrit avec une autre adresse ?"
},
"changedGroupMemberRole": "votre rôle dans le groupe « {groupName} » a été modifié. Cliquez sur le bouton pour voir ce groupe :",
"chatMessageStart": "vous avez reçu un nouveau message de chat de ",
"chatMessageEnd": ".",
"commentedOnPost": " a commenté une publication que vous suivez avec le titre « {postTitle} ». Cliquez sur le bouton pour voir ce commentaire :",
"followedUserPosted": ", un utilisateur que vous suivez, a écrit une nouvelle publication avec le titre « {postTitle} ». Cliquez sur le bouton pour voir cette publication :",
"mentionedInComment": " vous a mentionné dans un commentaire sur la publication avec le titre « {postTitle} ». Cliquez sur le bouton pour voir ce commentaire :",
"mentionedInPost": " vous a mentionné dans une publication avec le titre « {postTitle} ». Cliquez sur le bouton pour voir cette publication :",
"removedUserFromGroup": "vous avez été retiré du groupe « {groupName} ».",
"postInGroup": "quelqu'un a écrit une nouvelle publication avec le titre « {postTitle} » dans l'un de vos groupes. Cliquez sur le bouton pour voir cette publication :",
"userJoinedGroup": " a rejoint le groupe « {groupName} ». Cliquez sur le bouton pour voir ce groupe :",
"userLeftGroup": " a quitté le groupe « {groupName} ». Cliquez sur le bouton pour voir ce groupe :"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Notifica",
"subjects": {
"changedGroupMemberRole": "Ruolo nel gruppo modificato",
"chatMessage": "Nuovo messaggio in chat",
"commentedOnPost": "Nuovo commento su un post",
"followedUserPosted": "Nuovo post di un utente seguito",
"mentionedInComment": "Menzionato in un commento",
"mentionedInPost": "Menzionato in un post",
"newEmail": "Nuovo indirizzo e-mail",
"removedUserFromGroup": "Rimosso dal gruppo",
"postInGroup": "Nuovo post nel gruppo",
"resetPassword": "Reimposta la password",
"userJoinedGroup": "Un utente si è unito al gruppo",
"userLeftGroup": "Un utente ha lasciato il gruppo",
"wrongEmail": "E-mail sbagliata?"
},
"registration": {
"introduction": "Grazie per esserti registrato siamo felici di averti con noi. Manca solo un piccolo passo prima di poter cambiare il mondo insieme … Per favore, conferma il tuo indirizzo e-mail cliccando sul pulsante qui sotto:",
"codeHint": "Se il pulsante qui sopra non funziona, puoi anche copiare il seguente codice nella finestra del tuo browser: ",
"codeHintException": "Tuttavia, questo funziona solo se ti sei registrato tramite il nostro sito web.",
"notYouStart": "Se non ti sei registrato su ",
"notYouEnd": " ti consigliamo di dargli un'occhiata! È un social network di persone per persone che vogliono connettersi e cambiare il mondo insieme.",
"ps": "PS: Se ignori questa e-mail, non creeremo un account per te. ;)"
},
"emailVerification": {
"codeHint": "Se il pulsante qui sopra non funziona, puoi anche copiare il seguente codice nella finestra del tuo browser: ",
"introduction": "Vuoi cambiare il tuo indirizzo e-mail? Nessun problema! Clicca semplicemente sul pulsante qui sotto per verificare il tuo nuovo indirizzo:",
"doNotChange": "Se non vuoi cambiare il tuo indirizzo e-mail, puoi semplicemente ignorare questo messaggio. "
},
"support": "Se hai domande o problemi, non esitare a contattare il nostro supporto: ",
"buttons": {
"confirmEmail": "Conferma il tuo indirizzo e-mail",
"resetPassword": "Reimposta la password",
"tryAgain": "Prova con un altro indirizzo e-mail",
"verifyEmail": "Verifica l'indirizzo e-mail",
"viewChat": "Visualizza la chat",
"viewComment": "Visualizza il commento",
"viewGroup": "Visualizza il gruppo",
"viewPost": "Visualizza il post"
},
"general": {
"greeting": "Ciao",
"seeYou": "A presto su ",
"yourTeam": " Il team {team}",
"settingsHint": "PS: Se non vuoi più ricevere e-mail, modifica le tue ",
"settingsName": "impostazioni di notifica",
"welcome": "Benvenuto su"
},
"resetPassword": {
"codeHint": "Se il pulsante qui sopra non funziona, puoi anche copiare il seguente codice nella finestra del tuo browser: ",
"ignore": "Se non hai richiesto una nuova password, puoi semplicemente ignorare questa e-mail.",
"introduction": "Hai dimenticato la tua password? Nessun problema! Clicca semplicemente sul pulsante qui sotto per reimpostarla entro le prossime 24 ore:"
},
"wrongEmail": {
"ignoreEnd": " o se non volevi reimpostare la tua password, puoi semplicemente ignorare questa e-mail.",
"ignoreStart": "Se non hai un account su ",
"introduction": "Hai richiesto un ripristino della password, ma purtroppo non abbiamo trovato un account associato al tuo indirizzo e-mail. Ti sei forse registrato con un altro indirizzo?"
},
"changedGroupMemberRole": "il tuo ruolo nel gruppo \u201e{groupName}\u201c è stato modificato. Clicca sul pulsante per visualizzare questo gruppo:",
"chatMessageStart": "hai ricevuto un nuovo messaggio in chat da ",
"chatMessageEnd": ".",
"commentedOnPost": " ha commentato un post che stai seguendo con il titolo \u201e{postTitle}\u201c. Clicca sul pulsante per visualizzare questo commento:",
"followedUserPosted": ", un utente che segui, ha scritto un nuovo post con il titolo \u201e{postTitle}\u201c. Clicca sul pulsante per visualizzare questo post:",
"mentionedInComment": " ti ha menzionato in un commento al post con il titolo \u201e{postTitle}\u201c. Clicca sul pulsante per visualizzare questo commento:",
"mentionedInPost": " ti ha menzionato in un post con il titolo \u201e{postTitle}\u201c. Clicca sul pulsante per visualizzare questo post:",
"removedUserFromGroup": "sei stato rimosso dal gruppo \u201e{groupName}\u201c.",
"postInGroup": "qualcuno ha scritto un nuovo post con il titolo \u201e{postTitle}\u201c in uno dei tuoi gruppi. Clicca sul pulsante per visualizzare questo post:",
"userJoinedGroup": " si è unito al gruppo \u201e{groupName}\u201c. Clicca sul pulsante per visualizzare questo gruppo:",
"userLeftGroup": " ha lasciato il gruppo \u201e{groupName}\u201c. Clicca sul pulsante per visualizzare questo gruppo:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Melding",
"subjects": {
"changedGroupMemberRole": "Rol in groep gewijzigd",
"chatMessage": "Nieuw chatbericht",
"commentedOnPost": "Nieuwe reactie op bericht",
"followedUserPosted": "Nieuw bericht van gevolgde gebruiker",
"mentionedInComment": "Vermeld in reactie",
"mentionedInPost": "Vermeld in bericht",
"newEmail": "Nieuw e-mailadres",
"removedUserFromGroup": "Uit groep verwijderd",
"postInGroup": "Nieuw bericht in groep",
"resetPassword": "Wachtwoord herstellen",
"userJoinedGroup": "Gebruiker is lid geworden van groep",
"userLeftGroup": "Gebruiker heeft groep verlaten",
"wrongEmail": "Verkeerd e-mailadres?"
},
"registration": {
"introduction": "Bedankt voor je aanmelding fijn dat je erbij bent. Er is nog maar één klein stapje nodig voordat we samen de wereld kunnen verbeteren … Bevestig je e-mailadres door op de onderstaande knop te klikken:",
"codeHint": "Als de bovenstaande knop niet werkt, kun je ook de volgende code in je browservenster kopiëren: ",
"codeHintException": "Dit werkt echter alleen als je je via onze website hebt geregistreerd.",
"notYouStart": "Als je je niet hebt aangemeld bij ",
"notYouEnd": " raden we je aan om een kijkje te nemen! Het is een sociaal netwerk van mensen voor mensen die samen de wereld willen veranderen.",
"ps": "PS: Als je deze e-mail negeert, maken we geen account voor je aan. ;)"
},
"emailVerification": {
"codeHint": "Als de bovenstaande knop niet werkt, kun je ook de volgende code in je browservenster kopiëren: ",
"introduction": "Wil je je e-mailadres wijzigen? Geen probleem! Klik op de onderstaande knop om je nieuwe adres te verifiëren:",
"doNotChange": "Als je je e-mailadres niet wilt wijzigen, kun je dit bericht gewoon negeren. "
},
"support": "Als je vragen of problemen hebt, neem dan gerust contact op met onze ondersteuning: ",
"buttons": {
"confirmEmail": "Bevestig je e-mailadres",
"resetPassword": "Wachtwoord herstellen",
"tryAgain": "Probeer een ander e-mailadres",
"verifyEmail": "E-mailadres verifiëren",
"viewChat": "Chat bekijken",
"viewComment": "Reactie bekijken",
"viewGroup": "Groep bekijken",
"viewPost": "Bericht bekijken"
},
"general": {
"greeting": "Hallo",
"seeYou": "Tot snel bij ",
"yourTeam": " Het {team} Team",
"settingsHint": "PS: Als je geen e-mails meer wilt ontvangen, wijzig dan je ",
"settingsName": "meldingsinstellingen",
"welcome": "Welkom bij"
},
"resetPassword": {
"codeHint": "Als de bovenstaande knop niet werkt, kun je ook de volgende code in je browservenster kopiëren: ",
"ignore": "Als je geen nieuw wachtwoord hebt aangevraagd, kun je deze e-mail gewoon negeren.",
"introduction": "Wachtwoord vergeten? Geen probleem! Klik op de onderstaande knop om het binnen 24 uur te herstellen:"
},
"wrongEmail": {
"ignoreEnd": " hebt of als je je wachtwoord niet wilde herstellen, kun je deze e-mail gewoon negeren.",
"ignoreStart": "Als je geen account hebt bij ",
"introduction": "Je hebt een wachtwoordherstel aangevraagd, maar we konden helaas geen account vinden dat aan je e-mailadres is gekoppeld. Heb je je misschien met een ander adres aangemeld?"
},
"changedGroupMemberRole": "je rol in de groep \u201e{groupName}\u201c is gewijzigd. Klik op de knop om deze groep te bekijken:",
"chatMessageStart": "je hebt een nieuw chatbericht ontvangen van ",
"chatMessageEnd": ".",
"commentedOnPost": " heeft gereageerd op een bericht dat je volgt met de titel \u201e{postTitle}\u201c. Klik op de knop om deze reactie te bekijken:",
"followedUserPosted": ", een gebruiker die je volgt, heeft een nieuw bericht geschreven met de titel \u201e{postTitle}\u201c. Klik op de knop om dit bericht te bekijken:",
"mentionedInComment": " heeft je vermeld in een reactie op het bericht met de titel \u201e{postTitle}\u201c. Klik op de knop om deze reactie te bekijken:",
"mentionedInPost": " heeft je vermeld in een bericht met de titel \u201e{postTitle}\u201c. Klik op de knop om dit bericht te bekijken:",
"removedUserFromGroup": "je bent verwijderd uit de groep \u201e{groupName}\u201c.",
"postInGroup": "iemand heeft een nieuw bericht geschreven met de titel \u201e{postTitle}\u201c in een van je groepen. Klik op de knop om dit bericht te bekijken:",
"userJoinedGroup": " is lid geworden van de groep \u201e{groupName}\u201c. Klik op de knop om deze groep te bekijken:",
"userLeftGroup": " heeft de groep \u201e{groupName}\u201c verlaten. Klik op de knop om deze groep te bekijken:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Powiadomienie",
"subjects": {
"changedGroupMemberRole": "Zmieniono rolę w grupie",
"chatMessage": "Nowa wiadomość na czacie",
"commentedOnPost": "Nowy komentarz do wpisu",
"followedUserPosted": "Nowy wpis obserwowanego użytkownika",
"mentionedInComment": "Wspomniano w komentarzu",
"mentionedInPost": "Wspomniano we wpisie",
"newEmail": "Nowy adres e-mail",
"removedUserFromGroup": "Usunięto z grupy",
"postInGroup": "Nowy wpis w grupie",
"resetPassword": "Zresetuj hasło",
"userJoinedGroup": "Użytkownik dołączył do grupy",
"userLeftGroup": "Użytkownik opuścił grupę",
"wrongEmail": "Nieprawidłowy e-mail?"
},
"registration": {
"introduction": "Dziękujemy za rejestrację cieszymy się, że jesteś z nami. Został jeszcze tylko jeden mały krok, zanim razem zaczniemy zmieniać świat … Potwierdź swój adres e-mail, klikając poniższy przycisk:",
"codeHint": "Jeśli powyższy przycisk nie działa, możesz też skopiować następujący kod do okna przeglądarki: ",
"codeHintException": "Działa to jednak tylko wtedy, gdy zarejestrowałeś się przez naszą stronę internetową.",
"notYouStart": "Jeśli nie rejestrowałeś się w ",
"notYouEnd": " polecamy zajrzeć! To sieć społecznościowa ludzi dla ludzi, którzy chcą się łączyć i wspólnie zmieniać świat.",
"ps": "PS: Jeśli zignorujesz tego e-maila, nie utworzymy dla Ciebie konta. ;)"
},
"emailVerification": {
"codeHint": "Jeśli powyższy przycisk nie działa, możesz też skopiować następujący kod do okna przeglądarki: ",
"introduction": "Chcesz zmienić swój adres e-mail? Żaden problem! Po prostu kliknij poniższy przycisk, aby zweryfikować nowy adres:",
"doNotChange": "Jeśli nie chcesz zmieniać swojego adresu e-mail, po prostu zignoruj tę wiadomość. "
},
"support": "Jeśli masz pytania lub problemy, skontaktuj się z naszym wsparciem: ",
"buttons": {
"confirmEmail": "Potwierdź swój adres e-mail",
"resetPassword": "Zresetuj hasło",
"tryAgain": "Spróbuj z innym adresem e-mail",
"verifyEmail": "Zweryfikuj adres e-mail",
"viewChat": "Zobacz czat",
"viewComment": "Zobacz komentarz",
"viewGroup": "Zobacz grupę",
"viewPost": "Zobacz wpis"
},
"general": {
"greeting": "Cześć",
"seeYou": "Do zobaczenia wkrótce na ",
"yourTeam": " Zespół {team}",
"settingsHint": "PS: Jeśli nie chcesz już otrzymywać e-maili, zmień swoje ",
"settingsName": "ustawienia powiadomień",
"welcome": "Witamy w"
},
"resetPassword": {
"codeHint": "Jeśli powyższy przycisk nie działa, możesz też skopiować następujący kod do okna przeglądarki: ",
"ignore": "Jeśli nie prosiłeś o nowe hasło, po prostu zignoruj tego e-maila.",
"introduction": "Zapomniałeś hasła? Żaden problem! Po prostu kliknij poniższy przycisk, aby je zresetować w ciągu najbliższych 24 godzin:"
},
"wrongEmail": {
"ignoreEnd": " lub jeśli nie chciałeś resetować hasła, po prostu zignoruj tego e-maila.",
"ignoreStart": "Jeśli nie masz konta w ",
"introduction": "Poprosiłeś o zresetowanie hasła, ale niestety nie znaleźliśmy konta powiązanego z Twoim adresem e-mail. Czy może zarejestrowałeś się z innym adresem?"
},
"changedGroupMemberRole": "Twoja rola w grupie „{groupName}“ została zmieniona. Kliknij przycisk, aby zobaczyć tę grupę:",
"chatMessageStart": "otrzymałeś nową wiadomość na czacie od ",
"chatMessageEnd": ".",
"commentedOnPost": " skomentował wpis, który obserwujesz, o tytule „{postTitle}“. Kliknij przycisk, aby zobaczyć ten komentarz:",
"followedUserPosted": ", użytkownik, którego obserwujesz, napisał nowy wpis o tytule „{postTitle}“. Kliknij przycisk, aby zobaczyć ten wpis:",
"mentionedInComment": " wspomniał o Tobie w komentarzu do wpisu o tytule „{postTitle}“. Kliknij przycisk, aby zobaczyć ten komentarz:",
"mentionedInPost": " wspomniał o Tobie we wpisie o tytule „{postTitle}“. Kliknij przycisk, aby zobaczyć ten wpis:",
"removedUserFromGroup": "zostałeś usunięty z grupy „{groupName}“.",
"postInGroup": "ktoś napisał nowy wpis o tytule „{postTitle}“ w jednej z Twoich grup. Kliknij przycisk, aby zobaczyć ten wpis:",
"userJoinedGroup": " dołączył do grupy „{groupName}“. Kliknij przycisk, aby zobaczyć tę grupę:",
"userLeftGroup": " opuścił grupę „{groupName}“. Kliknij przycisk, aby zobaczyć tę grupę:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Notificação",
"subjects": {
"changedGroupMemberRole": "Função no grupo alterada",
"chatMessage": "Nova mensagem no chat",
"commentedOnPost": "Novo comentário numa publicação",
"followedUserPosted": "Nova publicação de um utilizador seguido",
"mentionedInComment": "Mencionado num comentário",
"mentionedInPost": "Mencionado numa publicação",
"newEmail": "Novo endereço de e-mail",
"removedUserFromGroup": "Removido do grupo",
"postInGroup": "Nova publicação no grupo",
"resetPassword": "Redefinir palavra-passe",
"userJoinedGroup": "Um utilizador juntou-se ao grupo",
"userLeftGroup": "Um utilizador saiu do grupo",
"wrongEmail": "E-mail errado?"
},
"registration": {
"introduction": "Obrigado por te registares é ótimo ter-te connosco. Falta apenas um pequeno passo antes de podermos mudar o mundo juntos … Por favor, confirma o teu endereço de e-mail clicando no botão abaixo:",
"codeHint": "Se o botão acima não funcionar, também podes copiar o seguinte código na janela do teu navegador: ",
"codeHintException": "No entanto, isto só funciona se te registaste através do nosso site.",
"notYouStart": "Se não te registaste em ",
"notYouEnd": " recomendamos que dês uma olhada! É uma rede social de pessoas para pessoas que querem conectar-se e mudar o mundo juntas.",
"ps": "PS: Se ignorares este e-mail, não criaremos uma conta para ti. ;)"
},
"emailVerification": {
"codeHint": "Se o botão acima não funcionar, também podes copiar o seguinte código na janela do teu navegador: ",
"introduction": "Queres alterar o teu endereço de e-mail? Sem problema! Basta clicar no botão abaixo para verificar o teu novo endereço:",
"doNotChange": "Se não quiseres alterar o teu endereço de e-mail, podes simplesmente ignorar esta mensagem. "
},
"support": "Se tiveres dúvidas ou problemas, não hesites em contactar o nosso suporte: ",
"buttons": {
"confirmEmail": "Confirma o teu endereço de e-mail",
"resetPassword": "Redefinir palavra-passe",
"tryAgain": "Tentar outro endereço de e-mail",
"verifyEmail": "Verificar endereço de e-mail",
"viewChat": "Ver chat",
"viewComment": "Ver comentário",
"viewGroup": "Ver grupo",
"viewPost": "Ver publicação"
},
"general": {
"greeting": "Olá",
"seeYou": "Até breve em ",
"yourTeam": " A equipa {team}",
"settingsHint": "PS: Se não quiseres receber mais e-mails, altera as tuas ",
"settingsName": "definições de notificação",
"welcome": "Bem-vindo a"
},
"resetPassword": {
"codeHint": "Se o botão acima não funcionar, também podes copiar o seguinte código na janela do teu navegador: ",
"ignore": "Se não solicitaste uma nova palavra-passe, podes simplesmente ignorar este e-mail.",
"introduction": "Esqueceste a tua palavra-passe? Sem problema! Basta clicar no botão abaixo para a redefinir nas próximas 24 horas:"
},
"wrongEmail": {
"ignoreEnd": " ou se não querias redefinir a tua palavra-passe, podes simplesmente ignorar este e-mail.",
"ignoreStart": "Se não tens uma conta em ",
"introduction": "Solicitaste uma redefinição de palavra-passe, mas infelizmente não encontrámos nenhuma conta associada ao teu endereço de e-mail. Será que te registaste com outro endereço?"
},
"changedGroupMemberRole": "a tua função no grupo \u201e{groupName}\u201c foi alterada. Clica no botão para ver este grupo:",
"chatMessageStart": "recebeste uma nova mensagem no chat de ",
"chatMessageEnd": ".",
"commentedOnPost": " comentou numa publicação que estás a seguir com o título \u201e{postTitle}\u201c. Clica no botão para ver este comentário:",
"followedUserPosted": ", um utilizador que segues, escreveu uma nova publicação com o título \u201e{postTitle}\u201c. Clica no botão para ver esta publicação:",
"mentionedInComment": " mencionou-te num comentário na publicação com o título \u201e{postTitle}\u201c. Clica no botão para ver este comentário:",
"mentionedInPost": " mencionou-te numa publicação com o título \u201e{postTitle}\u201c. Clica no botão para ver esta publicação:",
"removedUserFromGroup": "foste removido do grupo \u201e{groupName}\u201c.",
"postInGroup": "alguém escreveu uma nova publicação com o título \u201e{postTitle}\u201c num dos teus grupos. Clica no botão para ver esta publicação:",
"userJoinedGroup": " juntou-se ao grupo \u201e{groupName}\u201c. Clica no botão para ver este grupo:",
"userLeftGroup": " saiu do grupo \u201e{groupName}\u201c. Clica no botão para ver este grupo:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Уведомление",
"subjects": {
"changedGroupMemberRole": "Роль в группе изменена",
"chatMessage": "Новое сообщение в чате",
"commentedOnPost": "Новый комментарий к публикации",
"followedUserPosted": "Новая публикация от пользователя, на которого вы подписаны",
"mentionedInComment": "Упоминание в комментарии",
"mentionedInPost": "Упоминание в публикации",
"newEmail": "Новый адрес электронной почты",
"removedUserFromGroup": "Удалён из группы",
"postInGroup": "Новая публикация в группе",
"resetPassword": "Сброс пароля",
"userJoinedGroup": "Пользователь присоединился к группе",
"userLeftGroup": "Пользователь покинул группу",
"wrongEmail": "Неверный адрес электронной почты?"
},
"registration": {
"introduction": "Спасибо за регистрацию мы рады, что вы с нами. Остался всего один маленький шаг, прежде чем мы сможем вместе менять мир … Пожалуйста, подтвердите свой адрес электронной почты, нажав на кнопку ниже:",
"codeHint": "Если кнопка выше не работает, вы также можете скопировать следующий код в окно браузера: ",
"codeHintException": "Однако это работает только в том случае, если вы зарегистрировались через наш сайт.",
"notYouStart": "Если вы не регистрировались на ",
"notYouEnd": " рекомендуем заглянуть! Это социальная сеть от людей для людей, которые хотят объединяться и вместе менять мир.",
"ps": "PS: Если вы проигнорируете это письмо, мы не создадим для вас аккаунт. ;)"
},
"emailVerification": {
"codeHint": "Если кнопка выше не работает, вы также можете скопировать следующий код в окно браузера: ",
"introduction": "Хотите изменить свой адрес электронной почты? Нет проблем! Просто нажмите на кнопку ниже, чтобы подтвердить новый адрес:",
"doNotChange": "Если вы не хотите менять свой адрес электронной почты, просто проигнорируйте это сообщение. "
},
"support": "Если у вас есть вопросы или проблемы, обращайтесь в нашу службу поддержки: ",
"buttons": {
"confirmEmail": "Подтвердите свой адрес электронной почты",
"resetPassword": "Сбросить пароль",
"tryAgain": "Попробовать другой адрес электронной почты",
"verifyEmail": "Подтвердить адрес электронной почты",
"viewChat": "Открыть чат",
"viewComment": "Посмотреть комментарий",
"viewGroup": "Посмотреть группу",
"viewPost": "Посмотреть публикацию"
},
"general": {
"greeting": "Здравствуйте",
"seeYou": "До скорой встречи на ",
"yourTeam": " Команда {team}",
"settingsHint": "PS: Если вы больше не хотите получать электронные письма, измените свои ",
"settingsName": "настройки уведомлений",
"welcome": "Добро пожаловать в"
},
"resetPassword": {
"codeHint": "Если кнопка выше не работает, вы также можете скопировать следующий код в окно браузера: ",
"ignore": "Если вы не запрашивали новый пароль, просто проигнорируйте это письмо.",
"introduction": "Забыли пароль? Нет проблем! Просто нажмите на кнопку ниже, чтобы сбросить его в течение ближайших 24 часов:"
},
"wrongEmail": {
"ignoreEnd": " или если вы не хотели сбрасывать пароль, просто проигнорируйте это письмо.",
"ignoreStart": "Если у вас нет аккаунта на ",
"introduction": "Вы запросили сброс пароля, но, к сожалению, мы не нашли аккаунт, связанный с вашим адресом электронной почты. Возможно, вы зарегистрировались с другим адресом?"
},
"changedGroupMemberRole": "ваша роль в группе «{groupName}» была изменена. Нажмите на кнопку, чтобы посмотреть эту группу:",
"chatMessageStart": "вы получили новое сообщение в чате от ",
"chatMessageEnd": ".",
"commentedOnPost": " прокомментировал публикацию, за которой вы следите, с заголовком «{postTitle}». Нажмите на кнопку, чтобы посмотреть этот комментарий:",
"followedUserPosted": ", пользователь, на которого вы подписаны, написал новую публикацию с заголовком «{postTitle}». Нажмите на кнопку, чтобы посмотреть эту публикацию:",
"mentionedInComment": " упомянул вас в комментарии к публикации с заголовком «{postTitle}». Нажмите на кнопку, чтобы посмотреть этот комментарий:",
"mentionedInPost": " упомянул вас в публикации с заголовком «{postTitle}». Нажмите на кнопку, чтобы посмотреть эту публикацию:",
"removedUserFromGroup": "вы были удалены из группы «{groupName}».",
"postInGroup": "кто-то написал новую публикацию с заголовком «{postTitle}» в одной из ваших групп. Нажмите на кнопку, чтобы посмотреть эту публикацию:",
"userJoinedGroup": " присоединился к группе «{groupName}». Нажмите на кнопку, чтобы посмотреть эту группу:",
"userLeftGroup": " покинул группу «{groupName}». Нажмите на кнопку, чтобы посмотреть эту группу:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Njoftim",
"subjects": {
"changedGroupMemberRole": "Roli në grup u ndryshua",
"chatMessage": "Mesazh i ri në chat",
"commentedOnPost": "Koment i ri në postim",
"followedUserPosted": "Postim i ri nga një përdorues i ndjekur",
"mentionedInComment": "U përmend në koment",
"mentionedInPost": "U përmend në postim",
"newEmail": "Adresë e re e-mail",
"removedUserFromGroup": "U hoq nga grupi",
"postInGroup": "Postim i ri në grup",
"resetPassword": "Rivendos fjalëkalimin",
"userJoinedGroup": "Një përdorues u bashkua me grupin",
"userLeftGroup": "Një përdorues u largua nga grupi",
"wrongEmail": "E-mail e gabuar?"
},
"registration": {
"introduction": "Faleminderit që u regjistruat jemi të lumtur që jeni me ne. Mbetet vetëm një hap i vogël përpara se të ndryshojmë botën së bashku … Ju lutemi konfirmoni adresën tuaj të e-mailit duke klikuar butonin më poshtë:",
"codeHint": "Nëse butoni më sipër nuk funksionon, mund të kopjoni kodin e mëposhtëm në dritaren e shfletuesit tuaj: ",
"codeHintException": "Megjithatë, kjo funksionon vetëm nëse jeni regjistruar përmes faqes sonë të internetit.",
"notYouStart": "Nëse nuk jeni regjistruar në ",
"notYouEnd": " ju rekomandojmë ta shikoni! Është një rrjet social nga njerëz për njerëz që duan të lidhen dhe të ndryshojnë botën së bashku.",
"ps": "PS: Nëse e injoroni këtë e-mail, nuk do të krijojmë një llogari për ju. ;)"
},
"emailVerification": {
"codeHint": "Nëse butoni më sipër nuk funksionon, mund të kopjoni kodin e mëposhtëm në dritaren e shfletuesit tuaj: ",
"introduction": "Dëshironi të ndryshoni adresën tuaj të e-mailit? Asnjë problem! Thjesht klikoni butonin më poshtë për të verifikuar adresën tuaj të re:",
"doNotChange": "Nëse nuk dëshironi të ndryshoni adresën tuaj të e-mailit, thjesht injoroni këtë mesazh. "
},
"support": "Nëse keni pyetje ose probleme, mos hezitoni të kontaktoni mbështetjen tonë: ",
"buttons": {
"confirmEmail": "Konfirmoni adresën tuaj të e-mailit",
"resetPassword": "Rivendos fjalëkalimin",
"tryAgain": "Provoni me një e-mail tjetër",
"verifyEmail": "Verifiko adresën e e-mailit",
"viewChat": "Shiko chatin",
"viewComment": "Shiko komentin",
"viewGroup": "Shiko grupin",
"viewPost": "Shiko postimin"
},
"general": {
"greeting": "Përshëndetje",
"seeYou": "Shihemi së shpejti në ",
"yourTeam": " Ekipi {team}",
"settingsHint": "PS: Nëse nuk dëshironi të merrni më e-mail, ndryshoni ",
"settingsName": "cilësimet e njoftimeve",
"welcome": "Mirë se vini në"
},
"resetPassword": {
"codeHint": "Nëse butoni më sipër nuk funksionon, mund të kopjoni kodin e mëposhtëm në dritaren e shfletuesit tuaj: ",
"ignore": "Nëse nuk keni kërkuar një fjalëkalim të ri, thjesht injoroni këtë e-mail.",
"introduction": "Keni harruar fjalëkalimin? Asnjë problem! Thjesht klikoni butonin më poshtë për ta rivendosur brenda 24 orëve të ardhshme:"
},
"wrongEmail": {
"ignoreEnd": " ose nëse nuk dëshironit të rivendosnit fjalëkalimin, ju lutemi injoroni këtë e-mail.",
"ignoreStart": "Nëse nuk keni një llogari në ",
"introduction": "Ju kërkuat një rivendosje të fjalëkalimit, por fatkeqësisht nuk gjetëm asnjë llogari të lidhur me adresën tuaj të e-mailit. A mund të jeni regjistruar me një adresë tjetër?"
},
"changedGroupMemberRole": "roli juaj në grupin \u201e{groupName}\u201c u ndryshua. Klikoni butonin për të parë këtë grup:",
"chatMessageStart": "keni marrë një mesazh të ri në chat nga ",
"chatMessageEnd": ".",
"commentedOnPost": " komentoi në një postim që po ndiqni me titullin \u201e{postTitle}\u201c. Klikoni butonin për të parë këtë koment:",
"followedUserPosted": ", një përdorues që ndiqni, shkroi një postim të ri me titullin \u201e{postTitle}\u201c. Klikoni butonin për të parë këtë postim:",
"mentionedInComment": " ju përmendi në një koment te postimi me titullin \u201e{postTitle}\u201c. Klikoni butonin për të parë këtë koment:",
"mentionedInPost": " ju përmendi në një postim me titullin \u201e{postTitle}\u201c. Klikoni butonin për të parë këtë postim:",
"removedUserFromGroup": "jeni hequr nga grupi \u201e{groupName}\u201c.",
"postInGroup": "dikush shkroi një postim të ri me titullin \u201e{postTitle}\u201c në një nga grupet tuaja. Klikoni butonin për të parë këtë postim:",
"userJoinedGroup": " u bashkua me grupin \u201e{groupName}\u201c. Klikoni butonin për të parë këtë grup:",
"userLeftGroup": " u largua nga grupi \u201e{groupName}\u201c. Klikoni butonin për të parë këtë grup:"
}

View File

@ -0,0 +1,71 @@
{
"notification": "Сповіщення",
"subjects": {
"changedGroupMemberRole": "Роль у групі змінено",
"chatMessage": "Нове повідомлення в чаті",
"commentedOnPost": "Новий коментар до публікації",
"followedUserPosted": "Нова публікація від користувача, на якого ви підписані",
"mentionedInComment": "Згадка в коментарі",
"mentionedInPost": "Згадка в публікації",
"newEmail": "Нова адреса електронної пошти",
"removedUserFromGroup": "Видалено з групи",
"postInGroup": "Нова публікація в групі",
"resetPassword": "Скинути пароль",
"userJoinedGroup": "Користувач приєднався до групи",
"userLeftGroup": "Користувач покинув групу",
"wrongEmail": "Невірна адреса електронної пошти?"
},
"registration": {
"introduction": "Дякуємо за реєстрацію ми раді, що ви з нами. Залишився лише один маленький крок, перш ніж ми зможемо разом змінювати світ … Будь ласка, підтвердіть свою адресу електронної пошти, натиснувши кнопку нижче:",
"codeHint": "Якщо кнопка вище не працює, ви також можете скопіювати наступний код у вікно браузера: ",
"codeHintException": "Однак це працює лише в тому випадку, якщо ви зареєструвалися через наш сайт.",
"notYouStart": "Якщо ви не реєструвалися на ",
"notYouEnd": " рекомендуємо заглянути! Це соціальна мережа від людей для людей, які хочуть об'єднуватися і разом змінювати світ.",
"ps": "PS: Якщо ви проігноруєте цей лист, ми не створимо для вас обліковий запис. ;)"
},
"emailVerification": {
"codeHint": "Якщо кнопка вище не працює, ви також можете скопіювати наступний код у вікно браузера: ",
"introduction": "Хочете змінити свою адресу електронної пошти? Без проблем! Просто натисніть кнопку нижче, щоб підтвердити нову адресу:",
"doNotChange": "Якщо ви не хочете змінювати свою адресу електронної пошти, просто проігноруйте це повідомлення. "
},
"support": "Якщо у вас є запитання або проблеми, зверніться до нашої служби підтримки: ",
"buttons": {
"confirmEmail": "Підтвердіть свою адресу електронної пошти",
"resetPassword": "Скинути пароль",
"tryAgain": "Спробувати іншу адресу електронної пошти",
"verifyEmail": "Підтвердити адресу електронної пошти",
"viewChat": "Відкрити чат",
"viewComment": "Переглянути коментар",
"viewGroup": "Переглянути групу",
"viewPost": "Переглянути публікацію"
},
"general": {
"greeting": "Вітаємо",
"seeYou": "До зустрічі на ",
"yourTeam": " Команда {team}",
"settingsHint": "PS: Якщо ви більше не хочете отримувати електронні листи, змініть свої ",
"settingsName": "налаштування сповіщень",
"welcome": "Ласкаво просимо до"
},
"resetPassword": {
"codeHint": "Якщо кнопка вище не працює, ви також можете скопіювати наступний код у вікно браузера: ",
"ignore": "Якщо ви не запитували новий пароль, просто проігноруйте цей лист.",
"introduction": "Забули пароль? Без проблем! Просто натисніть кнопку нижче, щоб скинути його протягом наступних 24 годин:"
},
"wrongEmail": {
"ignoreEnd": " або якщо ви не хотіли скидати пароль, просто проігноруйте цей лист.",
"ignoreStart": "Якщо у вас немає облікового запису на ",
"introduction": "Ви запросили скидання пароля, але, на жаль, ми не знайшли облікового запису, пов'язаного з вашою адресою електронної пошти. Можливо, ви зареєструвалися з іншою адресою?"
},
"changedGroupMemberRole": "вашу роль у групі «{groupName}» було змінено. Натисніть кнопку, щоб переглянути цю групу:",
"chatMessageStart": "ви отримали нове повідомлення в чаті від ",
"chatMessageEnd": ".",
"commentedOnPost": " прокоментував публікацію, за якою ви стежите, з заголовком «{postTitle}». Натисніть кнопку, щоб переглянути цей коментар:",
"followedUserPosted": ", користувач, на якого ви підписані, написав нову публікацію з заголовком «{postTitle}». Натисніть кнопку, щоб переглянути цю публікацію:",
"mentionedInComment": " згадав вас у коментарі до публікації з заголовком «{postTitle}». Натисніть кнопку, щоб переглянути цей коментар:",
"mentionedInPost": " згадав вас у публікації з заголовком «{postTitle}». Натисніть кнопку, щоб переглянути цю публікацію:",
"removedUserFromGroup": "вас було видалено з групи «{groupName}».",
"postInGroup": "хтось написав нову публікацію з заголовком «{postTitle}» в одній з ваших груп. Натисніть кнопку, щоб переглянути цю публікацію:",
"userJoinedGroup": " приєднався до групи «{groupName}». Натисніть кнопку, щоб переглянути цю групу:",
"userLeftGroup": " покинув групу «{groupName}». Натисніть кнопку, щоб переглянути цю групу:"
}

View File

@ -2,7 +2,7 @@ import CONFIG from '@config/index'
CONFIG.SUPPORT_EMAIL = 'devops@ocelot.social'
// eslint-disable-next-line import/first
// eslint-disable-next-line import-x/first
import { sendChatMessageMail } from './sendEmail'
const senderUser = {

View File

@ -12,7 +12,8 @@ import { createTransport } from 'nodemailer'
import CONFIG, { nodemailerTransportOptions } from '@config/index'
import logosWebapp from '@config/logosBranded'
import metadata from '@config/metadata'
import { UserDbProperties } from '@db/types/User'
import type { UserDbProperties } from '@db/types/User'
const welcomeImageUrl = new URL(logosWebapp.LOGO_WELCOME_PATH, CONFIG.CLIENT_URI)
const settingsUrl = new URL('/settings/notifications', CONFIG.CLIENT_URI)
@ -38,7 +39,7 @@ const email = new Email({
},
transport,
i18n: {
locales: ['en', 'de'],
locales: ['en', 'de', 'nl', 'fr', 'it', 'es', 'pt', 'pl', 'ru', 'sq', 'uk'],
defaultLocale: CONFIG.LANGUAGE_DEFAULT,
retryInDefaultLocale: false,
directory: path.join(__dirname, 'locales'),

View File

@ -2,7 +2,7 @@ import CONFIG from '@config/index'
CONFIG.SUPPORT_EMAIL = 'devops@ocelot.social'
// eslint-disable-next-line import/first
// eslint-disable-next-line import-x/first
import { sendEmailVerification } from './sendEmail'
describe('sendEmailVerification', () => {

View File

@ -2,7 +2,7 @@ import CONFIG from '@config/index'
CONFIG.SUPPORT_EMAIL = 'devops@ocelot.social'
// eslint-disable-next-line import/first
// eslint-disable-next-line import-x/first
import { sendNotificationMail } from './sendEmail'
describe('sendNotificationMail', () => {

View File

@ -2,7 +2,7 @@ import CONFIG from '@config/index'
CONFIG.SUPPORT_EMAIL = 'devops@ocelot.social'
// eslint-disable-next-line import/first
// eslint-disable-next-line import-x/first
import { sendRegistrationMail } from './sendEmail'
describe('sendRegistrationMail', () => {

View File

@ -2,7 +2,7 @@ import CONFIG from '@config/index'
CONFIG.SUPPORT_EMAIL = 'devops@ocelot.social'
// eslint-disable-next-line import/first
// eslint-disable-next-line import-x/first
import { sendResetPasswordMail } from './sendEmail'
describe('sendResetPasswordMail', () => {

View File

@ -2,7 +2,7 @@ import CONFIG from '@config/index'
CONFIG.SUPPORT_EMAIL = 'devops@ocelot.social'
// eslint-disable-next-line import/first
// eslint-disable-next-line import-x/first
import { sendWrongEmail } from './sendEmail'
describe('sendWrongEmail', () => {

6
backend/src/graphql.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
declare module '*.gql' {
import type { DocumentNode } from 'graphql'
const value: DocumentNode
export default value
}

View File

@ -0,0 +1,19 @@
import { GraphQLError } from 'graphql'
export class UserInputError extends GraphQLError {
constructor(message: string) {
super(message, { extensions: { code: 'BAD_USER_INPUT' } })
}
}
export class AuthenticationError extends GraphQLError {
constructor(message: string) {
super(message, { extensions: { code: 'UNAUTHENTICATED' } })
}
}
export class ForbiddenError extends GraphQLError {
constructor(message: string) {
super(message, { extensions: { code: 'FORBIDDEN' } })
}
}

View File

@ -0,0 +1,21 @@
/* eslint-disable n/no-sync, security/detect-non-literal-fs-filename */
// Register a require hook for .gql files so they can be imported at runtime.
// Jest uses its own graphqlTransform.ts for this; this hook covers tsx/node usage
// (e.g. db:seed).
import { readFileSync } from 'node:fs'
import Module from 'node:module'
import { parse } from 'graphql'
// @ts-expect-error -- require.extensions is deprecated but still functional for CJS hooks
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Module._extensions['.gql'] = function (_module: typeof module, filename: string) {
const content = readFileSync(filename, 'utf-8')
try {
_module.exports = parse(content)
} catch (error: unknown) {
throw new Error(
`Failed to parse ${filename}: ${error instanceof Error ? error.message : String(error)}`,
)
}
}

View File

@ -1,11 +0,0 @@
import gql from 'graphql-tag'
export const AddEmailAddress = gql`
mutation ($email: String!) {
AddEmailAddress(email: $email) {
email
verifiedAt
createdAt
}
}
`

View File

@ -1,15 +0,0 @@
import gql from 'graphql-tag'
export const AddPostEmotions = gql`
mutation ($to: _PostInput!, $data: _EMOTEDInput!) {
AddPostEmotions(to: $to, data: $data) {
from {
id
}
to {
id
}
emotion
}
}
`

View File

@ -0,0 +1,8 @@
query Category {
Category {
id
slug
name
icon
}
}

View File

@ -1,12 +0,0 @@
import gql from 'graphql-tag'
export const Category = gql`
query {
Category {
id
slug
name
icon
}
}
`

View File

@ -1,16 +0,0 @@
import gql from 'graphql-tag'
export const ChangeGroupMemberRole = gql`
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

@ -1,15 +0,0 @@
import gql from 'graphql-tag'
export const CreateComment = gql`
mutation ($id: ID, $postId: ID!, $content: String!) {
CreateComment(id: $id, postId: $postId, content: $content) {
id
content
author {
name
}
isPostObservedByMe
postObservingUsersCount
}
}
`

View File

@ -1,53 +0,0 @@
import gql from 'graphql-tag'
export const CreateGroup = gql`
mutation (
$id: ID
$name: String!
$slug: String
$about: String
$description: String!
$groupType: GroupType!
$actionRadius: GroupActionRadius!
$categoryIds: [ID]
$locationName: String # empty string '' sets it to null
) {
CreateGroup(
id: $id
name: $name
slug: $slug
about: $about
description: $description
groupType: $groupType
actionRadius: $actionRadius
categoryIds: $categoryIds
locationName: $locationName
) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
locationName
location {
name
nameDE
nameEN
}
myRole
}
}
`

Some files were not shown because too many files have changed in this diff Show More