Compare commits

...

147 Commits

Author SHA1 Message Date
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
c33ec0bd11
refactor(backend): reports query parameterization and resolver cleanup with test coverage (#9156) 2026-02-09 19:05:59 +00:00
7162f3bd4e
fix(workflow): allow code rabbit to approve PRs (#9195) 2026-02-09 18:02:25 +00:00
66d17db54b
feat(workflow): coderabbit (#9194) 2026-02-09 13:11:41 +00:00
1f8f902a28
chore(release): v3.14.0 (#9181) 2026-02-09 12:47:48 +00:00
5d1cabda46
refactor(webapp): vue3 migration - phase 2 - setup (#9161) 2026-02-09 11:53:12 +01:00
dependabot[bot]
f945a4bafc
build(deps): bump nginx from 1.29.4-alpine to 1.29.5-alpine in /webapp (#9162)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-08 04:25:43 +00:00
dependabot[bot]
b39782b788
build(deps): bump node from 25.5.0-alpine to 25.6.0-alpine in /backend (#9163)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-08 03:34:59 +00:00
dependabot[bot]
99bf691ecb
build(deps): bump node from 25.5.0-alpine to 25.6.0-alpine in /webapp (#9164)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-08 04:14:15 +01:00
dependabot[bot]
9814c3e395
build(deps-dev): bump cypress from 15.9.0 to 15.10.0 in the cypress group (#9165)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-08 00:53:33 +00:00
dependabot[bot]
e0b3b7d375
build(deps-dev): bump webpack from 5.104.1 to 5.105.0 (#9167)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-08 00:14:48 +00:00
dependabot[bot]
5f5dced68e
build(deps): bump nodemailer from 7.0.13 to 8.0.0 in /backend (#9168)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-08 00:44:31 +01:00
dependabot[bot]
0190f52dfc
build(deps): bump minimatch from 10.1.1 to 10.1.2 in /backend (#9169)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-07 22:59:33 +00:00
dependabot[bot]
5b3e99bf76
build(deps-dev): bump @types/node from 25.1.0 to 25.2.1 in /backend (#9171)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-07 22:34:27 +00:00
dependabot[bot]
b526e1ffb4
build(deps): bump @aws-sdk/client-s3 and @aws-sdk/lib-storage in /backend (#9173)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-07 22:09:03 +00:00
8806abda6c
refactor(workflow): do not clean cache after run (#9155)
Co-authored-by: mahula <lenzmath@posteo.de>
2026-02-07 21:48:01 +00:00
dependabot[bot]
5294ab963a
build(deps-dev): bump eslint-plugin-jest from 29.12.1 to 29.12.2 in /backend (#9177)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-07 21:16:44 +00:00
dependabot[bot]
fac44d734e
build(deps): bump peter-evans/repository-dispatch from cf70392543065ca62813db6712a06df1c4f4ae9f to f49a8ac5751834a0666df77deb0289abbe2b3a78 (#9179)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-07 21:54:34 +01:00
0e4e72429d
refactor(webapp): vue 2.7.16 (#9160) 2026-02-04 10:32:18 +00:00
a78c25a258
refactor(backend): test roles (#9157) 2026-02-03 16:00:37 +00:00
753a300c3f
refactor(backend): middleware before/after (#9128) 2026-02-03 14:20:19 +01:00
1017 changed files with 96894 additions and 20578 deletions

103
.coderabbit.yaml Normal file
View File

@ -0,0 +1,103 @@
# CodeRabbit Configuration
# https://docs.coderabbit.ai/guides/configure-coderabbit
language: de
reviews:
pre_merge_checks:
docstrings:
mode: "off"
# Automatisches Review für alle PRs
auto_review:
enabled: true
drafts: false
base_branches:
- master
- main
auto_approve:
enabled: true
# Review-Einstellungen
request_changes_workflow: true
high_level_summary: true
poem: false
review_status: true
collapse_walkthrough: false
changed_files_summary: true
# Pfad-Filter (Dateien die ignoriert werden)
path_filters:
- "!**/*.lock"
- "!**/package-lock.json"
- "!**/yarn.lock"
- "!**/*.snap"
- "!**/coverage/**"
- "!**/dist/**"
- "!**/node_modules/**"
- "!**/*.min.js"
- "!**/*.min.css"
- "!**/.git/**"
- "!**/storybook-static/**"
# Instruktionen für spezifische Pfade
path_instructions:
- path: "webapp/**/*.vue"
instructions: |
Prüfe Vue.js Best Practices:
- Composition API Verwendung
- Props Validierung
- Event-Handling
- Reaktivität
- path: "webapp/**/*.spec.js"
instructions: |
Prüfe Test-Qualität:
- Aussagekräftige Test-Namen
- Edge Cases abgedeckt
- Mocking korrekt verwendet
- path: "backend/**/*.js"
instructions: |
Prüfe Backend Best Practices:
- Error Handling
- Input Validierung
- SQL Injection Prevention
- Performance (N+1 Queries)
- path: "packages/ui/**/*.ts"
instructions: |
Prüfe UI Library Standards:
- TypeScript Typisierung
- Vue 2/3 Kompatibilität (vue-demi)
- Accessibility (WCAG 2.1)
- CVA Varianten-Pattern
- path: "packages/ui/**/*.vue"
instructions: |
Prüfe UI Komponenten:
- Render-Funktion Pattern für vue-demi
- Props mit korrekten Types
- Slots dokumentiert
- Keine Template-Syntax (nur h() für Vue 2/3 Kompatibilität)
# Chat-Befehle
chat:
auto_reply: true
# Ton und Stil
tone_instructions: |
Sei konstruktiv und freundlich.
Erkläre das "Warum" hinter Vorschlägen.
Priorisiere Sicherheit > Korrektheit > Performance > Lesbarkeit.
Schlage konkrete Code-Änderungen vor wenn möglich.
# Knowledge Base (Repository-spezifisches Wissen)
knowledge_base:
learnings:
scope: auto
issues:
scope: auto
pull_requests:
scope: auto

View File

@ -126,3 +126,71 @@ updates:
day: "saturday" day: "saturday"
timezone: "Europe/Berlin" timezone: "Europe/Berlin"
time: "03:00" time: "03:00"
# ui library
- package-ecosystem: npm
open-pull-requests-limit: 99
directory: "/packages/ui"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"
groups:
vue:
applies-to: version-updates
patterns:
- "vue*"
- "@vue*"
vite:
applies-to: version-updates
patterns:
- "vite*"
- "@vitejs*"
vitest:
applies-to: version-updates
patterns:
- "vitest*"
- "@vitest*"
# ui examples
- package-ecosystem: npm
open-pull-requests-limit: 99
directory: "/packages/ui/examples/vue3-tailwind"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"
- package-ecosystem: npm
open-pull-requests-limit: 99
directory: "/packages/ui/examples/vue3-css"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"
- package-ecosystem: npm
open-pull-requests-limit: 99
directory: "/packages/ui/examples/vue2-tailwind"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"
- package-ecosystem: npm
open-pull-requests-limit: 99
directory: "/packages/ui/examples/vue2-css"
rebase-strategy: "disabled"
schedule:
interval: weekly
day: "saturday"
timezone: "Europe/Berlin"
time: "03:00"

View File

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

View File

@ -11,7 +11,7 @@ jobs:
documentation: ${{ steps.changes.outputs.documentation }} documentation: ${{ steps.changes.outputs.documentation }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for markdown file changes - name: Check for markdown file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -28,7 +28,7 @@ jobs:
if: needs.files-changed.outputs.markdown == 'true' if: needs.files-changed.outputs.markdown == 'true'
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Remove uncheckable documentation files - 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 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' if: needs.files-changed.outputs.documentation == 'true'
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node 20 - name: Setup Node 20
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version: '20' node-version: '20'

View File

@ -1,42 +0,0 @@
###############################################################################
# A Github repo has max 10 GB of cache.
# https://github.blog/changelog/2021-11-23-github-actions-cache-size-is-now-increased-to-10gb-per-repository/
#
# To avoid "cache thrashing" by their cache eviction policy it is recommended
# to apply a cache cleanup workflow at PR closing to dele cache leftovers of
# the current branch:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#force-deleting-cache-entries
###############################################################################
name: ocelot.social cache cleanup on pr closing
on:
pull_request:
types:
- closed
jobs:
clean-branch-cache:
name: Cleanup branch cache
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
REPO=${{ github.repository }}
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -13,7 +13,7 @@ jobs:
documentation: ${{ steps.changes.outputs.documentation }} documentation: ${{ steps.changes.outputs.documentation }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for file changes - name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -27,10 +27,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node 20 - name: Setup Node 20
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version: 20 node-version: 20

View File

@ -59,7 +59,9 @@ jobs:
steps: steps:
- name: Checkout repository - 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@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9
with: with:
@ -81,7 +83,7 @@ jobs:
type=sha type=sha
- name: Build and push Docker images - name: Build and push Docker images
id: push id: push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with: with:
context: ${{ matrix.app.context }} context: ${{ matrix.app.context }}
target: ${{ matrix.app.target }} target: ${{ matrix.app.target }}
@ -89,3 +91,5 @@ jobs:
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.app.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.app.name }}

View File

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

View File

@ -11,7 +11,7 @@ jobs:
backend: ${{ steps.changes.outputs.backend }} backend: ${{ steps.changes.outputs.backend }}
docker: ${{ steps.changes.outputs.docker }} docker: ${{ steps.changes.outputs.docker }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for backend file changes - name: Check for backend file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -28,13 +28,25 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - 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@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Neo4J | Build 'community' image - name: Neo4J | Build 'community' image
run: | uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
docker compose -f docker-compose.yml -f docker-compose.test.yml build neo4j with:
docker save "ghcr.io/ocelot-social-community/ocelot-social/neo4j:community" > /tmp/neo4j.tar 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 - name: Cache docker images
id: cache-neo4j id: cache-neo4j
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -49,13 +61,25 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - 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@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: backend | Build 'test' image - name: backend | Build 'test' image
run: | uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
docker compose -f docker-compose.yml -f docker-compose.test.yml build backend with:
docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar 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 - name: Cache docker images
id: cache-backend id: cache-backend
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -70,15 +94,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version-file: 'backend/.nvmrc' node-version-file: 'backend/.nvmrc'
cache: 'yarn'
cache-dependency-path: 'backend/yarn.lock'
- name: backend | Lint - name: backend | Lint
run: cd backend && yarn && yarn run lint run: cd backend && yarn --frozen-lockfile && yarn run lint
unit_test_backend: unit_test_backend:
name: Unit tests - Backend name: Unit tests - Backend
@ -89,7 +115,7 @@ jobs:
checks: write checks: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Restore Neo4J cache - name: Restore Neo4J cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -127,20 +153,3 @@ jobs:
- name: backend | Unit test incl. coverage check - name: backend | Unit test incl. coverage check
run: docker compose exec -T backend yarn test run: docker compose exec -T backend yarn test
cleanup:
name: Cleanup
if: ${{ needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.docker == 'true' }}
needs: [files-changed, unit_test_backend]
runs-on: ubuntu-latest
permissions: write-all
continue-on-error: true
steps:
- name: Delete cache
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh extension install actions/gh-actions-cache
KEY="${{ github.run_id }}-backend-neo4j-cache"
gh actions-cache delete $KEY -R Ocelot-Social-Community/Ocelot-Social --confirm
KEY="${{ github.run_id }}-backend-cache"
gh actions-cache delete $KEY -R Ocelot-Social-Community/Ocelot-Social --confirm

View File

@ -8,28 +8,52 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - 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@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Copy backend env file - name: Copy backend env file
run: | run: |
cp backend/.env.test_e2e backend/.env cp backend/.env.test_e2e backend/.env
cp webapp/.env.template webapp/.env cp webapp/.env.template webapp/.env
- name: Build backend and dependencies - name: Neo4J | Build image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
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: Backend | Build image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
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: | run: |
# Build and start all required images for backend docker pull quay.io/minio/minio:latest
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach neo4j backend --build docker pull quay.io/minio/mc:latest
docker pull maildev/maildev:latest
# Save the build images
docker save "ghcr.io/ocelot-social-community/ocelot-social/backend:test" > /tmp/backend.tar - 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 "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/minio:latest" > /tmp/minio.tar
docker save "quay.io/minio/mc:latest" > /tmp/minio-mc.tar docker save "quay.io/minio/mc:latest" > /tmp/minio-mc.tar
docker save "maildev/maildev:latest" > /tmp/mailserver.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 - name: Cache docker images
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
with: with:
@ -46,19 +70,26 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Copy backend env file - name: Set up Docker Buildx
run: | uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
cp backend/.env.test_e2e backend/.env
cp webapp/.env.template webapp/.env - name: Webapp | Build 'test' image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
- name: Build docker image with:
run: | context: .
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach webapp --build --no-deps file: webapp/Dockerfile
docker save "ghcr.io/ocelot-social-community/ocelot-social/webapp:test" > /tmp/webapp.tar target: test
load: true
- name: Cache docker image 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@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
with: with:
path: /tmp/webapp.tar path: /tmp/webapp.tar
@ -72,10 +103,10 @@ jobs:
run: rm -rf /opt/hostedtoolcache run: rm -rf /opt/hostedtoolcache
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.4.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version-file: 'backend/.nvmrc' node-version-file: 'backend/.nvmrc'
cache: 'yarn' cache: 'yarn'
@ -87,7 +118,8 @@ jobs:
- name: Install cypress requirements - name: Install cypress requirements
run: | 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 sudo chmod +x /opt/cucumber-json-formatter
cd backend cd backend
yarn install yarn install
@ -105,26 +137,39 @@ jobs:
/home/runner/work/Ocelot-Social/Ocelot-Social /home/runner/work/Ocelot-Social/Ocelot-Social
key: ${{ github.run_id }}-e2e-cypress key: ${{ github.run_id }}-e2e-cypress
fullstack_tests: list_features:
name: Fullstack | tests name: List Feature Files
if: success() runs-on: ubuntu-latest
needs: [prepare_backend_environment, prepare_webapp_image, prepare_cypress] 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=$(find cypress/e2e/ -maxdepth 1 -name "*.feature" -printf '%f\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 runs-on: ubuntu-latest
env:
jobs: 8
strategy: strategy:
fail-fast: false
matrix: matrix:
# run copies of the current job in parallel feature: ${{ fromJson(needs.list_features.outputs.features) }}
job: [1, 2, 3, 4, 5, 6, 7, 8]
steps: steps:
- name: Delete huge unnecessary tools folder - name: Delete huge unnecessary tools folder
run: rm -rf /opt/hostedtoolcache run: rm -rf /opt/hostedtoolcache
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.4.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version-file: 'backend/.nvmrc' node-version-file: 'backend/.nvmrc'
cache: 'yarn' cache: 'yarn'
@ -156,10 +201,22 @@ jobs:
path: /tmp/webapp.tar path: /tmp/webapp.tar
key: ${{ github.run_id }}-e2e-webapp-cache 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 - name: Boot up test system | docker compose
run: | 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/neo4j.tar
docker load < /tmp/backend.tar docker load < /tmp/backend.tar
docker load < /tmp/minio.tar docker load < /tmp/minio.tar
@ -167,11 +224,18 @@ jobs:
docker load < /tmp/mailserver.tar docker load < /tmp/mailserver.tar
docker load < /tmp/webapp.tar docker load < /tmp/webapp.tar
docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach backend mailserver webapp 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: Full stack tests | run tests - name: Full stack tests | run tests
id: e2e-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 - name: Full stack tests | if tests failed, compile html report
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }} if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
@ -184,27 +248,19 @@ jobs:
if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }} if: ${{ failure() && steps.e2e-tests.conclusion == 'failure' }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with: with:
name: ocelot-e2e-test-report-pr${{ needs.docker_preparation.outputs.pr-number }} name: e2e-report-${{ matrix.feature }}
path: /home/runner/work/Ocelot-Social/Ocelot-Social/cypress/reports/cucumber_html_report path: /home/runner/work/Ocelot-Social/Ocelot-Social/cypress/reports/cucumber_html_report
cleanup_cache: e2e_status:
name: Cleanup Cache name: E2E | Status
needs: fullstack_tests if: always()
needs: [fullstack_tests]
runs-on: ubuntu-latest runs-on: ubuntu-latest
continue-on-error: true
steps: steps:
- name: Checkout code - name: Check E2E results
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
- name: Full stack tests | cleanup cache
run: | run: |
cacheKeys=$(gh cache list --json key --jq '.[] | select(.key | startswith("${{ github.run_id }}-e2e-")) | .key') if [ "${{ needs.fullstack_tests.result }}" != "success" ]; then
set +e echo "E2E tests failed or were cancelled (result: ${{ needs.fullstack_tests.result }})"
echo "Deleting caches..." exit 1
for cacheKey in $cacheKeys fi
do
gh cache delete "$cacheKey"
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -11,7 +11,7 @@ jobs:
docker: ${{ steps.changes.outputs.docker }} docker: ${{ steps.changes.outputs.docker }}
webapp: ${{ steps.changes.outputs.webapp }} webapp: ${{ steps.changes.outputs.webapp }}
steps: steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check for frontend file changes - name: Check for frontend file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@ -28,10 +28,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version-file: 'webapp/.nvmrc' node-version-file: 'webapp/.nvmrc'
@ -43,16 +43,28 @@ jobs:
build_test_webapp: build_test_webapp:
name: Docker Build Test - Webapp name: Docker Build Test - Webapp
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.webapp == 'true' if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.webapp == 'true'
needs: [files-changed, prepare] needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - 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@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Webapp | Build 'test' image - name: Webapp | Build 'test' image
run: | uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
docker build --target test -f webapp/Dockerfile -t "ocelotsocialnetwork/webapp:test" . with:
docker save "ocelotsocialnetwork/webapp:test" > /tmp/webapp.tar 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 - name: Cache docker image
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -67,15 +79,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4.0.3 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with: with:
node-version-file: 'webapp/.nvmrc' node-version-file: 'webapp/.nvmrc'
cache: 'yarn'
cache-dependency-path: 'webapp/yarn.lock'
- name: webapp | Lint - name: webapp | Lint
run: cd webapp && yarn && yarn run lint run: cd webapp && yarn --frozen-lockfile && yarn run lint
unit_test_webapp: unit_test_webapp:
name: Unit Tests - Webapp name: Unit Tests - Webapp
@ -86,7 +100,7 @@ jobs:
checks: write checks: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.1.7 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Restore webapp cache - name: Restore webapp cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2 uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4.0.2
@ -102,26 +116,8 @@ jobs:
cp webapp/.env.template webapp/.env cp webapp/.env.template webapp/.env
cp backend/.env.template backend/.env cp backend/.env.template backend/.env
- name: backend | docker compose - name: Start webapp container
# 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
run: docker compose -f docker-compose.yml -f docker-compose.test.yml up --detach --no-deps webapp --build
- name: webapp | Unit tests incl. coverage check - name: webapp | Unit tests incl. coverage check
run: docker compose exec -T webapp yarn test run: docker compose exec -T webapp yarn test
cleanup:
name: Cleanup
if: ${{ needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.webapp == 'true' }}
needs: [files-changed, unit_test_webapp]
runs-on: ubuntu-latest
permissions: write-all
continue-on-error: true
steps:
- name: Delete cache
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh extension install actions/gh-actions-cache
KEY="${{ github.run_id }}-webapp-cache"
gh actions-cache delete $KEY -R Ocelot-Social-Community/Ocelot-Social --confirm

View File

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

95
.github/workflows/ui-build.yml vendored Normal file
View File

@ -0,0 +1,95 @@
name: UI Build
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build library
run: npm run build
- name: Verify build output
run: |
echo "Checking build output..."
# Check that dist directory exists
if [ ! -d "dist" ]; then
echo "::error::dist directory not found"
exit 1
fi
# Check required files exist
FILES=(
"dist/index.mjs"
"dist/index.cjs"
"dist/index.d.ts"
"dist/index.d.cts"
"dist/tailwind.preset.mjs"
"dist/tailwind.preset.cjs"
"dist/tailwind.preset.d.ts"
"dist/tailwind.preset.d.cts"
"dist/style.css"
)
for file in "${FILES[@]}"; do
if [ ! -f "$file" ]; then
echo "::error::Missing required file: $file"
exit 1
fi
echo "✓ $file"
done
echo ""
echo "All build outputs verified!"
- name: Validate package
run: npm run validate
- name: Upload build artifacts
uses: actions/upload-artifact@v6
with:
name: dist
path: packages/ui/dist/
retention-days: 7

121
.github/workflows/ui-compatibility.yml vendored Normal file
View File

@ -0,0 +1,121 @@
name: UI Compatibility
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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:
working-directory: packages/ui
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build library
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v6
with:
name: ui-dist
path: packages/ui/dist/
retention-days: 1
test-compatibility:
name: Test Compatibility
if: needs.files-changed.outputs.ui == 'true'
needs: [files-changed, build-library]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
example:
- vue3-tailwind
- vue3-css
- vue2-tailwind
- vue2-css
defaults:
run:
working-directory: packages/ui/examples/${{ matrix.example }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: ui-dist
path: packages/ui/dist/
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/examples/${{ matrix.example }}/package-lock.json
- name: Install dependencies
run: npm install
- name: Lint
run: npm run lint
- name: Run tests
run: npm test
- 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

59
.github/workflows/ui-docker.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: UI Docker
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Build development image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: ./packages/ui
file: ./packages/ui/Dockerfile
target: development
push: false
tags: ocelot-social/ui:development
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@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: ./packages/ui
file: ./packages/ui/Dockerfile
target: production
push: false
tags: ocelot-social/ui:latest
cache-from: type=gha,scope=ui-production
cache-to: type=gha,mode=max,scope=ui-production

54
.github/workflows/ui-lint.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: UI Lint
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run TypeScript type check
run: npm run typecheck

65
.github/workflows/ui-release.yml vendored Normal file
View File

@ -0,0 +1,65 @@
name: UI Release
on:
push:
branches: [master]
paths:
- 'packages/ui/**'
- 'release-please-config.json'
- '.release-please-manifest.json'
permissions:
contents: write
pull-requests: write
jobs:
release-please:
name: Release Please
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs['packages/ui--release_created'] }}
tag_name: ${{ steps.release.outputs['packages/ui--tag_name'] }}
version: ${{ steps.release.outputs['packages/ui--version'] }}
steps:
- name: Release Please
id: release
uses: googleapis/release-please-action@v4
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
publish:
name: Publish to npm
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/ui
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
registry-url: 'https://registry.npmjs.org'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Validate package
run: npm run validate
- name: Publish to npm
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

54
.github/workflows/ui-size.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: UI Size
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Check bundle size
run: npm run size

74
.github/workflows/ui-storybook.yml vendored Normal file
View File

@ -0,0 +1,74 @@
name: UI Storybook
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build Storybook
run: npm run storybook:build
- name: Verify build output
run: |
echo "Checking Storybook build output..."
if [ ! -d "storybook-static" ]; then
echo "::error::storybook-static directory not found"
exit 1
fi
if [ ! -f "storybook-static/index.html" ]; then
echo "::error::index.html not found in storybook-static"
exit 1
fi
echo "✓ Storybook build verified!"
- name: Upload Storybook artifacts
uses: actions/upload-artifact@v6
with:
name: storybook-static
path: packages/ui/storybook-static/
retention-days: 7

59
.github/workflows/ui-test.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: UI Test
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Run tests with coverage
run: npm run test:coverage
- name: Upload coverage report
uses: actions/upload-artifact@v6
if: always()
with:
name: coverage-report
path: packages/ui/coverage/
retention-days: 7

51
.github/workflows/ui-verify.yml vendored Normal file
View File

@ -0,0 +1,51 @@
name: UI Verify
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Check component completeness
run: npm run verify

64
.github/workflows/ui-visual.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: UI Visual
on:
push:
branches: [master]
pull_request:
branches: [master]
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@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
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@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version-file: 'packages/ui/.tool-versions'
cache: 'npm'
cache-dependency-path: packages/ui/package-lock.json
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install chromium --with-deps
- name: Run visual tests
run: npm run test:visual
- name: Upload test results
uses: actions/upload-artifact@v6
if: failure()
with:
name: visual-test-results
path: |
packages/ui/test-results/
packages/ui/playwright-report/
retention-days: 7

View File

@ -0,0 +1,3 @@
{
"packages/ui": "0.0.1"
}

View File

@ -4,8 +4,168 @@ 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). Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [3.14.1](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.14.0...3.14.1)
- 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)
- build(deps): bump node from 25.5.0-alpine to 25.6.0-alpine in /webapp [`#9164`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9164)
- build(deps-dev): bump cypress from 15.9.0 to 15.10.0 in the cypress group [`#9165`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9165)
- build(deps-dev): bump webpack from 5.104.1 to 5.105.0 [`#9167`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9167)
- build(deps): bump nodemailer from 7.0.13 to 8.0.0 in /backend [`#9168`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9168)
- build(deps): bump minimatch from 10.1.1 to 10.1.2 in /backend [`#9169`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9169)
- build(deps-dev): bump @types/node from 25.1.0 to 25.2.1 in /backend [`#9171`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9171)
- build(deps): bump @aws-sdk/client-s3 and @aws-sdk/lib-storage in /backend [`#9173`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9173)
- refactor(workflow): do not clean cache after run [`#9155`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9155)
- build(deps-dev): bump eslint-plugin-jest from 29.12.1 to 29.12.2 in /backend [`#9177`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9177)
- build(deps): bump peter-evans/repository-dispatch from cf70392543065ca62813db6712a06df1c4f4ae9f to f49a8ac5751834a0666df77deb0289abbe2b3a78 [`#9179`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9179)
- refactor(webapp): vue 2.7.16 [`#9160`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9160)
- refactor(backend): test roles [`#9157`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9157)
- refactor(backend): middleware before/after [`#9128`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9128)
- build(deps): bump node from 25.4.0-alpine to 25.5.0-alpine in /webapp [`#9147`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9147)
- build(deps): bump node from 25.4.0-alpine to 25.5.0-alpine in /backend [`#9148`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9148)
- build(deps): bump actions/cache from 5.0.2 to 5.0.3 [`#9149`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9149)
- build(deps): bump docker/login-action from 3.6.0 to 3.7.0 [`#9150`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9150)
- build(deps): bump @aws-sdk/client-s3 and @aws-sdk/lib-storage in /backend [`#9151`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9151)
- build(deps-dev): bump @types/node from 25.0.10 to 25.1.0 in /backend [`#9152`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9152)
- refactor(backend): properly model group-membership [`#9124`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9124)
- fix(webapp): allow internal path for custom button [`#9129`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9129)
- feat(backend): db script disable notifications [`#9131`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9131)
- feat(backend): group pins [`#9034`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9034)
- refactor(backend): lint graphql [`#8473`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/8473)
- fix(backend): fix bug in notifications settings for currentUser [`#9130`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9130)
- fix(backend): fix email url encoding [`#9127`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9127)
- refactor(other): consolidate Node.js versions and fix e2e workflow [`#9126`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9126)
- build(deps): bump cheerio from 1.1.2 to 1.2.0 in /backend [`#9141`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9141)
- build(deps-dev): bump @types/node from 25.0.9 to 25.0.10 in /backend [`#9142`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9142)
- build(deps): bump @aws-sdk/client-s3 and @aws-sdk/lib-storage in /backend [`#9144`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9144)
- build(deps): bump peter-evans/repository-dispatch from 09094272a794c6105029af051e3831908c649b6c to cf70392543065ca62813db6712a06df1c4f4ae9f [`#9145`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9145)
- build(deps): bump the metascraper group in /backend with 12 updates [`#9136`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9136)
- build(deps-dev): bump sass-embedded from 1.97.2 to 1.97.3 [`#9135`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9135)
- build(deps): bump preview-email from 3.1.0 to 3.1.1 in /backend [`#9138`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9138)
- fix(webapp): allow running frontend tests locally [`#9125`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9125)
- build(deps): bump node from 25.3.0-alpine to 25.4.0-alpine in /webapp [`#9133`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9133)
- build(deps-dev): bump @cucumber/cucumber from 12.5.0 to 12.6.0 in the cypress group [`#9134`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9134)
- build(deps): bump lodash from 4.17.21 to 4.17.23 in /backend [`#9140`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9140)
- build(deps-dev): bump prettier from 3.8.0 to 3.8.1 in /webapp [`#9139`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9139)
- build(deps-dev): bump prettier from 3.8.0 to 3.8.1 in /backend [`#9143`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9143)
- build(deps): bump actions/checkout from 6.0.1 to 6.0.2 [`#9146`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9146)
- build(deps): bump node from 25.3.0-alpine to 25.4.0-alpine in /backend [`#9132`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9132)
- feat(backend): admin creation command for production [`#9057`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9057)
- fix(backend): fix permissions for GroupInviteCodes [`#9121`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9121)
- fix(backend): fix group-myRole field query [`#9102`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9102)
- refactor(e2e): optimize step definitions loading with filepart pairing [`#9122`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9122)
- fix(webapp): fix cta-join-group, can crash when group is not defined [`#9103`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9103)
- fix(backend): fix active categories when inproperly configured [`#9123`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9123)
- fix(webapp): fix local webapp tests [`#9104`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9104)
- build(deps-dev): bump the cypress group across 1 directory with 3 updates [`#9058`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9058)
- build(deps): bump node from 25.2.1-alpine to 25.3.0-alpine in /webapp [`#9105`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9105)
- build(deps): bump actions/setup-node from 6.1.0 to 6.2.0 [`#9107`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9107)
- build(deps): bump node from 25.2.1-alpine to 25.3.0-alpine in /backend [`#9106`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9106)
- build(deps): bump actions/cache from 5.0.1 to 5.0.2 [`#9108`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9108)
- build(deps-dev): bump eslint-plugin-n from 17.23.1 to 17.23.2 in /backend [`#9110`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9110)
- build(deps-dev): bump @types/lodash from 4.17.21 to 4.17.23 in /backend [`#9111`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9111)
- build(deps): bump @aws-sdk/lib-storage from 3.958.0 to 3.967.0 in /backend [`#9113`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9113)
- build(deps-dev): bump eslint-plugin-prettier from 5.5.4 to 5.5.5 in /backend [`#9114`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9114)
- build(deps-dev): bump @eslint-community/eslint-plugin-eslint-comments from 4.5.0 to 4.6.0 in /backend [`#9120`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9120)
- build(deps-dev): bump prettier from 3.7.4 to 3.8.0 in /webapp [`#9117`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9117)
- build(deps): bump ioredis from 5.9.1 to 5.9.2 in /backend [`#9119`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9119)
- build(deps): bump @aws-sdk/client-s3 from 3.967.0 to 3.971.0 in /backend [`#9118`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9118)
- build(deps-dev): bump eslint-plugin-prettier from 5.5.4 to 5.5.5 in /webapp [`#9115`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9115)
- build(deps-dev): bump prettier from 3.7.4 to 3.8.0 in /backend [`#9116`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9116)
- build(deps-dev): bump @types/node from 25.0.7 to 25.0.9 in /backend [`#9112`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9112)
- build(deps): bump the metascraper group in /backend with 12 updates [`#9063`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9063)
- build(deps-dev): bump eslint-plugin-jest from 29.12.0 to 29.12.1 in /backend [`#9090`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9090)
- build(deps): bump ioredis from 5.8.2 to 5.9.1 in /backend [`#9095`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9095)
- build(deps): bump @aws-sdk/client-s3 from 3.958.0 to 3.966.0 in /backend [`#9100`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9100)
- build(deps): bump @aws-sdk/lib-storage from 3.933.0 to 3.958.0 in /backend [`#9093`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9093)
- build(deps-dev): bump @types/node from 25.0.3 to 25.0.5 in /backend [`#9096`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9096)
- build(deps): bump peter-evans/repository-dispatch from 46fabd2783425293d3f24bc1080da28d046e2dd3 to 09094272a794c6105029af051e3831908c649b6c [`#9089`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9089)
- build(deps): bump vue-advanced-chat from 2.0.11 to 2.1.2 in /webapp [`#9084`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9084)
- build(deps): bump nginx from 1.29.3-alpine to 1.29.4-alpine in /webapp [`#9070`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9070)
- build(deps): bump @aws-sdk/client-s3 from 3.933.0 to 3.958.0 in /backend [`#9086`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9086)
- build(deps-dev): bump @types/node from 24.10.1 to 25.0.3 in /backend [`#9078`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9078)
- build(deps-dev): bump eslint-plugin-jest from 29.1.0 to 29.11.0 in /backend [`#9087`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9087)
- build(deps): bump express from 5.1.0 to 5.2.1 in /backend [`#9065`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9065)
- build(deps-dev): bump @types/lodash from 4.17.20 to 4.17.21 in /backend [`#9051`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9051)
- build(deps-dev): bump ts-jest from 29.4.5 to 29.4.6 in /backend [`#9069`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9069)
- build(deps): bump validator from 13.15.23 to 13.15.26 in /webapp [`#9083`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9083)
- build(deps): bump validator from 13.15.23 to 13.15.26 in /backend [`#9080`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9080)
- build(deps): bump nodemailer from 7.0.10 to 7.0.12 in /backend [`#9088`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9088)
- build(deps): bump actions/upload-artifact from 5.0.0 to 6.0.0 [`#9072`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9072)
- build(deps): bump peter-evans/repository-dispatch from d2c43ab06ec1cddd2c2a0aae659681b8465ce87a to 46fabd2783425293d3f24bc1080da28d046e2dd3 [`#9060`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9060)
- build(deps-dev): bump prettier from 3.6.2 to 3.7.4 in /webapp [`#9059`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9059)
- build(deps): bump docker/metadata-action from 5.9.0 to 5.10.0 [`#9049`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9049)
- build(deps): bump actions/setup-node from 6.0.0 to 6.1.0 [`#9061`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9061)
- build(deps): bump gaurav-nelson/github-action-markdown-link-check from 1.0.16 to 1.0.17 [`#8329`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/8329)
- build(deps): bump actions/cache from 4.3.0 to 5.0.1 [`#9071`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9071)
- build(deps): bump actions/checkout from 5.0.0 to 6.0.1 [`#9062`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9062)
- build(deps-dev): bump prettier from 3.6.2 to 3.7.4 in /backend [`#9067`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9067)
- build(deps): bump mime-types from 3.0.1 to 3.0.2 in /backend [`#9044`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9044)
- build(deps): bump cross-env from 10.0.0 to 10.1.0 in /backend [`#8943`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/8943)
- build(deps): bump validator from 13.15.20 to 13.15.23 in /webapp [`#9029`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9029)
- build(deps-dev): bump nodemon from 3.1.10 to 3.1.11 in /backend [`#9028`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9028)
- build(deps): bump node from 25.1.0-alpine to 25.2.0-alpine in /backend [`#9024`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9024)
- build(deps): bump node from 25.1.0-alpine to 25.2.0-alpine in /webapp [`#9023`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9023)
- build(deps): bump docker/metadata-action from 5.8.0 to 5.9.0 [`#9014`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9014)
- build(deps-dev): bump cypress from 15.5.0 to 15.6.0 in the cypress group [`#9016`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9016)
- build(deps): bump bcryptjs from 3.0.2 to 3.0.3 in /backend [`#9019`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9019)
- build(deps): bump @aws-sdk/lib-storage from 3.917.0 to 3.922.0 in /backend [`#9022`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9022)
- build(deps): bump peter-evans/repository-dispatch from 2c856c63feddee6147cab2f38801935b6a59a765 to d2c43ab06ec1cddd2c2a0aae659681b8465ce87a [`#9025`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9025)
- build(deps): bump amannn/action-semantic-pull-request from e49f57ce06c1747542fce2243c7a98682384bc0e to 069817c298f23fab00a8f29a2e556a5eac0f6390 [`#9026`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9026)
- build(deps-dev): bump eslint-plugin-jest from 29.0.1 to 29.1.0 in /backend [`#9027`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9027)
- build(deps): bump @aws-sdk/client-s3 from 3.922.0 to 3.932.0 in /backend [`#9030`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9030)
- build(deps-dev): bump @types/node from 24.9.2 to 24.10.1 in /backend [`#9031`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9031)
- build(deps): bump validator from 13.15.20 to 13.15.23 in /backend [`#9033`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9033)
#### [3.13.1](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.13.0...3.13.1) #### [3.13.1](https://github.com/Ocelot-Social-Community/Ocelot-Social/compare/3.13.0...3.13.1)
> 1 November 2025
- chore(release): v3.13.1 [`#9003`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9003)
- build(deps): bump nginx from 1.29.2-alpine to 1.29.3-alpine in /webapp [`#9005`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9005) - build(deps): bump nginx from 1.29.2-alpine to 1.29.3-alpine in /webapp [`#9005`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9005)
- build(deps): bump minimatch from 10.0.3 to 10.1.1 in /backend [`#9009`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9009) - build(deps): bump minimatch from 10.0.3 to 10.1.1 in /backend [`#9009`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9009)
- build(deps-dev): bump @types/node from 24.9.1 to 24.9.2 in /backend [`#9010`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9010) - build(deps-dev): bump @types/node from 24.9.1 to 24.9.2 in /backend [`#9010`](https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/9010)

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.5.0-alpine AS base # syntax=docker/dockerfile:1
FROM node:25.6.1-alpine AS base
LABEL org.label-schema.name="ocelot.social:backend" 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.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" 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/middlewares/ src/middleware/branding/
ONBUILD COPY ./branding/data/ src/db/data ONBUILD COPY ./branding/data/ src/db/data
ONBUILD COPY ./branding/public/ public/ 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 yarn run build
ONBUILD RUN mkdir /build ONBUILD RUN mkdir /build
ONBUILD RUN cp -r ./build /build ONBUILD RUN cp -r ./build /build
ONBUILD RUN cp -r ./public /build ONBUILD RUN cp -r ./public /build
ONBUILD RUN cp -r ./package.json yarn.lock /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 FROM build AS test
# required for the migrations # 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: 92,
},
},
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", "name": "ocelot-social-backend",
"version": "3.13.1", "version": "3.14.1",
"description": "GraphQL Backend for ocelot.social", "description": "GraphQL Backend for ocelot.social",
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social", "repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
"author": "ocelot.social Community", "author": "ocelot.social Community",
@ -10,20 +10,20 @@
"scripts": { "scripts": {
"start": "node build/src/", "start": "node build/src/",
"build": "tsc && tsc-alias && ./scripts/build.copy.files.sh", "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", "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", "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": "tsx src/db/reset.ts",
"db:reset:withmigrations": "ts-node --require tsconfig-paths/register src/db/reset-with-migrations.ts", "db:reset:withmigrations": "tsx src/db/reset-with-migrations.ts",
"db:seed": "ts-node --require tsconfig-paths/register src/db/seed.ts", "db:seed": "tsx --require ./src/graphql/gql-register.ts src/db/seed.ts",
"db:data:admin": "ts-node --require tsconfig-paths/register src/db/admin.ts", "db:data:admin": "tsx src/db/admin.ts",
"db:data:badges": "ts-node --require tsconfig-paths/register src/db/badges.ts", "db:data:badges": "tsx src/db/badges.ts",
"db:data:branding": "ts-node --require tsconfig-paths/register src/db/data-branding.ts", "db:data:branding": "tsx src/db/data-branding.ts",
"db:data:categories": "ts-node --require tsconfig-paths/register src/db/categories.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": "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: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: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:branding": "node build/src/db/data-branding.js",
"prod:db:data:categories": "node build/src/db/categories.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" "prod:db:func:disable:notifications": "node build/src/db/disable-notifications.js"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.980.0", "@apollo/server": "^4.11.3",
"@aws-sdk/lib-storage": "^3.980.0", "@aws-sdk/client-s3": "^3.1000.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", "@sentry/node": "^5.30.0",
"@types/mime-types": "^3.0.1", "@types/mime-types": "^3.0.1",
"apollo-server": "~2.14.2",
"apollo-server-express": "^2.14.2",
"bcryptjs": "~3.0.3", "bcryptjs": "~3.0.3",
"body-parser": "^1.20.3", "body-parser": "^2.2.2",
"cheerio": "~1.2.0", "cheerio": "~1.2.0",
"cross-env": "~10.1.0", "cross-env": "~10.1.0",
"dotenv": "~17.0.1", "dotenv": "~17.0.1",
"email-templates": "^12.0.3", "email-templates": "^13.0.1",
"express": "^4.22.1", "express": "^4.22.1",
"graphql": "^14.6.0", "graphql": "^16.13.0",
"graphql-middleware": "~6.1.35", "graphql-middleware": "~6.1.35",
"graphql-middleware-sentry": "^3.2.1",
"graphql-redis-subscriptions": "^2.7.0", "graphql-redis-subscriptions": "^2.7.0",
"graphql-shield": "~7.2.2", "graphql-shield": "^7.6.5",
"graphql-subscriptions": "^1.1.0", "graphql-subscriptions": "^2.0.0",
"graphql-tag": "~2.10.3",
"graphql-upload": "^13.0.0", "graphql-upload": "^13.0.0",
"graphql-ws": "^5.16.2",
"helmet": "~8.1.0", "helmet": "~8.1.0",
"ioredis": "^5.9.2", "ioredis": "^5.9.3",
"jsonwebtoken": "~8.5.1", "jsonwebtoken": "~8.5.1",
"languagedetect": "^2.0.0", "languagedetect": "^2.0.0",
"linkify-html": "^4.3.2", "linkify-html": "^4.3.2",
"linkifyjs": "^4.3.2", "linkifyjs": "^4.3.2",
"lodash": "~4.17.23", "lodash": "~4.17.23",
"merge-graphql-schemas": "^1.7.8", "metascraper": "^5.49.24",
"metascraper": "^5.49.19", "metascraper-author": "^5.49.24",
"metascraper-author": "^5.49.19", "metascraper-date": "^5.49.24",
"metascraper-date": "^5.49.19", "metascraper-description": "^5.49.24",
"metascraper-description": "^5.49.19", "metascraper-image": "^5.49.24",
"metascraper-image": "^5.49.19", "metascraper-lang": "^5.49.24",
"metascraper-lang": "^5.49.19",
"metascraper-lang-detector": "^4.10.2", "metascraper-lang-detector": "^4.10.2",
"metascraper-logo": "^5.49.19", "metascraper-logo": "^5.49.24",
"metascraper-publisher": "^5.49.19", "metascraper-publisher": "^5.49.24",
"metascraper-soundcloud": "^5.34.4", "metascraper-soundcloud": "^5.34.4",
"metascraper-title": "^5.49.19", "metascraper-title": "^5.49.24",
"metascraper-url": "^5.49.19", "metascraper-url": "^5.49.24",
"metascraper-video": "^5.49.19", "metascraper-video": "^5.49.24",
"metascraper-youtube": "^5.49.20", "metascraper-youtube": "^5.49.24",
"migrate": "^2.1.0", "migrate": "^2.1.0",
"mime-types": "^3.0.2", "mime-types": "^3.0.2",
"minimatch": "^10.1.1", "minimatch": "^10.2.4",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"neo4j-driver": "^4.4.11", "neo4j-driver": "^4.4.11",
"neo4j-graphql-js": "2.11.5", "neo4j-graphql-js": "2.11.5",
"neode": "^0.4.9", "neode": "^0.4.9",
"node-fetch": "^2.7.0", "node-fetch": "^2.7.0",
"nodemailer": "^7.0.12", "nodemailer": "^8.0.1",
"nodemailer-html-to-text": "^3.2.0", "nodemailer-html-to-text": "^3.2.0",
"preview-email": "^3.1.1", "preview-email": "^3.1.1",
"pug": "^3.0.3", "pug": "^3.0.3",
"sanitize-html": "~2.17.0", "sanitize-html": "~2.17.1",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"subscriptions-transport-ws": "^0.11.0",
"trunc-html": "~1.1.2", "trunc-html": "~1.1.2",
"tslog": "^4.10.2", "tslog": "^4.10.2",
"uuid": "~9.0.1", "uuid": "~9.0.1",
"validator": "^13.15.26", "validator": "^13.15.26",
"ws": "^8.18.2",
"xregexp": "^5.1.2" "xregexp": "^5.1.2"
}, },
"devDependencies": { "devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "^4.6.0",
"@faker-js/faker": "9.9.0", "@faker-js/faker": "9.9.0",
"@graphql-eslint/eslint-plugin": "^3.20.1",
"@types/email-templates": "^10.0.4", "@types/email-templates": "^10.0.4",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/jsonwebtoken": "~8.5.1", "@types/jsonwebtoken": "~8.5.1",
"@types/lodash": "^4.17.23", "@types/lodash": "^4.17.24",
"@types/node": "^25.1.0", "@types/node": "^25.3.2",
"@types/request": "^2.48.13", "@types/request": "^2.48.13",
"@types/slug": "^5.0.9", "@types/slug": "^5.0.9",
"@types/uuid": "~9.0.1", "@types/uuid": "~9.0.1",
"@typescript-eslint/eslint-plugin": "^5.62.0", "@types/ws": "^8.18.1",
"@typescript-eslint/parser": "^5.62.0", "eslint": "^9.27.0",
"apollo-server-testing": "~2.11.0", "eslint-config-it4c": "^0.12.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.1",
"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", "jest": "^30.2.0",
"nodemon": "~3.1.11", "nodemon": "~3.1.14",
"prettier": "^3.8.1", "prettier": "^3.8.1",
"require-json5": "^1.3.0",
"rosie": "^2.1.1", "rosie": "^2.1.1",
"ts-jest": "^29.4.6", "ts-jest": "^29.4.6",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.16", "tsc-alias": "^1.8.16",
"tsconfig-paths": "^4.2.0", "tsx": "^4.21.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
}, },
"resolutions": { "resolutions": {
@ -139,7 +124,9 @@
"**/string-width": "4.2.0", "**/string-width": "4.2.0",
"**/wrap-ansi": "7.0.0", "**/wrap-ansi": "7.0.0",
"**/jwa": "^2.0.1", "**/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": { "engines": {
"node": ">=20.12.1" "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-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* 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 */ /* eslint-disable n/no-process-env */
import { config } from 'dotenv' import { config } from 'dotenv'
// eslint-disable-next-line import/no-namespace
import * as SMTPTransport from 'nodemailer/lib/smtp-pool'
import emails from './emails' import emails from './emails'
import metadata from './metadata' import metadata from './metadata'
import type * as SMTPTransport from 'nodemailer/lib/smtp-pool'
// Load env file // Load env file
config() config()

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-shadow */
import { getDriver, getNeode } from '@db/neo4j' import { getDriver, getNeode } from '@db/neo4j'
import type { Driver } from 'neo4j-driver' 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 databaseContext from '@context/database'
import pubsubContext from '@context/pubsub' import pubsubContext from '@context/pubsub'
import CONFIG from '@src/config' import CONFIG from '@src/config'
import type { DecodedUser } from '@src/jwt/decode'
import { decode } from '@src/jwt/decode' import { decode } from '@src/jwt/decode'
import ocelotLogger from '@src/logger' 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 serverDatabase = databaseContext()
const serverPubsub = pubsubContext() const serverPubsub = pubsubContext()
@ -18,14 +14,14 @@ export const getContext =
database?: ReturnType<typeof databaseContext> database?: ReturnType<typeof databaseContext>
pubsub?: ReturnType<typeof pubsubContext> pubsub?: ReturnType<typeof pubsubContext>
authenticatedUser: DecodedUser | null | undefined authenticatedUser: DecodedUser | null | undefined
logger?: typeof OcelotLogger logger?: typeof ocelotLogger
config: typeof CONFIG config: typeof CONFIG
}) => }) =>
async (req: { headers: { authorization?: string } }) => { async (req: { headers: { authorization?: string } }) => {
const { const {
database = serverDatabase, database = serverDatabase,
pubsub = serverPubsub, pubsub = serverPubsub,
authenticatedUser = undefined, authenticatedUser,
logger = ocelotLogger, logger = ocelotLogger,
config = CONFIG, config = CONFIG,
} = opts ?? {} } = opts ?? {}
@ -44,18 +40,11 @@ export const getContext =
req, req,
cypherParams: { cypherParams: {
currentUserId: user ? user.id : null, currentUserId: user ? user.id : null,
languageDefault: config.LANGUAGE_DEFAULT.toUpperCase(),
}, },
config, config,
} }
return result 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>>> export type Context = Awaited<ReturnType<ReturnType<typeof getContext>>>

View File

@ -2,7 +2,7 @@
import { getNeode } from './neo4j' import { getNeode } from './neo4j'
import { trophies, verification } from './seed/badges' 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 () { ;(async function () {
const neode = getNeode() const neode = getNeode()
try { try {

View File

@ -1,9 +1,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable import/no-commonjs */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
// eslint-disable-next-line n/no-unpublished-require, @typescript-eslint/no-var-requires /* eslint-disable @typescript-eslint/no-require-imports */
const tsNode = require('ts-node') /* eslint-disable import-x/no-commonjs */
// eslint-disable-next-line import/no-unassigned-import, n/no-unpublished-require // eslint-disable-next-line n/no-unpublished-require
require('tsconfig-paths/register') 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-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-floating-promises */ /* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/await-thenable */
import { readdir } from 'node:fs/promises' import { readdir } from 'node:fs/promises'
import path from 'node:path' import path from 'node:path'

View File

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

View File

@ -4,6 +4,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* 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 { faker } from '@faker-js/faker'
import { hashSync } from 'bcryptjs' import { hashSync } from 'bcryptjs'
import { Factory } from 'rosie' import { Factory } from 'rosie'
@ -13,10 +15,11 @@ import { v4 as uuid } from 'uuid'
import { generateInviteCode } from '@graphql/resolvers/inviteCodes' import { generateInviteCode } from '@graphql/resolvers/inviteCodes'
import { isUniqueFor } from '@middleware/sluggifyMiddleware' import { isUniqueFor } from '@middleware/sluggifyMiddleware'
import uniqueSlug from '@middleware/slugify/uniqueSlug' import uniqueSlug from '@middleware/slugify/uniqueSlug'
import { Context } from '@src/context'
import { getDriver, getNeode } from './neo4j' import { getDriver, getNeode } from './neo4j'
import type { Context } from '@src/context'
const neode = getNeode() const neode = getNeode()
const uniqueImageUrl = (imageUrl) => { const uniqueImageUrl = (imageUrl) => {
@ -49,14 +52,14 @@ Factory.define('category')
.attr('id', uuid) .attr('id', uuid)
.attr('icon', 'globe') .attr('icon', 'globe')
.attr('name', 'Global Peace & Nonviolence') .attr('name', 'Global Peace & Nonviolence')
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('Category', buildObject) return neode.create('Category', buildObject)
}) })
Factory.define('badge') Factory.define('badge')
.attr('type', 'crowdfunding') .attr('type', 'crowdfunding')
.attr('status', 'permanent') .attr('status', 'permanent')
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('Badge', buildObject) return neode.create('Badge', buildObject)
}) })
@ -67,7 +70,7 @@ Factory.define('image')
.attr('alt', faker.lorem.sentence) .attr('alt', faker.lorem.sentence)
.attr('type', 'image/jpeg') .attr('type', 'image/jpeg')
.attr('url', null) .attr('url', null)
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
if (!buildObject.url) { if (!buildObject.url) {
buildObject.url = faker.image.urlPicsumPhotos({ buildObject.url = faker.image.urlPicsumPhotos({
width: buildObject.width, width: buildObject.width,
@ -84,7 +87,7 @@ Factory.define('file')
.attr('name', faker.lorem.slug) .attr('name', faker.lorem.slug)
.attr('type', 'image/jpeg') .attr('type', 'image/jpeg')
.attr('url', null) .attr('url', null)
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
if (!buildObject.url) { if (!buildObject.url) {
buildObject.url = faker.image.urlPicsumPhotos() buildObject.url = faker.image.urlPicsumPhotos()
} }
@ -171,8 +174,8 @@ Factory.define('post')
return Promise.all([Factory.build('category')]) return Promise.all([Factory.build('category')])
}) */ }) */
.option('tagIds', []) .option('tagIds', [])
.option('tags', ['tagIds'], (tagIds) => { .option('tags', ['tagIds'], async (tagIds) => {
return Promise.all(tagIds.map((id) => neode.find('Tag', id))) return Promise.all(tagIds.map(async (id) => neode.find('Tag', id)))
}) })
.option('authorId', null) .option('authorId', null)
.option('author', ['authorId'], (authorId) => { .option('author', ['authorId'], (authorId) => {
@ -264,7 +267,7 @@ Factory.define('donations')
.attr('showDonations', true) .attr('showDonations', true)
.attr('goal', 15000) .attr('goal', 15000)
.attr('progress', 7000) .attr('progress', 7000)
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('Donations', buildObject) return neode.create('Donations', buildObject)
}) })
@ -275,13 +278,13 @@ const emailDefaults = {
Factory.define('emailAddress') Factory.define('emailAddress')
.attrs(emailDefaults) .attrs(emailDefaults)
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('EmailAddress', buildObject) return neode.create('EmailAddress', buildObject)
}) })
Factory.define('unverifiedEmailAddress') Factory.define('unverifiedEmailAddress')
.attr(emailDefaults) .attr(emailDefaults)
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('UnverifiedEmailAddress', buildObject) return neode.create('UnverifiedEmailAddress', buildObject)
}) })
@ -294,7 +297,7 @@ const inviteCodeDefaults = {
Factory.define('inviteCode') Factory.define('inviteCode')
.attrs(inviteCodeDefaults) .attrs(inviteCodeDefaults)
.option('groupId', null) .option('groupId', null)
.option('group', ['groupId'], (groupId) => { .option('group', ['groupId'], async (groupId) => {
if (groupId) { if (groupId) {
return neode.find('Group', groupId) return neode.find('Group', groupId)
} }
@ -331,11 +334,11 @@ Factory.define('location')
id: 'country.10743216036480410', id: 'country.10743216036480410',
type: 'country', type: 'country',
}) })
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('Location', buildObject) return neode.create('Location', buildObject)
}) })
Factory.define('report').after((buildObject, _options) => { Factory.define('report').after(async (buildObject, _options) => {
return neode.create('Report', buildObject) return neode.create('Report', buildObject)
}) })
@ -343,7 +346,7 @@ Factory.define('tag')
.attrs({ .attrs({
name: '#human-connection', name: '#human-connection',
}) })
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('Tag', buildObject) return neode.create('Tag', buildObject)
}) })
@ -351,7 +354,7 @@ Factory.define('socialMedia')
.attrs({ .attrs({
url: 'https://mastodon.social/@Gargron', url: 'https://mastodon.social/@Gargron',
}) })
.after((buildObject, _options) => { .after(async (buildObject, _options) => {
return neode.create('SocialMedia', buildObject) return neode.create('SocialMedia', buildObject)
}) })

View File

@ -2,6 +2,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-confusing-void-expression */
import { getDriver, getNeode } from '@db/neo4j' import { getDriver, getNeode } from '@db/neo4j'
class Store { class Store {
@ -83,7 +84,7 @@ class Store {
const driver = getDriver() const driver = getDriver()
const session = driver.session() const session = driver.session()
const { migrations } = set const { migrations } = set
const writeTxResultPromise = session.writeTransaction((txc) => { const writeTxResultPromise = session.writeTransaction(async (txc) => {
return Promise.all( return Promise.all(
migrations.map(async (migration) => { migrations.map(async (migration) => {
const { title, description, timestamp } = 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-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* 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 promise/prefer-await-to-callbacks */
/* eslint-disable import-x/no-deprecated */
import { throwError, concat } from 'rxjs' import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError, filter } from 'rxjs/operators' import { flatMap, mergeMap, map, catchError, filter } from 'rxjs/operators'
@ -71,7 +72,7 @@ export function up(next) {
), ),
) )
.subscribe({ .subscribe({
next: ({ user, email, _oldUser, oldEmail }) => next: ({ user, email, _oldUser, oldEmail }) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(` console.log(`
Merged: Merged:
@ -79,7 +80,8 @@ export function up(next) {
userId: ${user.id} userId: ${user.id}
email: ${oldEmail} => ${email.email} email: ${oldEmail} => ${email.email}
============================= =============================
`), `)
},
complete: () => { complete: () => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('Merging of duplicate users completed') 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-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* 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 promise/prefer-await-to-callbacks */
/* eslint-disable import-x/no-deprecated */
import { throwError, concat } from 'rxjs' import { throwError, concat } from 'rxjs'
import { flatMap, mergeMap, map, catchError } from 'rxjs/operators' import { flatMap, mergeMap, map, catchError } from 'rxjs/operators'
@ -65,7 +66,7 @@ export function up(next) {
), ),
) )
.subscribe({ .subscribe({
next: ({ updatedLocation, location }) => next: ({ updatedLocation, location }) => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(` console.log(`
Merged: Merged:
@ -73,7 +74,8 @@ export function up(next) {
locationId: ${location.id} locationId: ${location.id}
updatedLocation: ${location.id} => ${updatedLocation.id} updatedLocation: ${location.id} => ${updatedLocation.id}
============================= =============================
`), `)
},
complete: () => { complete: () => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('Merging of duplicate locations completed') console.log('Merging of duplicate locations completed')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,19 +2,22 @@
/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-floating-promises */ /* 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 { faker } from '@faker-js/faker'
import sample from 'lodash/sample' import sample from 'lodash/sample'
import CONFIG from '@config/index' import CONFIG from '@config/index'
import { categories } from '@constants/categories' import { categories } from '@constants/categories'
import { ChangeGroupMemberRole } from '@graphql/queries/ChangeGroupMemberRole' import CreateComment from '@graphql/queries/comments/CreateComment.gql'
import { CreateComment } from '@graphql/queries/CreateComment' import ChangeGroupMemberRole from '@graphql/queries/groups/ChangeGroupMemberRole.gql'
import { CreateGroup } from '@graphql/queries/CreateGroup' import CreateGroup from '@graphql/queries/groups/CreateGroup.gql'
import { CreateMessage } from '@graphql/queries/CreateMessage' import JoinGroup from '@graphql/queries/groups/JoinGroup.gql'
import { CreatePost } from '@graphql/queries/CreatePost' import CreateMessage from '@graphql/queries/messaging/CreateMessage.gql'
import { CreateRoom } from '@graphql/queries/CreateRoom' import CreateRoom from '@graphql/queries/messaging/CreateRoom.gql'
import { JoinGroup } from '@graphql/queries/JoinGroup' import CreatePost from '@graphql/queries/posts/CreatePost.gql'
import { createApolloTestSetup } from '@root/test/helpers' import { createApolloTestSetup } from '@root/test/helpers'
import Factory from './factories' import Factory from './factories'
@ -39,7 +42,7 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
authenticatedUser, authenticatedUser,
config: CONFIG, config: CONFIG,
}) })
const apolloSetup = createApolloTestSetup({ context }) const apolloSetup = await createApolloTestSetup({ context })
const { mutate, server, database } = apolloSetup const { mutate, server, database } = apolloSetup
const { neode } = database const { neode } = database

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver' import type { Integer, Node } from 'neo4j-driver'
export interface LocationDbProperties { export interface LocationDbProperties {
id: string id: string
@ -14,6 +14,7 @@ export interface LocationDbProperties {
namePL: string namePL: string
namePT: string namePT: string
nameRU: string nameRU: string
nameSQ: string
type: 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 { export interface MessageDbProperties {
content: string content: string

View File

@ -1,4 +1,4 @@
import { Integer, Node } from 'neo4j-driver' import type { Integer, Node } from 'neo4j-driver'
export interface PostDbProperties { export interface PostDbProperties {
clickedCount: number clickedCount: number

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,8 @@ import { createTransport } from 'nodemailer'
import CONFIG, { nodemailerTransportOptions } from '@config/index' import CONFIG, { nodemailerTransportOptions } from '@config/index'
import logosWebapp from '@config/logosBranded' import logosWebapp from '@config/logosBranded'
import metadata from '@config/metadata' 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 welcomeImageUrl = new URL(logosWebapp.LOGO_WELCOME_PATH, CONFIG.CLIENT_URI)
const settingsUrl = new URL('/settings/notifications', CONFIG.CLIENT_URI) const settingsUrl = new URL('/settings/notifications', CONFIG.CLIENT_URI)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,22 +0,0 @@
import gql from 'graphql-tag'
export const CreateMessage = gql`
mutation ($roomId: ID!, $content: String!, $files: [FileInput]) {
CreateMessage(roomId: $roomId, content: $content, files: $files) {
id
content
senderId
username
avatar
date
saved
distributed
seen
files {
url
name
type
}
}
}
`

View File

@ -1,51 +0,0 @@
import gql from 'graphql-tag'
export const CreatePost = gql`
mutation (
$id: ID
$title: String!
$slug: String
$content: String!
$categoryIds: [ID]
$groupId: ID
$postType: PostType
$eventInput: _EventInput
) {
CreatePost(
id: $id
title: $title
slug: $slug
content: $content
categoryIds: $categoryIds
groupId: $groupId
postType: $postType
eventInput: $eventInput
) {
id
slug
title
content
disabled
deleted
postType
author {
name
}
categories {
id
}
eventStart
eventEnd
eventLocationName
eventVenue
eventIsOnline
eventLocation {
lng
lat
}
isObservedByMe
observingUsersCount
language
}
}
`

View File

@ -1,22 +0,0 @@
import gql from 'graphql-tag'
export const CreateRoom = gql`
mutation ($userId: ID!) {
CreateRoom(userId: $userId) {
id
roomId
roomName
lastMessageAt
unreadCount
#avatar
users {
_id
id
name
avatar {
url
}
}
}
}
`

View File

@ -1,14 +0,0 @@
import gql from 'graphql-tag'
export const CreateSocialMedia = gql`
mutation ($url: String!) {
CreateSocialMedia(url: $url) {
id
url
url
ownedBy {
name
}
}
}
`

View File

@ -1,12 +0,0 @@
import gql from 'graphql-tag'
export const DeleteComment = gql`
mutation ($id: ID!) {
DeleteComment(id: $id) {
id
content
contentExcerpt
deleted
}
}
`

View File

@ -1,20 +0,0 @@
import gql from 'graphql-tag'
export const DeletePost = gql`
mutation ($id: ID!) {
DeletePost(id: $id) {
id
deleted
content
contentExcerpt
image {
url
}
comments {
deleted
content
contentExcerpt
}
}
}
`

View File

@ -1,10 +0,0 @@
import gql from 'graphql-tag'
export const DeleteSocialMedia = gql`
mutation ($id: ID!) {
DeleteSocialMedia(id: $id) {
id
url
}
}
`

View File

@ -1,30 +0,0 @@
import gql from 'graphql-tag'
export const DeleteUser = gql`
mutation ($id: ID!, $resource: [Deletable]) {
DeleteUser(id: $id, resource: $resource) {
id
name
about
deleted
contributions {
id
content
contentExcerpt
deleted
comments {
id
content
contentExcerpt
deleted
}
}
comments {
id
content
contentExcerpt
deleted
}
}
}
`

View File

@ -1,12 +0,0 @@
import gql from 'graphql-tag'
export const Donations = gql`
query {
Donations {
id
showDonations
goal
progress
}
}
`

View File

@ -1,40 +0,0 @@
import gql from 'graphql-tag'
export const Group = gql`
query Group($isMember: Boolean, $id: ID, $slug: String) {
Group(isMember: $isMember, id: $id, slug: $slug) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
descriptionExcerpt
groupType
actionRadius
categories {
id
slug
name
icon
}
avatar {
url
}
locationName
location {
name
nameDE
nameEN
}
myRole
inviteCodes {
code
redeemedByCount
}
}
}
`

View File

@ -1,16 +0,0 @@
import gql from 'graphql-tag'
export const GroupMembers = gql`
query GroupMembers($id: ID!) {
GroupMembers(id: $id) {
user {
id
name
slug
}
membership {
role
}
}
}
`

View File

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

View File

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

View File

@ -1,7 +0,0 @@
import gql from 'graphql-tag'
export const MarkMessagesAsSeen = gql`
mutation ($messageIds: [String!]) {
MarkMessagesAsSeen(messageIds: $messageIds)
}
`

View File

@ -1,27 +0,0 @@
import gql from 'graphql-tag'
export const Message = gql`
query ($roomId: ID!, $first: Int, $offset: Int) {
Message(roomId: $roomId, first: $first, offset: $offset, orderBy: indexId_desc) {
_id
id
indexId
content
senderId
author {
id
}
username
avatar
date
saved
distributed
seen
files {
url
name
type
}
}
}
`

View File

@ -1,39 +0,0 @@
import gql from 'graphql-tag'
export const Post = gql`
query ($id: ID, $filter: _PostFilter, $first: Int, $offset: Int, $orderBy: [_PostOrdering]) {
Post(id: $id, filter: $filter, first: $first, offset: $offset, orderBy: $orderBy) {
id
title
content
contentExcerpt
eventStart
pinned
createdAt
pinnedAt
isObservedByMe
observingUsersCount
clickedCount
emotionsCount
emotions {
emotion
User {
id
}
}
author {
id
name
}
shoutedBy {
id
}
tags {
id
}
comments {
content
}
}
}
`

View File

@ -1,7 +0,0 @@
import gql from 'graphql-tag'
export const PostsEmotionsByCurrentUser = gql`
query ($postId: ID!) {
PostsEmotionsByCurrentUser(postId: $postId)
}
`

View File

@ -1,7 +0,0 @@
import gql from 'graphql-tag'
export const PostsEmotionsCountByEmotion = gql`
query ($postId: ID!, $data: _EMOTEDInput!) {
PostsEmotionsCountByEmotion(postId: $postId, data: $data)
}
`

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