mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-07 22:12:53 +00:00
Compare commits
2463 Commits
v0.0.2
...
v3.0.0-nex
| Author | SHA1 | Date | |
|---|---|---|---|
| 2d061b1638 | |||
| 0a7e6af141 | |||
| 1aaf85b444 | |||
| 98546a97a3 | |||
| 64caebafe5 | |||
| f1bc41c4df | |||
| 6a8b3d2fe2 | |||
| 129f25d1f0 | |||
| c4260dc882 | |||
| 5b4d2bd16c | |||
|
|
d61d16e752 | ||
| 3b8a344d73 | |||
| b21833de40 | |||
| 495a63977c | |||
| 45444d9373 | |||
| 68400f2480 | |||
| 0d60b8bfad | |||
| d6d4f6e5c4 | |||
| 0a76427ba8 | |||
| d8c79256c9 | |||
| 8cb9285462 | |||
| 4df19e8c20 | |||
| fd740b3091 | |||
| 3792a14e90 | |||
| be1774b1cd | |||
|
|
7c3ccc35af | ||
| 881734c29e | |||
| ac62e621d5 | |||
| cc7406c07f | |||
| 3ab8bc1517 | |||
| 44f2b4a2b3 | |||
| 2dc8fd98b8 | |||
| 2d139e478a | |||
| 9aad8eda9a | |||
| 522b951490 | |||
| b819dba17f | |||
| e76ffe9371 | |||
| c8703ec66b | |||
| 23d0c6971c | |||
| f69edc6393 | |||
| 1ea219b1ef | |||
| 857e829e8b | |||
| b6b745310a | |||
| 1bd1672276 | |||
| 1fdcae7aaf | |||
| 927f8df900 | |||
|
|
fd63fb764f | ||
|
|
35611af501 | ||
|
|
826eaa7825 | ||
|
|
b7407eb057 | ||
|
|
20a336d3c4 | ||
|
|
41c5541dd1 | ||
|
|
71eaf046d8 | ||
|
|
28f106b530 | ||
|
|
f4b2d747a3 | ||
|
|
4ebe44a5a7 | ||
|
|
3471591a7d | ||
|
|
5eae0d5955 | ||
|
|
a5291af838 | ||
|
|
10f7cb8028 | ||
|
|
0f970fa1f1 | ||
|
|
7073dfd0dd | ||
|
|
9e45c46eb8 | ||
|
|
2efa29f61c | ||
|
|
4a0986bdad | ||
|
|
881db8b9f0 | ||
|
|
d6d10a2a0d | ||
|
|
d16ae93a7a | ||
|
|
de71d68051 | ||
|
|
c9b83b5d71 | ||
|
|
b21dc75964 | ||
|
|
4a18cd5cf5 | ||
|
|
e0e803fba0 | ||
|
|
bcba3435df | ||
|
|
d90416e201 | ||
|
|
937586ca43 | ||
|
|
afcc73f3da | ||
|
|
fc850fe7ac | ||
|
|
898480e254 | ||
|
|
3bca003d16 | ||
| abf2ab6a5a | |||
|
|
61fee2bbf3 | ||
|
|
f49c44f5c5 | ||
|
|
9937dcab52 | ||
|
|
b5a325eb56 | ||
|
|
cd554e8403 | ||
|
|
f430621cb7 | ||
|
|
afbd1fc048 | ||
| 9e160e8d1e | |||
|
|
7f6de94ab5 | ||
|
|
cc939f3887 | ||
| 3e5724d9be | |||
|
|
22e70ae92b | ||
| 3e99d7fa8f | |||
|
|
e8dee1fd47 | ||
| e90286fc68 | |||
|
|
05e996ae90 | ||
|
|
947cab458c | ||
|
|
2220ab24b3 | ||
|
|
e75a46633c | ||
|
|
23bd5a431c | ||
|
|
47565e51b0 | ||
|
|
8c30a47706 | ||
| dff4a95acc | |||
|
|
95f2da2def | ||
|
|
f207e029f1 | ||
|
|
2f1298c9d7 | ||
|
|
8cd2d777ab | ||
|
|
a8c7d5ab59 | ||
|
|
968cb72957 | ||
| f5ca1508fb | |||
|
|
33a74d96ae | ||
|
|
1318cbca7f | ||
|
|
982fb1653b | ||
|
|
6270a93151 | ||
| 44ab2cafd3 | |||
| e64f66feb0 | |||
| 24b50d471b | |||
| 93b651b35b | |||
| bbed8bf182 | |||
| d8baa99fc6 | |||
| db58aa4873 | |||
| 163dff7bc6 | |||
| 0a37c252e3 | |||
| d32b88cfef | |||
| 76886ae502 | |||
| d5130aa0e4 | |||
| 8c7d9a942b | |||
| ee57dd163c | |||
| 4f91f46af6 | |||
| 3e6154e4aa | |||
| 07150d8fc5 | |||
| 37baabb1fb | |||
| 4445c5eef9 | |||
| 52847f472d | |||
|
|
ceed1ed706 | ||
| 3ddc9d3320 | |||
| e9185d248b | |||
| 67fdb6f70a | |||
| a9fad2e442 | |||
| 4ffb02fa97 | |||
| ae053147d4 | |||
| 30db9d8215 | |||
| 086584af8e | |||
| 3405850e85 | |||
| 721ea0fe67 | |||
| 980d5034f2 | |||
| 54ed0a2f27 | |||
| cffad4d148 | |||
| 58e6b390c2 | |||
| 73edb5fd43 | |||
| 9b2bc2299d | |||
|
|
2f65ebf57f | ||
|
|
61debcf1a5 | ||
| 94df92fb98 | |||
|
|
6b37ca4b96 | ||
|
|
05a0bf53fa | ||
|
|
3f5b77520c | ||
|
|
ef7752ad49 | ||
|
|
515a6eeea5 | ||
|
|
b2a8cba1aa | ||
|
|
260fbe01db | ||
|
|
95b2fc5c18 | ||
| 110544c793 | |||
|
|
298f48a914 | ||
|
|
28eacf7925 | ||
|
|
ec2ac250bc | ||
|
|
66719d6cb7 | ||
|
|
fdf7999437 | ||
|
|
a24e2f36fd | ||
|
|
f5bd04930b | ||
|
|
5c3e75e3f3 | ||
|
|
aefae33d5c | ||
|
|
9b4caf526f | ||
|
|
3e490aeeb9 | ||
|
|
2a380c63b2 | ||
|
|
aac173d7a1 | ||
|
|
6d058f0750 | ||
|
|
0550f92b5f | ||
|
|
2afbdabc54 | ||
|
|
4e521926d3 | ||
|
|
3b0014abac | ||
|
|
0ebfc57fd6 | ||
|
|
a13702922b | ||
|
|
0995e7500c | ||
|
|
c6f4660b3a | ||
|
|
d2009e62ca | ||
| 11d1ac3f7c | |||
|
|
1eee652533 | ||
|
|
9c462a6eca | ||
|
|
2428042fa3 | ||
|
|
61eff4f929 | ||
|
|
116c8809e4 | ||
|
|
a37d3a9ec4 | ||
|
|
1105a7e3e1 | ||
|
|
b1e460314e | ||
|
|
96f1bb0429 | ||
|
|
49d6db178c | ||
|
|
a16771898c | ||
|
|
65de6f581f | ||
| f986b3da0f | |||
|
|
d46ddc0e8a | ||
|
|
a88d000ccd | ||
|
|
317b720045 | ||
|
|
3c6f48e138 | ||
|
|
3d53615447 | ||
| c36c47267b | |||
|
|
939fb6ef0f | ||
|
|
63bb1967e1 | ||
|
|
bdaa1f0201 | ||
|
|
1703a3dd40 | ||
|
|
877903dd1a | ||
|
|
2873e22038 | ||
|
|
08ec4e4381 | ||
|
|
f0a1f665ff | ||
|
|
925dc26d7a | ||
|
|
d285faaa45 | ||
|
|
74282995fd | ||
|
|
b1a552f68b | ||
|
|
7f0c54a826 | ||
|
|
cd19cf5b92 | ||
|
|
a07db5a3a6 | ||
|
|
01f3827c4c | ||
|
|
7aafd9cc85 | ||
|
|
360a2e434d | ||
|
|
cf74c8e19f | ||
|
|
d1b78491c3 | ||
|
|
f55f3ae518 | ||
|
|
95e1734d26 | ||
|
|
31bfd4a8a4 | ||
|
|
af57804c56 | ||
|
|
99e8d6c9bc | ||
|
|
6720265410 | ||
|
|
dcdda16bcf | ||
|
|
92adb9dd2d | ||
|
|
400c6b8d8c | ||
|
|
33e6a76dbd | ||
|
|
450b52517e | ||
|
|
9188728376 | ||
|
|
63053e9cf8 | ||
|
|
871a5f8fa1 | ||
|
|
94e2a0d34c | ||
|
|
d0608ccd31 | ||
|
|
7fdf6f7c25 | ||
|
|
17dc720df6 | ||
|
|
be98fd8c4c | ||
|
|
1007c280df | ||
|
|
c8318305f9 | ||
|
|
4133ff36b7 | ||
|
|
25e506f54d | ||
|
|
181e0528b5 | ||
|
|
48d784a147 | ||
|
|
f51397a17a | ||
|
|
c0a2dd9a14 | ||
|
|
8c032209a0 | ||
|
|
82aaefe843 | ||
|
|
0ad7e48462 | ||
|
|
9854541a0c | ||
|
|
cbb949e397 | ||
|
|
eb62d4606c | ||
|
|
8e92ec3cb2 | ||
|
|
3695f9fbb0 | ||
|
|
69fd8ff701 | ||
|
|
30492c03ca | ||
|
|
b693960ac2 | ||
|
|
cafadb92b1 | ||
|
|
f60a228392 | ||
|
|
3ede650cc5 | ||
|
|
e504d8cf6d | ||
|
|
42b860e417 | ||
|
|
cbbcc2e5e4 | ||
|
|
3f030fd50f | ||
|
|
5f77877bb4 | ||
|
|
6aea21e81f | ||
|
|
2982c8598e | ||
|
|
0486d733a1 | ||
|
|
8c49c31760 | ||
| 6b08af6a74 | |||
|
|
bd696f400f | ||
|
|
aac8e584a9 | ||
|
|
8d6ea040c1 | ||
|
|
b1a9043047 | ||
|
|
bafabb1d4e | ||
|
|
0caa69c28c | ||
|
|
f7726378f4 | ||
|
|
3e6e1f7bc0 | ||
|
|
5f91229e82 | ||
|
|
0d3055f936 | ||
|
|
15ccbe4c18 | ||
|
|
5fdef95c06 | ||
|
|
e0f4ce134d | ||
|
|
276e6d3b40 | ||
|
|
ae0612c6d5 | ||
|
|
8aef5b8d5b | ||
|
|
fdee2db8a4 | ||
|
|
82ba5f8121 | ||
|
|
9c6b5131cd | ||
|
|
a037090eec | ||
|
|
bc13cc5e1f | ||
|
|
aba9627661 | ||
|
|
18ab92909d | ||
|
|
44b6a4aea0 | ||
|
|
f349bd7233 | ||
| 38f0a30076 | |||
|
|
8b2f2c063c | ||
|
|
bc4c3d78db | ||
|
|
42e2f3a0cb | ||
|
|
d647719201 | ||
|
|
107d94d499 | ||
|
|
1a340ff700 | ||
|
|
f6f93df2fa | ||
|
|
1791b0df51 | ||
|
|
d59b55c152 | ||
| c8f6a27c57 | |||
|
|
acdd93eb99 | ||
|
|
c3130a392a | ||
|
|
c3d66b36c8 | ||
|
|
e6df1a2185 | ||
|
|
67f4a3f2c4 | ||
|
|
edaff443e8 | ||
|
|
33c134e4de | ||
|
|
baafbcb598 | ||
|
|
34c30d1b14 | ||
|
|
a19893e56d | ||
|
|
5e1a902d4c | ||
|
|
998edcb5cd | ||
|
|
8dae143d72 | ||
|
|
e280e995bf | ||
|
|
3980496c77 | ||
|
|
e0717a96ef | ||
|
|
b88c2f6428 | ||
|
|
937ee4ddce | ||
|
|
7eb727ea27 | ||
|
|
134c2e4c84 | ||
|
|
e395e9d270 | ||
|
|
60bc460841 | ||
|
|
48218e89da | ||
|
|
02d7208d73 | ||
|
|
6b9b1fa854 | ||
|
|
75155a9a86 | ||
|
|
dd138fd0be | ||
|
|
c8be14f9d8 | ||
|
|
3e831c1648 | ||
|
|
5a2d9f3075 | ||
|
|
28fbfef18c | ||
|
|
4056f09448 | ||
|
|
c86880da39 | ||
|
|
8d82119d95 | ||
|
|
6f2fdf9219 | ||
|
|
d7abfec9fd | ||
|
|
0d28f6ae55 | ||
|
|
57a0c02805 | ||
|
|
ec511fb8f4 | ||
|
|
fed4f20c3c | ||
|
|
5ddff5fe12 | ||
|
|
c712fa17f7 | ||
|
|
a0c1045c58 | ||
|
|
7799b5187a | ||
|
|
2da9e8ad1e | ||
|
|
feee9e8db9 | ||
|
|
3316ad9169 | ||
|
|
1af9140cea | ||
|
|
2ddffe6d4f | ||
|
|
9f8ab5c7a1 | ||
|
|
eb108c7414 | ||
| b8db0f3e70 | |||
|
|
92eb0ee3b0 | ||
|
|
7ecba0b781 | ||
|
|
b2cc1fd91f | ||
|
|
4a3f79ca20 | ||
|
|
8a04a43903 | ||
|
|
f39c29f10b | ||
|
|
848d2574c7 | ||
|
|
1211369724 | ||
|
|
13cee2d426 | ||
|
|
b38a96996a | ||
|
|
7bfc3fc026 | ||
|
|
855531fefb | ||
|
|
37dd29a60f | ||
|
|
d571b1dbe5 | ||
|
|
605aa1b782 | ||
|
|
0d755bcbd3 | ||
|
|
d22a67f842 | ||
|
|
0b037f96e6 | ||
|
|
1ba66aa4fb | ||
|
|
b71a30db1f | ||
|
|
43c469d66a | ||
|
|
608429c139 | ||
|
|
27ed3c11f1 | ||
|
|
b183198029 | ||
|
|
9ad402842d | ||
| 9bc3642990 | |||
|
|
de10654675 | ||
|
|
608f58ccbf | ||
|
|
dde4a0d1cd | ||
|
|
f2d9c945e5 | ||
|
|
769c6f1f7e | ||
|
|
8c9fdb4f24 | ||
|
|
ba07267372 | ||
|
|
001cd4b4de | ||
|
|
c2b0d22a25 | ||
|
|
9e1017edfb | ||
|
|
557d050b36 | ||
|
|
6c64086fef | ||
|
|
8ec8fb3386 | ||
|
|
f432d57004 | ||
|
|
26a4e6dcf1 | ||
| 0bce9e5452 | |||
|
|
2130d84920 | ||
|
|
c7b30cf749 | ||
|
|
399e1a6f7e | ||
|
|
68734bfe21 | ||
|
|
f3cf3b30e3 | ||
|
|
ebdc14d3c3 | ||
|
|
5e8745e742 | ||
|
|
6e07041215 | ||
|
|
54dc63d848 | ||
|
|
949063eff8 | ||
|
|
f2cb318a09 | ||
|
|
c4016fd29a | ||
|
|
6e50b89b1a | ||
|
|
62ab6384d3 | ||
|
|
f864c64efa | ||
|
|
c1dc7b4e8f | ||
|
|
a096d5be62 | ||
|
|
ed6358a0c8 | ||
|
|
784c3ee2d9 | ||
|
|
123c330d50 | ||
|
|
37483abb9f | ||
|
|
746d98fed5 | ||
|
|
4be5cb2b6a | ||
|
|
678323cc09 | ||
|
|
910bbf923b | ||
|
|
b97c0adc21 | ||
|
|
dd95fa0d1e | ||
|
|
35b4b6c823 | ||
|
|
308a6cf1ea | ||
|
|
e14b1248d5 | ||
|
|
734c6ec262 | ||
|
|
6c51f777dd | ||
|
|
82a3651fb3 | ||
|
|
e6e75db3e8 | ||
|
|
eeda6ef26c | ||
|
|
7b1f0493da | ||
|
|
a20200e52a | ||
|
|
82479f463c | ||
|
|
a4de628495 | ||
|
|
e9bedb78c6 | ||
|
|
68877fe850 | ||
|
|
7bbdba5c0b | ||
|
|
c9cfe7e3ed | ||
|
|
75138c7061 | ||
|
|
0753ab9f33 | ||
|
|
f16e5394cc | ||
|
|
cef38e0f83 | ||
|
|
383778e1e7 | ||
|
|
40cb266d09 | ||
|
|
e2e0e8aa70 | ||
|
|
df92e97cb6 | ||
|
|
612648e5d7 | ||
|
|
97f48fcbb6 | ||
|
|
ac226d178a | ||
|
|
0080b3782c | ||
|
|
c717bd3fe0 | ||
|
|
8f7b2236de | ||
|
|
a2ba60abe7 | ||
|
|
75846c54b7 | ||
|
|
b66cecbdd9 | ||
|
|
0b112f1d01 | ||
|
|
bb45c36d86 | ||
|
|
3e2c7a1927 | ||
|
|
61be2a34c9 | ||
|
|
2e4a47ee8f | ||
|
|
903bfe1967 | ||
|
|
a004fb8188 | ||
|
|
e9ec49a772 | ||
|
|
389df797ad | ||
|
|
f8453561d8 | ||
|
|
418ba67d15 | ||
|
|
7f22cbb54c | ||
|
|
8b9bb45868 | ||
|
|
77f1f0a5b8 | ||
|
|
4bb007ede3 | ||
|
|
51ae246a0f | ||
|
|
4afbb9722e | ||
|
|
1b0c5d6981 | ||
|
|
be889ae17d | ||
|
|
cace737b92 | ||
|
|
4052278d94 | ||
|
|
0f73c9cb01 | ||
|
|
8156885293 | ||
|
|
7534744294 | ||
|
|
aeac607bf5 | ||
|
|
0d3c2151d7 | ||
|
|
448b5631ad | ||
|
|
0d0ba10922 | ||
|
|
1547eab6a1 | ||
|
|
57860b8933 | ||
|
|
43064b2d2c | ||
|
|
d724db01ee | ||
|
|
e2a22653ca | ||
|
|
5d79ea75dd | ||
|
|
786abdbefa | ||
|
|
9d31365d0a | ||
|
|
8ee364b2f7 | ||
|
|
ae429ca5fb | ||
|
|
8ecf347c9a | ||
|
|
c1f90b0a68 | ||
| 8710ba43ff | |||
|
|
ca1d2444e0 | ||
|
|
9e71efca9f | ||
|
|
915fd72bd4 | ||
|
|
04afdb7543 | ||
|
|
401e96e86e | ||
|
|
9832b0395a | ||
|
|
1515e7778f | ||
|
|
139e405bd3 | ||
|
|
5522ac55ac | ||
|
|
83d9a4a8b8 | ||
|
|
17a796e97b | ||
|
|
62c60448aa | ||
|
|
a4277d392d | ||
|
|
32480b7bfa | ||
|
|
405f8cf496 | ||
| 899e3c6ac0 | |||
| 134acd61db | |||
| a2c334526c | |||
|
|
3f81afda82 | ||
|
|
9430e10387 | ||
|
|
0698ca616c | ||
|
|
2361c100bb | ||
|
|
51bb8e3b9c | ||
|
|
1015fd24ac | ||
|
|
618a9046bc | ||
|
|
c43e2b38e6 | ||
|
|
9d0ff36af5 | ||
|
|
0fe315dcd7 | ||
|
|
b97006e71e | ||
|
|
869eafb629 | ||
|
|
0dc3792fb9 | ||
|
|
223b5ee5c0 | ||
|
|
31bb7e89ea | ||
|
|
942f04e250 | ||
|
|
930b574618 | ||
|
|
b0666060ab | ||
|
|
448055fd23 | ||
|
|
65f25afd89 | ||
|
|
28e03d7e18 | ||
|
|
8035d6ef5a | ||
|
|
9ed2a4da0c | ||
|
|
73501e0fa3 | ||
|
|
8d654f22cb | ||
|
|
9560e0c526 | ||
|
|
73e331cd94 | ||
|
|
3ae31f0b2d | ||
|
|
15286dd717 | ||
|
|
7b88be3a75 | ||
|
|
ae5299c128 | ||
|
|
bc1ae1f02f | ||
|
|
2212e0723e | ||
|
|
9db2489ab2 | ||
|
|
7111f44fb0 | ||
|
|
5edec7154e | ||
|
|
9efc41a8f8 | ||
|
|
6e94e1f7e5 | ||
|
|
a65cfc1176 | ||
|
|
f54d04f94d | ||
|
|
315e15f53d | ||
|
|
bb3be5a816 | ||
|
|
b7ae2cf019 | ||
|
|
9ce8c58b98 | ||
|
|
5277f7601c | ||
|
|
5241a01b55 | ||
|
|
39e710e685 | ||
|
|
4bb46d8a06 | ||
|
|
ac144095bf | ||
|
|
1fcf7340d4 | ||
|
|
427e357b8d | ||
|
|
12fc2d6532 | ||
|
|
ed7b5eaf65 | ||
|
|
28caaf1d21 | ||
|
|
418fc6ba05 | ||
|
|
cb19ff3598 | ||
|
|
b8adbcd030 | ||
|
|
9242438132 | ||
| 484be6a890 | |||
|
|
25171fe4d7 | ||
|
|
9d634f2a89 | ||
|
|
f0bbed1445 | ||
|
|
334f0d7069 | ||
|
|
8ceffa23a9 | ||
|
|
8edaa5def1 | ||
|
|
ee744cf2cc | ||
|
|
f1480f3d72 | ||
|
|
ab6173ccff | ||
|
|
7a841a554a | ||
|
|
f36b1c0588 | ||
|
|
bc15df828d | ||
|
|
5f8907ff7d | ||
|
|
30f773627e | ||
|
|
e9bd2b7a6c | ||
|
|
29585faff6 | ||
|
|
30d801a3b4 | ||
|
|
c54ea867bd | ||
|
|
488150f7f5 | ||
|
|
f0a2ca7e8e | ||
|
|
1442e53430 | ||
|
|
387769b05d | ||
|
|
dac2f5656a | ||
|
|
7b491ed3bb | ||
|
|
552911cfcf | ||
|
|
72e5fcca77 | ||
|
|
fd7f664792 | ||
|
|
d2a23e581e | ||
|
|
d3c509ccb4 | ||
|
|
d2fe89ec3a | ||
|
|
0d3248fff0 | ||
|
|
1748ba3825 | ||
|
|
45e0f26391 | ||
|
|
ead47aca19 | ||
|
|
f9c2414000 | ||
|
|
523de51160 | ||
|
|
d912c03eb0 | ||
|
|
a638f5447b | ||
|
|
f6168bf678 | ||
|
|
5f1cf06ce3 | ||
|
|
4c86ced5b7 | ||
|
|
93c37b26cc | ||
|
|
2e2a5897b8 | ||
|
|
0479e7cdc3 | ||
|
|
b95c796358 | ||
|
|
87323e70cf | ||
|
|
edd2ccffe9 | ||
|
|
e30ef33cc8 | ||
|
|
5405c5bc31 | ||
|
|
28552a665f | ||
|
|
cecf95aa46 | ||
|
|
6fd8c5adf3 | ||
|
|
db24b41d99 | ||
|
|
b1fcd22ab2 | ||
|
|
8962da31a3 | ||
|
|
de8033c218 | ||
|
|
cb9dd83bef | ||
|
|
e68d1b73f9 | ||
|
|
ec8b553d2b | ||
|
|
368c26ce8c | ||
|
|
58ce196507 | ||
|
|
6756f6ccd4 | ||
|
|
9990759de0 | ||
|
|
dcb56f7721 | ||
|
|
20f281a544 | ||
|
|
712f204ade | ||
|
|
86535bb1bb | ||
|
|
392d743444 | ||
|
|
edbd739db9 | ||
|
|
3eeab34bc1 | ||
|
|
0edc598667 | ||
|
|
9537833247 | ||
|
|
84b699ba26 | ||
|
|
a9b495b4a1 | ||
|
|
eea8d6d339 | ||
|
|
91b1e3a52b | ||
|
|
bdf85112b1 | ||
|
|
f10cd6c431 | ||
|
|
f3e83bfcc8 | ||
|
|
b56322b05c | ||
|
|
098b1d733e | ||
|
|
37fe25c42f | ||
|
|
89dc41ad35 | ||
|
|
562f357374 | ||
|
|
93863510fa | ||
|
|
b7be5b9dbc | ||
|
|
aabb29ad05 | ||
|
|
6a5bad7896 | ||
|
|
7596759f77 | ||
|
|
4b258234e0 | ||
|
|
75f4644940 | ||
|
|
cdb6ac4084 | ||
|
|
11017955ee | ||
|
|
eaf9da3c84 | ||
|
|
a5e5a5b407 | ||
|
|
8abd993667 | ||
|
|
19b36c07b7 | ||
|
|
c9720dc104 | ||
|
|
bde0df219c | ||
|
|
e78496fb8b | ||
|
|
411e0970b8 | ||
|
|
d22e6ff87f | ||
|
|
6ce435fc05 | ||
|
|
988236e646 | ||
|
|
2cd0a70fd4 | ||
|
|
faa0ed60f4 | ||
|
|
1727c0280f | ||
|
|
ea935232ab | ||
|
|
35c9991a61 | ||
|
|
fb7b3fd1d2 | ||
|
|
c88ffe549f | ||
|
|
18c628a002 | ||
|
|
9c5581af2c | ||
|
|
a1592f84cc | ||
|
|
1195c5ffc8 | ||
|
|
7bece91206 | ||
|
|
90b97339d3 | ||
|
|
df31e4f6fd | ||
|
|
4615fe804b | ||
|
|
d99b80d2c2 | ||
|
|
e7d5f83100 | ||
|
|
a57c3029df | ||
|
|
f6003d7f87 | ||
|
|
080e6fa3e8 | ||
|
|
863a3ffd48 | ||
|
|
9a3241c42a | ||
|
|
e4165901bb | ||
|
|
5bd0b50816 | ||
|
|
72060cbed7 | ||
|
|
e65a81fcfa | ||
|
|
bbdf14c7a4 | ||
|
|
be40adcbf4 | ||
|
|
0b33db9f89 | ||
|
|
d86a7353dd | ||
|
|
4f87968943 | ||
|
|
6257ca0dd3 | ||
|
|
6a87557109 | ||
|
|
07feb8f03f | ||
|
|
9d8fe643a5 | ||
|
|
c0d0b1bd99 | ||
|
|
b5f239ea4e | ||
|
|
83120a6734 | ||
|
|
d601880be1 | ||
|
|
268588fb6f | ||
|
|
d3048a12d8 | ||
|
|
e14993114f | ||
|
|
046a95ba1d | ||
|
|
54cc8838ae | ||
|
|
4237f6ad60 | ||
|
|
e7c1000bc4 | ||
|
|
e0adb2332e | ||
|
|
e5696b23e7 | ||
|
|
659d0974f7 | ||
|
|
e8304eeeb4 | ||
|
|
dca9d26c66 | ||
|
|
852e0f5373 | ||
|
|
26dd531d24 | ||
|
|
52bdf93356 | ||
|
|
7509610145 | ||
|
|
972cdf392d | ||
|
|
4f758f7d0c | ||
|
|
980e899807 | ||
|
|
d1c5bb9595 | ||
|
|
dc9c0f528f | ||
|
|
66d64e0858 | ||
|
|
06339786c2 | ||
|
|
8ed68481fa | ||
|
|
e26042957c | ||
|
|
7553620a5d | ||
|
|
482dec345c | ||
|
|
e73d8e6bc4 | ||
|
|
33c60e414d | ||
|
|
f068de3031 | ||
|
|
8615203a3e | ||
|
|
3a5ee64db5 | ||
|
|
bfe3faa01c | ||
|
|
322c001e70 | ||
|
|
830e249ac4 | ||
|
|
8c9df3ea9a | ||
|
|
f85768d32e | ||
|
|
71593b44c8 | ||
|
|
408b61a57a | ||
|
|
e82f4e9209 | ||
|
|
9a9bc029f8 | ||
|
|
c7cdb013e2 | ||
|
|
5d38d6f180 | ||
|
|
8b98b8afdc | ||
|
|
7a01a6b305 | ||
|
|
bc2274a9ef | ||
|
|
580ace368f | ||
|
|
522be6643a | ||
|
|
8784309ddb | ||
|
|
f602d6fe41 | ||
|
|
fe72cfec43 | ||
|
|
c1b956986d | ||
|
|
6a655fe28a | ||
|
|
78d15cabc8 | ||
|
|
0ca252b221 | ||
|
|
7e35fae34e | ||
|
|
564a4e2994 | ||
|
|
3d406ddf88 | ||
|
|
66d6b07485 | ||
|
|
48ce0f241c | ||
|
|
c8b459fb6a | ||
|
|
2c04fd6efc | ||
|
|
f75e532d44 | ||
|
|
70ce8ea0d6 | ||
|
|
e8eacd2c74 | ||
|
|
9e6e2be2e7 | ||
|
|
8c8f44b6f1 | ||
|
|
e1d0d20296 | ||
|
|
3c3a571dca | ||
|
|
1bf44d887d | ||
|
|
e57555aea8 | ||
|
|
a6e19b1230 | ||
|
|
3afeb0e936 | ||
|
|
2566a71a81 | ||
|
|
3d8f996690 | ||
|
|
8f3df58e42 | ||
|
|
c5b826080c | ||
|
|
b509dd2e2d | ||
|
|
5ffa699f57 | ||
|
|
b909e0bed4 | ||
|
|
2e3f6684ef | ||
|
|
36a4bfcbbc | ||
|
|
db347bf324 | ||
|
|
837c69bb21 | ||
|
|
7a2e0f20d1 | ||
|
|
1c56c891e1 | ||
|
|
7f23a0e6cf | ||
|
|
523e34f6e4 | ||
|
|
d6cb7e1d3b | ||
|
|
d3188f5090 | ||
|
|
e29a68bb03 | ||
|
|
88684f068a | ||
|
|
d420008926 | ||
|
|
7d449b43d0 | ||
|
|
867f9e9b83 | ||
|
|
0becdeb6d9 | ||
|
|
dacb1c66e8 | ||
|
|
e187ee8c44 | ||
|
|
18ab8d592e | ||
|
|
3b4cb2b420 | ||
|
|
b2d18da82a | ||
|
|
fae7395cf0 | ||
|
|
fdd27d946c | ||
|
|
0745b1af72 | ||
|
|
a2b2cefe8e | ||
|
|
d6f126f197 | ||
|
|
581a5b2e55 | ||
|
|
72988e9241 | ||
|
|
def31cd036 | ||
|
|
9011e345a2 | ||
|
|
82bb15b863 | ||
|
|
3672cb47a8 | ||
|
|
c9f37a1df0 | ||
|
|
6dd5fcdde5 | ||
|
|
26c14fa7e9 | ||
|
|
d083105d6d | ||
|
|
8cb4ee12a6 | ||
|
|
f8c3b29c60 | ||
|
|
03c2b8aeab | ||
|
|
88909a5650 | ||
|
|
8cf40900bb | ||
|
|
04b21a7c5d | ||
|
|
ca7626db17 | ||
|
|
92741d6613 | ||
|
|
f0401e1889 | ||
|
|
9bc05d2c99 | ||
|
|
210e7ac021 | ||
|
|
e8d492a18a | ||
|
|
7aefa50101 | ||
|
|
9ef14774d2 | ||
|
|
a09359d0b2 | ||
|
|
bd132f9f6a | ||
|
|
8b2b853942 | ||
|
|
a1bf950c88 | ||
|
|
03084b1c96 | ||
|
|
aa294c4e29 | ||
|
|
e628f396e2 | ||
|
|
3c7ada4eea | ||
|
|
bf3a716767 | ||
|
|
1b3c43d2cb | ||
|
|
fee9a163e1 | ||
|
|
7ba647271e | ||
|
|
e5c227073a | ||
|
|
472a1b97d6 | ||
|
|
f1b4930a30 | ||
|
|
49a1758da3 | ||
|
|
e42149e93f | ||
|
|
53b3e8909c | ||
|
|
7d396f9202 | ||
|
|
c40ceef039 | ||
|
|
98896d5474 | ||
|
|
6125d43e8c | ||
|
|
e9452d6520 | ||
|
|
7ed2921efb | ||
|
|
1596b6e3b8 | ||
|
|
369bb906c1 | ||
|
|
aa38fef293 | ||
|
|
ded8e7dfd5 | ||
|
|
c4f5fb80b5 | ||
|
|
c31540e835 | ||
|
|
b42db4d8b0 | ||
|
|
293ed6ba5f | ||
|
|
972b551a57 | ||
|
|
4ab7b40b73 | ||
|
|
1cdac9f60d | ||
|
|
109b9e3cbd | ||
|
|
fb96a4e8be | ||
|
|
377435f3eb | ||
|
|
581e60267d | ||
|
|
c03b5d3faa | ||
|
|
52c33f47da | ||
|
|
cb890556d7 | ||
|
|
8dffe29146 | ||
|
|
aeebbf9656 | ||
|
|
452273248d | ||
|
|
43a89ec4f2 | ||
|
|
6f2990b804 | ||
|
|
459b1ed19f | ||
|
|
227abeb36d | ||
|
|
be1fef2e25 | ||
|
|
587c98a50e | ||
|
|
d47897c7e8 | ||
|
|
9ab5280b2e | ||
|
|
596788f3a1 | ||
|
|
2bddddbf39 | ||
|
|
08e632250f | ||
|
|
4f02d87f29 | ||
|
|
863bd58cad | ||
|
|
fe90cd098a | ||
|
|
cb43171640 | ||
|
|
96e3acf9ba | ||
|
|
70271a4849 | ||
|
|
98ab64403f | ||
|
|
3d1bb6ef13 | ||
|
|
d5f39517e8 | ||
|
|
dfe35d71a3 | ||
|
|
c685adcac6 | ||
|
|
da056b75d0 | ||
|
|
51c157d577 | ||
|
|
32fc24f986 | ||
|
|
2f9e1353a7 | ||
|
|
f82b465263 | ||
|
|
9f744a3c88 | ||
|
|
d6823a1206 | ||
|
|
3fd23689c1 | ||
|
|
96bb8bbff3 | ||
|
|
aa0ba51a34 | ||
|
|
20f68ed581 | ||
|
|
23cdf29fc5 | ||
|
|
c5a8f7ebea | ||
|
|
7238c2f333 | ||
|
|
074cc061f5 | ||
|
|
fe59204b42 | ||
|
|
a811bf9f4f | ||
|
|
bbd20effb6 | ||
|
|
640df473f7 | ||
|
|
9f75f47e9c | ||
|
|
02cc2a8879 | ||
|
|
7afa66e01a | ||
|
|
bb8a9f6ba5 | ||
|
|
b89f5c4edd | ||
|
|
4cf27b2c32 | ||
|
|
95b183b1bb | ||
|
|
4b932af1c0 | ||
|
|
6f7c680ed8 | ||
|
|
b56a428c92 | ||
|
|
cdaa83122f | ||
|
|
937919f1a7 | ||
|
|
3249300dac | ||
|
|
5acf49fd52 | ||
|
|
07b5ad1618 | ||
|
|
d56c3d11a8 | ||
|
|
beb57b2f5a | ||
|
|
0bda134bfe | ||
|
|
dbcde48c14 | ||
|
|
09aa7bb5c5 | ||
|
|
388e4fbb76 | ||
|
|
d8ede006df | ||
|
|
83f00f40bf | ||
|
|
782ee3758a | ||
|
|
8a28d6fa86 | ||
|
|
ed53c6595e | ||
|
|
49ea2c59ab | ||
|
|
869fa831ea | ||
|
|
21eeecd5ee | ||
|
|
2dfb64bafd | ||
|
|
61b1fde0ec | ||
|
|
58e6b19a70 | ||
|
|
e81b2e161d | ||
|
|
873d6459b5 | ||
|
|
5bd8025d08 | ||
|
|
32c4cee4aa | ||
|
|
1d043c2ef1 | ||
|
|
9a881299dc | ||
|
|
9c78fc2366 | ||
|
|
614a1b1e9b | ||
|
|
4ab8770fbc | ||
|
|
4e42772ca3 | ||
|
|
2cf1027796 | ||
|
|
aa39a5947c | ||
|
|
9272060a8b | ||
|
|
9463130e7d | ||
|
|
3a3cf835a5 | ||
|
|
0a10ef1362 | ||
|
|
546aa14895 | ||
|
|
3aed37ecb4 | ||
|
|
70db25ca64 | ||
|
|
106dd26f89 | ||
|
|
6e9e57d251 | ||
|
|
d804085c54 | ||
|
|
79943bc687 | ||
|
|
7a5d2bb1e9 | ||
|
|
a11a24225b | ||
|
|
ddb26b8207 | ||
|
|
805c1f0937 | ||
|
|
d27bf7ea94 | ||
|
|
5435f85cc4 | ||
|
|
364edff8b7 | ||
|
|
efedaba94d | ||
|
|
5377d026f3 | ||
|
|
de0617b8dd | ||
|
|
c9dedf6a9f | ||
|
|
f4bf7abc89 | ||
|
|
4fc7838a22 | ||
|
|
e48134eddc | ||
|
|
975f8e25e4 | ||
|
|
a1e820336f | ||
|
|
5dce28fb99 | ||
|
|
148fd77f4d | ||
|
|
4036bfd193 | ||
|
|
f4f372b9ad | ||
|
|
872c1f5fc3 | ||
|
|
4f2ca30dab | ||
|
|
ccb851c0b5 | ||
|
|
c1c9a92ec9 | ||
|
|
882483ee24 | ||
|
|
d696215d08 | ||
|
|
dd8a6b3abc | ||
|
|
1f7c9aba33 | ||
|
|
deaebd754d | ||
|
|
f20038c8f9 | ||
|
|
99c698bd16 | ||
|
|
7106996cc3 | ||
|
|
3d36ecc2b0 | ||
|
|
c998166938 | ||
|
|
d0847a8bf6 | ||
|
|
b42e911a11 | ||
|
|
67fb4a43c9 | ||
|
|
0aa26020be | ||
|
|
93877c9fc7 | ||
|
|
5c78973887 | ||
|
|
d61e33de39 | ||
|
|
07d6c4770a | ||
|
|
aab3e9fa6c | ||
|
|
4a4cd4e6d4 | ||
|
|
360cddbf15 | ||
|
|
42e68120b7 | ||
|
|
4955d8b6be | ||
|
|
08c2a6c8ab | ||
|
|
7b402d61c3 | ||
|
|
643b6c967f | ||
|
|
942cd11469 | ||
|
|
d0c0d7d9d4 | ||
|
|
27cf62f952 | ||
|
|
66167831e6 | ||
|
|
00d52fa069 | ||
|
|
ef87601e84 | ||
|
|
f0a45d1b8e | ||
|
|
1a6f816b66 | ||
|
|
d69ac01bbf | ||
|
|
dbea099d92 | ||
|
|
add690c842 | ||
|
|
ad0dae46ff | ||
|
|
a75f3af979 | ||
|
|
af2fd6763d | ||
|
|
124e3754fd | ||
|
|
aedeab30f2 | ||
|
|
3c582cebc6 | ||
|
|
e486d25537 | ||
|
|
9621d2528d | ||
|
|
47f3232f15 | ||
|
|
308965a2fa | ||
|
|
fe090c7387 | ||
|
|
f0782d8820 | ||
|
|
90fc78c142 | ||
|
|
c213df6724 | ||
|
|
74298065e0 | ||
|
|
6f1820ff91 | ||
|
|
a2461d5904 | ||
|
|
d2e0069dc2 | ||
|
|
9c6972af78 | ||
|
|
98cfcab15a | ||
|
|
f8a51b9828 | ||
|
|
1591c38c0a | ||
|
|
810c3027ea | ||
|
|
c12fa6f4e6 | ||
|
|
8e88b7241a | ||
|
|
a1c02dadfc | ||
|
|
9712b5ebc3 | ||
|
|
a63668ce74 | ||
|
|
61ad5abc2b | ||
|
|
fa76d9e356 | ||
|
|
90301517c2 | ||
|
|
b97aeaf5df | ||
|
|
bf3dee067b | ||
|
|
90eb22509a | ||
|
|
96741f3789 | ||
|
|
59db3b5c50 | ||
|
|
56cd8d2ab7 | ||
|
|
578fd58cd9 | ||
|
|
994d6c1e6b | ||
|
|
fa041efcbb | ||
|
|
da59fcbfa8 | ||
|
|
ae7a879e64 | ||
|
|
c54aa25f34 | ||
|
|
053a6ce23f | ||
|
|
9512bca329 | ||
|
|
30a2d3dcf4 | ||
|
|
bf5eeb6a5a | ||
|
|
b624ed3426 | ||
|
|
8fe6a2795f | ||
|
|
5f969c53f6 | ||
|
|
b3ee587831 | ||
|
|
8f10626e52 | ||
|
|
ab9168cb24 | ||
|
|
f59cc5832c | ||
|
|
9637574071 | ||
|
|
9144a4a031 | ||
|
|
9ded905fbd | ||
|
|
61c5ba6747 | ||
|
|
fbe1a65cd1 | ||
|
|
4ead266a07 | ||
|
|
6f377264e9 | ||
|
|
334f5a7507 | ||
|
|
7424ad9831 | ||
|
|
df69bfd95f | ||
|
|
650b5c1ed3 | ||
|
|
de60311bd0 | ||
|
|
15ac0e2f59 | ||
|
|
ab30ad76c1 | ||
|
|
1d5f99b1fa | ||
|
|
9488451080 | ||
|
|
ff9fb49deb | ||
|
|
31acec2a05 | ||
|
|
dc169746e7 | ||
|
|
dcf7906f79 | ||
|
|
785813c3fb | ||
|
|
e2b4b0467d | ||
|
|
570d7bac7c | ||
|
|
b74e056826 | ||
|
|
26f3f4620b | ||
|
|
32c8a2149a | ||
|
|
e59689e94c | ||
|
|
2259da317a | ||
|
|
18359fdab3 | ||
|
|
948ec1848f | ||
|
|
5eefa3c2e1 | ||
|
|
fe7dd09d7e | ||
|
|
f3b86f0f0d | ||
|
|
dd6ea1c6f3 | ||
|
|
af305aa196 | ||
|
|
7a9f3eaca4 | ||
|
|
80e62496f0 | ||
|
|
8dbb3ca19a | ||
|
|
7d4c27ec26 | ||
|
|
3a7cc8d7c1 | ||
|
|
60b689f28c | ||
|
|
d3955b3cdd | ||
|
|
751693bebc | ||
|
|
81cfd0986f | ||
|
|
9f4350eea7 | ||
|
|
006bbebe60 | ||
|
|
5ff16c1005 | ||
|
|
e165837a15 | ||
|
|
0c43be2dbe | ||
|
|
24a91229f2 | ||
|
|
677be5173d | ||
|
|
ce06e735be | ||
|
|
bbbe4d5f1f | ||
|
|
21710ee492 | ||
|
|
6483221b62 | ||
|
|
c61c37dc27 | ||
|
|
23eb1e2263 | ||
|
|
4cfb560954 | ||
|
|
4a64f26e43 | ||
|
|
c2728b2a1d | ||
|
|
b629d058eb | ||
|
|
1bad092185 | ||
|
|
54301ae8fb | ||
|
|
ba2c6f655c | ||
|
|
496e6c5bd0 | ||
|
|
4ac6987813 | ||
|
|
13938ecf21 | ||
|
|
afd324fc6a | ||
|
|
d917627d58 | ||
|
|
5d6d4b53f0 | ||
|
|
8eab6b8531 | ||
|
|
7e04fad28b | ||
|
|
b98418f9e1 | ||
|
|
3ea2c3b98d | ||
|
|
992a0a6f2c | ||
|
|
3d51ccfac2 | ||
|
|
59ea7a5ba6 | ||
|
|
9adc0b88d7 | ||
|
|
90187ce936 | ||
|
|
0cbf9b26a9 | ||
|
|
9db091c26f | ||
|
|
fc4f16ac44 | ||
|
|
684d52c917 | ||
|
|
f4a699e0e5 | ||
|
|
8b457c9911 | ||
|
|
42c7350c36 | ||
|
|
dd4be92f90 | ||
|
|
67c814443c | ||
|
|
fa2c9d7a88 | ||
|
|
24e27c1d9e | ||
|
|
59e4009c5d | ||
|
|
8c48552abf | ||
|
|
2f13010480 | ||
|
|
6f7e23df20 | ||
|
|
a1c14e8e6f | ||
|
|
e17db521e2 | ||
|
|
d110d60123 | ||
|
|
eabd885cd4 | ||
|
|
e70e50a1ea | ||
|
|
12b71ba1f1 | ||
|
|
f11376ecf8 | ||
|
|
827827905b | ||
|
|
2b894bd1b6 | ||
|
|
b67ec14573 | ||
|
|
8be85536eb | ||
|
|
a91277c502 | ||
|
|
2b6707e369 | ||
|
|
9b889c8736 | ||
|
|
30082f8726 | ||
|
|
90822f5888 | ||
|
|
d95436c733 | ||
|
|
6ceb763b5a | ||
|
|
98f02b8830 | ||
|
|
16bbb7e9e3 | ||
|
|
a599c87384 | ||
|
|
56b03aa0b9 | ||
|
|
b517837671 | ||
|
|
89bbb4ecf5 | ||
|
|
1e75b1d1bf | ||
|
|
1d94dd5bf3 | ||
|
|
f0df58695d | ||
|
|
7ba8233f5b | ||
|
|
3da7c7d009 | ||
|
|
7928534d88 | ||
|
|
a8f22c1e96 | ||
|
|
223de443a3 | ||
|
|
6f03ede8bf | ||
|
|
6312e47796 | ||
|
|
952207ace1 | ||
|
|
3d9d28c60c | ||
|
|
64fde65859 | ||
|
|
1f6b314a8f | ||
|
|
0bc95ca4ed | ||
|
|
c97ecd698c | ||
|
|
0f46811175 | ||
|
|
f725732772 | ||
|
|
dca6287b90 | ||
|
|
3fc7c781ec | ||
|
|
4e367254c2 | ||
|
|
f432f27c64 | ||
|
|
bb9ad9a957 | ||
|
|
913c5691da | ||
|
|
2c08a1cefd | ||
|
|
9566f7aa0a | ||
|
|
025335432d | ||
|
|
9f71e46f66 | ||
|
|
03cdbc6f9b | ||
|
|
9f886a8968 | ||
|
|
c75ca68c44 | ||
|
|
e80afe2c93 | ||
|
|
ebc8a3bc39 | ||
|
|
bea4face58 | ||
|
|
6b66e92d61 | ||
|
|
78e7d7456b | ||
|
|
822823ea1a | ||
|
|
2df53fcd95 | ||
|
|
e6bc84adf5 | ||
|
|
f7113400d7 | ||
|
|
2fe9f51460 | ||
|
|
30d2108634 | ||
|
|
088beb8c11 | ||
|
|
af965bce7a | ||
|
|
52a058c2df | ||
|
|
6b10cc86d8 | ||
|
|
55be9d4d4e | ||
|
|
cd191e09da | ||
|
|
2dbbea8992 | ||
|
|
33bde7d3df | ||
|
|
b372e6886b | ||
|
|
1aedd6332f | ||
|
|
d61be19a18 | ||
|
|
87099a3a0a | ||
|
|
f3a5a99f23 | ||
|
|
724a6866c8 | ||
|
|
1a8660590f | ||
|
|
8b0978c7eb | ||
|
|
550b376a97 | ||
|
|
7d471409cb | ||
|
|
5a4d63dedd | ||
|
|
82bad1d3f2 | ||
|
|
e9978a2d93 | ||
|
|
ccf8b1a5cc | ||
|
|
350185b0d3 | ||
|
|
abf7595c03 | ||
|
|
3d4c476549 | ||
|
|
42384f0ed0 | ||
|
|
0219d0571b | ||
|
|
8043752146 | ||
|
|
29cd22f2d1 | ||
|
|
0a3a2dc2ec | ||
|
|
456560026c | ||
|
|
e3d9ef40cc | ||
|
|
5abdd9f98f | ||
|
|
327e49ec88 | ||
|
|
13857cd66e | ||
|
|
e17bfa9d77 | ||
|
|
d63c355601 | ||
|
|
190e7c7b60 | ||
|
|
f13a9a2036 | ||
|
|
a87969813f | ||
|
|
790c8bbc3f | ||
|
|
e934017a65 | ||
|
|
88dbedd932 | ||
|
|
8b1b3444fd | ||
|
|
d5f3d71a41 | ||
|
|
0641ab12c8 | ||
|
|
5790bec724 | ||
|
|
b4bed4e834 | ||
|
|
7b767001ad | ||
|
|
65c0f12c1c | ||
|
|
c10ae803d1 | ||
|
|
f4b6eb35e9 | ||
|
|
3e93ae7363 | ||
|
|
68303e1f09 | ||
|
|
6ca0b97637 | ||
|
|
cbcf9c9adb | ||
|
|
321e4f6f24 | ||
|
|
8280917312 | ||
|
|
8510f11d7b | ||
|
|
68aa377fe2 | ||
|
|
29f2c77ecc | ||
|
|
29bc00616e | ||
|
|
33397e90fe | ||
|
|
02920af4a4 | ||
|
|
bb94c71761 | ||
|
|
1f3d9ad5f0 | ||
|
|
22cd0af1bf | ||
|
|
3c079cd189 | ||
|
|
2796fd8ec9 | ||
|
|
02178d5a5e | ||
|
|
9a939e9ccd | ||
|
|
0c14b0f1a0 | ||
|
|
db0a239761 | ||
|
|
62a739048c | ||
|
|
2c6ac1abd6 | ||
|
|
377f55bbbe | ||
|
|
8d7a0e10c6 | ||
|
|
058de208db | ||
|
|
66b8720da0 | ||
|
|
072204b748 | ||
|
|
bba0964fae | ||
|
|
b0cd37732e | ||
|
|
6647750a6c | ||
|
|
c326929415 | ||
|
|
7e23941d0b | ||
|
|
c22957efe3 | ||
|
|
abdd62a4db | ||
|
|
a09be1d941 | ||
|
|
0d649a30cf | ||
|
|
84921ad5ce | ||
|
|
ccb1b56a0f | ||
|
|
4865f911d1 | ||
|
|
15ae5e0873 | ||
|
|
a246bdea84 | ||
|
|
987f9d45f5 | ||
|
|
8641bfc877 | ||
|
|
485430b7f2 | ||
|
|
5f34bc900c | ||
|
|
bc2b0ce136 | ||
|
|
dfc0a3aed9 | ||
|
|
2cd2513f64 | ||
|
|
9067d7d6cf | ||
|
|
f0c54777eb | ||
|
|
c8ceefda80 | ||
|
|
b6d83089d5 | ||
|
|
49ff960616 | ||
|
|
f7790426cd | ||
|
|
2822aac652 | ||
|
|
d34e66fbbc | ||
|
|
c6273a85d9 | ||
|
|
5558d29c2b | ||
|
|
69dfd1ae39 | ||
|
|
4638bb3684 | ||
|
|
6c687c6004 | ||
|
|
0bf1301733 | ||
|
|
827ba47892 | ||
|
|
2e8d717607 | ||
|
|
97f6c42407 | ||
|
|
732d60883e | ||
|
|
5330255b7e | ||
|
|
cc357f36b6 | ||
|
|
06e5226bbf | ||
|
|
28de70abd3 | ||
|
|
2b88518ca4 | ||
|
|
3dc115eb3a | ||
|
|
8b7428d5df | ||
|
|
92a21052f1 | ||
|
|
8013d73fe4 | ||
|
|
3f441505c6 | ||
|
|
965637cb9c | ||
|
|
f2ca308a29 | ||
|
|
b7cdb6a9ad | ||
|
|
681cef9260 | ||
|
|
cc22e01e62 | ||
|
|
1dbf4515fe | ||
|
|
3ce3c9ba16 | ||
|
|
24ea449dd4 | ||
|
|
5e06df2e3f | ||
|
|
5a0f274be6 | ||
|
|
755a3013a6 | ||
|
|
d3b620a745 | ||
|
|
821834cfa0 | ||
|
|
a99fc357fe | ||
|
|
ef47d1085a | ||
|
|
38bb0ed5da | ||
|
|
ea606b6313 | ||
|
|
c369c8520a | ||
|
|
e5511d0738 | ||
|
|
aa9991ad70 | ||
|
|
ec15ebe5c5 | ||
|
|
66075ef99b | ||
|
|
7a6333aa8f | ||
|
|
e242a21e99 | ||
|
|
c19fd4fae2 | ||
|
|
6fecd1e89d | ||
|
|
7aafb12f6f | ||
|
|
31cd3c6381 | ||
|
|
b3e107528b | ||
|
|
c6e1f96f5f | ||
|
|
f6a93e668b | ||
|
|
2f96bc8569 | ||
|
|
96e977b365 | ||
|
|
8d52051cc2 | ||
|
|
cd768a9dcd | ||
|
|
e4c065d505 | ||
|
|
9ce4026b1a | ||
|
|
e434b2d26e | ||
|
|
fe7f1a53ae | ||
|
|
96e5cd3f50 | ||
|
|
7c9e192923 | ||
|
|
907d61b5d2 | ||
|
|
8f844ecdeb | ||
|
|
c11b1da9a6 | ||
|
|
9a93ea78c3 | ||
|
|
25434d54e3 | ||
|
|
770945e0e9 | ||
|
|
c1d33303aa | ||
|
|
d2517ae114 | ||
|
|
1913e89366 | ||
|
|
8b8088545b | ||
|
|
195958a3b6 | ||
|
|
f7ffb8525a | ||
|
|
65d05bfe69 | ||
|
|
5fb9755841 | ||
|
|
e5dd02eeca | ||
|
|
9f9167c9c7 | ||
|
|
d30de896f0 | ||
|
|
e0ee3258e4 | ||
|
|
c09ecbb4b5 | ||
|
|
85b3fc4faa | ||
|
|
3713fa7006 | ||
|
|
a5fa2ccc2e | ||
|
|
7e0a044388 | ||
|
|
e5c9d06ef8 | ||
|
|
fa2b118545 | ||
|
|
99a231800c | ||
|
|
393c50a685 | ||
|
|
3fc0bb0a1f | ||
|
|
b98f856b89 | ||
|
|
e7b4a426a9 | ||
|
|
7dd74af305 | ||
|
|
4409101647 | ||
|
|
3a141e6cf4 | ||
|
|
545d62907e | ||
|
|
927dcb159b | ||
|
|
6f85885a88 | ||
|
|
5ea40b2ece | ||
|
|
8a20e3e873 | ||
|
|
e196303e64 | ||
|
|
70c1a3eaa3 | ||
|
|
6060113df5 | ||
|
|
9de064756a | ||
|
|
edc6e6fad5 | ||
|
|
9ab2510631 | ||
|
|
c570d39637 | ||
|
|
5815ad8ffd | ||
|
|
4ae968ff0f | ||
|
|
e18858fc58 | ||
|
|
3196cd986e | ||
|
|
3fb99ad896 | ||
|
|
100b921488 | ||
|
|
39d5becb56 | ||
|
|
1b677dd16d | ||
|
|
508f2c39a8 | ||
|
|
5456d4e7c0 | ||
|
|
f5e88569eb | ||
|
|
bcf212d777 | ||
|
|
67041aa39d | ||
|
|
18943612a8 | ||
|
|
d167947e04 | ||
|
|
e3658862ac | ||
|
|
948975f442 | ||
|
|
b74d56d7c0 | ||
|
|
2d30f0575d | ||
|
|
b4131471ea | ||
|
|
ed18c74f14 | ||
|
|
2a0dc812d8 | ||
|
|
87b59d84f1 | ||
|
|
c264c2ac36 | ||
|
|
d364df38de | ||
|
|
d45c4b7154 | ||
|
|
cdb8a6507d | ||
|
|
5bedb27cad | ||
|
|
9eab730414 | ||
|
|
8b3a8f929b | ||
|
|
e6f6412b5b | ||
|
|
83831deb68 | ||
|
|
311b62291d | ||
|
|
878568c6e6 | ||
|
|
8438fa09d3 | ||
|
|
db5645732c | ||
|
|
07b8d2aabf | ||
|
|
466836cfd0 | ||
|
|
dc79dc8feb | ||
|
|
91de58b5ae | ||
|
|
25a795bc91 | ||
|
|
3dc48aad7e | ||
|
|
8f5570e2e2 | ||
|
|
49b7c6d383 | ||
|
|
0d89b14932 | ||
|
|
62972f13bd | ||
|
|
3e036e1560 | ||
|
|
240052cba8 | ||
|
|
554cbfa110 | ||
|
|
25ff38ef24 | ||
|
|
3bf0939599 | ||
|
|
a187471f4b | ||
|
|
0c7b447b93 | ||
|
|
c9c8a64c0e | ||
|
|
90513868c5 | ||
|
|
24dbb42b34 | ||
|
|
2c32b58af3 | ||
|
|
5585fb9140 | ||
|
|
dbcdb9fc1f | ||
|
|
249e8e0905 | ||
|
|
b4aea2ac4b | ||
|
|
5f97843868 | ||
|
|
69e5aea08c | ||
|
|
fcf7caca50 | ||
|
|
61195370c7 | ||
|
|
edca51be10 | ||
|
|
8a9ab5c041 | ||
|
|
1796e88227 | ||
|
|
86709a3465 | ||
|
|
13b4d34341 | ||
|
|
ab45e35117 | ||
|
|
a0731bc26d | ||
|
|
5de523a4bf | ||
|
|
f97e199bb9 | ||
|
|
c598b12014 | ||
|
|
41bf86e64c | ||
|
|
e2c6c8bc94 | ||
|
|
98c73b5758 | ||
|
|
48dc47d70a | ||
|
|
53beede1dd | ||
|
|
4c1a374a9e | ||
|
|
abda5cf0ca | ||
|
|
9658f05d31 | ||
|
|
e92bf6f7c7 | ||
|
|
ca8c4d1c05 | ||
|
|
d7cc4301c0 | ||
|
|
02c483ba44 | ||
|
|
19ef656289 | ||
|
|
443cb748fb | ||
|
|
8f7201e2cf | ||
|
|
47361d412a | ||
|
|
faf0276810 | ||
|
|
5561b36a34 | ||
|
|
49b55db66f | ||
|
|
01f92baa98 | ||
|
|
18ad651286 | ||
|
|
ce5856cd86 | ||
|
|
a821bcae83 | ||
|
|
149f3ffff1 | ||
|
|
84acd7f3ab | ||
|
|
33057e1bd7 | ||
|
|
9ca7870183 | ||
|
|
87ee92b19b | ||
|
|
44e61bf336 | ||
|
|
fba63db137 | ||
|
|
9ee4c12fff | ||
|
|
8f62b0faa0 | ||
|
|
238ceaaaa9 | ||
|
|
52c2ee5d67 | ||
|
|
3baeff23ca | ||
|
|
77e49146c0 | ||
|
|
8a5251c2e6 | ||
|
|
bde71c7e3a | ||
|
|
c2848fc7a5 | ||
|
|
fec33715ad | ||
|
|
36bf17e323 | ||
|
|
b1c019bece | ||
|
|
9e0da3d65b | ||
|
|
7d271a7364 | ||
|
|
8a883cab86 | ||
|
|
29066210cd | ||
|
|
d7b68ae45c | ||
|
|
78e71910f4 | ||
|
|
67ab2616be | ||
|
|
e32da822e1 | ||
|
|
cc6e29619d | ||
|
|
963b0f897c | ||
|
|
6dcca89257 | ||
|
|
3a65d4ba2f | ||
|
|
88f579e09b | ||
|
|
be2bfb4017 | ||
|
|
bad15dc872 | ||
|
|
8b090af3ed | ||
|
|
747497699d | ||
|
|
80a102cb6a | ||
|
|
234cb57070 | ||
|
|
d4a8ef6a9c | ||
|
|
689dc99414 | ||
|
|
8bb09994de | ||
|
|
8d95db2e72 | ||
|
|
7b198f95ce | ||
|
|
9bcf30f336 | ||
|
|
74cd1a7ace | ||
|
|
19e556c76e | ||
|
|
d6a2f125f4 | ||
|
|
203a8127f5 | ||
|
|
23f4f2de2f | ||
|
|
27a48dd168 | ||
|
|
cc402a0690 | ||
|
|
7c9f2c52b7 | ||
|
|
4699d2d946 | ||
|
|
1eb0a50b03 | ||
|
|
4f47409b54 | ||
|
|
a255a50a19 | ||
|
|
28500f64be | ||
|
|
27d97c4c95 | ||
|
|
e71dace32f | ||
|
|
180c966891 | ||
|
|
65730d603a | ||
|
|
7fbe1620ee | ||
|
|
d781dd6de5 | ||
|
|
8f3478911f | ||
|
|
c34b736edd | ||
|
|
92c9604f8d | ||
|
|
067a2011c0 | ||
|
|
9d3dd97830 | ||
|
|
69b3395a1c | ||
|
|
312890f7d8 | ||
|
|
6b92007e3e | ||
|
|
3a5062d9a9 | ||
|
|
ded221c175 | ||
|
|
73e797e28a | ||
|
|
32190cb8d5 | ||
|
|
46cc4b87a0 | ||
|
|
355da9e8c4 | ||
|
|
fee004c79f | ||
|
|
2398acfe37 | ||
|
|
cccfb975ff | ||
|
|
24f28346bf | ||
|
|
698fd6fa8f | ||
|
|
32eb493f13 | ||
|
|
86f3f8dfae | ||
|
|
34fe32b404 | ||
|
|
f95fd09112 | ||
|
|
f262a6b8fa | ||
|
|
7cc2e45b21 | ||
|
|
8290973014 | ||
|
|
1958f7f0b4 | ||
|
|
3220739ae4 | ||
|
|
6f3b122231 | ||
|
|
6a1499725c | ||
|
|
37e25800dc | ||
|
|
b8cefa4254 | ||
|
|
ddbe00d2a5 | ||
|
|
8e7992046c | ||
|
|
911492d064 | ||
|
|
03c317430a | ||
|
|
e1d4b2bc9d | ||
|
|
e5659c1aa6 | ||
|
|
d50addf563 | ||
|
|
fd0bab6130 | ||
|
|
c3a9606f9d | ||
|
|
dd56d97945 | ||
|
|
43851d2d35 | ||
|
|
78e9e8250c | ||
|
|
b6272e9229 | ||
|
|
13dae1fb06 | ||
|
|
c18e3c15f1 | ||
|
|
54d44f1acb | ||
|
|
47b686dfd0 | ||
|
|
89eb10451c | ||
|
|
969badfb29 | ||
|
|
967f946527 | ||
|
|
38a5bfed52 | ||
|
|
5d50abd411 | ||
|
|
6e434145ba | ||
|
|
53e80476c8 | ||
|
|
23cbc53fef | ||
|
|
843e59811a | ||
|
|
67b31182e4 | ||
|
|
a478715d80 | ||
|
|
af904a7a05 | ||
|
|
0f21da4a92 | ||
|
|
039905742f | ||
|
|
9c90dadbef | ||
|
|
198372288f | ||
|
|
a9c0fddb23 | ||
|
|
ef7724759d | ||
|
|
4ea066af1d | ||
|
|
92f3520f7b | ||
|
|
8ece33b6e6 | ||
|
|
337ed38d9c | ||
|
|
c1aa5b4661 | ||
|
|
ceab7cc7ef | ||
|
|
6fb58f3790 | ||
|
|
45755000f3 | ||
|
|
38f5445634 | ||
|
|
5de9bf3794 | ||
|
|
02593a013c | ||
|
|
472038ec62 | ||
|
|
3a84d12f26 | ||
|
|
b621a12689 | ||
|
|
dbc0586fc2 | ||
|
|
b965f7cd6e | ||
|
|
c4a403e807 | ||
|
|
6ffa4efbaf | ||
|
|
e41169a9c7 | ||
|
|
46194b177b | ||
|
|
ff1f554e0b | ||
|
|
9c424b0f96 | ||
|
|
55b5248660 | ||
|
|
961103c4e8 | ||
|
|
03510d6af8 | ||
|
|
ff68fac5ed | ||
|
|
60cabb6406 | ||
|
|
b2b0f5fca1 | ||
|
|
f90e93c1f4 | ||
|
|
4d4f7bf7ac | ||
|
|
e70d5dccab | ||
|
|
771c417db8 | ||
|
|
f847a2aa0c | ||
|
|
a5b8d459d9 | ||
|
|
6d0a1f98ee | ||
|
|
f470cc061f | ||
|
|
d05fd8a2a5 | ||
|
|
b2053c116e | ||
|
|
d2cb99f70f | ||
|
|
1e6e951dea | ||
|
|
2485b68b4a | ||
|
|
1a4ec52712 | ||
|
|
b995bb5c14 | ||
|
|
3c91c1558e | ||
|
|
7bb2e21df5 | ||
|
|
7ad0a843e0 | ||
|
|
3641ec4d00 | ||
|
|
65a7233905 | ||
|
|
bafcabf7cb | ||
|
|
1252c612f0 | ||
|
|
3d1985368d | ||
|
|
c30e83086a | ||
|
|
15a61f6932 | ||
|
|
c29420805e | ||
|
|
27a8bccf5a | ||
|
|
5f5d66e23a | ||
|
|
ce58450c54 | ||
|
|
c69c5ece6f | ||
|
|
4b5ce9cca5 | ||
|
|
cd646a2795 | ||
|
|
f07eaaa7c3 | ||
|
|
7d7919551b | ||
|
|
78b64bae08 | ||
|
|
7754617c39 | ||
|
|
2ec80fbb2f | ||
|
|
cbee9b888c | ||
|
|
048a067ab7 | ||
|
|
b0180d5cdd | ||
|
|
9e7f467070 | ||
|
|
fa3db85d6a | ||
|
|
dae1909d63 | ||
|
|
5659295b88 | ||
|
|
9945333379 | ||
|
|
025ab59a05 | ||
|
|
626d87639f | ||
|
|
13b4d3d498 | ||
|
|
3fda81d279 | ||
|
|
e8863db4a2 | ||
|
|
59af9607b6 | ||
|
|
22b1b86b40 | ||
|
|
39a1f9ae8f | ||
|
|
fc6d73514f | ||
|
|
ac0166020e | ||
|
|
14b6420c33 | ||
|
|
76ebbfab53 | ||
|
|
f2e40638c2 | ||
|
|
728fdc8d9f | ||
|
|
ab30d89d3b | ||
|
|
d5f33d45e2 | ||
|
|
305c158a76 | ||
|
|
0ac9a82a9e | ||
|
|
4a8569fbee | ||
|
|
5fc36ad28c | ||
|
|
0986b42897 | ||
|
|
ea5cc912f0 | ||
|
|
579544a2b0 | ||
|
|
d60625c461 | ||
|
|
57f3ad1fe2 | ||
|
|
527a6f9364 | ||
|
|
8642155097 | ||
|
|
4343b0ffc7 | ||
|
|
60f7e4cae2 | ||
|
|
d9c4ce48dc | ||
|
|
9a2eaa4f3d | ||
|
|
1b5fdd15e1 | ||
|
|
ec8c891a7a | ||
|
|
0c8aa7257a | ||
|
|
aadd424400 | ||
|
|
ec6296a606 | ||
|
|
00f4659895 | ||
|
|
04cd5ff69f | ||
|
|
1e3e7dfac8 | ||
|
|
70b54164cd | ||
|
|
cf81c1e520 | ||
|
|
73e6f2413b | ||
|
|
e3ea846470 | ||
|
|
3f10129356 | ||
|
|
68c5fcacbb | ||
|
|
56d43bb59a | ||
|
|
2ad314eda6 | ||
|
|
f2a86fb6bd | ||
|
|
198f48add4 | ||
|
|
5e29203e3d | ||
|
|
ca72c20bd0 | ||
|
|
da0507ee34 | ||
|
|
1a73208c6f | ||
|
|
1d6a2b7841 | ||
|
|
e3d3d022c7 | ||
|
|
bff6079f60 | ||
|
|
1c826a41e0 | ||
|
|
c0058f9c29 | ||
|
|
44c82ade69 | ||
|
|
7dfbb9a650 | ||
|
|
bac09ffebc | ||
|
|
2c43fc09b5 | ||
|
|
b7d092bf94 | ||
|
|
0f056cb650 | ||
|
|
d8cdce680d | ||
|
|
1c5a931e09 | ||
|
|
e8da621558 | ||
|
|
6f12fbda94 | ||
|
|
cf83692e71 | ||
|
|
6822e92749 | ||
|
|
3ed681d444 | ||
|
|
e1313b55ff | ||
|
|
27417e80e1 | ||
|
|
235693a9e2 | ||
|
|
fb9791767d | ||
|
|
5b5080dcc7 | ||
|
|
3a86af72e2 | ||
|
|
cf71e50368 | ||
|
|
98a1baf7a7 | ||
|
|
4292e2d1e5 | ||
|
|
de05b52f24 | ||
|
|
3ba2b0bf3c | ||
|
|
766205049b | ||
|
|
1ae3beb347 | ||
|
|
7ef29ef56d | ||
|
|
f8f94dc026 | ||
|
|
370658fa67 | ||
|
|
f63be608b8 | ||
|
|
116ddebfb8 | ||
|
|
e1039aa226 | ||
|
|
bab675b806 | ||
|
|
2bdf0e00eb | ||
|
|
c70151e566 | ||
|
|
7f924dc810 | ||
|
|
88f87a2ce1 | ||
|
|
38c026fd7d | ||
|
|
b9a95313cd | ||
|
|
371dbc2890 | ||
|
|
478f49a874 | ||
|
|
58989b44b2 | ||
|
|
6baad0ae31 | ||
|
|
1692051255 | ||
|
|
da2d7f6f91 | ||
|
|
9d682125db | ||
|
|
6e00fc1eed | ||
|
|
01aa39b8ff | ||
|
|
6628bdfd20 | ||
|
|
ad99e45ee3 | ||
|
|
d86236e944 | ||
|
|
87801ee921 | ||
|
|
d3790adbd8 | ||
|
|
f417525195 | ||
|
|
cbc5a57cae | ||
|
|
e7fb36c190 | ||
|
|
075c4e7205 | ||
|
|
9e28ddb313 | ||
|
|
e431098395 | ||
|
|
c1ad32a527 | ||
|
|
d8aa023b28 | ||
|
|
4217e237fb | ||
|
|
c7e2584472 | ||
|
|
e30e04384f | ||
|
|
8c0613b3da | ||
|
|
d7ef81f045 | ||
|
|
19a403c14d | ||
|
|
271da70483 | ||
|
|
011c191538 | ||
|
|
c0f37ccd69 | ||
|
|
748cea493c | ||
|
|
e60d2b6bb5 | ||
|
|
a0c3a12799 | ||
|
|
34d3d43ff5 | ||
|
|
77bed076bb | ||
|
|
6fb9ccb821 | ||
|
|
9fb0a7c885 | ||
|
|
b5e0b76c24 | ||
|
|
9bd2ba3767 | ||
|
|
5cacfadef6 | ||
|
|
d652085b09 | ||
|
|
d7b6ecb734 | ||
|
|
58960a29ea | ||
|
|
c3bc227a3c | ||
|
|
5855accc16 | ||
|
|
75ca8c8a73 | ||
|
|
3e697b17b4 | ||
|
|
9850cf77c2 | ||
|
|
b6f92a7449 | ||
|
|
2558163ad6 | ||
|
|
8c3c2810e5 | ||
|
|
017fc67765 | ||
|
|
7caaa18b7e | ||
|
|
ffe05e4548 | ||
|
|
c819d15386 | ||
|
|
63266f588f | ||
|
|
4334cad68c | ||
|
|
86b9bff09a | ||
|
|
246dddd5a5 | ||
|
|
83a2c85e05 | ||
|
|
a503811c1c | ||
|
|
2c70896c1c | ||
|
|
132ca7755e | ||
|
|
a2f44762f9 | ||
|
|
d46abbe29b | ||
|
|
161da630ea | ||
|
|
301f872c06 | ||
|
|
b1cee16bde | ||
|
|
7f8b158eae | ||
|
|
4986042428 | ||
|
|
89232d9de8 | ||
|
|
de3cbdb60a | ||
|
|
7512135393 | ||
|
|
3242411768 | ||
|
|
bc4a85f542 | ||
|
|
1f839b46ea | ||
|
|
f0303d27b6 | ||
|
|
b8e3322d7f | ||
|
|
37e5f6c490 | ||
|
|
641b80964e | ||
|
|
67b6d50459 | ||
|
|
cbe465efd5 | ||
|
|
e34ac4308e | ||
|
|
ab81aab046 | ||
|
|
61d2285a1f | ||
|
|
081e6008cd | ||
|
|
e4f6e7ca98 | ||
|
|
497db2cd07 | ||
|
|
9e8dc186f3 | ||
|
|
feb0c3ba01 | ||
|
|
fa66a3abc1 | ||
|
|
e4b97151ae | ||
|
|
1b5dbdb8bc | ||
|
|
385617fe39 | ||
|
|
9cf6fde050 | ||
|
|
a3b16b8a37 | ||
|
|
eed01d6d3d | ||
|
|
623ed613a9 | ||
|
|
f09d00dd7d | ||
|
|
92bfe50e1c | ||
|
|
277118b6e8 | ||
|
|
fd994e2c08 | ||
|
|
8dc40dbb00 | ||
|
|
406f400555 | ||
|
|
c4e30c5fdd | ||
|
|
81887315f8 | ||
|
|
a7ac4fe23d | ||
|
|
bd41c3a707 | ||
|
|
944f4e252d | ||
|
|
1022150ca3 | ||
|
|
55687daca9 | ||
|
|
2bf65a9086 | ||
|
|
d9347ece05 | ||
|
|
acdca2f554 | ||
|
|
67868e9eb8 | ||
|
|
bc00f62117 | ||
|
|
75e833d841 | ||
|
|
a97805172c | ||
|
|
c8bda2eae7 | ||
|
|
1e9f36c4be | ||
|
|
6da9d73477 | ||
|
|
1090d9361b | ||
|
|
bbe4fcac42 | ||
|
|
e3bf266d60 | ||
|
|
c25b449c82 | ||
|
|
a2cf41e977 | ||
|
|
bf26effe68 | ||
|
|
5d1e79d487 | ||
|
|
7532a9bb62 | ||
|
|
af49f4a429 | ||
|
|
e65a18964a | ||
|
|
5577ffee7d | ||
|
|
04eb1f1f36 | ||
|
|
06ff995d9a | ||
|
|
95f7521dbd | ||
|
|
9847fc809c | ||
|
|
638fb7571a | ||
|
|
940e0136a1 | ||
|
|
17ae4cd0b2 | ||
|
|
5bdfb69072 | ||
|
|
8c2e1ad9e1 | ||
|
|
184f6dee77 | ||
|
|
923a26ef05 | ||
|
|
7f8c9eda2f | ||
|
|
fba64a4ef2 | ||
|
|
e98c938ba8 | ||
|
|
782fdbebba | ||
|
|
f3d27a8c6e | ||
|
|
2692263533 | ||
|
|
58802562f3 | ||
|
|
62e36ba5a3 | ||
|
|
a4db76ec36 | ||
|
|
2ff10692d5 | ||
|
|
d12c2e7308 | ||
|
|
7c7f2726aa | ||
|
|
c609078e47 | ||
|
|
0679690a18 | ||
|
|
186ce89b91 | ||
|
|
123c9d26df | ||
|
|
818cad1c14 | ||
|
|
4f5b913539 | ||
|
|
0d1d26cd5d | ||
|
|
5a74d7e85f | ||
|
|
11be564c8a | ||
|
|
62975b9ded | ||
|
|
90e3d22399 | ||
|
|
7ebe58781b | ||
|
|
797e5ca9de | ||
|
|
04fabac8ea | ||
|
|
36265c19e7 | ||
|
|
96021991fb | ||
|
|
3e5fa7fc2f | ||
|
|
15e9432ae0 | ||
|
|
89fcf5b642 | ||
|
|
d3ce936626 | ||
|
|
4073642ec4 | ||
|
|
6c6fc0d559 | ||
|
|
3f4f47715f | ||
|
|
662f534550 | ||
|
|
c3dde94530 | ||
|
|
0de6ce30c1 | ||
|
|
7a773b6d79 | ||
|
|
e02939c470 | ||
|
|
5c6bdb98ad | ||
|
|
dfb9d533f1 | ||
|
|
a64e975df1 | ||
|
|
131bd7030c | ||
|
|
a74ad2f6d3 | ||
|
|
2464772b4c | ||
|
|
a5e38bac45 | ||
|
|
4ef2cfb738 | ||
|
|
7c9b56f678 | ||
|
|
58bb6f805b | ||
|
|
562ee5707b | ||
|
|
3759dd59c7 | ||
|
|
86d9696f58 | ||
|
|
94f528bb92 | ||
|
|
9a49442902 | ||
|
|
1dcf0bca7c | ||
|
|
21a5986e3f | ||
|
|
1dbb59b9d7 | ||
|
|
d2eeaeffd8 | ||
|
|
7ffc613bd7 | ||
|
|
47e9d0f570 | ||
|
|
1a76c98300 | ||
|
|
c74b7c639b | ||
|
|
1fe63c133d | ||
|
|
ac08d226e9 | ||
|
|
c7462237eb | ||
|
|
b5bd09e40b | ||
|
|
8f66abbb73 | ||
|
|
224c3466fb | ||
|
|
a0ab72e597 | ||
|
|
33dae87a49 | ||
|
|
9ade1da6db | ||
|
|
8fd916c857 | ||
|
|
dd6a09a4c4 | ||
|
|
b4229aac35 | ||
|
|
824e841dad | ||
|
|
bc3a0f6d11 | ||
|
|
a09aae5d5d | ||
|
|
c5c59412f4 | ||
|
|
2b54af6c7e | ||
|
|
85b62544bf | ||
|
|
b219fb2c0f | ||
|
|
e2ff4f4ec6 | ||
|
|
ad89bbbdcd | ||
|
|
777864964e | ||
|
|
638b79d7f9 | ||
|
|
f9c357fccf | ||
|
|
6618f91ab6 | ||
|
|
c7ab47397e | ||
|
|
d3f1e0ff99 | ||
|
|
5eb614789a | ||
|
|
ce8873544d | ||
|
|
5bf06ea75d | ||
|
|
267fde4024 | ||
|
|
418b605e0c | ||
|
|
584878d950 | ||
|
|
a0c798f765 | ||
|
|
9c8ce486ce | ||
|
|
cb70ac5354 | ||
|
|
a12bcb3dbf | ||
|
|
8ec4401d21 | ||
|
|
207ed23478 | ||
|
|
15ae7e5bd8 | ||
|
|
11fa530d7f | ||
|
|
99f3236c12 | ||
|
|
bceb402b5f | ||
|
|
80b420e7f5 | ||
|
|
e0169daa00 | ||
|
|
01a1d40f11 | ||
|
|
4984f78d95 | ||
|
|
bf7ff5abd5 | ||
|
|
1c744328eb | ||
|
|
06f8e1f436 | ||
|
|
16deed5e54 | ||
|
|
a3f9fcbfb0 | ||
|
|
558a04cfd8 | ||
|
|
221b54fb09 | ||
|
|
8b0799eb9d | ||
|
|
9b68b492ad | ||
|
|
cb7268802a | ||
|
|
cd48929ca1 | ||
|
|
201ec093b7 | ||
|
|
b15ef713a3 | ||
|
|
774b76b170 | ||
|
|
e7be1697ec | ||
|
|
dc4a119172 | ||
|
|
80fd3aa42e | ||
|
|
e4cf8dac78 | ||
|
|
203700a16d | ||
|
|
9d5e2727f8 | ||
|
|
2dc6e808a9 | ||
|
|
5f12c8e70a | ||
|
|
62ae50d4cb | ||
|
|
fa6f3271cb | ||
|
|
9f50c9c565 | ||
|
|
bd3d3820c6 | ||
|
|
38257c0d39 | ||
|
|
5238abee57 | ||
|
|
05d346b5c6 | ||
|
|
d5a0c6ba11 | ||
|
|
f78ed3b9eb | ||
|
|
5aaa679d30 | ||
|
|
85ee44626e | ||
|
|
7519ba2bfe | ||
|
|
f73d0779f1 | ||
|
|
6b1a4202f9 | ||
|
|
aa645a2cc4 | ||
|
|
f2fb634bf3 | ||
|
|
87f812c857 | ||
|
|
4327e74970 | ||
|
|
f04c9df48c | ||
|
|
9a7f4cac0b | ||
|
|
f769b012d1 | ||
|
|
1607666266 | ||
|
|
031bbfbedb | ||
|
|
321c79e59e | ||
|
|
47e977583b | ||
|
|
b094885b05 | ||
|
|
3bf69988f4 | ||
|
|
2adc0a0213 | ||
|
|
466cc2579c | ||
|
|
0f179f1200 | ||
|
|
2860a11b61 | ||
|
|
e559234cea | ||
|
|
721fa02d5b | ||
|
|
d75f9429ac | ||
|
|
ba2de4b48f | ||
|
|
1589845ccb | ||
|
|
da044bf470 | ||
|
|
91851d8ade | ||
|
|
713bda7e04 | ||
|
|
6fae6180c0 | ||
|
|
a309c4026f | ||
|
|
3fa84fe1b0 | ||
|
|
88331171f5 | ||
|
|
d3fb89c651 | ||
|
|
040c666e74 | ||
|
|
f1fe412734 | ||
|
|
42f9d22481 | ||
|
|
a68ba59697 | ||
|
|
3e494ce0dc | ||
|
|
16f67c71eb | ||
|
|
be71d66218 | ||
|
|
1854f38190 | ||
|
|
e37a23e8e0 | ||
|
|
557880d846 | ||
|
|
3d9afcabb6 | ||
|
|
fdd372f864 | ||
|
|
c46dc1828c | ||
|
|
db240aa4b1 | ||
|
|
120f697a9b | ||
|
|
ab263a0a9f | ||
|
|
deafd8ab64 | ||
|
|
3cf4e99fee | ||
|
|
fd3cc7e3f2 | ||
|
|
3301545d45 | ||
|
|
4f8af3b2c2 | ||
|
|
8f06fc3534 | ||
|
|
0e87e4f60d | ||
|
|
7ec00a415a | ||
|
|
d3a9f38539 | ||
|
|
5d105c4fa4 | ||
|
|
db607545bb | ||
|
|
515536f629 | ||
|
|
cac7dbfa7d | ||
|
|
df28f487e5 | ||
|
|
5e3518bd62 | ||
|
|
44713d3852 | ||
|
|
c9d9cebfce | ||
|
|
f2933ef9e2 | ||
|
|
9c3cd369b0 | ||
|
|
15e20ab73c | ||
|
|
a22ace9c18 | ||
|
|
a95ec14be8 | ||
|
|
e902d705bf | ||
|
|
98d58fa472 | ||
|
|
48c34d9e1f | ||
|
|
6d5a47292c | ||
|
|
f9a73e2b9c | ||
|
|
41a349ead5 | ||
|
|
3a37e607ae | ||
|
|
ab19086400 | ||
|
|
f26153d970 | ||
|
|
42713f061a | ||
|
|
7590497b8c | ||
|
|
27b18bec89 | ||
|
|
ad2e83379a | ||
|
|
faca4e1300 | ||
|
|
7438465149 | ||
|
|
b9bd9ace50 | ||
|
|
73484ac686 | ||
|
|
5194c0fb11 | ||
|
|
0cdc5b97bf | ||
|
|
9852f67838 | ||
|
|
b3ca8a2744 | ||
|
|
d5fa2fd9a5 | ||
|
|
b248d1b5e0 | ||
|
|
8c76221aad | ||
|
|
3d82c94577 | ||
|
|
d9f5532350 | ||
|
|
d3d08e7735 | ||
|
|
e0e0a09c7c | ||
|
|
a4f3fab033 | ||
|
|
13a49650c4 | ||
|
|
cd5ac500a0 | ||
|
|
e58d92e781 | ||
|
|
a989f6f431 | ||
|
|
e17ba3ea35 | ||
|
|
93736043cc | ||
|
|
3a15b6cf5b | ||
|
|
7f248eea13 | ||
|
|
75ceeb4500 | ||
|
|
6d11c9b915 | ||
|
|
2cfd08e911 | ||
|
|
a2ab90656f | ||
|
|
a2bd0d113b | ||
|
|
0876e0cdf8 | ||
|
|
cc1074b817 | ||
|
|
e82f235616 | ||
|
|
e7a36635ff | ||
|
|
6adf5990ce | ||
|
|
961c70b5b0 | ||
|
|
2a7669de4a | ||
|
|
577168d62e | ||
|
|
085727e4a2 | ||
|
|
2044621fb3 | ||
|
|
ac8f2e10f9 | ||
|
|
5452fc86b3 | ||
|
|
4e5c3b127d | ||
|
|
4f1ab517c6 | ||
|
|
20cd3677ee | ||
|
|
62a507163a | ||
|
|
c1e8cadf24 | ||
|
|
0a1a81cfc0 | ||
|
|
f65b9aaf7f | ||
|
|
130b39e3a2 | ||
|
|
f4bee971f5 | ||
|
|
5f36b5372f | ||
|
|
ea2880e5f6 | ||
|
|
2f43948307 | ||
|
|
f9056eeb33 | ||
|
|
7b7299d9c4 | ||
|
|
308235c6b4 | ||
|
|
c84ecf146e | ||
|
|
b3dcc2853b | ||
|
|
623e0da721 | ||
|
|
611882f752 | ||
|
|
6502bcf2b5 | ||
|
|
b623f1cb3b | ||
|
|
ff3d73cb5e | ||
|
|
1950032519 | ||
|
|
1aa9e2e316 | ||
|
|
ec98d20b4a | ||
|
|
40a21110db | ||
|
|
e4cdba3c03 | ||
|
|
d747477428 | ||
|
|
1ac90ef633 | ||
|
|
0c368eeba6 | ||
|
|
0c07fc801e | ||
|
|
04b6154f9a | ||
|
|
d5e4259e58 | ||
|
|
641eff15b8 | ||
|
|
1fb550f25a | ||
|
|
8978bd4a14 | ||
|
|
c15a98af36 | ||
|
|
67a692c08a | ||
|
|
1a07df2d67 | ||
|
|
0bec18bdf7 | ||
|
|
6a90b0791d | ||
|
|
47e9576624 | ||
|
|
6a05909ab7 | ||
|
|
7cb64d7f86 | ||
|
|
62ca2c33ea | ||
|
|
643cc6f159 | ||
|
|
8b23159e67 | ||
|
|
b4268b236f | ||
|
|
5f6be5fce1 | ||
|
|
c382ecc4ee | ||
|
|
e134778aa2 | ||
|
|
4b23f8cd7e | ||
|
|
f81be04e22 | ||
|
|
b277d9fd39 | ||
|
|
7981463255 | ||
|
|
c3182caba5 | ||
|
|
4e1441564b | ||
|
|
b64e9063a3 | ||
|
|
eb7c334bb8 | ||
|
|
8541b00dbb | ||
|
|
d7f33f733a | ||
|
|
411773d1f6 | ||
|
|
b1c27c064a | ||
|
|
941570a140 | ||
|
|
48fbd6ee38 | ||
|
|
611dea4210 | ||
|
|
a5c39aa4f3 | ||
|
|
d06c56aec4 | ||
|
|
bb0f1637c7 | ||
|
|
1a72f20c10 | ||
|
|
adfc5aa5dc | ||
|
|
594842c7b8 | ||
|
|
96651b1c12 | ||
|
|
a3f858942b | ||
|
|
d5e58586a6 | ||
|
|
f53e2aa3b8 | ||
|
|
ffe2bda937 | ||
|
|
827d87ba03 | ||
|
|
0017c0f3ce | ||
|
|
dae09c5c59 | ||
|
|
98aa5a5f70 | ||
|
|
47f0a4bd3d | ||
|
|
a8307bf975 | ||
|
|
d09744c5ff | ||
|
|
3adad8d95b | ||
|
|
d332f6e6b5 | ||
|
|
5ff7111a16 | ||
|
|
071f39fdd8 | ||
|
|
aa2cffa95e | ||
|
|
94538ad5ac | ||
|
|
0757b7b3bd | ||
|
|
67cf59c50d | ||
|
|
cb8bb21d0d | ||
|
|
756eca860a | ||
|
|
e3404793db | ||
|
|
84beb5065e | ||
|
|
3d8b03d241 | ||
|
|
2d4a76a555 | ||
|
|
85c8fc49c1 | ||
|
|
06bbbd4891 | ||
|
|
50b5cf04f1 | ||
|
|
37a424c311 | ||
|
|
767df6ba32 | ||
|
|
f228af24f9 | ||
|
|
7cc274c3d5 | ||
|
|
6dcf959355 | ||
|
|
d28d19bfc7 | ||
|
|
fc3f54d3cf | ||
|
|
90d496f7b9 | ||
|
|
ecbc768b32 | ||
|
|
e2b9e1a07e | ||
|
|
07b1c76a57 | ||
|
|
20e73a0f26 | ||
|
|
ae6968afa4 | ||
|
|
ad5b0b9fe5 | ||
|
|
c163285d05 | ||
|
|
b828bd89ee | ||
|
|
f8f099bb93 | ||
|
|
5e358bcacd | ||
|
|
100d1781ba | ||
|
|
b59dde2a48 | ||
|
|
4839f941c6 | ||
|
|
067f583de0 | ||
|
|
67bb33b2f5 | ||
|
|
a5767063e6 | ||
|
|
8c30b2a5c6 | ||
|
|
2d770dde44 | ||
|
|
0ca6af8226 | ||
|
|
67bfc53af2 | ||
|
|
547e28fc57 | ||
|
|
0ff24e2ca8 | ||
|
|
d8a5ea03ab | ||
|
|
b55799b851 | ||
|
|
a706928f51 | ||
|
|
8ae1a51669 | ||
|
|
82cb6970bf | ||
|
|
883ab9bfa5 | ||
|
|
85228cef80 | ||
|
|
19fd0f6e4c | ||
|
|
40beb93a17 | ||
|
|
6266eef401 | ||
|
|
9b8c960144 | ||
|
|
fd9fd8dbd9 | ||
|
|
8a823f0e3c | ||
|
|
54d212963c | ||
|
|
6bc370c577 | ||
|
|
cdbbb0ae1f | ||
|
|
eff8216aff | ||
|
|
77c5be6747 | ||
|
|
ac589f0173 | ||
|
|
35fc915696 | ||
|
|
9cde9aa95a | ||
|
|
ebae32b88f | ||
|
|
7aeef17f20 | ||
|
|
ae868a890f | ||
|
|
2e0bbb87df | ||
|
|
911d71cf3b | ||
|
|
ac8119e82c | ||
|
|
d11c8270d0 | ||
|
|
a529126f61 | ||
|
|
71a8729d4d | ||
|
|
ccc5ba5313 | ||
|
|
e2bb08d1e8 |
5
.c8rc.json
Normal file
5
.c8rc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"all": true,
|
||||
"src": "./src",
|
||||
"reporter": ["text", "text-summary", "cobertura"]
|
||||
}
|
||||
8
.changeset/README.md
Normal file
8
.changeset/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Changesets
|
||||
|
||||
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
||||
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
||||
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
||||
|
||||
We have a quick list of common questions to get you started engaging with this project in
|
||||
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
||||
11
.changeset/config.json
Normal file
11
.changeset/config.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
|
||||
"changelog": "@changesets/changelog-git",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [["@openstapps/*"]],
|
||||
"access": "restricted",
|
||||
"baseBranch": "master",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": []
|
||||
}
|
||||
8
.changeset/cool-jars-kiss.md
Normal file
8
.changeset/cool-jars-kiss.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@openstapps/core-tools': major
|
||||
---
|
||||
|
||||
Removed pack tool
|
||||
|
||||
Use a bundler like `tsup` in conjunction with an
|
||||
`index.ts` that aggregates all exports instead.
|
||||
11
.changeset/cuddly-bobcats-roll.md
Normal file
11
.changeset/cuddly-bobcats-roll.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
'@openstapps/api-plugin': major
|
||||
'@openstapps/api-cli': major
|
||||
'@openstapps/api': major
|
||||
---
|
||||
|
||||
Split API into API, API-CLI and API-Plugin
|
||||
|
||||
Plugins are now required to use `api-plugin`.
|
||||
Consumers of `api` can benefit from a slimmer package with
|
||||
no NodeJS dependencies.
|
||||
31
.changeset/dull-news-appear.md
Normal file
31
.changeset/dull-news-appear.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
'@openstapps/backend': major
|
||||
---
|
||||
|
||||
Migrate config system to cosmiconfig
|
||||
|
||||
Configs are now written using type-checked JavaScript
|
||||
|
||||
```js
|
||||
// @ts-check
|
||||
|
||||
// This file is now type-safe just like TypeScript, but
|
||||
// without the compilation step
|
||||
|
||||
/** @type {import('@openstapps/package').Type} */
|
||||
const foo = {};
|
||||
```
|
||||
|
||||
You can write config files in JavaScript, JSON, or other
|
||||
cosmiconfig-supported formats.
|
||||
|
||||
The config files now are
|
||||
|
||||
- `backendrc.{js,json,...}`
|
||||
- `elasticsearchrc.{js,json,...}`
|
||||
- `prometheusrc.{js,json,...}`
|
||||
|
||||
You can also split them into multiple files,
|
||||
as well as using the `markdown.js` helper in
|
||||
`config/default/tools` to include markdown files
|
||||
as text (see `config/f-u/about-pages`)
|
||||
51
.changeset/five-ears-wash.md
Normal file
51
.changeset/five-ears-wash.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': major
|
||||
'@openstapps/prettier-config': major
|
||||
'@openstapps/es-mapping-generator': major
|
||||
'@openstapps/backend-config': major
|
||||
'@openstapps/eslint-config': major
|
||||
'@openstapps/minimal-connector': major
|
||||
'@openstapps/collection-utils': major
|
||||
'@openstapps/minimal-plugin': major
|
||||
'@openstapps/tsconfig': major
|
||||
'@openstapps/api-plugin': major
|
||||
'@openstapps/core-tools': major
|
||||
'@openstapps/gitlab-api': major
|
||||
'@openstapps/easy-ast': major
|
||||
'@openstapps/api-cli': major
|
||||
'@openstapps/backend': major
|
||||
'@openstapps/logger': major
|
||||
'@openstapps/proxy': major
|
||||
'@openstapps/core': major
|
||||
'@openstapps/app': major
|
||||
'@openstapps/api': major
|
||||
---
|
||||
|
||||
Move project to a turbo monorepo & pnpm
|
||||
|
||||
Internal dependencies are now defined using `"@openstapps/package": "workspace:*"`
|
||||
|
||||
- Removed extraneous files from packages
|
||||
- `.npmrc`
|
||||
- `.npmignore`
|
||||
- `.mailmap`
|
||||
- `.gitignore`
|
||||
- `CONTRIBUTING.md`
|
||||
- `LICENSE` (Project license file is added upon publishing, see [pnpm.io](https://pnpm.io/cli/publish))
|
||||
- `package-lock.json`
|
||||
- `.editorconfig`
|
||||
- `.eslintrc.json` (moved eslint config to `package.json`)
|
||||
- `.eslintignore`
|
||||
- `.gitlab-ci.yml` (Most workflows are workspace-level)
|
||||
- `.gitlab/**` (issue templates etc. are now workspace-level)
|
||||
- `.dockerignore` (Docker files are determined by which files are deployed with `pnpm deploy`, as per `package.json/files`)
|
||||
- TSConfig has been moved to its own package (You can now use `"extends": "@openstapps/tsconfig"`)
|
||||
- Removed ESLint and Prettier peer dependency hell by injecting them through the `.pnpmfile.cjs`
|
||||
- Added syncpack for keeping dependency versions in sync (and consistent key ordering in `package.json`)
|
||||
- Replaced conventional changelog with changesets
|
||||
- Apps with binaries now use a top level `app.js`
|
||||
|
||||
```js
|
||||
#!/usr/bin/env node
|
||||
import './lib/app.js';
|
||||
```
|
||||
13
.changeset/fuzzy-walls-greet.md
Normal file
13
.changeset/fuzzy-walls-greet.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
'@openstapps/core': major
|
||||
---
|
||||
|
||||
Migrate away from [ts-optchain](https://www.npmjs.com/package/ts-optchain)
|
||||
|
||||
The package has been deprecated with the last releast being 4 years ago.
|
||||
|
||||
TypeScript as well as ECMAScript have native support for optional
|
||||
chaining with the `?.` operator now.
|
||||
|
||||
You will need to update any packages that rely on the translator
|
||||
module.
|
||||
25
.changeset/giant-crabs-cheer.md
Normal file
25
.changeset/giant-crabs-cheer.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': patch
|
||||
'@openstapps/prettier-config': patch
|
||||
'@openstapps/es-mapping-generator': patch
|
||||
'@openstapps/eslint-config': patch
|
||||
'@openstapps/minimal-connector': patch
|
||||
'@openstapps/minimal-plugin': patch
|
||||
'@openstapps/core-tools': patch
|
||||
'@openstapps/gitlab-api': patch
|
||||
'@openstapps/backend': patch
|
||||
'@openstapps/logger': patch
|
||||
'@openstapps/proxy': patch
|
||||
'@openstapps/core': patch
|
||||
'@openstapps/api': patch
|
||||
---
|
||||
|
||||
Migrated changelogs to changeset format
|
||||
|
||||
```js
|
||||
import fs from 'fs';
|
||||
|
||||
const path = 'packages/logger/CHANGELOG.md';
|
||||
|
||||
fs.writeFileSync(path, fs.readFileSync(path, 'utf8').replace(/^#+\s+\[/gm, '## ['));
|
||||
```
|
||||
8
.changeset/gorgeous-flowers-reflect.md
Normal file
8
.changeset/gorgeous-flowers-reflect.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
'@openstapps/backend': minor
|
||||
'@openstapps/api-cli': major
|
||||
---
|
||||
|
||||
Migrate integration tests from docker-compose solution to a shell script
|
||||
|
||||
`api-cli` no longer builds as a Docker container as a result.
|
||||
34
.changeset/healthy-steaks-shop.md
Normal file
34
.changeset/healthy-steaks-shop.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': major
|
||||
'@openstapps/prettier-config': major
|
||||
'@openstapps/es-mapping-generator': major
|
||||
'@openstapps/backend-config': major
|
||||
'@openstapps/eslint-config': major
|
||||
'@openstapps/minimal-connector': major
|
||||
'@openstapps/collection-utils': major
|
||||
'@openstapps/minimal-plugin': major
|
||||
'@openstapps/tsconfig': major
|
||||
'@openstapps/api-plugin': major
|
||||
'@openstapps/core-tools': major
|
||||
'@openstapps/gitlab-api': major
|
||||
'@openstapps/easy-ast': major
|
||||
'@openstapps/api-cli': major
|
||||
'@openstapps/backend': major
|
||||
'@openstapps/logger': major
|
||||
'@openstapps/proxy': major
|
||||
'@openstapps/core': major
|
||||
'@openstapps/app': major
|
||||
'@openstapps/api': major
|
||||
---
|
||||
|
||||
Migrate to ESM
|
||||
|
||||
CommonJS is no longer supported in any capacity. To use the new
|
||||
version, you will need to migrate your package to ESM.
|
||||
We recommend using `tsup` and `Node 18`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
```
|
||||
30
.changeset/honest-sheep-train.md
Normal file
30
.changeset/honest-sheep-train.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': major
|
||||
'@openstapps/prettier-config': major
|
||||
'@openstapps/es-mapping-generator': major
|
||||
'@openstapps/backend-config': major
|
||||
'@openstapps/eslint-config': major
|
||||
'@openstapps/minimal-connector': major
|
||||
'@openstapps/collection-utils': major
|
||||
'@openstapps/minimal-plugin': major
|
||||
'@openstapps/tsconfig': major
|
||||
'@openstapps/api-plugin': major
|
||||
'@openstapps/core-tools': major
|
||||
'@openstapps/gitlab-api': major
|
||||
'@openstapps/easy-ast': major
|
||||
'@openstapps/api-cli': major
|
||||
'@openstapps/backend': major
|
||||
'@openstapps/logger': major
|
||||
'@openstapps/proxy': major
|
||||
'@openstapps/core': major
|
||||
'@openstapps/app': major
|
||||
'@openstapps/api': major
|
||||
---
|
||||
|
||||
Migrate package to Node 18
|
||||
|
||||
- Consumers of this package will need to migrate to Node 18 or
|
||||
higher.
|
||||
- Packages have been migrated from promisified `readFile` or
|
||||
`readFileSync` towards `fs/promises`
|
||||
- Packages use native `flatMap` now
|
||||
5
.changeset/late-zoos-breathe.md
Normal file
5
.changeset/late-zoos-breathe.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/gitlab-api': minor
|
||||
---
|
||||
|
||||
Migrate from request-promise-native to got
|
||||
5
.changeset/moody-parrots-develop.md
Normal file
5
.changeset/moody-parrots-develop.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': patch
|
||||
---
|
||||
|
||||
Moved project-docs to the [GitLab Wiki](https://gitlab.com/openstapps/openstapps/-/wikis/home) repo.
|
||||
31
.changeset/neat-hats-trade.md
Normal file
31
.changeset/neat-hats-trade.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': minor
|
||||
'@openstapps/prettier-config': minor
|
||||
'@openstapps/es-mapping-generator': minor
|
||||
'@openstapps/backend-config': minor
|
||||
'@openstapps/eslint-config': minor
|
||||
'@openstapps/minimal-connector': minor
|
||||
'@openstapps/collection-utils': minor
|
||||
'@openstapps/minimal-plugin': minor
|
||||
'@openstapps/tsconfig': minor
|
||||
'@openstapps/api-plugin': minor
|
||||
'@openstapps/core-tools': minor
|
||||
'@openstapps/gitlab-api': minor
|
||||
'@openstapps/easy-ast': minor
|
||||
'@openstapps/api-cli': minor
|
||||
'@openstapps/backend': minor
|
||||
'@openstapps/logger': minor
|
||||
'@openstapps/proxy': minor
|
||||
'@openstapps/core': minor
|
||||
'@openstapps/app': minor
|
||||
'@openstapps/api': minor
|
||||
---
|
||||
|
||||
Migrate tests to C8/Chai/Mocha
|
||||
|
||||
- `@testdeck` OOP testing has been removed.
|
||||
- Tests have been unified
|
||||
- CommonJS module mocking has been replaced through
|
||||
refactoring of tests, as ES Modules cannot be mocked
|
||||
(do yourself a favor and don't try to mock them)
|
||||
- C8 now replaces NYC as a native coverage tool
|
||||
5
.changeset/new-pianos-joke.md
Normal file
5
.changeset/new-pianos-joke.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/es-mapping-generator': patch
|
||||
---
|
||||
|
||||
Remove @openstapps/logger dependency
|
||||
59
.changeset/pre.json
Normal file
59
.changeset/pre.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"mode": "pre",
|
||||
"tag": "next",
|
||||
"initialVersions": {
|
||||
"@openstapps/backend": "2.0.0",
|
||||
"@openstapps/database": "2.0.0",
|
||||
"@openstapps/proxy": "2.0.0",
|
||||
"@openstapps/backend-config": "2.0.0",
|
||||
"@openstapps/eslint-config": "2.0.0",
|
||||
"@openstapps/prettier-config": "2.0.0",
|
||||
"@openstapps/projectmanagement": "2.0.0",
|
||||
"@openstapps/tsconfig": "2.0.0",
|
||||
"@openstapps/minimal-connector": "2.0.0",
|
||||
"@openstapps/minimal-deployment": "2.0.0",
|
||||
"@openstapps/minimal-plugin": "2.0.0",
|
||||
"@openstapps/app": "2.0.0",
|
||||
"@openstapps/app-release-template": "2.0.0",
|
||||
"@openstapps/api": "2.0.0",
|
||||
"@openstapps/api-cli": "2.0.0",
|
||||
"@openstapps/api-plugin": "2.0.0",
|
||||
"@openstapps/collection-utils": "2.0.0",
|
||||
"@openstapps/core": "2.0.0",
|
||||
"@openstapps/core-tools": "2.0.0",
|
||||
"@openstapps/easy-ast": "2.0.0",
|
||||
"@openstapps/es-mapping-generator": "2.0.0",
|
||||
"@openstapps/gitlab-api": "2.0.0",
|
||||
"@openstapps/logger": "2.0.0"
|
||||
},
|
||||
"changesets": [
|
||||
"cool-jars-kiss",
|
||||
"cuddly-bobcats-roll",
|
||||
"dull-news-appear",
|
||||
"five-ears-wash",
|
||||
"fuzzy-walls-greet",
|
||||
"giant-crabs-cheer",
|
||||
"gorgeous-flowers-reflect",
|
||||
"healthy-steaks-shop",
|
||||
"honest-sheep-train",
|
||||
"late-zoos-breathe",
|
||||
"moody-parrots-develop",
|
||||
"neat-hats-trade",
|
||||
"new-pianos-joke",
|
||||
"proud-wolves-end",
|
||||
"quick-houses-count",
|
||||
"rare-squids-bake",
|
||||
"soft-donuts-fail",
|
||||
"sour-coins-visit",
|
||||
"spicy-snails-sort",
|
||||
"stale-garlics-share",
|
||||
"strange-hounds-repair",
|
||||
"tall-ducks-dream",
|
||||
"tame-mayflies-hug",
|
||||
"tame-rings-dream",
|
||||
"thick-weeks-compete",
|
||||
"thin-camels-give",
|
||||
"tidy-buses-reflect",
|
||||
"tough-hairs-provide"
|
||||
]
|
||||
}
|
||||
9
.changeset/proud-wolves-end.md
Normal file
9
.changeset/proud-wolves-end.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@openstapps/eslint-config': minor
|
||||
---
|
||||
|
||||
Update rules
|
||||
|
||||
- `unicorn/no-array-reduce` is now off
|
||||
- `unicorn/no-non-null-assertion` is now off
|
||||
- Removed prettier rules (use prettier formatting instead)
|
||||
7
.changeset/quick-houses-count.md
Normal file
7
.changeset/quick-houses-count.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@openstapps/es-mapping-generator': major
|
||||
---
|
||||
|
||||
Remove put-es-templates
|
||||
|
||||
The `put-es-templates` functionality has been removed.
|
||||
24
.changeset/rare-squids-bake.md
Normal file
24
.changeset/rare-squids-bake.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': patch
|
||||
'@openstapps/prettier-config': patch
|
||||
'@openstapps/es-mapping-generator': patch
|
||||
'@openstapps/backend-config': patch
|
||||
'@openstapps/eslint-config': patch
|
||||
'@openstapps/minimal-connector': patch
|
||||
'@openstapps/collection-utils': patch
|
||||
'@openstapps/minimal-plugin': patch
|
||||
'@openstapps/tsconfig': patch
|
||||
'@openstapps/api-plugin': patch
|
||||
'@openstapps/core-tools': patch
|
||||
'@openstapps/gitlab-api': patch
|
||||
'@openstapps/easy-ast': patch
|
||||
'@openstapps/api-cli': patch
|
||||
'@openstapps/backend': patch
|
||||
'@openstapps/logger': patch
|
||||
'@openstapps/proxy': patch
|
||||
'@openstapps/core': patch
|
||||
'@openstapps/app': patch
|
||||
'@openstapps/api': patch
|
||||
---
|
||||
|
||||
Migrate away from @openstapps/configuration
|
||||
7
.changeset/soft-donuts-fail.md
Normal file
7
.changeset/soft-donuts-fail.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@openstapps/api': minor
|
||||
---
|
||||
|
||||
Migrate HttpClient to Node 18's native `fetch` API
|
||||
|
||||
HttpClient can now be used both in NodeJS and browsers.
|
||||
7
.changeset/sour-coins-visit.md
Normal file
7
.changeset/sour-coins-visit.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@openstapps/es-mapping-generator': major
|
||||
'@openstapps/backend': major
|
||||
'@openstapps/core': major
|
||||
---
|
||||
|
||||
Migrate es mapping types from es-mapping-generator to .d.ts next to generated mappings
|
||||
5
.changeset/spicy-snails-sort.md
Normal file
5
.changeset/spicy-snails-sort.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/eslint-config': patch
|
||||
---
|
||||
|
||||
Add license header enforcement rule (unfinished)
|
||||
5
.changeset/stale-garlics-share.md
Normal file
5
.changeset/stale-garlics-share.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/core': minor
|
||||
---
|
||||
|
||||
Include openapi.json in built package
|
||||
26
.changeset/strange-hounds-repair.md
Normal file
26
.changeset/strange-hounds-repair.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': minor
|
||||
'@openstapps/minimal-connector': minor
|
||||
'@openstapps/minimal-plugin': minor
|
||||
'@openstapps/collection-utils': minor
|
||||
'@openstapps/core-tools': minor
|
||||
'@openstapps/gitlab-api': minor
|
||||
'@openstapps/backend': minor
|
||||
'@openstapps/logger': minor
|
||||
'@openstapps/core': minor
|
||||
'@openstapps/api': minor
|
||||
---
|
||||
|
||||
Migrate away from `@krlwlfrt/async-pool`
|
||||
|
||||
```ts
|
||||
import {mapAsyncLimit} from '@openstapps/collection-utils';
|
||||
|
||||
await mapAsyncLimit(
|
||||
[1, 2, 3],
|
||||
async it => {
|
||||
await someNetworkRequest(it);
|
||||
},
|
||||
5,
|
||||
);
|
||||
```
|
||||
5
.changeset/tall-ducks-dream.md
Normal file
5
.changeset/tall-ducks-dream.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/app': minor
|
||||
---
|
||||
|
||||
Migrate away from JIT compilation
|
||||
5
.changeset/tame-mayflies-hug.md
Normal file
5
.changeset/tame-mayflies-hug.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/logger': patch
|
||||
---
|
||||
|
||||
Fix an issue with chalk terminal colors in tests
|
||||
9
.changeset/tame-rings-dream.md
Normal file
9
.changeset/tame-rings-dream.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@openstapps/core-tools': major
|
||||
---
|
||||
|
||||
Migrate openapi generation to output single file
|
||||
|
||||
The OpenAPI generator now outputs a single file instead
|
||||
of a directory with the `openapi.json` and copied schema
|
||||
files.
|
||||
5
.changeset/thick-weeks-compete.md
Normal file
5
.changeset/thick-weeks-compete.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': minor
|
||||
---
|
||||
|
||||
Migrate moment.js to date-fns
|
||||
23
.changeset/thin-camels-give.md
Normal file
23
.changeset/thin-camels-give.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
'@openstapps/projectmanagement': major
|
||||
'@openstapps/es-mapping-generator': major
|
||||
'@openstapps/minimal-connector': major
|
||||
'@openstapps/collection-utils': major
|
||||
'@openstapps/minimal-plugin': major
|
||||
'@openstapps/api-plugin': major
|
||||
'@openstapps/core-tools': major
|
||||
'@openstapps/gitlab-api': major
|
||||
'@openstapps/easy-ast': major
|
||||
'@openstapps/api-cli': major
|
||||
'@openstapps/backend': major
|
||||
'@openstapps/logger': major
|
||||
'@openstapps/proxy': major
|
||||
'@openstapps/core': major
|
||||
'@openstapps/api': major
|
||||
---
|
||||
|
||||
Migrate build system to `tsup`
|
||||
|
||||
All packages now use an `index.ts` file to expose contents.
|
||||
|
||||
You will need to migrate paths from `import foo from '@scope/package/lib/foo` to `import foo from '@scope/package'`
|
||||
9
.changeset/tidy-buses-reflect.md
Normal file
9
.changeset/tidy-buses-reflect.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@openstapps/core-tools': major
|
||||
'@openstapps/easy-ast': major
|
||||
---
|
||||
|
||||
Migrate easy-ast to separate package
|
||||
|
||||
The `easy-ast` part of `core-tools` has been moved to its own package.
|
||||
For migration, simply use the new package.
|
||||
5
.changeset/tough-hairs-provide.md
Normal file
5
.changeset/tough-hairs-provide.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@openstapps/core-tools': patch
|
||||
---
|
||||
|
||||
Migrate from away from lodash
|
||||
17
.gitattributes
vendored
Normal file
17
.gitattributes
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
28
.gitignore
vendored
28
.gitignore
vendored
@@ -10,9 +10,15 @@ pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
.DS_Store
|
||||
|
||||
# Schema generation data
|
||||
Diagram-*.svg
|
||||
.angular/
|
||||
www/
|
||||
|
||||
.docs.json
|
||||
coverage.xml
|
||||
report-junit.xml
|
||||
.deploy/
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
@@ -37,6 +43,7 @@ build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
.pnpm-store/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
@@ -58,7 +65,7 @@ typings/
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
@@ -87,11 +94,14 @@ typings/
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# ignore lib directory
|
||||
lib/
|
||||
# ignore lib
|
||||
lib
|
||||
|
||||
# ignore docs directory
|
||||
docs/
|
||||
# ignore docs
|
||||
docs
|
||||
|
||||
# ignore openapi resources
|
||||
openapi/
|
||||
# report directory
|
||||
report
|
||||
|
||||
# turbo cache
|
||||
.turbo/
|
||||
|
||||
165
.gitlab-ci.yml
165
.gitlab-ci.yml
@@ -1,71 +1,128 @@
|
||||
image: registry.gitlab.com/openstapps/projectmanagement/node
|
||||
# `rules: if $CI_PIPELINE_SOURCE == 'merge_request_event'` seems to convert the whole
|
||||
# workflow into a merge request pipeline, effectively removing all the jobs.
|
||||
# To work around that, add:
|
||||
# ```
|
||||
# rules:
|
||||
# when: on_success
|
||||
# ```
|
||||
# To your pipeline.
|
||||
# https://docs.gitlab.com/ee/ci/pipelines/merge_request_pipelines.html#use-rules-to-add-jobs
|
||||
include:
|
||||
- local: /backend/backend/.gitlab-ci.yml
|
||||
- local: /frontend/app/.gitlab-ci.yml
|
||||
- local: /.gitlab/publishing.gitlab-ci.yml
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
when: never
|
||||
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- node_modules
|
||||
variables:
|
||||
TURBO_CACHE_BYPASS:
|
||||
value: ''
|
||||
options:
|
||||
- '--force'
|
||||
- '--no-cache'
|
||||
- ''
|
||||
description: Bypass turbo cache
|
||||
|
||||
before_script:
|
||||
- npm install
|
||||
default:
|
||||
image: registry.gitlab.com/openstapps/projectmanagement/builder:v18
|
||||
tags:
|
||||
- performance
|
||||
interruptible: true
|
||||
before_script:
|
||||
- corepack enable
|
||||
- corepack prepare pnpm@latest-8 --activate
|
||||
- echo TURBO_API=$TURBO_API >> .env.local
|
||||
- echo TURBO_TOKEN=$TURBO_TOKEN >> .env.local
|
||||
- echo TURBO_TEAM=$TURBO_TEAM >> .env.local
|
||||
- pnpm config set store-dir .pnpm-store
|
||||
cache: &pnpm_cache
|
||||
key:
|
||||
files:
|
||||
- pnpm-lock.yaml
|
||||
paths:
|
||||
- .pnpm-store/
|
||||
policy: pull
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- audit
|
||||
- deploy
|
||||
- publish
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- npm run build
|
||||
artifacts:
|
||||
paths:
|
||||
- lib
|
||||
# - pnpm config set recursive-install false
|
||||
# - pnpm i --prefer-offline
|
||||
# - pnpm build:full:skip || pnpm i -r --prefer-offline
|
||||
- pnpm install
|
||||
# TODO: something doesn't work with git here...
|
||||
# "🦋 error Error: Failed to find where HEAD diverged from master. Does master exist?"
|
||||
# - pnpm changeset:status
|
||||
- pnpm build:full $TURBO_CACHE_BYPASS
|
||||
# pretty sure this is deprecated?
|
||||
# TODO: - .gitlab/ci/enableGitlabReviewToolbar.sh www/index.html "$CI_PROJECT_ID" "$CI_OPEN_MERGE_REQUESTS"
|
||||
- cp frontend/app/www/index.html frontend/app/www/200.html
|
||||
- pnpm dlx surge -p frontend/app/www -d https://$CI_PROJECT_NAME-$DEPLOY_ID.surge.sh/
|
||||
cache:
|
||||
<<: *pnpm_cache
|
||||
policy: pull-push
|
||||
environment:
|
||||
name: review/$DEPLOY_ID
|
||||
url: https://$CI_PROJECT_NAME-$DEPLOY_ID.surge.sh/
|
||||
on_stop: stop review
|
||||
rules: &deploy-rules
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
variables:
|
||||
DEPLOY_ID: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||
- if: $CI_COMMIT_BRANCH == 'main'
|
||||
variables:
|
||||
DEPLOY_ID: production
|
||||
- if: $CI_COMMIT_BRANCH == 'develop'
|
||||
variables:
|
||||
DEPLOY_ID: staging
|
||||
|
||||
test:
|
||||
tags:
|
||||
- docker
|
||||
stage: test
|
||||
stop review:
|
||||
stage: build
|
||||
needs: ['build']
|
||||
script:
|
||||
- npm test
|
||||
- pnpm dlx surge teardown $CI_PROJECT_NAME-$DEPLOY_ID.surge.sh
|
||||
environment:
|
||||
name: review/$DEPLOY_ID
|
||||
action: stop
|
||||
when: manual
|
||||
rules: *deploy-rules
|
||||
|
||||
unit:
|
||||
stage: test
|
||||
needs: ['build']
|
||||
script:
|
||||
# - pnpm config set recursive-install false
|
||||
# - pnpm i --prefer-offline
|
||||
# - pnpm test:skip || pnpm i -r --prefer-offline
|
||||
- pnpm install
|
||||
- pnpm test $TURBO_CACHE_BYPASS
|
||||
coverage: '/Statements[^:]*\:[^:]*\s+([\d\.]+)%/'
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- report-junit.xml
|
||||
- coverage.xml
|
||||
reports:
|
||||
junit:
|
||||
- report-junit.xml
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: coverage.xml
|
||||
rules:
|
||||
- when: on_success
|
||||
|
||||
audit:
|
||||
stage: audit
|
||||
needs: []
|
||||
script:
|
||||
- npm audit
|
||||
allow_failure: true
|
||||
except:
|
||||
- schedules
|
||||
|
||||
scheduled-audit:
|
||||
stage: audit
|
||||
script:
|
||||
- npm audit --audit-level=high
|
||||
only:
|
||||
- schedules
|
||||
|
||||
package:
|
||||
dependencies:
|
||||
- build
|
||||
tags:
|
||||
- secrecy
|
||||
stage: deploy
|
||||
script:
|
||||
- echo "//registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN" > ~/.npmrc
|
||||
- npm publish
|
||||
only:
|
||||
- /^v[0-9]+.[0-9]+.[0-9]+$/
|
||||
artifacts:
|
||||
paths:
|
||||
- lib
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
script:
|
||||
- npm run documentation
|
||||
- mv docs public
|
||||
only:
|
||||
- /^v[0-9]+\.[0-9]+\.[0-9]+$/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
- pnpm audit --prod
|
||||
rules:
|
||||
- when: on_success
|
||||
allow_failure: true
|
||||
|
||||
15
.gitlab/ci/enableGitlabReviewToolbar.sh
Normal file
15
.gitlab/ci/enableGitlabReviewToolbar.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Adds a preedefined script tag including the merge current request id to the angular web app index.html.
|
||||
# This enables the interactive gitlab review toolbar.
|
||||
|
||||
MERGE_REQUEST_ID=""
|
||||
if echo -n $3 | grep -Eq '[0-9]+$'; then
|
||||
MERGE_REQUEST_ID="$(echo -n "$3" | grep -Eo '[0-9]+$')"
|
||||
fi
|
||||
|
||||
INDEX_PATH=$(dirname $1)
|
||||
SCRIPT_TAG="<script defer data-project-id=\"$2\" data-project-path=\"openstapps/app\" data-merge-request-id=\"$MERGE_REQUEST_ID\" data-mr-url=\"https://gitlab.com\" id=\"review-app-toolbar-script\" src=\"visual_review_toolbar.js\"></script>"
|
||||
|
||||
curl https://gitlab.com/assets/webpack/visual_review_toolbar.js --output "$INDEX_PATH/visual_review_toolbar.js" --silent
|
||||
sed -i -e "\@</head>@i\\$SCRIPT_TAG" $1
|
||||
4
.gitlab/ci/getRegistryBranch.sh
Normal file
4
.gitlab/ci/getRegistryBranch.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# script returns string with everything after the last colon of $1 input
|
||||
echo -n $1 | grep -oE '[^:]+$'
|
||||
8
.gitlab/ci/getRegistryTag.sh
Normal file
8
.gitlab/ci/getRegistryTag.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# script returns semantical versioning string like 2.0.0 (if $1 is v2.0.0) or $1
|
||||
if echo -n $1 | grep -Eq 'v[0-9]+\.[0-9]+\.[0-9]+'; then
|
||||
echo $(echo -n "$1" | cut -c 2-);
|
||||
else
|
||||
echo $1;
|
||||
fi
|
||||
6
.gitlab/ci/install-for-turbo.sh
Normal file
6
.gitlab/ci/install-for-turbo.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
if pnpm dlx turbo-ignore "$@"
|
||||
then
|
||||
pnpm config --location=project set recursive-install false
|
||||
fi
|
||||
7
.gitlab/ci/pushAsLatestVersion.sh
Normal file
7
.gitlab/ci/pushAsLatestVersion.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# If this is a pipeline of a version tag, also push this version
|
||||
# as latest to the registry alias $2:latest
|
||||
if echo -n $1 | grep -Eq 'v[0-9]+\.[0-9]+\.[0-9]+'; then
|
||||
docker push $2:latest;
|
||||
fi
|
||||
5
.gitlab/ci/setup_turbo_env.sh
Normal file
5
.gitlab/ci/setup_turbo_env.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo TURBO_API=$TURBO_API >> .env.local
|
||||
echo TURBO_TOKEN=$TURBO_TOKEN >> .env.local
|
||||
echo TURBO_TEAM=$TURBO_TEAM >> .env.local
|
||||
29
.gitlab/ci/testCIScripts.sh
Normal file
29
.gitlab/ci/testCIScripts.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# test all CI scripts
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
|
||||
TAG_VERSION=$(sh $SCRIPT_DIR/getRegistryTag.sh "v1.0.0")
|
||||
TAG_TEST=$(sh $SCRIPT_DIR/getRegistryTag.sh "TEST")
|
||||
BRANCH_NAME=$(sh $SCRIPT_DIR/getRegistryBranch.sh "very:first:test")
|
||||
|
||||
# Leaving out pushAsLatestVersion.sh as its control flow
|
||||
# is based on the same condition as getRegistryTag.sh
|
||||
|
||||
if [ $TAG_VERSION != "1.0.0" ]; then
|
||||
echo "ERROR in CI SCRIPT: $SCRIPT_DIR/getRegistryTag.sh"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ $TAG_TEST != "TEST" ]; then
|
||||
echo "ERROR in CI SCRIPT: $SCRIPT_DIR/getRegistryTag.sh"
|
||||
return 2
|
||||
fi
|
||||
|
||||
if [ $BRANCH_NAME != "test" ]; then
|
||||
echo "ERROR in CI SCRIPT: $SCRIPT_DIR/getRegistryBranch.sh"
|
||||
return 3
|
||||
fi
|
||||
|
||||
return 0
|
||||
32
.gitlab/issue_templates/bug.md
Normal file
32
.gitlab/issue_templates/bug.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## Summary
|
||||
|
||||
(Summarize the bug encountered concisely)
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
(How one can reproduce the issue - this is very important)
|
||||
|
||||
## Example Project
|
||||
|
||||
(If possible, please create an example project here on GitLab.com that exhibits the problematic behaviour, and link to it here in the bug report)
|
||||
|
||||
(If you are using an older version of GitLab, this will also determine whether the bug has been fixed in a more recent version)
|
||||
|
||||
## What is the current bug behavior?
|
||||
|
||||
(What actually happens)
|
||||
|
||||
## What is the expected correct behavior?
|
||||
|
||||
(What you should see instead)
|
||||
|
||||
## Relevant logs and/or screenshots
|
||||
|
||||
(Paste any relevant logs - please use code blocks (```) to format console output,
|
||||
logs, and code as it's very hard to read otherwise.)
|
||||
|
||||
## Possible fixes
|
||||
|
||||
(If you can, link to the line of code that might be responsible for the problem)
|
||||
|
||||
/label ~bug ~meeting
|
||||
17
.gitlab/issue_templates/feature.md
Normal file
17
.gitlab/issue_templates/feature.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## Description
|
||||
|
||||
(Describe the feature that you're requesting concisely)
|
||||
|
||||
## Explanation
|
||||
|
||||
(Explain why the feature is necessary)
|
||||
|
||||
## Mockups/Screenshots
|
||||
|
||||
(If possible, provide mockups or screenshots, which demonstrate the feature)
|
||||
|
||||
## Dependencies, issues to be resolved beforehand
|
||||
|
||||
(List issues or dependencies that need to be resolved before this feature can be implemented)
|
||||
|
||||
/label ~feature ~meeting
|
||||
17
.gitlab/issue_templates/improvement.md
Normal file
17
.gitlab/issue_templates/improvement.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## What needs to be changed?
|
||||
|
||||
??? - Describe use case!
|
||||
|
||||
## How is the current state not sufficient?
|
||||
|
||||
???
|
||||
|
||||
## Which changes are necessary?
|
||||
|
||||
???
|
||||
|
||||
## Do the proposed changes impact current use cases?
|
||||
|
||||
???
|
||||
|
||||
/label ~improvement ~meeting
|
||||
70
.gitlab/publishing.gitlab-ci.yml
Normal file
70
.gitlab/publishing.gitlab-ci.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
deploy:
|
||||
stage: publish
|
||||
needs: ['build']
|
||||
script:
|
||||
- pnpm install
|
||||
- pnpm run deploy
|
||||
artifacts:
|
||||
paths:
|
||||
- ./.deploy
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
when: manual
|
||||
- if: $CI_COMMIT_TAG
|
||||
|
||||
publish images:
|
||||
stage: publish
|
||||
inherit:
|
||||
default:
|
||||
- tags
|
||||
needs: ['deploy']
|
||||
image:
|
||||
name: gcr.io/kaniko-project/executor:v1.9.0-debug
|
||||
entrypoint: [""]
|
||||
script:
|
||||
- /kaniko/executor
|
||||
--context "${CI_PROJECT_DIR}/${DEPLOY_DIR}"
|
||||
--dockerfile "${CI_PROJECT_DIR}/${DEPLOY_DIR}/Dockerfile"
|
||||
--destination "${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${DOCKER_TAG}"
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
variables:
|
||||
DOCKER_TAG: $CI_COMMIT_TAG
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
variables:
|
||||
DOCKER_TAG: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||
parallel:
|
||||
matrix:
|
||||
- DEPLOY_DIR: backend/database
|
||||
IMAGE_NAME: database
|
||||
- DEPLOY_DIR: .deploy/backend
|
||||
IMAGE_NAME: backend
|
||||
- DEPLOY_DIR: .deploy/proxy
|
||||
IMAGE_NAME: proxy
|
||||
|
||||
publish:
|
||||
stage: publish
|
||||
needs: ['deploy']
|
||||
script:
|
||||
- pnpm install --prefer-offline
|
||||
- pnpm build
|
||||
- pnpm changeset version $PUBLISH_TYPE
|
||||
- pnpm changeset publish
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
variables:
|
||||
PUBLISH_TYPE: --snapshot $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||
|
||||
pages:docs:
|
||||
stage: publish
|
||||
needs: ['deploy']
|
||||
script:
|
||||
- pnpm install --prefer-offline
|
||||
- pnpm run docs
|
||||
- mv docs public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
when: on_success
|
||||
3
.mailmap
Normal file
3
.mailmap
Normal file
@@ -0,0 +1,3 @@
|
||||
Rainer Killinger <mail-openstapps@killinger.co> Rainer Killinger <git@killinger.co>
|
||||
Rainer Killinger <mail-openstapps@killinger.co> Rainer Killinger <killinge@hrz.uni-frankfurt.de>
|
||||
Rainer Killinger <mail-openstapps@killinger.co> Rainer Killinger <killinger@hrz.uni-frankfurt.de>
|
||||
7
.mocharc.json
Normal file
7
.mocharc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extension": ["ts"],
|
||||
"node-option": ["loader=ts-node/esm"],
|
||||
"reporter": "mocha-junit-reporter",
|
||||
"reporter-option": ["mochaFile=coverage/report-junit.xml"],
|
||||
"spec": ["test/**/*.spec.ts"]
|
||||
}
|
||||
2
.npmrc
Normal file
2
.npmrc
Normal file
@@ -0,0 +1,2 @@
|
||||
auto-install-peers=true
|
||||
package-import-method=hardlink
|
||||
23
.pnpmfile.cjs
Normal file
23
.pnpmfile.cjs
Normal file
@@ -0,0 +1,23 @@
|
||||
const path = require("path");
|
||||
// const merge = require("deepmerge");
|
||||
|
||||
const additionalDeps = {
|
||||
'@openstapps/eslint-config': require('./configuration/eslint-config/package.json'),
|
||||
'@openstapps/prettier-config': require('./configuration/prettier-config/package.json'),
|
||||
}
|
||||
|
||||
function readPackage(pkg, context) {
|
||||
for (const dep in additionalDeps) {
|
||||
if (dep in pkg.devDependencies) {
|
||||
Object.assign(pkg.devDependencies, additionalDeps[dep].peerDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage,
|
||||
}
|
||||
}
|
||||
58
.syncpackrc.cjs
Normal file
58
.syncpackrc.cjs
Normal file
@@ -0,0 +1,58 @@
|
||||
// @ts-check
|
||||
|
||||
/** @type {import('syncpack').RcFile} */
|
||||
const config = {
|
||||
semverRange: '',
|
||||
source: ['package.json', '**/package.json'],
|
||||
indent: ' ',
|
||||
sortFirst: [
|
||||
'name',
|
||||
'description',
|
||||
'version',
|
||||
'private',
|
||||
'type',
|
||||
'license',
|
||||
'repository',
|
||||
'author',
|
||||
'contributors',
|
||||
'keywords',
|
||||
'main',
|
||||
'types',
|
||||
'bin',
|
||||
'files',
|
||||
'engines',
|
||||
'scripts',
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
'peerDependencies',
|
||||
'pnpm',
|
||||
'tsup',
|
||||
'prettier',
|
||||
'eslintConfig',
|
||||
'eslintIgnore',
|
||||
'nyc',
|
||||
],
|
||||
versionGroups: [
|
||||
{
|
||||
label: 'ES Mapping Generator Special Dependencies',
|
||||
dependencies: ['typescript', 'typedoc', 'ts-node', '@types/node', 'got'],
|
||||
packages: ['@openstapps/es-mapping-generator'],
|
||||
isIgnored: true,
|
||||
},
|
||||
{
|
||||
label: 'Packages should use workspace version',
|
||||
dependencies: ['@openstapps/**'],
|
||||
dependencyTypes: ['prod', 'dev'],
|
||||
packages: ['**'],
|
||||
pinVersion: 'workspace:*',
|
||||
},
|
||||
{
|
||||
label: 'App may have some dependency exceptions',
|
||||
dependencies: ['typescript', '@typescript-eslint/**', 'eslint**'],
|
||||
packages: ['@openstapps/app'],
|
||||
isIgnored: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,6 +0,0 @@
|
||||
### Features
|
||||
|
||||
* add es-mapping-gen ([42c9d020](https://gitlab.com/openstapps/es-mapping-gen/commit/42c9d020361eca12370b7af27fb4502335df82bc))
|
||||
|
||||
|
||||
|
||||
100
CONTRIBUTING.md
Normal file
100
CONTRIBUTING.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Contributing to `@openstapps/core`
|
||||
|
||||
Please see the appropriate general group contributing guides in [project-management](https://gitlab.com/openstapps/projectmanagement/tree/master/project-docs/workflow).
|
||||
|
||||
## Updating and releasing related projects
|
||||
|
||||
Following semantic versioning patches to the core should not break existing usage.
|
||||
|
||||
### API
|
||||
|
||||
Every minor and major version of the core needs a corresponding version of the [API](https://openstapps.gitlab.io/api) to be used in the app and connectors.
|
||||
|
||||
Because the API is an integral part of the App and Node.js-based connectors this should be done for every new minor and major release of the core.
|
||||
|
||||
### Backend
|
||||
|
||||
The [backend](https://openstapps.gitlab.io/backend) uses the core to validate requests and responses. With the use of the [core tools](https://openstapps.gitlab.io/core-tools) it uses the core to set up the database according to the model.
|
||||
|
||||
Like for the API there should be a new release of the backend for every minor and major release of the core.
|
||||
|
||||
### Core tools
|
||||
|
||||
The [core tools](https://openstapps.gitlab.io/core-tools) are more or less not dependent on a specific core version and should normally not need adjustments for new core versions as long the structure of the code in the core stays the same.
|
||||
|
||||
### App and connectors
|
||||
|
||||
[App](https://openstapps.gitlab.io/app) and connectors use the API to communicate with the backend. To ensure compatibility the version of the used core must be the same as the one that is used in the used API.
|
||||
|
||||
App and connectors should be updated regularly to new releases of the core but not as important like API and backend. Since the app is just a view for the data stored in the backend it is not necessary to be up to date with the newest core immediately and the connectors are developed independently by every school and up to their responsibility.
|
||||
|
||||
## Adding new Types
|
||||
|
||||
Adding new types requires changes at multiple locations for it to work correctly
|
||||
|
||||
### Required changes
|
||||
|
||||
- Add your SCThing and SCThingWithoutReferences to `src/things/your-thing-name.ts` and make them extend `SCThingWithoutReferences` and `SCThing` respectively
|
||||
- Add your SCThingMeta to `src/things/your-thing-name.ts` and make it extend `SCThingMeta`
|
||||
- Add your SCThingMeta to `SCClasses` in `src/meta.ts`
|
||||
- Add your SCThing to `SCThingsWithoutDiff` in `src/meta.ts`
|
||||
- Add your SCThingWithoutReferences to `SCAssociatedThingWithoutReferences` in `src/meta.ts`
|
||||
- Add your SCThing to `SCAssociatedThing` in `src/meta.ts`
|
||||
- Add your SCThing to the `SCThingType` enum in `src/things/abstract/thing.ts`
|
||||
- Add an example file for your SCThing in `test/resources/YourThingName.json`
|
||||
- Add the following lines for your SCThing in `test/type.spec.ts`:
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Types of properties of SCYourThingName
|
||||
*/
|
||||
type SCYourThingNamePropertyTypes = PropertyTypesNested<SCYourThingName>;
|
||||
assert<NotHas<SCYourThingNamePropertyTypes, SCThingWithoutReferences>>(false);
|
||||
assert<Has<SCYourThingNamePropertyTypes, SCThingWithoutReferences>>(true);
|
||||
assert<NotHas<SCYourThingNamePropertyTypes, SCThing>>(true);
|
||||
assert<Has<SCYourThingNamePropertyTypes, SCThing>>(false);
|
||||
assert<Extends<SCYourThingNameWithoutReferences, SCThing>>(false);
|
||||
assert<Extends<SCYourThingName, SCThing>>(true);
|
||||
```
|
||||
|
||||
## Additional coding style
|
||||
|
||||
### Extract inline type definitions
|
||||
|
||||
For consistency and correct functionality of `core-tools` we need well-defined type assignments.
|
||||
|
||||
Type assignments shall always be primitive types, classes, interfaces, enums or unions. Not allowed are inline type-definitions. Those shall be refactored accordingly:
|
||||
|
||||
```typescript
|
||||
export interface SCPlaceWithoutReferences extends SCThing {
|
||||
...
|
||||
// Use this:
|
||||
geo: SCGeoInformation;
|
||||
|
||||
// Instead of:
|
||||
geo: {
|
||||
point: Point,
|
||||
polygon?: Polygon,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Reuse the map structure
|
||||
|
||||
If you come around a map-like-type use `SCMap<T>`.
|
||||
|
||||
```typescript
|
||||
// Use this:
|
||||
interface AnyClass {
|
||||
inventory: SCMap<number>;
|
||||
}
|
||||
|
||||
// Instead of:
|
||||
interface AnyClass {
|
||||
inventory?: Array<{key: string; value: number}>;
|
||||
}
|
||||
// or instead of
|
||||
interface AnyClass {
|
||||
inventory?: {[key: string]: number};
|
||||
}
|
||||
```
|
||||
122
README.md
122
README.md
@@ -1,64 +1,94 @@
|
||||
# @openstapps/es-mapping-generator
|
||||
# Open StApps Monorepo
|
||||
|
||||
[](https://gitlab.com/openstapps/es-mapping-gen/commits/master)
|
||||
[](https://npmjs.com/package/@openstapps/es-mapping-gen)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://openstapps.gitlab.io/es-mapping-gen)
|
||||
Refer to the [contribution guide](./CONTRIBUTING.md)
|
||||
|
||||
Tools to convert and validate StAppsCore
|
||||
## Projects
|
||||
|
||||
## What is the ES Mapping Generator for?
|
||||
### Apps
|
||||
|
||||
The ES Mapping Generator is for converting TypeScript interfaces to Elasticsearch mappings,
|
||||
with support for Integer and Float types, Dates, etc.
|
||||
| Name | Version | License | Readme |
|
||||
| -------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- |
|
||||
| Core | [](https://npmjs.com/package/@openstapps/app) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`frontend/app`](./frontend/app/README.md) |
|
||||
| Backend | [](https://npmjs.com/package/@openstapps/backend) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`backend/backend`](./backend/backend/README.md) |
|
||||
| Proxy | [](https://npmjs.com/package/@openstapps/proxy) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`backend/proxy`](./backend/proxy/README.md) |
|
||||
| Database | [](https://npmjs.com/package/@openstapps/database) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`backend/database`](./backend/database/README.md) |
|
||||
|
||||
## Why is this a separate package?
|
||||
### Libraries
|
||||
|
||||
The ES Mapping Generator relies on an outdated version of TypeDoc, that can't be updated.
|
||||
Because of that, it then also relies on an outdated version of TypeScript, resulting
|
||||
in a cascade effect things that can't be updated. Because of that, we decided to isolate
|
||||
it to the best of our abilities.
|
||||
| Name | Version | License | Readme |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| Core | [](https://npmjs.com/package/@openstapps/core) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`packages/core`](./packages/core/README.md) |
|
||||
| API | [](https://npmjs.com/package/@openstapps/api) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`packages/api`](./packages/api/README.md) |
|
||||
| API Plugin | [](https://npmjs.com/package/@openstapps/api-plugin) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`packages/api-plugin`](./packages/api-plugin/README.md) |
|
||||
| Logger | [](https://npmjs.com/package/@openstapps/logger) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`packages/logger`](./packages/logger/README.md) |
|
||||
| Core Tools | [](https://npmjs.com/package/@openstapps/core-tools) | [](https://www.gnu.org/licenses/gpl-3.0.en.html) | [`packages/core-tools`](./packages/core-tools/README.md) |
|
||||
|
||||
## How to use the Elasticsearch Mapping generator
|
||||
## Publishing
|
||||
|
||||
The mapping generator is intended to be used by the backend directly, but it can also be used to generate these files
|
||||
manually.
|
||||
After having added all changes using `pnpm changeset`
|
||||
|
||||
### Generating the mapping files by hand
|
||||
|
||||
To generate the mapping files by hand, you need a local copy of the core-tools and the core, both need to be built first.
|
||||
After that you can run
|
||||
```shell
|
||||
pnpm changeset version # bump versions
|
||||
pnpm install # update lockfile and rebuild packages
|
||||
pnpm build # make sure all packages are built
|
||||
pnpm publish -r # publish all packages not yet in the registry
|
||||
git add .
|
||||
git commit -m "v[VERSION]"
|
||||
git tag -a "v[VERSION]"
|
||||
git push --follow-tags
|
||||
```
|
||||
node lib/cli.js mapping path/to/core path/to/destination ignoredTag1,ignoredTag2,ignoredTag3
|
||||
|
||||
## Remote caching
|
||||
|
||||
Turbo supports remote caching, which massively speeds up build processes.
|
||||
|
||||
### Connecting to the remote cache locally
|
||||
|
||||
`.env.local`
|
||||
|
||||
```dotenv
|
||||
TURBO_API=http://example:3000
|
||||
TURBO_TEAM=openstapps
|
||||
TURBO_TOKEN=abc123
|
||||
```
|
||||
If you don't pass in any ignored tags, you will likely be prompted with errors, despite the core being absolutely correct.
|
||||
This is because there are some tags that are not relevant to Elasticsearch, but the program has no direct way to tell
|
||||
which ones simply lack an implementation and which ones can be ignored. Currently the ignored tags include
|
||||
`minlength`, `pattern` and `see`.
|
||||
|
||||
### Generating the mapping directly from another TypeScript program
|
||||
### Connecting to the remote cache in GitLab Pipelines
|
||||
|
||||
This is the more easy way, and it gives you direct access to the generated mapping as a (mostly typesafe) object. To
|
||||
use it, call `generateTemplate`, However you will first need to generate a ProjectReflection of the core you are working
|
||||
with. If you use the core as a dependency, you can for example use
|
||||
```typescript
|
||||
const map = generateTemplate(getProjectReflection(resolve('node_modules', '@openstapps', 'core', 'src')),
|
||||
ignoredTags, false);
|
||||
You will need to define
|
||||
|
||||
- `TURBO_API`
|
||||
- `TURBO_TEAM`
|
||||
- `TURBO_TOKEN`
|
||||
Like you did locally as described in [this](https://turbo.build/repo/docs/ci/gitlabci#remote-caching)
|
||||
guide.
|
||||
|
||||
### Hosting a cache
|
||||
|
||||
Self-hosting via Docker is extremely simple, just follow
|
||||
[this](http://v2202207178592194230.supersrv.de:6341) guide
|
||||
or in short:
|
||||
|
||||
`.env`
|
||||
|
||||
```dotenv
|
||||
PORT=...
|
||||
TURBO_TOKEN=...
|
||||
```
|
||||
to generate the mappings. Note that the result object contains both a list of errors in `map.errors` and the actual mapping
|
||||
in `map.template`. You can also specify whether you want the generator to show any errors while generating the mappings
|
||||
in the console in the last parameter, `true` (default) being show errors and `false` to suppress them. That said it is very
|
||||
easy to replace all `type: "MISSING_PREMAP"`, `type: "PARSE_ERROR"`, `type: "TYPE_CONFLICT"` with `dynamic: true` (you
|
||||
can take these exactly like written here and run a replace over the file).
|
||||
|
||||
### Fixing a generated mapping by hand
|
||||
```shell
|
||||
docker run --env-file=.env -p 3000:3000 fox1t/turborepo-remote-cache
|
||||
```
|
||||
|
||||
If you get errors when generating the mappings, the mappings might not work, however they will still be generated to the
|
||||
programs best efforts. Most small issues can be fixed after the mapping was generated as a temporary solution and without
|
||||
changing anything in the mapper's code. This however requires some understanding of how mappings work.
|
||||
## Useful commands
|
||||
|
||||
The output of the program can easily reach 25.000 lines, but you can find errors quickly by searching for `MISSING_PREMAP`,
|
||||
`PARSE_ERROR` and `TYPE_CONFLICT`. When you reach them you can then manually replace them with your code.
|
||||
#### Why is this package bloating the app?
|
||||
|
||||
As a last resort you can also replace all errors with dynamic types, this should get the mapping working, but it is NOT
|
||||
RECOMMENDED as a fix other than using it locally.
|
||||
```shell
|
||||
pnpm why --prod -r --filter @openstapps/app PACKAGE
|
||||
```
|
||||
|
||||
#### Licenses
|
||||
|
||||
```shell
|
||||
pnpm licenses --prod --filter PROJECT
|
||||
```
|
||||
|
||||
22
backend/backend/.gitlab-ci.yml
Normal file
22
backend/backend/.gitlab-ci.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
integration:
|
||||
image: registry.gitlab.com/openstapps/projectmanagement/builder:v18
|
||||
stage: test
|
||||
needs: ['build']
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
WAIT_FOR_SERVICES_TIMEOUT: 1
|
||||
services:
|
||||
- name: registry.gitlab.com/openstapps/database:latest
|
||||
alias: elasticsearch
|
||||
script:
|
||||
- pnpm --filter=@openstapps/backend install
|
||||
- pnpm test:integration:backend
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- backend/backend/coverage/integration-report-junit.xml
|
||||
reports:
|
||||
junit:
|
||||
- backend/backend/coverage/integration-report-junit.xml
|
||||
rules:
|
||||
- when: on_success
|
||||
248
backend/backend/CHANGELOG.md
Normal file
248
backend/backend/CHANGELOG.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# @openstapps/backend
|
||||
|
||||
## 3.0.0-next.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 64caebaf: Migrate config system to cosmiconfig
|
||||
|
||||
Configs are now written using type-checked JavaScript
|
||||
|
||||
```js
|
||||
// @ts-check
|
||||
|
||||
// This file is now type-safe just like TypeScript, but
|
||||
// without the compilation step
|
||||
|
||||
/** @type {import('@openstapps/package').Type} */
|
||||
const foo = {};
|
||||
```
|
||||
|
||||
You can write config files in JavaScript, JSON, or other
|
||||
cosmiconfig-supported formats.
|
||||
|
||||
The config files now are
|
||||
|
||||
- `backendrc.{js,json,...}`
|
||||
- `elasticsearchrc.{js,json,...}`
|
||||
- `prometheusrc.{js,json,...}`
|
||||
|
||||
You can also split them into multiple files,
|
||||
as well as using the `markdown.js` helper in
|
||||
`config/default/tools` to include markdown files
|
||||
as text (see `config/f-u/about-pages`)
|
||||
|
||||
- 64caebaf: Move project to a turbo monorepo & pnpm
|
||||
|
||||
Internal dependencies are now defined using `"@openstapps/package": "workspace:*"`
|
||||
|
||||
- Removed extraneous files from packages
|
||||
- `.npmrc`
|
||||
- `.npmignore`
|
||||
- `.mailmap`
|
||||
- `.gitignore`
|
||||
- `CONTRIBUTING.md`
|
||||
- `LICENSE` (Project license file is added upon publishing, see [pnpm.io](https://pnpm.io/cli/publish))
|
||||
- `package-lock.json`
|
||||
- `.editorconfig`
|
||||
- `.eslintrc.json` (moved eslint config to `package.json`)
|
||||
- `.eslintignore`
|
||||
- `.gitlab-ci.yml` (Most workflows are workspace-level)
|
||||
- `.gitlab/**` (issue templates etc. are now workspace-level)
|
||||
- `.dockerignore` (Docker files are determined by which files are deployed with `pnpm deploy`, as per `package.json/files`)
|
||||
- TSConfig has been moved to its own package (You can now use `"extends": "@openstapps/tsconfig"`)
|
||||
- Removed ESLint and Prettier peer dependency hell by injecting them through the `.pnpmfile.cjs`
|
||||
- Added syncpack for keeping dependency versions in sync (and consistent key ordering in `package.json`)
|
||||
- Replaced conventional changelog with changesets
|
||||
- Apps with binaries now use a top level `app.js`
|
||||
|
||||
```js
|
||||
#!/usr/bin/env node
|
||||
import './lib/app.js';
|
||||
```
|
||||
|
||||
- 64caebaf: Migrate to ESM
|
||||
|
||||
CommonJS is no longer supported in any capacity. To use the new
|
||||
version, you will need to migrate your package to ESM.
|
||||
We recommend using `tsup` and `Node 18`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
```
|
||||
|
||||
- 64caebaf: Migrate package to Node 18
|
||||
|
||||
- Consumers of this package will need to migrate to Node 18 or
|
||||
higher.
|
||||
- Packages have been migrated from promisified `readFile` or
|
||||
`readFileSync` towards `fs/promises`
|
||||
- Packages use native `flatMap` now
|
||||
|
||||
- 0a7e6af1: Migrate es mapping types from es-mapping-generator to .d.ts next to generated mappings
|
||||
- 64caebaf: Migrate build system to `tsup`
|
||||
|
||||
All packages now use an `index.ts` file to expose contents.
|
||||
|
||||
You will need to migrate paths from `import foo from '@scope/package/lib/foo` to `import foo from '@scope/package'`
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 64caebaf: Migrate integration tests from docker-compose solution to a shell script
|
||||
|
||||
`api-cli` no longer builds as a Docker container as a result.
|
||||
|
||||
- 64caebaf: Migrate tests to C8/Chai/Mocha
|
||||
|
||||
- `@testdeck` OOP testing has been removed.
|
||||
- Tests have been unified
|
||||
- CommonJS module mocking has been replaced through
|
||||
refactoring of tests, as ES Modules cannot be mocked
|
||||
(do yourself a favor and don't try to mock them)
|
||||
- C8 now replaces NYC as a native coverage tool
|
||||
|
||||
- 64caebaf: Migrate away from `@krlwlfrt/async-pool`
|
||||
|
||||
```ts
|
||||
import {mapAsyncLimit} from '@openstapps/collection-utils';
|
||||
|
||||
await mapAsyncLimit(
|
||||
[1, 2, 3],
|
||||
async it => {
|
||||
await someNetworkRequest(it);
|
||||
},
|
||||
5,
|
||||
);
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 64caebaf: Migrated changelogs to changeset format
|
||||
|
||||
```js
|
||||
import fs from 'fs';
|
||||
|
||||
const path = 'packages/logger/CHANGELOG.md';
|
||||
|
||||
fs.writeFileSync(path, fs.readFileSync(path, 'utf8').replace(/^#+\s+\[/gm, '## ['));
|
||||
```
|
||||
|
||||
- 98546a97: Migrate away from @openstapps/configuration
|
||||
- Updated dependencies [98546a97]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [98546a97]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [98546a97]
|
||||
- Updated dependencies [0a7e6af1]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [98546a97]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [64caebaf]
|
||||
- Updated dependencies [98546a97]
|
||||
- @openstapps/core-tools@3.0.0-next.0
|
||||
- @openstapps/logger@3.0.0-next.0
|
||||
- @openstapps/core@3.0.0-next.0
|
||||
|
||||
## [1.0.0](https://gitlab.com/openstapps/backend/compare/v0.6.0...v1.0.0) (2023-05-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- openapi docs generation ([4ebe44a](https://gitlab.com/openstapps/backend/commit/4ebe44a5a7a1b7bfd0aa5b84d47d4056d3068ffe))
|
||||
- rename deprecated Gitlab CI variables ([3471591](https://gitlab.com/openstapps/backend/commit/3471591a7d458df70447c8dac91f96f3c83e763c))
|
||||
- semster boosting ([515a6ee](https://gitlab.com/openstapps/backend/commit/515a6eeea56305a37510d99b9f84a6b118b66f8a))
|
||||
|
||||
### Features
|
||||
|
||||
- update to of elasticsearch 8.4 ([c9b83b5](https://gitlab.com/openstapps/backend/commit/c9b83b5d71610f82bd1d99e837e29ad445758aea))
|
||||
|
||||
## [0.6.0](https://gitlab.com/openstapps/backend/compare/v0.5.0...v0.6.0) (2023-01-30)
|
||||
|
||||
## [0.5.0](https://gitlab.com/openstapps/backend/compare/v0.4.1...v0.5.0) (2022-12-06)
|
||||
|
||||
## [0.4.1](https://gitlab.com/openstapps/backend/compare/v0.4.0...v0.4.1) (2022-11-02)
|
||||
|
||||
## [0.4.0](https://gitlab.com/openstapps/backend/compare/v0.3.1...v0.4.0) (2022-10-21)
|
||||
|
||||
## [0.3.1](https://gitlab.com/openstapps/backend/compare/v0.3.0...v0.3.1) (2022-09-02)
|
||||
|
||||
## [0.3.0](https://gitlab.com/openstapps/backend/compare/v0.2.0...v0.3.0) (2022-08-24)
|
||||
|
||||
## [0.2.0](https://gitlab.com/openstapps/backend/compare/v0.1.0...v0.2.0) (2022-08-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- update PAIA API URL ([a20200e](https://gitlab.com/openstapps/backend/commit/a20200e52a725ede42cb5e026a5a693b1ba3d149))
|
||||
|
||||
## [0.1.0](https://gitlab.com/openstapps/backend/compare/16bbb7e9e36b7adf27452e1b09f7970e98aa27df...v0.1.0) (2022-06-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add default configuration file for prometheus monitoring ([7ed2921](https://gitlab.com/openstapps/backend/commit/7ed2921efbce7fa5134206763eea986c6ef9a919))
|
||||
- add prefix to schema names ([90822f5](https://gitlab.com/openstapps/backend/commit/90822f5888ed34d594b02df3f5cd9ec8ce74251e))
|
||||
- apply correct types and tslint rules ([0cbf9b2](https://gitlab.com/openstapps/backend/commit/0cbf9b26a972563ad9483d78cea9ba809381f7dd))
|
||||
- automatically remove invalid characters for aliases generated from index names ([6f7e23d](https://gitlab.com/openstapps/backend/commit/6f7e23df20af54abf2459da8aaebe236b82a5f1c))
|
||||
- Don't force Mapping generation with 'npm start' ([4cfb560](https://gitlab.com/openstapps/backend/commit/4cfb560954ca97e22091e13d515475218885b1de))
|
||||
- enhance default search query generation ([24a9122](https://gitlab.com/openstapps/backend/commit/24a91229f28fb17cb4941aab688a08266437c1eb))
|
||||
- error thrown on consecutive connector executions ([2259da3](https://gitlab.com/openstapps/backend/commit/2259da317a848660fc2b0a14e50e2ae5ae329889)), closes [#73](https://gitlab.com/openstapps/backend/issues/73)
|
||||
- esacpe mappin template filename ([496e6c5](https://gitlab.com/openstapps/backend/commit/496e6c5bd0563bd2dc0c6eff45c9bd685d95b453))
|
||||
- fix markdown formatting in config ([9c5581a](https://gitlab.com/openstapps/backend/commit/9c5581af2cc131b81c288eadc39827124963ce55))
|
||||
- fix reading url path as parameters ([9b889c8](https://gitlab.com/openstapps/backend/commit/9b889c873624d43baed4769a788db39528b143d8))
|
||||
- imports from src in config files lead to crash ([f6003d7](https://gitlab.com/openstapps/backend/commit/f6003d7f8709d4424acd261cc7804e4d2684a9f4))
|
||||
- invalid monthly cron execution time ([7a9f3ea](https://gitlab.com/openstapps/backend/commit/7a9f3eaca4667870ed19b17fd26c3c6d8e1fadd5))
|
||||
- make config compatible with core, update database version ([f11376e](https://gitlab.com/openstapps/backend/commit/f11376ecf8c4997f6d0a85b3f3fde9e8b02bd61b))
|
||||
- make facets work again ([d917627](https://gitlab.com/openstapps/backend/commit/d917627d588783d8734bd1d0c30d3d2782d02761))
|
||||
- make index route work correctly ([fa2c9d7](https://gitlab.com/openstapps/backend/commit/fa2c9d7a881d9e94da8512349056b69206e4e3d0))
|
||||
- properly check if an object exists before update ([e165837](https://gitlab.com/openstapps/backend/commit/e165837a154243305dc300acaa29605732290f6a)), closes [#70](https://gitlab.com/openstapps/backend/issues/70)
|
||||
- remove onlyOnTypes from mustMatch ([1d5f99b](https://gitlab.com/openstapps/backend/commit/1d5f99b1fa74c486dc4df29daf9c0aa453935821)), closes [#83](https://gitlab.com/openstapps/backend/issues/83)
|
||||
- replace isProductiveEnvironment with isTestEnvironment ([8c48552](https://gitlab.com/openstapps/backend/commit/8c48552abf7b7983e966ebc22299b334cae46167))
|
||||
- return syntax error when receiving bad json ([12b71ba](https://gitlab.com/openstapps/backend/commit/12b71ba1f1f3e45a84b001b395dcfa1578355276)), closes [#3](https://gitlab.com/openstapps/backend/issues/3)
|
||||
- return validation error instead of internal server error ([24e27c1](https://gitlab.com/openstapps/backend/commit/24e27c1d9e002db3b8f4afb4a31ad994c0eaad42))
|
||||
- route for news ([7e35fae](https://gitlab.com/openstapps/backend/commit/7e35fae34e02bf2e12cf0d0b960d48de97fd4200))
|
||||
- set config file before accessing it ([e17db52](https://gitlab.com/openstapps/backend/commit/e17db521e2a3f4f15dc5e5b758bd1ada10c78161)), closes [#27](https://gitlab.com/openstapps/backend/issues/27)
|
||||
- stapps core version in config ([32c8a21](https://gitlab.com/openstapps/backend/commit/32c8a2149ad18179610af02483b794b426b7b9dc)), closes [#74](https://gitlab.com/openstapps/backend/issues/74)
|
||||
- take coordinates in right order ([bb3be5a](https://gitlab.com/openstapps/backend/commit/bb3be5a816f7e4eb85b69ec558572bed9c3b6b39)), closes [#116](https://gitlab.com/openstapps/backend/issues/116)
|
||||
- use SCRequestBodyTooLargeError ([e70e50a](https://gitlab.com/openstapps/backend/commit/e70e50a1eab00cd180479c5e0299f974da92fe94)), closes [#20](https://gitlab.com/openstapps/backend/issues/20)
|
||||
- use specific time from filter if defined ([80e6249](https://gitlab.com/openstapps/backend/commit/80e62496f0731af721193875d5a6cdbf10b34607))
|
||||
- wait for config file validation ([30082f8](https://gitlab.com/openstapps/backend/commit/30082f87262fa7428172fcbb6710b66d4bfe6261))
|
||||
- wrong way alias names are generated ([9488451](https://gitlab.com/openstapps/backend/commit/94884510802906cdbfdd3490fac5fc9401937da7)), closes [#79](https://gitlab.com/openstapps/backend/issues/79)
|
||||
|
||||
### Features
|
||||
|
||||
- add backend ([16bbb7e](https://gitlab.com/openstapps/backend/commit/16bbb7e9e36b7adf27452e1b09f7970e98aa27df))
|
||||
- add boosting to context based search ([dd4be92](https://gitlab.com/openstapps/backend/commit/dd4be92f90c6e7047eea0d00a2442b75673329f6))
|
||||
- add catalog menu entry and rearrange ([4e42772](https://gitlab.com/openstapps/backend/commit/4e42772ca3788d3ee7af78266ee223e05fe6a8f3))
|
||||
- add default app settings and menus ([54301ae](https://gitlab.com/openstapps/backend/commit/54301ae8fb656db17e231197c3a64fc27f541024))
|
||||
- add dummy about config ([d6f126f](https://gitlab.com/openstapps/backend/commit/d6f126f19776ee7902e65d9248501b4986657ed9))
|
||||
- add favorites to personal menu ([de0617b](https://gitlab.com/openstapps/backend/commit/de0617b8dd51182326094543110b8ed294a6e940))
|
||||
- add feedback to config as menu item ([7ba6472](https://gitlab.com/openstapps/backend/commit/7ba647271efd87c422ce302bd5baf5760671e1a1))
|
||||
- add functionality to register plugins via http ([3d51ccf](https://gitlab.com/openstapps/backend/commit/3d51ccfac26b2c3ad1271c29c1e736aaf7fcd88f)), closes [#2](https://gitlab.com/openstapps/backend/issues/2) [#37](https://gitlab.com/openstapps/backend/issues/37)
|
||||
- add hebis proxy url ([ca1d244](https://gitlab.com/openstapps/backend/commit/ca1d2444e03aacad37219d93d657968b7a933f78)), closes [#120](https://gitlab.com/openstapps/backend/issues/120)
|
||||
- add openapi docs generation to api ([614a1b1](https://gitlab.com/openstapps/backend/commit/614a1b1e9b3c525d5524065851689f793a4b3b4b))
|
||||
- Add prometheus middleware to express ([b42e911](https://gitlab.com/openstapps/backend/commit/b42e911a117c59b2d70c1587f9e9b20a846e92d0))
|
||||
- add routes doc generation to npm documentation script ([4a64f26](https://gitlab.com/openstapps/backend/commit/4a64f26e43979cdd4390bad796e1b7dc3f8c7027))
|
||||
- add schedule route ([785813c](https://gitlab.com/openstapps/backend/commit/785813c3fb92bbebd7b07246bbcec77a9a4520e3))
|
||||
- Add start-debug npm run script ([23eb1e2](https://gitlab.com/openstapps/backend/commit/23eb1e2263d2dd9d55f9a6ac5fca2a8fad7f1e84))
|
||||
- add support for generated elasticsearch mappings ([8eab6b8](https://gitlab.com/openstapps/backend/commit/8eab6b8531d91d4569fe13743624f5ce91a7dc1e)), closes [#38](https://gitlab.com/openstapps/backend/issues/38)
|
||||
- add support for multiple values in value filter ([de60311](https://gitlab.com/openstapps/backend/commit/de60311bd072db01eaf50965f3fdc307bfedc4c2))
|
||||
- add support for new availability filter ([47f3232](https://gitlab.com/openstapps/backend/commit/47f3232f155a13ea39abb2aaaecafd54fa7d98ce))
|
||||
- add support for range filters ([dc16974](https://gitlab.com/openstapps/backend/commit/dc169746e7fa0f50a1f969653043e5a4d5fa0f01))
|
||||
- add support for range filters ([dcf7906](https://gitlab.com/openstapps/backend/commit/dcf7906f79f07d9cfee704454eedddb452a1f255))
|
||||
- adjust to changes of SCFacet in core v0.12.0 ([2f13010](https://gitlab.com/openstapps/backend/commit/2f13010480b87a4a06634084033b3b0822eb78ee)), closes [#30](https://gitlab.com/openstapps/backend/issues/30)
|
||||
- allow for searching illegal elasticsearch characters ([b629d05](https://gitlab.com/openstapps/backend/commit/b629d058eb64c7a785648fab0a7073eeaa37e895))
|
||||
- boost academic terms dynamically ([13938ec](https://gitlab.com/openstapps/backend/commit/13938ecf211060a3f50747ac7fed343b71a6aa4b))
|
||||
- log registration and removal of plugins ([006bbeb](https://gitlab.com/openstapps/backend/commit/006bbebe60b7f5015d80ac825622cefbc25cd959)), closes [#71](https://gitlab.com/openstapps/backend/issues/71)
|
||||
- make backend work with automatically generated aggregations ([ba2c6f6](https://gitlab.com/openstapps/backend/commit/ba2c6f655c263f0b1d1e55b739adde0004bbf408))
|
||||
- move EXTERNAL_REQUEST_TIMEOUT to config file ([5d6d4b5](https://gitlab.com/openstapps/backend/commit/5d6d4b53f01550365a330daecbcb4e0f6bdb8aef))
|
||||
- move up and enable cors ([6483221](https://gitlab.com/openstapps/backend/commit/6483221b62d84c5871ee4ec82158f8b9ef1ed54e))
|
||||
- support geo shape filter ([dd8a6b3](https://gitlab.com/openstapps/backend/commit/dd8a6b3abcc90c50a16167054e2f3cdcee40c863))
|
||||
- use config file for maxRequestBodySize ([d110d60](https://gitlab.com/openstapps/backend/commit/d110d60123a28563fe0c58ab903f61255a9644a2))
|
||||
- use config for MultiSearchRoute ([8278279](https://gitlab.com/openstapps/backend/commit/827827905b71c71dfa9299a9deb92a8c9cfc0e20))
|
||||
- use new Elasticsearch package ([1bad092](https://gitlab.com/openstapps/backend/commit/1bad092185d989078badc66f9c138d2e1baa27e4))
|
||||
- utilize api-cli for e2e integration test ([ce06e73](https://gitlab.com/openstapps/backend/commit/ce06e735bea379c9ad955a627e3e1cead37c85fe))
|
||||
12
backend/backend/Dockerfile
Normal file
12
backend/backend/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM registry.gitlab.com/openstapps/projectmanagement/node:v18
|
||||
|
||||
USER root
|
||||
RUN apk add --update python3 py3-pip make g++ gcompat
|
||||
|
||||
USER node
|
||||
ADD --chown=node:node . /app
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /app
|
||||
|
||||
EXPOSE 3000
|
||||
ENTRYPOINT ["node", "app.js"]
|
||||
114
backend/backend/README.md
Normal file
114
backend/backend/README.md
Normal file
@@ -0,0 +1,114 @@
|
||||
[](https://gitlab.com/openstapps/backend/commits/master)
|
||||
|
||||
# backend (a reference implementation of a StApps backend)
|
||||
|
||||
This project is a reference implementation for a StApps backend. It provides an HTTP API to index data into a database,
|
||||
perform full text search, sorts and filters. It also delivers the configuration needed by the app. The API is specified
|
||||
within the [@openstapps/core](https://gitlab.com/openstapps/core).
|
||||
|
||||
If you want to perform requests, index data or search within JavaScript or TypeScript you should consider using our client
|
||||
[@openstapps/api](https://gitlab.com/openstapps/api).
|
||||
|
||||
Or generate your own client using the openapi/swagger definitions you can get form the [API documentation](https://openstapps.gitlab.io/backend).
|
||||
|
||||
# Usage
|
||||
|
||||
This backend is not a standalone software. It needs a database like Elasticsearch to work.
|
||||
|
||||
If you just want to use the backend you should consider using
|
||||
[minimal-deployment](https://gitlab.com/openstapps/minimal-deployment). The minimal-deployment will provide
|
||||
you with everything you need to run this backend.
|
||||
|
||||
# Local usage for development purposes
|
||||
|
||||
## Requirements
|
||||
|
||||
- Elasticsearch (8.4)
|
||||
- [ICU analysis plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-icu.html)
|
||||
- OR Docker
|
||||
- Node.js (~14) / NPM
|
||||
|
||||
### Startup Behaviour
|
||||
|
||||
_This might be important if you work on the Core_
|
||||
|
||||
The backend is using Elasticsearch Mappings and Aggregations from its currently used `core` dependency.
|
||||
|
||||
## Start Database (Elasticsearch)
|
||||
|
||||
Elasticsearch needs some configuration and plugins to be able to work
|
||||
with the backend. To save you some work we provide a
|
||||
[docker image](https://gitlab.com/openstapps/database) which
|
||||
only needs to be executed to work with the backend.
|
||||
|
||||
Run `docker run -d -p 9200:9200 registry.gitlab.com/openstapps/database:latest`
|
||||
|
||||
Elasticsearch should be running at port 9200 now. If you have problems with
|
||||
getting elasticsearch to work, have a look in the
|
||||
[README](https://gitlab.com/openstapps/database) of the image
|
||||
first.
|
||||
|
||||
## Metrics collection
|
||||
|
||||
The backend contains an express middleware which can be optionally enabled by setting the environment variable
|
||||
`PROMETHEUS_MIDDLEWARE` to `true`. The middleware collects metrics and provides a [Prometheus](https://prometheus.io/)
|
||||
compatible endpoint from which the metrics may be scraped by Prometheus.
|
||||
|
||||
The middleware may be configured with JSON provided in `config/prometheus.json`, i.e.
|
||||
|
||||
```JSON
|
||||
{
|
||||
"metricsPath": "/metrics",
|
||||
"collectDefaultMetrics": true,
|
||||
"requestDurationBuckets": [0.1, 0.5, 1, 2, 5, 10, 20],
|
||||
"requestLengthBuckets": [512, 1024, 5120, 10240, 51200, 102400],
|
||||
"responseLengthBuckets": [512, 1024, 5120, 10240, 51200, 102400]
|
||||
}
|
||||
```
|
||||
|
||||
The available options are documented on [npmjs](https://www.npmjs.com/package/express-prometheus-middleware) or the [homepage](https://github.com/joao-fontenele/express-prometheus-middleware#readme) of the express-prometheus-middleware project. You may get a compatible grafana dashboard at [grafana.com](https://grafana.com/grafana/dashboards/14565).
|
||||
|
||||
## Start backend
|
||||
|
||||
Run `npm install` and `npm run build`, then start with `npm start`. The server should now be accepting connections at `http://localhost:3000`.
|
||||
|
||||
# Environment Variables
|
||||
|
||||
To select a database implementation you have to set the `NODE_CONFIG_ENV` variable. At the time only `NODE_CONFIG_ENV=elasticsearch` is supported.
|
||||
Set `NODE_ENV=production` to run backend for production usages. In production the backend expects some kind of monitoring to be set via the
|
||||
environment. At the time only SMTP is being implemented. The backend wouldn't start if you don't provide SMTP authentification. Alternatively
|
||||
you can set `ALLOW_NO_TRANSPORT=true`. To set up an SMTP configuration have a look at
|
||||
[@openstapps/logger](https://gitlab.com/openstapps/logger).
|
||||
|
||||
The list of environment variables includes:
|
||||
|
||||
- `NODE_ENV` when set to `production`, there will be a reduced amount of output from the logger
|
||||
- `PORT` when this is not set, the backend will default to port 3000
|
||||
- `ES_ADDR` the Elasticsearch address, if not set it will default the Elasticsearch address to `http://localhost:9200`
|
||||
- `ALLOW_NO_TRANSPORT` if set to true, the backend will allow starting without an Email configured that receives critical errors.
|
||||
- `ES_DEBUG` setting this to `true` will result in Elasticsearch logging to be **VERY** extensive, in almost all situation this should no be enabled.
|
||||
- `PROMETHEUS_MIDDLEWARE` if set to `true` will enable metrics collection with [Express Prometheus Middleware](https://www.npmjs.com/package/express-prometheus-middleware)
|
||||
|
||||
## Config files
|
||||
|
||||
Each university can have it's specific config for the general backend and app and for all databases.
|
||||
|
||||
All config files can be found in `./config/`. There is a `default.ts` which is used by default. You can create an
|
||||
university specific file with following naming scheme: `default-<university license plate>.ts`
|
||||
|
||||
A university specific file will only overwrite all properties of the `default.ts` that are set in the file itself.
|
||||
To start the backend using your configuration you have to provide the `NODE_APP_INSTANCE` environment variable
|
||||
with your university license plate.
|
||||
|
||||
To set a database you have to provide the `NODE_CONFIG_ENV` environment variable with the name of the database.
|
||||
At the time only Elasticsearch is implemented.
|
||||
|
||||
To create your university specific config file for the elasticsearch you have to create a file with following naming
|
||||
scheme: `elasticsearch-<university license plate>.ts`.
|
||||
|
||||
## Debugging
|
||||
|
||||
Set `ES_DEBUG=true` to enable verbose Elasticsearch tracing information.
|
||||
This can be useful to debug some issues between backend and elasticsearch.
|
||||
|
||||
## [Contributing](https://gitlab.com/openstapps/projectmanagement/blob/master/CONTRIBUTING.md)
|
||||
145
backend/backend/ROUTES.md
Normal file
145
backend/backend/ROUTES.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Routes
|
||||
|
||||
## `POST /bookAvailability` [Book availability route](https://openstapps.gitlab.io/core/classes/_index.d_.scbookavailabilityroute.html)
|
||||
|
||||
**Route for book availability**
|
||||
|
||||
This checks if a book is available in a library.<br>
|
||||
**Example**:
|
||||
|
||||
`POST https://example.com/bookAvailability`
|
||||
|
||||
```json
|
||||
{
|
||||
"isbn": "978-3-16-148410-0"
|
||||
}
|
||||
```
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCBookAvailabilityRequest](https://openstapps.gitlab.io/core/modules/_index.d_.html#scbookavailabilityrequest) |
|
||||
| response | [SCBookAvailabilityResponse](https://openstapps.gitlab.io/core/modules/_index.d_.html#scbookavailabilityresponse) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCNotFoundErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scnotfounderrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
|
||||
## `POST /bulk/:UID` [Bulk add route](https://openstapps.gitlab.io/core/classes/_index.d_.scbulkaddroute.html)
|
||||
|
||||
**Route for indexing SC things in a bulk**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCBulkAddRequest](https://openstapps.gitlab.io/core/modules/_index.d_.html#scbulkaddrequest) |
|
||||
| response | [SCBulkAddResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scbulkaddresponse.html) |
|
||||
| success code | 201 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCNotFoundErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scnotfounderrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
| obligatory parameters | <table><tr><th>parameter</th><th>type</th></tr><tr><td>UID</td><td>[SCUuid](https://openstapps.gitlab.io/core/modules/_index.d_.html#scuuid)</td></tr></table> |
|
||||
|
||||
## `POST /bulk/:UID/done` [Bulk done route](https://openstapps.gitlab.io/core/classes/_index.d_.scbulkdoneroute.html)
|
||||
|
||||
**Route for closing bulks**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCBulkDoneRequest](https://openstapps.gitlab.io/core/interfaces/_index.d_.scbulkdonerequest.html) |
|
||||
| response | [SCBulkDoneResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scbulkdoneresponse.html) |
|
||||
| success code | 204 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCNotFoundErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scnotfounderrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
| obligatory parameters | <table><tr><th>parameter</th><th>type</th></tr><tr><td>UID</td><td>[SCUuid](https://openstapps.gitlab.io/core/modules/_index.d_.html#scuuid)</td></tr></table> |
|
||||
|
||||
## `POST /bulk` [Bulk route](https://openstapps.gitlab.io/core/classes/_index.d_.scbulkroute.html)
|
||||
|
||||
**Route for bulk creation**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCBulkRequest](https://openstapps.gitlab.io/core/interfaces/_index.d_.scbulkrequest.html) |
|
||||
| response | [SCBulkResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scbulkresponse.html) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
|
||||
## `POST /feedback` [Feedback route](https://openstapps.gitlab.io/core/classes/_index.d_.scfeedbackroute.html)
|
||||
|
||||
**Route for feedback submission**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCFeedbackRequest](https://openstapps.gitlab.io/core/interfaces/_index.d_.scfeedbackrequest.html) |
|
||||
| response | [SCFeedbackResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scfeedbackresponse.html) |
|
||||
| success code | 204 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
|
||||
## `POST /` [Index route](https://openstapps.gitlab.io/core/classes/_index.d_.scindexroute.html)
|
||||
|
||||
**Route to request meta information about the deployment**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCIndexRequest](https://openstapps.gitlab.io/core/interfaces/_index.d_.scindexrequest.html) |
|
||||
| response | [SCIndexResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scindexresponse.html) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
|
||||
## `POST /search/multi` [Multi search route](https://openstapps.gitlab.io/core/classes/_index.d_.scmultisearchroute.html)
|
||||
|
||||
**Route for submission of multiple search requests at once**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCMultiSearchRequest](https://openstapps.gitlab.io/core/modules/_index.d_.html#scmultisearchrequest) |
|
||||
| response | [SCMultiSearchResponse](https://openstapps.gitlab.io/core/modules/_index.d_.html#scmultisearchresponse) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCTooManyRequestsErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.sctoomanyrequestserrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
|
||||
## `POST /plugin/register` [Plugin register route](https://openstapps.gitlab.io/core/classes/_index.d_.scpluginregisterroute.html)
|
||||
|
||||
**Route to register plugins**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCPluginRegisterRequest](https://openstapps.gitlab.io/core/modules/_index.d_.html#scpluginregisterrequest) |
|
||||
| response | [SCPluginRegisterResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scpluginregisterresponse.html) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCNotFoundErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scnotfounderrorresponse.html)<br>[SCParametersNotAcceptable](https://openstapps.gitlab.io/core/classes/_index.d_.scparametersnotacceptable.html)<br>[SCPluginAlreadyRegisteredErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scpluginalreadyregisterederrorresponse.html)<br>[SCPluginRegisteringFailedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scpluginregisteringfailederrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html) |
|
||||
|
||||
## `POST /search` [Search route](https://openstapps.gitlab.io/core/classes/_index.d_.scsearchroute.html)
|
||||
|
||||
**Route for searching things**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCSearchRequest](https://openstapps.gitlab.io/core/interfaces/_index.d_.scsearchrequest.html) |
|
||||
| response | [SCSearchResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scsearchresponse.html) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
|
||||
## `PUT /:TYPE/:UID` [Thing update route](https://openstapps.gitlab.io/core/classes/_index.d_.scthingupdateroute.html)
|
||||
|
||||
**Route for updating existing things**
|
||||
|
||||
### Definition
|
||||
|
||||
| parameter | value |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| request | [SCThingUpdateRequest](https://openstapps.gitlab.io/core/modules/_index.d_.html#scthingupdaterequest) |
|
||||
| response | [SCThingUpdateResponse](https://openstapps.gitlab.io/core/interfaces/_index.d_.scthingupdateresponse.html) |
|
||||
| success code | 200 |
|
||||
| errors | [SCInternalServerErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scinternalservererrorresponse.html)<br>[SCMethodNotAllowedErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scmethodnotallowederrorresponse.html)<br>[SCNotFoundErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scnotfounderrorresponse.html)<br>[SCRequestBodyTooLargeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.screquestbodytoolargeerrorresponse.html)<br>[SCSyntaxErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scsyntaxerrorresponse.html)<br>[SCUnsupportedMediaTypeErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scunsupportedmediatypeerrorresponse.html)<br>[SCValidationErrorResponse](https://openstapps.gitlab.io/core/classes/_index.d_.scvalidationerrorresponse.html) |
|
||||
| obligatory parameters | <table><tr><th>parameter</th><th>type</th></tr><tr><td>TYPE</td><td>SCThingTypes</td></tr><tr><td>UID</td><td>[SCUuid](https://openstapps.gitlab.io/core/modules/_index.d_.html#scuuid)</td></tr></table> |
|
||||
2
backend/backend/app.js
Normal file
2
backend/backend/app.js
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
import './lib/cli.js';
|
||||
20
backend/backend/config/b-tu/elasticsearchrc.js
Normal file
20
backend/backend/config/b-tu/elasticsearchrc.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* This is the database configuration for the technical university of berlin
|
||||
*
|
||||
* @type {import('@openstapps/logger').RecursivePartial<import('../../src/storage/elasticsearch/types/elasticsearch-config.js').ElasticsearchConfigFile>}
|
||||
*/
|
||||
const config = {
|
||||
internal: {
|
||||
database: {
|
||||
name: 'elasticsearch',
|
||||
query: {
|
||||
minMatch: '60%',
|
||||
queryType: 'query_string',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
27
backend/backend/config/default/app/index.js
Normal file
27
backend/backend/config/default/app/index.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import userGroupSetting from './user-group-setting.js';
|
||||
import languageSetting from './language-setting.js';
|
||||
import menus from './menu.js';
|
||||
|
||||
/** @type {import('@openstapps/core').SCAppConfiguration} */
|
||||
const app = {
|
||||
aboutPages: {},
|
||||
campusPolygon: {
|
||||
coordinates: [
|
||||
[
|
||||
[8.660_432_999_690_723, 50.123_027_017_044_436],
|
||||
[8.675_496_285_518_358, 50.123_027_017_044_436],
|
||||
[8.675_496_285_518_358, 50.130_661_764_486_42],
|
||||
[8.660_432_999_690_723, 50.130_661_764_486_42],
|
||||
[8.660_432_999_690_723, 50.123_027_017_044_436],
|
||||
],
|
||||
],
|
||||
type: 'Polygon',
|
||||
},
|
||||
features: {},
|
||||
menus,
|
||||
name: 'Goethe-Uni',
|
||||
privacyPolicyUrl: 'https://mobile.server.uni-frankfurt.de/_static/privacy.md',
|
||||
settings: [userGroupSetting, languageSetting],
|
||||
};
|
||||
|
||||
export default app;
|
||||
34
backend/backend/config/default/app/language-setting.js
Normal file
34
backend/backend/config/default/app/language-setting.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// @ts-check
|
||||
import {SCSettingInputType, SCThingOriginType, SCThingType} from '@openstapps/core';
|
||||
|
||||
/** @type {import('@openstapps/core').SCLanguageSetting} */
|
||||
const languageSetting = {
|
||||
categories: ['profile'],
|
||||
defaultValue: 'en',
|
||||
description: 'The language this app is going to use.',
|
||||
inputType: SCSettingInputType.SingleChoice,
|
||||
name: 'language',
|
||||
order: 0,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'SCConfigFile Default Values',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
description: 'Die Sprache in der die App angezeigt wird.',
|
||||
name: 'Sprache',
|
||||
values: ['Deutsch', 'English'],
|
||||
},
|
||||
en: {
|
||||
description: 'The language this app is going to use.',
|
||||
name: 'Language',
|
||||
values: ['Deutsch', 'English'],
|
||||
},
|
||||
},
|
||||
type: SCThingType.Setting,
|
||||
uid: 'dc9d6dec-6576-45ef-9e35-3598c0d6a662',
|
||||
values: ['de', 'en'],
|
||||
};
|
||||
|
||||
export default languageSetting;
|
||||
195
backend/backend/config/default/app/menu.js
Normal file
195
backend/backend/config/default/app/menu.js
Normal file
@@ -0,0 +1,195 @@
|
||||
// @ts-check
|
||||
/** @type {import('@openstapps/core').SCAppConfigurationMenuCategory[]} */
|
||||
const menus = [
|
||||
{
|
||||
icon: 'home',
|
||||
items: [
|
||||
{
|
||||
icon: 'newspaper',
|
||||
route: '/news',
|
||||
title: 'news',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Aktuelles',
|
||||
},
|
||||
en: {
|
||||
title: 'news',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'search',
|
||||
route: '/search',
|
||||
title: 'search',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Suche',
|
||||
},
|
||||
en: {
|
||||
title: 'search',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'local_library',
|
||||
route: '/hebis-search',
|
||||
title: 'library catalog',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Bibliothekskatalog',
|
||||
},
|
||||
en: {
|
||||
title: 'library catalog',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'inventory_2',
|
||||
route: '/catalog',
|
||||
title: 'course catalog',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Vorlesungsverzeichnis',
|
||||
},
|
||||
en: {
|
||||
title: 'course catalog',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
title: 'overview',
|
||||
route: '/overview',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Übersicht',
|
||||
},
|
||||
en: {
|
||||
title: 'overview',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'local_cafe',
|
||||
items: [],
|
||||
route: '/canteen',
|
||||
title: 'canteen',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Mensa',
|
||||
},
|
||||
en: {
|
||||
title: 'canteen',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'map',
|
||||
items: [],
|
||||
route: '/map',
|
||||
title: 'campus map',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Campus Karte',
|
||||
},
|
||||
en: {
|
||||
title: 'campus map',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'school',
|
||||
items: [
|
||||
{
|
||||
icon: 'grade',
|
||||
route: '/favorites',
|
||||
title: 'favorites',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Favoriten',
|
||||
},
|
||||
en: {
|
||||
title: 'favorites',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'calendar_today',
|
||||
route: '/schedule',
|
||||
title: 'schedule',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Stundenplan',
|
||||
},
|
||||
en: {
|
||||
title: 'schedule',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
authProvider: 'paia',
|
||||
icon: 'badge',
|
||||
route: '/library-account',
|
||||
title: 'library account',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Bibliothekskonto',
|
||||
},
|
||||
en: {
|
||||
title: 'library account',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'settings',
|
||||
route: '/settings',
|
||||
title: 'settings',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Einstellungen',
|
||||
},
|
||||
en: {
|
||||
title: 'settings',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'rate_review',
|
||||
route: '/feedback',
|
||||
title: 'feedback',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Feedback',
|
||||
},
|
||||
en: {
|
||||
title: 'feedback',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: 'info',
|
||||
route: '/about',
|
||||
title: 'about',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Über die App',
|
||||
},
|
||||
en: {
|
||||
title: 'About the App',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
title: 'my app',
|
||||
route: '/profile',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Meine App',
|
||||
},
|
||||
en: {
|
||||
title: 'my app',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default menus;
|
||||
40
backend/backend/config/default/app/user-group-setting.js
Normal file
40
backend/backend/config/default/app/user-group-setting.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// @ts-check
|
||||
import {SCSettingInputType, SCThingOriginType, SCThingType} from '@openstapps/core';
|
||||
|
||||
/** @type {import('@openstapps/core').SCUserGroupSetting} */
|
||||
const userGroupSetting = {
|
||||
categories: ['profile'],
|
||||
defaultValue: 'students',
|
||||
description:
|
||||
'The user group the app is going to be used.' +
|
||||
'This settings for example is getting used for the predefined price category of mensa meals.',
|
||||
inputType: SCSettingInputType.SingleChoice,
|
||||
name: 'group',
|
||||
order: 1,
|
||||
origin: {
|
||||
indexed: '2018-09-11T12:30:00Z',
|
||||
name: 'SCConfigFile Default Values',
|
||||
type: SCThingOriginType.Remote,
|
||||
},
|
||||
translations: {
|
||||
de: {
|
||||
description:
|
||||
'Mit welcher Benutzergruppe soll die App verwendet werden?' +
|
||||
' Die Einstellung wird beispielsweise für die Vorauswahl der Preiskategorie der Mensa verwendet.',
|
||||
name: 'Gruppe',
|
||||
values: ['Studierende', 'Angestellte', 'Gäste'],
|
||||
},
|
||||
en: {
|
||||
description:
|
||||
'The user group the app is going to be used.' +
|
||||
' This settings for example is getting used for the predefined price category of mensa meals.',
|
||||
name: 'Group',
|
||||
values: ['students', 'employees', 'guests'],
|
||||
},
|
||||
},
|
||||
type: SCThingType.Setting,
|
||||
uid: '2c97aa36-4aa2-43de-bc5d-a2b2cb3a530e',
|
||||
values: ['students', 'employees', 'guests'],
|
||||
};
|
||||
|
||||
export default userGroupSetting;
|
||||
51
backend/backend/config/default/backend/aggregations.js
Normal file
51
backend/backend/config/default/backend/aggregations.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// @ts-check
|
||||
import {SCThingType} from '@openstapps/core';
|
||||
|
||||
/** @type {import('@openstapps/core').SCBackendAggregationConfiguration[]} */
|
||||
const aggregations = [
|
||||
{
|
||||
fieldName: 'categories',
|
||||
onlyOnTypes: [
|
||||
SCThingType.AcademicEvent,
|
||||
SCThingType.Article,
|
||||
SCThingType.Building,
|
||||
SCThingType.Catalog,
|
||||
SCThingType.Dish,
|
||||
SCThingType.PointOfInterest,
|
||||
SCThingType.Room,
|
||||
],
|
||||
},
|
||||
{
|
||||
fieldName: 'inPlace.name',
|
||||
onlyOnTypes: [
|
||||
SCThingType.DateSeries,
|
||||
SCThingType.Dish,
|
||||
SCThingType.Floor,
|
||||
SCThingType.Organization,
|
||||
SCThingType.PointOfInterest,
|
||||
SCThingType.Room,
|
||||
SCThingType.Ticket,
|
||||
],
|
||||
},
|
||||
{
|
||||
fieldName: 'academicTerms.acronym',
|
||||
onlyOnTypes: [SCThingType.AcademicEvent, SCThingType.SportCourse],
|
||||
},
|
||||
{
|
||||
fieldName: 'academicTerm.acronym',
|
||||
onlyOnTypes: [SCThingType.Catalog],
|
||||
},
|
||||
{
|
||||
fieldName: 'majors',
|
||||
onlyOnTypes: [SCThingType.AcademicEvent],
|
||||
},
|
||||
{
|
||||
fieldName: 'keywords',
|
||||
onlyOnTypes: [SCThingType.Article, SCThingType.Book, SCThingType.Message, SCThingType.Video],
|
||||
},
|
||||
{
|
||||
fieldName: 'type',
|
||||
},
|
||||
];
|
||||
|
||||
export default aggregations;
|
||||
103
backend/backend/config/default/backend/boostings.js
Normal file
103
backend/backend/config/default/backend/boostings.js
Normal file
@@ -0,0 +1,103 @@
|
||||
// @ts-check
|
||||
import {
|
||||
month,
|
||||
sommerRange,
|
||||
ssAcronymLong,
|
||||
ssAcronymShort,
|
||||
winterRange,
|
||||
wsAcronymLong,
|
||||
wsAcronymShort,
|
||||
} from '../tools/semester-acronym.js';
|
||||
import {SCThingType} from '@openstapps/core';
|
||||
|
||||
/** @type {import('@openstapps/core').SCBackendConfigurationSearchBoostingContext} */
|
||||
const boostings = {
|
||||
default: [
|
||||
{
|
||||
factor: 1,
|
||||
fields: {
|
||||
'academicTerms.acronym': {
|
||||
[ssAcronymShort]: sommerRange.includes(month) ? 1.1 : 1.05,
|
||||
[wsAcronymShort]: winterRange.includes(month) ? 1.1 : 1.05,
|
||||
[ssAcronymLong]: sommerRange.includes(month) ? 1.1 : 1.05,
|
||||
[wsAcronymLong]: winterRange.includes(month) ? 1.1 : 1.05,
|
||||
},
|
||||
},
|
||||
type: SCThingType.AcademicEvent,
|
||||
},
|
||||
{
|
||||
factor: 1,
|
||||
fields: {
|
||||
categories: {
|
||||
'course': 1.08,
|
||||
'integrated course': 1.08,
|
||||
'introductory class': 1.05,
|
||||
'lecture': 1.1,
|
||||
'seminar': 1.01,
|
||||
'tutorial': 1.05,
|
||||
},
|
||||
},
|
||||
type: SCThingType.AcademicEvent,
|
||||
},
|
||||
{
|
||||
factor: 1.6,
|
||||
type: SCThingType.Building,
|
||||
},
|
||||
{
|
||||
factor: 1,
|
||||
fields: {
|
||||
categories: {
|
||||
cafe: 1.1,
|
||||
learn: 1.1,
|
||||
library: 1.2,
|
||||
restaurant: 1.1,
|
||||
},
|
||||
},
|
||||
type: SCThingType.PointOfInterest,
|
||||
},
|
||||
{
|
||||
factor: 1,
|
||||
fields: {
|
||||
categories: {
|
||||
'main dish': 2,
|
||||
},
|
||||
},
|
||||
type: SCThingType.Dish,
|
||||
},
|
||||
],
|
||||
dining: [
|
||||
{
|
||||
factor: 1,
|
||||
fields: {
|
||||
categories: {
|
||||
'cafe': 2,
|
||||
'canteen': 2,
|
||||
'restaurant': 2,
|
||||
'restroom': 1.2,
|
||||
'student canteen': 2,
|
||||
},
|
||||
},
|
||||
type: SCThingType.Building,
|
||||
},
|
||||
{
|
||||
factor: 2,
|
||||
type: SCThingType.Dish,
|
||||
},
|
||||
],
|
||||
place: [
|
||||
{
|
||||
factor: 2,
|
||||
type: SCThingType.Building,
|
||||
},
|
||||
{
|
||||
factor: 2,
|
||||
type: SCThingType.PointOfInterest,
|
||||
},
|
||||
{
|
||||
factor: 2,
|
||||
type: SCThingType.Room,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default boostings;
|
||||
73
backend/backend/config/default/backend/index.js
Normal file
73
backend/backend/config/default/backend/index.js
Normal file
@@ -0,0 +1,73 @@
|
||||
// @ts-check
|
||||
import {SCThingType} from '@openstapps/core';
|
||||
import aggregations from './aggregations.js';
|
||||
import boostings from './boostings.js';
|
||||
import {readFile} from 'fs/promises';
|
||||
|
||||
/** @type {import('@openstapps/core').SCBackendInternalConfiguration} */
|
||||
export const internal = {
|
||||
aggregations,
|
||||
boostings,
|
||||
};
|
||||
|
||||
/** @type {import('@openstapps/core').SCBackendConfiguration} */
|
||||
export const backend = {
|
||||
SCVersion: JSON.parse(await readFile('package.json', 'utf8')).version,
|
||||
externalRequestTimeout: 5000,
|
||||
hiddenTypes: [SCThingType.DateSeries, SCThingType.Diff, SCThingType.Floor],
|
||||
mappingIgnoredTags: ['minlength', 'pattern', 'see', 'tjs-format'],
|
||||
maxMultiSearchRouteQueries: 5,
|
||||
maxRequestBodySize: 512 * 1024,
|
||||
name: 'Goethe-Universität Frankfurt am Main',
|
||||
namespace: '909a8cbc-8520-456c-b474-ef1525f14209',
|
||||
sortableFields: [
|
||||
{
|
||||
fieldName: 'name',
|
||||
sortTypes: ['ducet'],
|
||||
},
|
||||
{
|
||||
fieldName: 'type',
|
||||
sortTypes: ['ducet'],
|
||||
},
|
||||
{
|
||||
fieldName: 'categories',
|
||||
onlyOnTypes: [
|
||||
SCThingType.AcademicEvent,
|
||||
SCThingType.Building,
|
||||
SCThingType.Catalog,
|
||||
SCThingType.Dish,
|
||||
SCThingType.PointOfInterest,
|
||||
SCThingType.Room,
|
||||
],
|
||||
sortTypes: ['ducet'],
|
||||
},
|
||||
{
|
||||
fieldName: 'geo',
|
||||
onlyOnTypes: [SCThingType.Building, SCThingType.PointOfInterest, SCThingType.Room],
|
||||
sortTypes: ['distance'],
|
||||
},
|
||||
{
|
||||
fieldName: 'geo',
|
||||
onlyOnTypes: [SCThingType.Building, SCThingType.PointOfInterest, SCThingType.Room],
|
||||
sortTypes: ['distance'],
|
||||
},
|
||||
{
|
||||
fieldName: 'inPlace.geo',
|
||||
onlyOnTypes: [
|
||||
SCThingType.DateSeries,
|
||||
SCThingType.Dish,
|
||||
SCThingType.Floor,
|
||||
SCThingType.Organization,
|
||||
SCThingType.PointOfInterest,
|
||||
SCThingType.Room,
|
||||
SCThingType.Ticket,
|
||||
],
|
||||
sortTypes: ['distance'],
|
||||
},
|
||||
{
|
||||
fieldName: 'offers',
|
||||
onlyOnTypes: [SCThingType.Dish],
|
||||
sortTypes: ['price'],
|
||||
},
|
||||
],
|
||||
};
|
||||
26
backend/backend/config/default/backendrc.js
Normal file
26
backend/backend/config/default/backendrc.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// @ts-check
|
||||
import app from './app/index.js';
|
||||
import {backend, internal} from './backend/index.js';
|
||||
|
||||
/**
|
||||
* This is the default configuration for app and backend
|
||||
*
|
||||
* University-specific files can be created with the following naming scheme: default-<university license plate>.ts
|
||||
*
|
||||
* To select your university-specific configuration which is merged from this default file and your university-specific
|
||||
* file, you have to supply the `NODE_APP_INSTANCE` environment variable with your license plate
|
||||
*
|
||||
* To get more information about the meaning of specific fields, please have a look at `@openstapps/core` or use your
|
||||
* IDE to read the TSDoc documentation.
|
||||
*
|
||||
* @type {import('@openstapps/core').SCConfigFile}
|
||||
*/
|
||||
const config = {
|
||||
app,
|
||||
auth: {},
|
||||
backend,
|
||||
internal,
|
||||
uid: 'f-u',
|
||||
};
|
||||
|
||||
export default config;
|
||||
33
backend/backend/config/default/elasticsearchrc.js
Normal file
33
backend/backend/config/default/elasticsearchrc.js
Normal file
@@ -0,0 +1,33 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* This is the default configuration for elasticsearch (a database)
|
||||
*
|
||||
* To select your university-specific configuration which is merged from this default file and your university-specific
|
||||
* file, you have to supply the `NODE_APP_INSTANCE` environment variable with your license plate
|
||||
*
|
||||
* To select a different database, you have to supply the `NODE_CONFIG_ENV` environment variable with a database name
|
||||
* that is implemented in the backend
|
||||
*
|
||||
* To get more information about the meaning of specific fields, please use your IDE to read the TSDoc documentation.
|
||||
*
|
||||
* @type {import('../../src/storage/elasticsearch/types/elasticsearch-config.js')}
|
||||
*/
|
||||
const config = {
|
||||
internal: {
|
||||
database: {
|
||||
name: 'elasticsearch',
|
||||
version: '5.6',
|
||||
query: {
|
||||
minMatch: '75%',
|
||||
queryType: 'dis_max',
|
||||
matchBoosting: 1.3,
|
||||
fuzziness: 'AUTO',
|
||||
cutoffFrequency: 0,
|
||||
tieBreaker: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
9
backend/backend/config/default/prometheusrc.json
Normal file
9
backend/backend/config/default/prometheusrc.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"metricsPath": "/metrics",
|
||||
"includeMethod": true,
|
||||
"includePath": true,
|
||||
"promClient": {
|
||||
"collectDefaultMetrics": {}
|
||||
},
|
||||
"for-more-options-see": "https://github.com/jochen-schweizer/express-prom-bundle#options"
|
||||
}
|
||||
29
backend/backend/config/default/tools/markdown.js
Normal file
29
backend/backend/config/default/tools/markdown.js
Normal file
@@ -0,0 +1,29 @@
|
||||
// @ts-check
|
||||
import {readFile} from 'fs/promises';
|
||||
import {SCAboutPageContentType} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
*
|
||||
* ```js
|
||||
* await markdown('./page.md', import.meta.url)
|
||||
* ```
|
||||
*
|
||||
* @param {string} path relative path to the file, omitting the language marker
|
||||
* @param {string | URL} base base path, usually import.meta.url
|
||||
* @returns {Promise<import('@openstapps/core').SCAboutPageMarkdown>}
|
||||
*/
|
||||
export async function markdown(path, base) {
|
||||
const de = await readFile(new URL(path.replace(/\.md$/, '.de.md'), base), 'utf8');
|
||||
const en = await readFile(new URL(path.replace(/\.md$/, '.en.md'), base), 'utf8');
|
||||
|
||||
return {
|
||||
value: de,
|
||||
translations: {
|
||||
en: {
|
||||
value: en,
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.MARKDOWN,
|
||||
};
|
||||
}
|
||||
34
backend/backend/config/default/tools/semester-acronym.js
Normal file
34
backend/backend/config/default/tools/semester-acronym.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// @ts-check
|
||||
/**
|
||||
* Generates a range of numbers that represent consecutive calendar months
|
||||
*
|
||||
* @param {number} startMonth The month to start with (inclusive)
|
||||
* @param {number} endMonth The month to end with (inclusive)
|
||||
* @returns {number[]}
|
||||
*/
|
||||
export function yearSlice(startMonth, endMonth) {
|
||||
let months = [...Array.from({length: 13}).keys()].slice(1);
|
||||
months = [...months, ...months];
|
||||
if (!months.includes(startMonth) || !months.includes(endMonth)) {
|
||||
throw new Error(`Given months not part of a year! Check ${startMonth} or ${endMonth}!`);
|
||||
}
|
||||
|
||||
const startIndex = months.indexOf(startMonth);
|
||||
const endIndex =
|
||||
months.indexOf(endMonth) <= startIndex ? months.lastIndexOf(endMonth) : months.indexOf(endMonth);
|
||||
|
||||
return months.slice(startIndex, endIndex + 1);
|
||||
}
|
||||
|
||||
export const sommerRange = yearSlice(3, 8);
|
||||
export const winterRange = yearSlice(9, 2);
|
||||
export const month = new Date().getMonth();
|
||||
export const year = new Date().getFullYear();
|
||||
export const winterYearOffset = month < winterRange[0] ? -1 : 0;
|
||||
export const sommerYear = year + (month <= winterRange[winterRange.length] ? -1 : 0);
|
||||
export const winterYear = `${year + winterYearOffset}/${(year + 1 + winterYearOffset).toString().slice(-2)}`;
|
||||
|
||||
export const wsAcronymShort = `WS ${winterYear}`;
|
||||
export const ssAcronymShort = `SS ${sommerYear}`;
|
||||
export const wsAcronymLong = `WiSe ${winterYear}`;
|
||||
export const ssAcronymLong = `SoSe ${sommerYear}`;
|
||||
7
backend/backend/config/f-u/about-pages/about.de.md
Normal file
7
backend/backend/config/f-u/about-pages/about.de.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Open StApps bietet Studierenden aller beteiligten Hochschulen eine qualitativ
|
||||
hochwertige App für den Studienalltag. Open StApps-Verbundpartner integrieren
|
||||
generalisierbare Studierendenprozesse so in App-Module, dass diese auch
|
||||
von anderen Hochschulen verwendet werden können. Die in der Open StApps App
|
||||
verwendeten Daten einer Datenquelle sind in einem generalisierten Datenmodell
|
||||
so aufbereitet, dass ein Austausch oder Abschaltung der Datenquelle problemlos möglich
|
||||
ist und die Open StApps App problemlos weiterhin funktionsfähig bleibt.
|
||||
6
backend/backend/config/f-u/about-pages/about.en.md
Normal file
6
backend/backend/config/f-u/about-pages/about.en.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Open StApps provides students from all participating universities with a
|
||||
high-quality app for everyday study. Open StApps partners integrate
|
||||
generalizable student processes into app modules in such a way that they can be
|
||||
used by other universities. The data of a data source used in the Open StApps app
|
||||
is prepared in a generalized data model in a way that the data source can be easily
|
||||
exchanged or switched off while the app continues to function without any problems.
|
||||
126
backend/backend/config/f-u/about-pages/about.js
Normal file
126
backend/backend/config/f-u/about-pages/about.js
Normal file
@@ -0,0 +1,126 @@
|
||||
// @ts-check
|
||||
import {SCAboutPageContentType} from '@openstapps/core';
|
||||
import {markdown} from '../../default/tools/markdown.js';
|
||||
|
||||
/** @type {import('@openstapps/core').SCAboutPage} */
|
||||
export const about = {
|
||||
title: 'Über Open StApps',
|
||||
content: [
|
||||
{
|
||||
title: 'Verbundprojekt mehrerer Hochschulen für eine generische Studierenden-App',
|
||||
content: await markdown('./about.md', import.meta.url),
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Collaborative project of multiple universities for a single generic study app',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.SECTION,
|
||||
},
|
||||
{
|
||||
title: 'Goethe-Uni Kontakt',
|
||||
content: {
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
value: 'Adresse',
|
||||
translations: {
|
||||
en: {
|
||||
value: 'Address',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.MARKDOWN,
|
||||
},
|
||||
{
|
||||
// language=Markdown
|
||||
value:
|
||||
'Goethe Universität<br>' +
|
||||
'Hochschulrechenzentrum (HRZ)<br>' +
|
||||
'Norbert-Wollheim-Platz 1<br>' +
|
||||
'60629 Frankfurt',
|
||||
translations: {},
|
||||
type: SCAboutPageContentType.MARKDOWN,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
value: 'Kontaktinformation',
|
||||
translations: {
|
||||
en: {
|
||||
value: 'Contact information',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.MARKDOWN,
|
||||
},
|
||||
{
|
||||
// language=Markdown
|
||||
value:
|
||||
'[app@rz.uni-frankfurt.de](mailto:app@rz.uni-frankfurt.de)<br>' +
|
||||
'[+49 69 798 32936](tel:+496979832936)<br>' +
|
||||
'[https://app.rz.uni-frankfurt.de](https://app.rz.uni-frankfurt.de)',
|
||||
translations: {},
|
||||
type: SCAboutPageContentType.MARKDOWN,
|
||||
},
|
||||
],
|
||||
],
|
||||
type: SCAboutPageContentType.TABLE,
|
||||
},
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Goethe-Uni Contact',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.SECTION,
|
||||
},
|
||||
{
|
||||
icon: 'newspaper',
|
||||
title: 'Neue Funktionen / Gelöste Probleme',
|
||||
link: 'changelog',
|
||||
translations: {
|
||||
en: {
|
||||
title: 'New features / Resolved issues',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.ROUTER_LINK,
|
||||
},
|
||||
{
|
||||
icon: 'description',
|
||||
title: 'Impressum',
|
||||
link: 'imprint',
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Imprint',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.ROUTER_LINK,
|
||||
},
|
||||
{
|
||||
icon: 'policy',
|
||||
title: 'Datenschutz',
|
||||
link: 'privacy',
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Privacy policy',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.ROUTER_LINK,
|
||||
},
|
||||
{
|
||||
icon: 'copyright',
|
||||
title: 'Bibliotheken und Lizenzen',
|
||||
link: 'licenses',
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Libraries and licenses',
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.ROUTER_LINK,
|
||||
},
|
||||
],
|
||||
translations: {
|
||||
en: {
|
||||
title: 'About Open StApps',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default about;
|
||||
27
backend/backend/config/f-u/about-pages/imprint.js
Normal file
27
backend/backend/config/f-u/about-pages/imprint.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// @ts-check
|
||||
import {SCAboutPageContentType} from '@openstapps/core';
|
||||
|
||||
/** @type {import('@openstapps/core').SCAboutPage} */
|
||||
export const imprint = {
|
||||
title: 'Impressum',
|
||||
content: [
|
||||
{
|
||||
// language=Markdown
|
||||
value: `[Impressum der Johann Wolfgang Goethe-Universität Frankfurt am Main](https://www.uni-frankfurt.de/impressum)`,
|
||||
translations: {
|
||||
en: {
|
||||
// language=Markdown
|
||||
value: `[Imprint of the Goethe University Frankfurt](https://www.uni-frankfurt.de/impressum)`,
|
||||
},
|
||||
},
|
||||
type: SCAboutPageContentType.MARKDOWN,
|
||||
},
|
||||
],
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Imprint',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default imprint;
|
||||
13
backend/backend/config/f-u/about-pages/index.js
Normal file
13
backend/backend/config/f-u/about-pages/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
// @ts-check
|
||||
import about from './about.js';
|
||||
import imprint from './imprint.js';
|
||||
import privacy from './privacy.js';
|
||||
|
||||
/** @type {import('@openstapps/core').SCMap<import('@openstapps/core').SCAboutPage>} */
|
||||
const aboutPages = {
|
||||
'about': about,
|
||||
'about/imprint': imprint,
|
||||
'about/privacy': privacy,
|
||||
};
|
||||
|
||||
export default aboutPages;
|
||||
166
backend/backend/config/f-u/about-pages/privacy.de.md
Normal file
166
backend/backend/config/f-u/about-pages/privacy.de.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Datenschutzerklärung
|
||||
|
||||
## Kontaktdaten des Verantwortlichen
|
||||
|
||||
Verantwortlich im Sinne der Datenschutz-Grundverordnung und weiterer Vorschriften zum Datenschutz ist die:
|
||||
|
||||
Johann Wolfgang Goethe-Universität Frankfurt am Main vertreten durch ihren Präsidenten<br />
|
||||
Theodor-W.-Adorno-Platz 1<br />
|
||||
60323 Frankfurt am Main
|
||||
|
||||
Postanschrift:<br />
|
||||
Goethe-Universität Frankfurt am Main<br />
|
||||
60629 Frankfurt
|
||||
|
||||
Website: http://www.uni-frankfurt.de
|
||||
|
||||
## Kontaktdaten der Datenschutzbeauftragten an der Goethe-Universität
|
||||
|
||||
Sie erreichen die behördlichen Datenschutzbeauftragten der Johann Wolfgang Goethe-Universität Frankfurt am Main unter:<br />
|
||||
Mail: <dsb@uni-frankfurt.de><br />
|
||||
Website: http://www.uni-frankfurt.de/47859992/datenschutzbeauftragte
|
||||
|
||||
## Informationen zur Verarbeitung personenbezogener Daten
|
||||
|
||||
### <u>1. Umfang der Verarbeitung personenbezogener Daten</u>
|
||||
|
||||
Personenbezogene Daten sind gemäß Artikel 4 DSGVO alle Informationen, die sich auf eine identifizierte oder identifizierbare natürliche Person beziehen.
|
||||
|
||||
Wir verarbeiten personenbezogene Daten von Ihnen als Nutzer:innen der Goethe-Uni-App, soweit dies zur Bereitstellung einer **funktionsfähigen Applikation** technisch erforderlich ist.
|
||||
|
||||
Weiterhin kann eine Datenverarbeitung auf Ihrer freiwilligen Einwilligung basieren, wenn Sie **spezifische Funktionen** nutzen möchten.
|
||||
|
||||
Wir unterscheiden daher nachfolgend zwischen
|
||||
|
||||
- Zugriffsdaten bei der Nutzung der App: Inhalt der Anfragen, IP-Adressen, Datum/Uhrzeit der Anfrage, Angefragte URL, Fehlermeldungen, Browser-Kennung, HTTP-Header
|
||||
|
||||
- Standortbestimmung und Navigation: freiwillige Standortangaben
|
||||
|
||||
- Nutzer:inneneinstellungen: freiwillige Angabe von a) Sprachpräferenzen (derzeit: deutsch/englisch), b) Status (z. B. Gast/Student) oder c) spezifischen Suchanfragen und Suchergebnissen (Notifications)
|
||||
|
||||
- Kalenderfunktion: freiwillige Nutzung der Kalenderfunktion (optional mit freiwilliger Nutzung einer Synchronisationsfunktion: Opt-in) oder der integrierten Stundenplanfunktion, hierbei werden folgende Daten auf dem Endgerät verarbeitet und gespeichert: Termine und Veranstaltungen
|
||||
|
||||
- Feedbackfunktion und Kontaktaufnahme: freiwillige Nutzung mit der Angabe von Kontaktdaten und ggf. freiwilliger Übermittlung von Protokolldaten
|
||||
|
||||
- Campus Dienste: freiwillige Nutzung mit Verarbeitung von Notenansicht, Matrikelnummer, E-Mailadresse, Name
|
||||
|
||||
- Funktionen der Bibliothek: freiwillige Nutzung mit Verarbeitung von Bibliothekskontodaten, wie z.B. Ausweisnummer mit Name, E-Mailadresse, postalischer Adresse, Nutzungsberechtigung, Bestelldaten, Gebühren, Vormerkung, Ausleihdaten. Die vollständigen Angaben zur Verarbeitung finden Sie in der Datenschutzerklärung der Bibliothek:<br />
|
||||
https://www.ub.uni-frankfurt.de/benutzung/datenschutz.html
|
||||
|
||||
Die App verlinkt an einigen Stellen auf die Website der Goethe-Universität sowie auf andere, externe Websites, die in einem In-App-Browser dargestellt werden. Wir bitten Sie bei Aufruf dieser Websites, die dort geltenden gesonderte Datenschutzhinweise und Erklärungen zu beachten.
|
||||
|
||||
### <u>2. Zweck(e) der Datenverarbeitung</u>
|
||||
|
||||
**Zugriff auf Standortdaten**
|
||||
|
||||
Für die Navigation benötigt die Goethe-Uni-App Zugriff auf den Standort des verwendeten Endgerätes (Location Based Services). Bei einer Anfrage erhebt die App den aktuellen Standort über GPS, Funkzellendaten und WLAN-Datenbanken, um Ihnen als Nutzer:in Informationen zu Ihrer unmittelbaren Umgebung geben zu können. Der Zugriff auf die Standortdaten erfolgt nur, wenn Sie den Zugriff auf die Standortdaten erlauben. Daten zu Ihrem Standort werden ausschließlich für die Bearbeitung von standortbezogenen Anfragen genutzt und um Ihren Standort auf der Karte anzuzeigen.
|
||||
|
||||
**Zugriff auf Zugriffsdaten**
|
||||
|
||||
Die Speicherung und Verarbeitung von Protokolldateien erfolgt, um die Funktionsfähigkeit der Goethe Uni-App für Sie sicherzustellen. Zudem benötigen wir die die Daten aus Gründen der Sicherheit unserer informationstechnischen Systeme. Eine anderweitige Auswertung oder Weitergabe findet in diesem Zusammenhang nicht statt.
|
||||
|
||||
**Zugriff auf Spracheinstellungen**
|
||||
|
||||
Der Zugriff auf die Spracheinstellung erfolgt um Ihnen die Oberfläche der App in der von Ihnen gewünschten Sprache anzuzeigen.
|
||||
|
||||
**Zugriff auf die Einstellung der Statusgruppe**
|
||||
|
||||
Der Zugriff auf die Einstellung der Statusgruppe erfolgt um Ihnen in der App die für Ihre Gruppe zutreffenden Informationen anzuzeigen, z.B. Mensapreise
|
||||
|
||||
**Zugriff auf personenbezogene Daten bei der Nutzung der Feedbackfunktion**
|
||||
|
||||
Die Verarbeitung der personenbezogenen Daten aus der Feedbackfunktion dient uns zur Kontaktaufnahme und Fehlerbehebung.
|
||||
|
||||
**Zugriff auf personenbezogene Daten bei der Kalendersynchronisation**
|
||||
|
||||
Der Zugriff auf die Termindaten erfolgt um sie bei aktivierter Kalenderfunktion in den Gerätekalender zu schreiben.
|
||||
|
||||
**Zugriff auf Daten der Campus Dienste**
|
||||
|
||||
Der Zugriff auf das Campus Management Systems erfolgt ausschließlich um persönliche Daten der Studierendenverwaltung in der App anzuzeigen (z.B. Prüfungsnoten).
|
||||
|
||||
**Zugriff auf bibliotheksspezifische personenbezogene Daten**
|
||||
|
||||
Der Zugriff auf die Daten (z.B. Ausweisnummer, Name, Postanschrift) erfolgt zur Durchführung von Bestell- und Ausleihverfahren von Büchern und sonstigen Materialien der Universitätsbibliothek. Die vollständigen Angaben zu den Verarbeitungszwecken finden Sie in der Datenschutzerklärung der Bibliothek: https://www.ub.uni-frankfurt.de/benutzung/datenschutz.html
|
||||
|
||||
### <u>3. Rechtsgrundlage(n) für die Datenverarbeitung</u>
|
||||
|
||||
Die Nutzung der Nutzungs-/Zugriffsdaten („Protokolldateien") basiert auf Artikel 6 Absatz 1 lit. f) DSGVO.
|
||||
|
||||
Für alle spezifischen Funktionen, bei denen die Datenverarbeitung auf Ihrer freiwilligen Einwilligung als Nutzer:innen basiert, werden explizit Einwilligungen bzw. aktive Zustimmungsakte („Opt-In") eingeholt. Die Bereitstellung personenbezogener Daten zu Ihrer Person gegenüber der Goethe-Universität erfolgen dabei auf freiwilliger Basis. Die Rechtsgrundlage ist in diesen Fällen jeweils Artikel 6 Absatz 1 lit. a) DSGVO. Sie können Ihre jeweilige Einwilligung jederzeit einzeln widerrufen bzw. Ihre Einstellungen ändern.
|
||||
|
||||
### <u>4. Datenlöschung und Speicherdauer</u>
|
||||
|
||||
Die in den Protokolldateien der App erfassten Daten werden sieben Tage nach dem Ende des Zugriffs automatisch gelöscht oder anonymisiert.
|
||||
|
||||
Die Löschfristen bzw. Speicherdauer der in den Bibliotheksystemen erfassten Daten finden Sie in der Datenschutzerklärung der Bibliothek: https://www.ub.uni-frankfurt.de/benutzung/datenschutz.html
|
||||
|
||||
Für alle anderen Funktionen und Dienste gilt: Die Löschung erfolgt hier je nach Vorgabe des genutzten Dienstes. Die personenbezogenen Daten der betroffenen Person werden gelöscht oder gesperrt, sobald der Zweck der Speicherung entfällt.
|
||||
|
||||
### <u>5. Datenweitergabe/Datenübermittlung</u>
|
||||
|
||||
Ihre personenbezogenen Daten werden von uns nicht an Dritte weitergegeben.
|
||||
|
||||
Von Betreiberseite wird durch technische und organisatorische Maßnahmen sichergestellt, dass Dritte keinen Zugriff auf die verarbeiteten Daten, wie z. B. Nutzungsdaten, erhalten. Ein Auftragsverarbeitungsverhältnis nach Art. 28 DSGVO besteht nicht, da ausschließlich eigene Server verwendet werden.
|
||||
|
||||
### <u>6. Automatisierte Entscheidungsfindung</u>
|
||||
|
||||
Eine automatisierte Entscheidungsfindung einschließlich Profiling erfolgt nicht.
|
||||
|
||||
## Rechte der betroffenen Person
|
||||
|
||||
Werden personenbezogene Daten von Ihnen verarbeitet, sind Sie Betroffener im Sinne der DSGVO. Die Geltendmachung Ihrer Betroffenenrechte ist kostenfrei. Sie können sich dafür selbstverständlich an uns wenden. Es stehen Ihnen folgende Betroffenenrechte gegenüber der Goethe-Universität zu:
|
||||
|
||||
### <u>1. Auskunftsrecht</u>
|
||||
|
||||
Sie können von uns als verantwortlicher Stelle eine Bestätigung darüber verlangen, ob und welche Ihrer personenbezogenen Daten von uns verarbeitet werden. Sie haben das Recht, von uns Kopien Ihrer personenbezogenen Daten zu verlangen. Bitte beachten Sie die Ausnahmen, die sich durch spezifische Vorschriften ergeben können.
|
||||
|
||||
### <u>2. Recht auf Berichtigung</u>
|
||||
|
||||
Sie haben das Recht von uns die Berichtigung und/oder Vervollständigung zu verlangen, sofern die verarbeiteten personenbezogenen Daten, die Sie betreffen, nicht (mehr) richtig oder nicht (mehr) vollständig sind.
|
||||
|
||||
### <u>3. Recht auf Einschränkung der Verarbeitung</u>
|
||||
|
||||
Unter bestimmten Voraussetzungen können Sie die Einschränkung der Verarbeitung der Sie betreffenden personenbezogenen Daten verlangen, d. h. dass dann Ihre personenbezogenen Daten zwar nicht gelöscht, aber gekennzeichnet werden, so dass eine weitere Verarbeitung eingeschränkt ist.
|
||||
|
||||
### <u>4. Recht auf Löschung</u>
|
||||
|
||||
Sie können unter bestimmten Voraussetzungen von uns verlangen, dass die Sie betreffenden personenbezogenen Daten unverzüglich gelöscht werden. Dies ist insbesondere der Fall, wenn die personenbezogenen Daten zu dem Zweck, zu dem sie ursprünglich erhoben oder verarbeitet wurden, nicht mehr erforderlich sind.
|
||||
|
||||
### <u>5. Recht auf Unterrichtung</u>
|
||||
|
||||
Haben Sie das Recht auf Berichtigung, Löschung oder Einschränkung der Verarbeitung uns gegenüber geltend gemacht, sind wir verpflichtet, allen Empfänger/innen, denen die Sie betreffenden personenbezogenen Daten offengelegt wurden, diese Berichtigung oder Löschung der Daten oder Einschränkung der Verarbeitung mitzuteilen, es sei denn, dies erweist sich als unmöglich oder ist mit einem unverhältnismäßigen Aufwand verbunden. Sie sind berechtigt, über diese Empfänger unterrichtet zu werden.
|
||||
|
||||
### <u>6. Recht auf Datenübertragbarkeit</u>
|
||||
|
||||
Sie haben unter bestimmten Voraussetzungen das Recht von uns zu verlangen, dass Ihre personenbezogenen Daten von uns direkt an einen anderen Verantwortlichen oder an eine andere Organisation übermittelt werden. Alternativ haben Sie unter bestimmten Voraussetzungen das Recht von uns zu verlangen, dass wir Ihnen selbst die Daten in einem maschinenlesbaren Format bereitstellen.
|
||||
|
||||
### <u>7. Widerspruchsrecht</u>
|
||||
|
||||
Wenn wir Ihre personenbezogenen Daten verarbeiten, weil die Verarbeitung im öffentlichen Interesse, Teil unserer öffentlichen Aufgaben ist bzw. wenn wir Ihre Daten auf Basis eines berechtigten Interesses verarbeiten, haben Sie aus Gründen, die sich aus Ihrer besonderen Situation ergeben, das Recht, jederzeit der Verarbeitung der Sie betreffenden Daten zu widersprechen.
|
||||
|
||||
### <u>8. Recht auf Widerruf der datenschutzrechtlichen Einwilligungserklärung</u>
|
||||
|
||||
Wenn wir Ihre personenbezogenen Daten verarbeiten, weil Sie uns Ihre Einwilligung gegeben haben, haben Sie jederzeit das Recht, Ihre Einwilligungserklärung zu widerrufen.
|
||||
|
||||
### <u>9. Recht auf Beschwerde bei einer Aufsichtsbehörde</u>
|
||||
|
||||
Sie haben ferner das Recht auf Beschwerde bei einer Aufsichtsbehörde. Die zuständige Aufsichtsbehörde wird Ihre Beschwerde prüfen.
|
||||
|
||||
## **Kontaktdaten der Aufsichtsbehörde im Bereich Datenschutz**
|
||||
|
||||
Wenn Sie der Ansicht sind, dass eine Verarbeitung der Sie betreffenden personenbezogenen Daten gegen Datenschutzvorschriften verstößt, wenn Sie eine allgemeine Anfrage haben oder wenn Sie sich bei einer zuständigen Fachaufsichtsbehörde beschweren wollen, können Sie sich an den Hessischen Beauftragten für Datenschutz und Informationsfreiheit (HBDI) wenden.
|
||||
|
||||
**Der Hessische Beauftragte für Datenschutz und Informationsfreiheit ist auf unterschiedlichen Wegen erreichbar:**
|
||||
|
||||
<u>**Der Hessische Beauftragte für Datenschutz und Informationsfreiheit**</u><br />
|
||||
Postfach 3163<br />
|
||||
65021 Wiesbaden
|
||||
|
||||
Telefon: +49 611 1408 -- 0
|
||||
|
||||
Für allgemeine Anfragen können Sie ein Kontaktformular nutzen:<br />
|
||||
<https://datenschutz.hessen.de/kontakt><br />
|
||||
<br />
|
||||
Für Beschwerden steht Ihnen zudem ein Beschwerdeformular zur Verfügung:<br />
|
||||
<https://datenschutz.hessen.de/service/beschwerde-uebermitteln>
|
||||
166
backend/backend/config/f-u/about-pages/privacy.en.md
Normal file
166
backend/backend/config/f-u/about-pages/privacy.en.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Privacy policy
|
||||
|
||||
## Contact details of the person responsible
|
||||
|
||||
Responsible in the sense of the General Data Protection Regulation and further regulations on data protection is the:
|
||||
|
||||
Johann Wolfgang Goethe-Universität Frankfurt am Main represented by its president<br />
|
||||
Theodor-W.-Adorno-Platz 1<br />
|
||||
60323 Frankfurt am Main
|
||||
|
||||
Postanschrift:<br />
|
||||
Goethe-Universität Frankfurt am Main<br />
|
||||
60629 Frankfurt
|
||||
|
||||
Website: http://www.uni-frankfurt.de
|
||||
|
||||
## Contact details of the data protection officer at Goethe University
|
||||
|
||||
You can reach the data protection officers at Johann Wolfgang Goethe University Frankfurt am Main at:<br />
|
||||
Mail: <dsb@uni-frankfurt.de><br />
|
||||
Website: http://www.uni-frankfurt.de/47859992/datenschutzbeauftragte
|
||||
|
||||
## Information on the processing of personal data
|
||||
|
||||
### <u>1. Scope of the processing of personal data</u>.
|
||||
|
||||
According to Article 4 DSGVO, personal data is any information relating to an identified or identifiable natural person.
|
||||
|
||||
We process personal data of you as a user inside of the Goethe University App to the extent that this is technically necessary for the provision of a **functional application**.
|
||||
|
||||
Furthermore, data processing may be based on your voluntary consent if you wish to use **specific functions**.
|
||||
|
||||
We therefore distinguish below between
|
||||
|
||||
- Access data when using the app: content of requests, IP addresses, date/time of request, requested URL, error codes, browser identifier, HTTP header.
|
||||
|
||||
- Location and navigation: voluntary location information
|
||||
|
||||
- User settings: voluntary specification of a) language preferences (currently: German/English), b) status (e.g. guest/student) or c) specific search queries and search results (notifications)
|
||||
|
||||
- Calendar function: voluntary use of the calendar function (optional with voluntary use of a sync function: opt-in) or the integrated timetable function. The following data is processed and stored on the users device: appointments and events
|
||||
|
||||
- Feedback function and contacting: voluntary use with the provision of contact data and, if applicable, voluntary transmission of log data
|
||||
|
||||
- Campus services: voluntary use with processing of grade view, matriculation number, email address, name
|
||||
|
||||
- Services of the library: voluntary use with processing of library account data, such as ID number with name, e-mail address, postal address, right of use, order data, fees, reservation, loan data. Full details of processing can be found in the library's privacy policy:<br />
|
||||
https://www.ub.uni-frankfurt.de/benutzung/datenschutz.html
|
||||
|
||||
In some places, the app links to the Goethe University website and to other external websites that are displayed in an in-app browser. When you visit these websites, we ask you to pay attention to the separate data protection notices and declarations that apply there.
|
||||
|
||||
### <u>2. Purpose(s) of data processing</u>
|
||||
|
||||
**Access to location data**.
|
||||
|
||||
For navigation, the Goethe University app requires access to the location of the end device used (location-based services). When a request is made, the app collects the current location via GPS, radio cell data and WLAN databases in order to be able to give you as a user:in information about your immediate surroundings. The location data is only accessed if you allow access to the location data. Data about your location is only used to process location-related requests and to display your location on the map.
|
||||
|
||||
**Access to access data**.
|
||||
|
||||
Log files are stored and processed to ensure that the Goethe Uni app functions properly for you. In addition, we need the data for reasons of security of our information technology systems. No other evaluation or disclosure takes place in this context.
|
||||
|
||||
**Access to language settings**.
|
||||
|
||||
Access to the language setting is made in order to display the interface of the app in the language of your choice.
|
||||
|
||||
**Access to the status group setting**.
|
||||
|
||||
Access to the status group setting is provided to show you the information in the app that applies to your group, e.g. canteen prices.
|
||||
|
||||
**Access to personal data when using the feedback function**.
|
||||
|
||||
We use the processing of personal data from the feedback function to contact you and troubleshoot problems.
|
||||
|
||||
**Access to personal data when synchronizing calendars**.
|
||||
|
||||
Appointment data is accessed in order to write it to the device calendar when the calendar function is enabled.
|
||||
|
||||
**Access to Campus Services data**.
|
||||
|
||||
Access to the Campus Management System is solely for the purpose of displaying personal student management data in the app (e.g., exam grades).
|
||||
|
||||
**Access to library-specific personal data**.
|
||||
|
||||
Access to data (e.g., ID number, name, mailing address) is for the purpose of carrying out ordering and borrowing procedures for books and other materials from the University Library. Full details of the purposes of processing can be found in the Library's Privacy Policy: https://www.ub.uni-frankfurt.de/benutzung/datenschutz.html
|
||||
|
||||
### <u>3. Rechtsgrundlage(n) für die Datenverarbeitung</u>
|
||||
|
||||
The use of usage/access data ("log files") is based on Article 6(1)(f) DSGVO.
|
||||
|
||||
For all specific functions where data processing is based on your voluntary consent as a user:in, explicit consent or active acts of consent ("opt-in") are obtained. The provision of personal data about you to Goethe University is done on a voluntary basis. The legal basis in each of these cases is Article 6 (1) a) DSGVO. You can individually revoke your respective consent or change your settings at any time.
|
||||
|
||||
### <u>4. Data deletion and storage duration</u>
|
||||
|
||||
The data collected in the log files of the app are automatically deleted or anonymized seven days after the end of the access.
|
||||
|
||||
The deletion periods or storage duration of the data collected in the library systems can be found in the library's privacy policy: https://www.ub.uni-frankfurt.de/benutzung/datenschutz.html
|
||||
|
||||
For all other functions and services, the following applies: deletion takes place here depending on the specifications of the service used. The personal data of the data subject will be deleted or blocked as soon as the purpose of the storage no longer applies.
|
||||
|
||||
### <u>5. Data disclosure/data transfer</u>
|
||||
|
||||
We will not pass on your personal data to third parties.
|
||||
|
||||
On the part of the operator, technical and organizational measures are taken to ensure that third parties do not gain access to the processed data, such as usage data. An order processing relationship according to Art. 28 DSGVO does not exist, as only our own servers are used.
|
||||
|
||||
### <u>6. Automated decision-making</u>
|
||||
|
||||
Automated decision-making, including profiling, does not take place.
|
||||
|
||||
## Rights of the data subject
|
||||
|
||||
If personal data is processed by you, you are a data subject within the meaning of the GDPR. The assertion of your data subject rights is free of charge. You can, of course, contact us for this purpose. You are entitled to the following data subject rights vis-à-vis Goethe University:
|
||||
|
||||
### <u>1. Right of access</u>
|
||||
|
||||
You can request confirmation from us as the controller as to whether and which of your personal data is being processed by us. You have the right to request copies of your personal data from us. Please note the exceptions that may arise due to specific regulations.
|
||||
|
||||
### <u>2. Right of rectification</u>
|
||||
|
||||
You have the right to request us to rectify and/or complete, if the processed personal data concerning you is not (anymore) accurate or not (anymore) complete.
|
||||
|
||||
### <u>3. Right to restriction of processing</u>
|
||||
|
||||
Under certain conditions, you can request the restriction of the processing of personal data concerning you, i.e. that your personal data is then not deleted, but marked so that further processing is restricted.
|
||||
|
||||
### <u>4. Right to erasure</u>
|
||||
|
||||
Under certain conditions, you can demand that we delete the personal data concerning you without delay. This is particularly the case if the personal data is no longer necessary for the purpose for which it was originally collected or processed.
|
||||
|
||||
### <u>5. Right to information</u>
|
||||
|
||||
If you have asserted the right to rectification, erasure or restriction of processing against us, we are obliged to inform all recipients to whom the personal data concerning you have been disclosed of this rectification or erasure of the data or restriction of processing, unless this proves impossible or involves a disproportionate effort. You are entitled to be informed about these recipients.
|
||||
|
||||
### <u>6. Right to data portability</u>
|
||||
|
||||
Under certain conditions, you have the right to request that we transfer your personal data directly to another controller or organization. Alternatively, under certain conditions, you have the right to request that we ourselves provide you with the data in a machine-readable format.
|
||||
|
||||
### <u>7. Right to object</u>
|
||||
|
||||
If we process your personal data because the processing is in the public interest, part of our public duties, or if we process your data on the basis of a legitimate interest, you have the right to object at any time to the processing of data relating to you for reasons arising from your particular situation.
|
||||
|
||||
### <u>8. Right to revoke the declaration of consent under data protection law</u>
|
||||
|
||||
If we process your personal data because you have given us your consent, you have the right to revoke your declaration of consent at any time.
|
||||
|
||||
### <u>9. Right to lodge a complaint with a supervisory authority</u>
|
||||
|
||||
You also have the right to lodge a complaint with a supervisory authority. The competent supervisory authority will examine your complaint.
|
||||
|
||||
## **Contact details of the supervisory authority in the area of data protection**
|
||||
|
||||
If you believe that the processing of your personal data violates data protection regulations, if you have a general inquiry or if you want to complain to a competent supervisory authority, you can contact the Hessian Commissioner for Data Protection and Freedom of Information (HBDI).
|
||||
|
||||
**The Hessian Commissioner for Data Protection and Freedom of Information can be reached in different ways:**
|
||||
|
||||
<u>**The Hessian Commissioner for Data Protection and Freedom of Information**</u><br />
|
||||
PO Box 3163<br />
|
||||
65021 Wiesbaden
|
||||
|
||||
Telephone: +49 611 1408 -- 0
|
||||
|
||||
For general inquiries you can use a contact form:<br />
|
||||
<https://datenschutz.hessen.de/kontakt><br />
|
||||
<br />
|
||||
A complaint form is also available for complaints:<br />
|
||||
<https://datenschutz.hessen.de/service/beschwerde-uebermitteln>
|
||||
15
backend/backend/config/f-u/about-pages/privacy.js
Normal file
15
backend/backend/config/f-u/about-pages/privacy.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// @ts-check
|
||||
import {markdown} from '../../default/tools/markdown.js';
|
||||
|
||||
/** @type {import('@openstapps/core').SCAboutPage} */
|
||||
export const privacy = {
|
||||
title: 'Datenschutz',
|
||||
content: [await markdown('./privacy.md', import.meta.url)],
|
||||
translations: {
|
||||
en: {
|
||||
title: 'Privacy Policy',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default privacy;
|
||||
82
backend/backend/config/f-u/backendrc.js
Normal file
82
backend/backend/config/f-u/backendrc.js
Normal file
@@ -0,0 +1,82 @@
|
||||
// @ts-check
|
||||
import aboutPages from './about-pages/index.js';
|
||||
import defaultApp from '../default/app/index.js';
|
||||
import {backend as defaultBackend, internal as defaultInternal} from '../default/backend/index.js';
|
||||
|
||||
/**
|
||||
* This is the default configuration for the Goethe university of Frankfurt
|
||||
*
|
||||
* @type {import('@openstapps/core').SCConfigFile}
|
||||
*/
|
||||
const config = {
|
||||
auth: {
|
||||
default: {
|
||||
client: {
|
||||
clientId: '1cac3f99-33fa-4234-8438-979f07e0cdab',
|
||||
scopes: '',
|
||||
url: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0',
|
||||
},
|
||||
endpoints: {
|
||||
authorization: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/authorize',
|
||||
endSession: 'https://cas.rz.uni-frankfurt.de/cas/logout',
|
||||
mapping: {
|
||||
id: '$.id',
|
||||
email: '$.attributes.mailPrimaryAddress',
|
||||
familyName: '$.attributes.sn',
|
||||
givenName: '$.attributes.givenName',
|
||||
name: '$.attributes.givenName',
|
||||
role: '$.attributes.eduPersonPrimaryAffiliation',
|
||||
studentId: '$.attributes.employeeNumber',
|
||||
},
|
||||
token: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/accessToken',
|
||||
userinfo: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/profile',
|
||||
},
|
||||
},
|
||||
paia: {
|
||||
client: {
|
||||
clientId: '',
|
||||
scopes: '',
|
||||
url: 'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
},
|
||||
endpoints: {
|
||||
authorization:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
endSession: 'https://ubffm.hds.hebis.de/Shibboleth.sso/Logout',
|
||||
mapping: {
|
||||
id: '$.email',
|
||||
name: '$.name',
|
||||
role: '$.type',
|
||||
},
|
||||
token: 'https://hds.hebis.de/paia/auth/login',
|
||||
userinfo: 'https://hds.hebis.de/paia/core',
|
||||
},
|
||||
},
|
||||
},
|
||||
app: {
|
||||
...defaultApp,
|
||||
features: {
|
||||
extern: {
|
||||
hisometry: {
|
||||
authProvider: 'default',
|
||||
url: 'https://his-self-service.rz.uni-frankfurt.de',
|
||||
},
|
||||
daia: {
|
||||
url: 'https://daia.hebis.de/DAIA2/UB_Frankfurt',
|
||||
},
|
||||
hebisProxy: {
|
||||
url: 'https://proxy.ub.uni-frankfurt.de/login?qurl=',
|
||||
},
|
||||
paia: {
|
||||
authProvider: 'paia',
|
||||
url: 'https://hds.hebis.de/paia/core',
|
||||
},
|
||||
},
|
||||
},
|
||||
aboutPages,
|
||||
},
|
||||
backend: defaultBackend,
|
||||
internal: defaultInternal,
|
||||
uid: 'f-u',
|
||||
};
|
||||
|
||||
export default config;
|
||||
22
backend/backend/integration-test.sh
Executable file
22
backend/backend/integration-test.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
ES_HOST="elasticsearch"
|
||||
BACKEND_HOST="localhost"
|
||||
if [ -z $GITLAB_CI ]; then
|
||||
ES_HOST=localhost
|
||||
fi
|
||||
|
||||
( STAPPS_LOG_LEVEL=31 STAPPS_EXIT_LEVEL=8 NODE_CONFIG_ENV=elasticsearch NODE_ENV=integration-test ALLOW_NO_TRANSPORT=true ES_ADDR=http://$ES_HOST:9200 node app.js ) & backend_pid=$!
|
||||
( openstapps-api e2e http://$BACKEND_HOST:3000 --reportPath coverage/integration-report-junit.xml --waiton tcp:$BACKEND_HOST:3000 --samples node_modules/@openstapps/core/test/resources/indexable ) & api_cli_pid=$!
|
||||
|
||||
## Check output codes
|
||||
# api-cli output defines passing the test
|
||||
# backend should not exit early
|
||||
|
||||
wait $api_cli_pid
|
||||
api_cli_exit=$?
|
||||
wait $backend_pid
|
||||
backend_exit=$?
|
||||
|
||||
if [ "$api_cli_exit" -eq "0" ]; then
|
||||
echo "FINISHED";
|
||||
exit;
|
||||
fi
|
||||
128
backend/backend/package.json
Normal file
128
backend/backend/package.json
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"name": "@openstapps/backend",
|
||||
"description": "A reference implementation for a StApps backend",
|
||||
"version": "3.0.0-next.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "AGPL-3.0-only",
|
||||
"author": "André Bierlein <andre.mt.bierlein@gmail.com>",
|
||||
"contributors": [
|
||||
"Anselm Stordeur <anselmstordeur@gmail.com>",
|
||||
"Benjamin Jöckel",
|
||||
"Jovan Krunić <jovan.krunic@gmail.com>",
|
||||
"Karl-Philipp Wulfert <krlwlfrt@gmail.com>",
|
||||
"Michel Jonathan Schmitz",
|
||||
"Rainer Killinger <mail-openstapps@killinger.co>",
|
||||
"Sebastian Lange",
|
||||
"Thea Schöbl <dev@theaninova.de>"
|
||||
],
|
||||
"main": "lib/app.js",
|
||||
"bin": "app.js",
|
||||
"files": [
|
||||
"app.js",
|
||||
"lib",
|
||||
"config",
|
||||
"Dockerfile",
|
||||
"README.md",
|
||||
"ROUTES.md",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup-node",
|
||||
"build:docker": "docker build -t openstapps:backend ../../.deploy/backend",
|
||||
"deploy": "pnpm --prod --filter=@openstapps/backend deploy ../../.deploy/backend",
|
||||
"dev": "tsup --watch --onSuccess \"pnpm run start\"",
|
||||
"docs": "openapi build-docs ./node_modules/@openstapps/core/lib/openapi.json -o docs/openapi/index.html",
|
||||
"format": "prettier . -c --ignore-path ../../.gitignore",
|
||||
"format:fix": "prettier --write . --ignore-path ../../.gitignore",
|
||||
"lint": "tsc --noEmit && eslint --ext .ts src/",
|
||||
"lint:fix": "eslint --fix --ext .ts src/",
|
||||
"start": "cross-env NODE_CONFIG_ENV=elasticsearch ALLOW_NO_TRANSPORT=true node app.js",
|
||||
"start:debug": "cross-env STAPPS_LOG_LEVEL=31 NODE_CONFIG_ENV=elasticsearch ALLOW_NO_TRANSPORT=true node app.js",
|
||||
"test": "pnpm run test:unit",
|
||||
"test:integration": "sh integration-test.sh",
|
||||
"test:unit": "cross-env NODE_CONFIG_ENV=elasticsearch ALLOW_NO_TRANSPORT=true STAPPS_LOG_LEVEL=0 mocha --exit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@elastic/elasticsearch": "8.4.0",
|
||||
"@openstapps/core": "workspace:*",
|
||||
"@openstapps/core-tools": "workspace:*",
|
||||
"@openstapps/logger": "workspace:*",
|
||||
"@types/body-parser": "1.19.2",
|
||||
"@types/cors": "2.8.13",
|
||||
"@types/express": "4.17.17",
|
||||
"@types/geojson": "1.0.6",
|
||||
"@types/node": "18.15.3",
|
||||
"@types/node-cron": "3.0.7",
|
||||
"@types/nodemailer": "6.4.7",
|
||||
"@types/promise-queue": "2.2.0",
|
||||
"@types/uuid": "8.3.4",
|
||||
"body-parser": "1.20.2",
|
||||
"cors": "2.8.5",
|
||||
"cosmiconfig": "8.1.3",
|
||||
"express": "4.18.2",
|
||||
"express-prom-bundle": "6.6.0",
|
||||
"express-promise-router": "4.1.1",
|
||||
"got": "12.6.0",
|
||||
"moment": "2.29.4",
|
||||
"morgan": "1.10.0",
|
||||
"nock": "13.3.1",
|
||||
"node-cache": "5.1.2",
|
||||
"node-cron": "3.0.2",
|
||||
"nodemailer": "6.9.1",
|
||||
"prom-client": "14.1.1",
|
||||
"promise-queue": "2.2.5",
|
||||
"uuid": "8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openstapps/api-cli": "workspace:*",
|
||||
"@openstapps/eslint-config": "workspace:*",
|
||||
"@openstapps/prettier-config": "workspace:*",
|
||||
"@openstapps/tsconfig": "workspace:*",
|
||||
"@testdeck/mocha": "0.3.3",
|
||||
"@types/chai": "4.3.5",
|
||||
"@types/chai-as-promised": "7.1.5",
|
||||
"@types/mocha": "10.0.1",
|
||||
"@types/morgan": "1.9.4",
|
||||
"@types/sinon": "10.0.14",
|
||||
"@types/sinon-express-mock": "1.3.9",
|
||||
"@types/supertest": "2.0.12",
|
||||
"c8": "7.14.0",
|
||||
"chai": "4.3.7",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"cross-env": "7.0.3",
|
||||
"get-port": "5.1.1",
|
||||
"mocha": "10.2.0",
|
||||
"mocha-junit-reporter": "2.2.0",
|
||||
"mocked-env": "1.3.5",
|
||||
"openapi": "1.0.1",
|
||||
"redoc-cli": "0.13.20",
|
||||
"sinon": "15.0.4",
|
||||
"sinon-express-mock": "2.2.1",
|
||||
"supertest": "6.3.3",
|
||||
"ts-node": "10.9.1",
|
||||
"tsup": "6.7.0",
|
||||
"typescript": "4.9.5"
|
||||
},
|
||||
"tsup": {
|
||||
"entry": [
|
||||
"src/cli.ts"
|
||||
],
|
||||
"sourcemap": true,
|
||||
"clean": true,
|
||||
"target": "es2022",
|
||||
"format": "esm",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"prettier": "@openstapps/prettier-config",
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"@openstapps"
|
||||
]
|
||||
},
|
||||
"openstapps-configuration": {
|
||||
"overrides": [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
}
|
||||
226
backend/backend/src/app.ts
Normal file
226
backend/backend/src/app.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
SCNotFoundErrorResponse,
|
||||
SCRequestBodyTooLargeErrorResponse,
|
||||
SCSyntaxErrorResponse,
|
||||
SCUnsupportedMediaTypeErrorResponse,
|
||||
} from '@openstapps/core';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import cors from 'cors';
|
||||
import {Express} from 'express';
|
||||
import morgan from 'morgan';
|
||||
import path from 'path';
|
||||
import {DEFAULT_TIMEOUT, isTestEnvironment, mailer, plugins, validator} from './common.js';
|
||||
import {getPrometheusMiddleware} from './middleware/prometheus.js';
|
||||
import {MailQueue} from './notification/mail-queue.js';
|
||||
import {bulkAddRouter} from './routes/bulk-add-route.js';
|
||||
import {bulkDoneRouter} from './routes/bulk-done-route.js';
|
||||
import {bulkRouter} from './routes/bulk-route.js';
|
||||
import {indexRouter} from './routes/index-route.js';
|
||||
import {multiSearchRouter} from './routes/multi-search-route.js';
|
||||
import {pluginRegisterRouter} from './routes/plugin-register-route.js';
|
||||
import {searchRouter} from './routes/search-route.js';
|
||||
import {thingUpdateRouter} from './routes/thing-update-route.js';
|
||||
import {virtualPluginRoute} from './routes/virtual-plugin-route.js';
|
||||
import {BulkStorage} from './storage/bulk-storage.js';
|
||||
import {DatabaseConstructor} from './storage/database.js';
|
||||
import {backendConfig} from './config.js';
|
||||
import {fileURLToPath} from 'url';
|
||||
|
||||
/**
|
||||
* Configure the backend
|
||||
*/
|
||||
export async function configureApp(app: Express, databases: {[name: string]: DatabaseConstructor}) {
|
||||
let integrationTestTimeout: NodeJS.Timeout;
|
||||
// request loggers have to be the first middleware to be set in express
|
||||
app.use(
|
||||
morgan('dev', {
|
||||
skip: (_request, response) => {
|
||||
if (process.env.NODE_ENV === 'integration-test') {
|
||||
clearTimeout(integrationTestTimeout);
|
||||
integrationTestTimeout = setTimeout(() => {
|
||||
process.exit(1);
|
||||
}, DEFAULT_TIMEOUT);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return response.statusCode < 400;
|
||||
},
|
||||
stream: process.stdout,
|
||||
}),
|
||||
);
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (process.env.PROMETHEUS_MIDDLEWARE === 'true') {
|
||||
app.use(getPrometheusMiddleware());
|
||||
}
|
||||
|
||||
const corsOptions = {
|
||||
allowedHeaders: [
|
||||
'DNT',
|
||||
'Keep-Alive',
|
||||
'User-Agent',
|
||||
'X-Requested-With',
|
||||
'If-Modified-Since',
|
||||
'Cache-Control',
|
||||
'Content-Type',
|
||||
'X-StApps-Version',
|
||||
],
|
||||
credentials: true,
|
||||
maxAge: 1_728_000,
|
||||
methods: ['GET', 'POST', 'PUT', 'OPTIONS'],
|
||||
optionsSuccessStatus: 204,
|
||||
};
|
||||
|
||||
// allow all origins on all routes
|
||||
app.use(cors(corsOptions));
|
||||
// TODO: See if it can handle options request with no content-type
|
||||
|
||||
// allow cors preflight requests on every route
|
||||
app.options('*', [cors(corsOptions)]);
|
||||
|
||||
// only accept json as content-type for all requests
|
||||
app.use((request, response, next) => {
|
||||
// Only accept json as content-type
|
||||
if (request.is('application/json') !== 'application/json') {
|
||||
// return an error in the response
|
||||
const error = new SCUnsupportedMediaTypeErrorResponse(isTestEnvironment);
|
||||
response.status(error.statusCode);
|
||||
response.json(error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const bodyBuffer: Buffer[] = [];
|
||||
// we don't know the full size, the only way we can get is by adding up all individual chunk sizes
|
||||
let bodySize = 0;
|
||||
const chunkGatherer = (chunk: Buffer) => {
|
||||
bodySize += chunk.byteLength;
|
||||
// when adding each chunk size to the total size, check how large it now is.
|
||||
if (bodySize > backendConfig.backend.maxRequestBodySize) {
|
||||
request.off('data', chunkGatherer);
|
||||
request.off('end', endCallback);
|
||||
// return an error in the response
|
||||
const error = new SCRequestBodyTooLargeErrorResponse(isTestEnvironment);
|
||||
response.status(error.statusCode);
|
||||
response.json(error);
|
||||
|
||||
return;
|
||||
}
|
||||
// push the chunk in the buffer
|
||||
bodyBuffer.push(chunk);
|
||||
};
|
||||
|
||||
const endCallback = () => {
|
||||
request.body = Buffer.concat(bodyBuffer).toString();
|
||||
|
||||
try {
|
||||
request.body = JSON.parse(request.body);
|
||||
next();
|
||||
} catch (error) {
|
||||
const error_ = new SCSyntaxErrorResponse(error.message, isTestEnvironment);
|
||||
response.status(error_.statusCode);
|
||||
response.json(error_);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
request.on('data', chunkGatherer).on('end', endCallback);
|
||||
});
|
||||
|
||||
// validate config file
|
||||
const directory = path.dirname(fileURLToPath(import.meta.url));
|
||||
await validator.addSchemas(
|
||||
path.join(directory, '..', 'node_modules', '@openstapps', 'core', 'lib', 'schema'),
|
||||
);
|
||||
|
||||
// validate the config file
|
||||
const configValidation = validator.validate(backendConfig, 'SCConfigFile');
|
||||
|
||||
// validation failed
|
||||
if (configValidation.errors.length > 0) {
|
||||
throw new Error(
|
||||
`Validation of config file failed. Errors were: ${JSON.stringify(configValidation.errors)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// check if a database name was given
|
||||
if (!backendConfig.internal.database?.name) {
|
||||
throw new Error('You have to configure a database');
|
||||
}
|
||||
|
||||
const database = new databases[backendConfig.internal.database.name](
|
||||
backendConfig,
|
||||
// mailQueue
|
||||
mailer !== undefined && backendConfig.internal.monitoring ? new MailQueue(mailer) : undefined,
|
||||
);
|
||||
|
||||
await database.init();
|
||||
|
||||
if (database === undefined) {
|
||||
throw new TypeError('No implementation for configured database found. Please check your configuration.');
|
||||
}
|
||||
|
||||
Logger.ok('Validated config file successfully');
|
||||
|
||||
// treats /foo and /foo/ as two different routes
|
||||
// see http://expressjs.com/en/api.html#app.set
|
||||
app.enable('strict routing');
|
||||
|
||||
// make the bulk storage available to all http middlewares/routes
|
||||
app.set('bulk', new BulkStorage(database));
|
||||
|
||||
app.set('env', process.env.NODE_ENV);
|
||||
|
||||
// load routes before plugins
|
||||
// they now can be used or overwritten by any plugin
|
||||
app.use(
|
||||
bulkAddRouter,
|
||||
bulkDoneRouter,
|
||||
bulkRouter,
|
||||
indexRouter,
|
||||
multiSearchRouter,
|
||||
pluginRegisterRouter,
|
||||
searchRouter,
|
||||
thingUpdateRouter,
|
||||
);
|
||||
|
||||
// for plugins, as Express doesn't really want you to unregister routes (and doesn't offer any method to do so at all)
|
||||
app.all('*', async (request, response, next) => {
|
||||
// if the route exists, call virtual route on the plugin that registered that route
|
||||
if (plugins.has(request.originalUrl)) {
|
||||
try {
|
||||
response.json(await virtualPluginRoute(request, plugins.get(request.originalUrl)!));
|
||||
} catch (error) {
|
||||
// in case of an error: send an error response
|
||||
response.status(error.statusCode);
|
||||
response.json(error);
|
||||
}
|
||||
} else {
|
||||
// pass to the next matching route (which is 404)
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
// add a route for a missing resource (404)
|
||||
app.use((_request, response) => {
|
||||
const errorResponse = new SCNotFoundErrorResponse(isTestEnvironment);
|
||||
response.status(errorResponse.statusCode);
|
||||
response.json(errorResponse);
|
||||
});
|
||||
}
|
||||
110
backend/backend/src/cli.ts
Normal file
110
backend/backend/src/cli.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import express from 'express';
|
||||
import http from 'http';
|
||||
import {configureApp} from './app.js';
|
||||
import {Elasticsearch} from './storage/elasticsearch/elasticsearch.js';
|
||||
|
||||
const app = express();
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
*/
|
||||
const port = normalizePort(process.env.PORT || '3000');
|
||||
|
||||
/**
|
||||
* Create HTTP server.
|
||||
*/
|
||||
const server = http.createServer(app);
|
||||
|
||||
/**
|
||||
* Define server handling for specific events
|
||||
*/
|
||||
server.on('error', onError);
|
||||
server.on('listening', onListening);
|
||||
|
||||
/**
|
||||
* Normalize a port into a number, string, or false.
|
||||
*/
|
||||
function normalizePort(value: string) {
|
||||
const portNumber = Number.parseInt(value, 10);
|
||||
|
||||
if (Number.isNaN(portNumber)) {
|
||||
// named pipe
|
||||
return value;
|
||||
}
|
||||
|
||||
if (portNumber >= 0) {
|
||||
// port number
|
||||
return portNumber;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "error" event.
|
||||
*/
|
||||
async function onError(error: {code: string; syscall: string}) {
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`;
|
||||
|
||||
// handle specific listen errors with friendly messages
|
||||
switch (error.code) {
|
||||
case 'EACCES': {
|
||||
await Logger.error(`${bind} requires elevated privileges`);
|
||||
process.exit(1);
|
||||
break;
|
||||
}
|
||||
case 'EADDRINUSE': {
|
||||
await Logger.error(`${bind} is already in use`);
|
||||
process.exit(1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "listening" event.
|
||||
*/
|
||||
function onListening() {
|
||||
const addr = server.address();
|
||||
|
||||
if (addr === null) {
|
||||
void Logger.error(`Failed to start binding`);
|
||||
} else {
|
||||
const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`;
|
||||
Logger.ok(`Listening on ${bind}`);
|
||||
}
|
||||
}
|
||||
|
||||
configureApp(app, {elasticsearch: Elasticsearch})
|
||||
.then(() => {
|
||||
Logger.ok('Successfully configured express server');
|
||||
// After app setup listen on provided port, on all network interfaces
|
||||
server.listen(port);
|
||||
})
|
||||
// eslint-disable-next-line unicorn/prefer-top-level-await
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
43
backend/backend/src/common.ts
Normal file
43
backend/backend/src/common.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCPluginMetaData} from '@openstapps/core';
|
||||
import {Validator} from '@openstapps/core-tools';
|
||||
import {BackendTransport} from './notification/backend-transport.js';
|
||||
|
||||
/**
|
||||
* Instance of the transport for sending mails
|
||||
*/
|
||||
export const mailer = BackendTransport.getTransportInstance();
|
||||
|
||||
/**
|
||||
* A validator instance to check if something is a valid JSON object (e.g. a request or a thing)
|
||||
*/
|
||||
export const validator = new Validator();
|
||||
|
||||
/**
|
||||
* Provides information if the backend is executed in the "test" (non-production) environment
|
||||
*/
|
||||
export const isTestEnvironment = process.env.NODE_ENV !== 'production';
|
||||
|
||||
/*
|
||||
* Stores a ("key-value") list of plugins where key is route and value is plugin information
|
||||
*/
|
||||
export const plugins = new Map<string, SCPluginMetaData>();
|
||||
|
||||
/**
|
||||
* The default timeout in milliseconds
|
||||
*/
|
||||
export const DEFAULT_TIMEOUT = 20_000;
|
||||
53
backend/backend/src/config.ts
Normal file
53
backend/backend/src/config.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import {cosmiconfig, PublicExplorer} from 'cosmiconfig';
|
||||
import {SCConfigFile} from '@openstapps/core';
|
||||
import path from 'path';
|
||||
import deepmerge from 'deepmerge';
|
||||
|
||||
const fallbackNamespace = 'default';
|
||||
const configPath = 'config';
|
||||
|
||||
/**
|
||||
* Creates a config loader
|
||||
* @param moduleName the name of the config file (module)
|
||||
*/
|
||||
function configLoader(moduleName: string): PublicExplorer {
|
||||
return cosmiconfig(moduleName, {
|
||||
searchPlaces: ['js', 'json', 'yml', 'yaml'].map(it => `${moduleName}rc.${it}`),
|
||||
loaders: {
|
||||
'.js': filepath => import(`file://${filepath}`).then(it => it.default),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and load a config file
|
||||
*/
|
||||
async function findConfig<T>(moduleName: string, namespace = fallbackNamespace): Promise<T> {
|
||||
return configLoader(moduleName)
|
||||
.search(path.posix.join('.', configPath, namespace))
|
||||
.then(it => it!.config as T)
|
||||
.catch(() =>
|
||||
configLoader(moduleName)
|
||||
.search(path.posix.join('.', configPath, fallbackNamespace))
|
||||
.then(it => it!.config),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a config file
|
||||
*/
|
||||
async function loadConfig<T>(moduleName: string): Promise<T> {
|
||||
const namespace = process.env.NODE_APP_INSTANCE;
|
||||
const database = process.env.NODE_CONFIG_ENV;
|
||||
|
||||
const config = await findConfig<T>(moduleName, namespace);
|
||||
if (database) {
|
||||
const databaseConfig = await findConfig<T>(database, namespace);
|
||||
return deepmerge(config, databaseConfig);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
export const backendConfig = await loadConfig<SCConfigFile>('backend');
|
||||
export const prometheusConfig = await loadConfig<unknown>('prometheus');
|
||||
17
backend/backend/src/environment.d.ts
vendored
Normal file
17
backend/backend/src/environment.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
// eslint-disable-next-line unicorn/prevent-abbreviations
|
||||
interface ProcessEnv {
|
||||
NODE_APP_INSTANCE: 'default' | 'b-tu' | 'f-u' | 'fb-fh' | 'ks-ug' | string | undefined;
|
||||
NODE_CONFIG_ENV: 'elasticsearch' | string | undefined;
|
||||
STAPPS_LOG_LEVEL: `${number}`;
|
||||
ALLOW_NO_TRANSPORT: `${boolean}`;
|
||||
PORT: `${number}`;
|
||||
ES_DEBUG: `${boolean}`;
|
||||
ES_ADDR: string;
|
||||
PROMETHEUS_MIDDLEWARE: `${boolean}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
39
backend/backend/src/middleware/prometheus.ts
Normal file
39
backend/backend/src/middleware/prometheus.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import express_prom_bundle from 'express-prom-bundle';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Create and configure a new Express Prometheus Middleware instance
|
||||
*
|
||||
* This function tries to configure the new instance with JSON read from
|
||||
* `./conf/prometheus.json`. When this fails an instance configured with
|
||||
* default options is returned.
|
||||
* @returns express.Express
|
||||
*/
|
||||
export function getPrometheusMiddleware(): express_prom_bundle.Middleware {
|
||||
const configFileName = path.join('./config', 'prometheus.json');
|
||||
let options: express_prom_bundle.Opts = {};
|
||||
|
||||
try {
|
||||
options = JSON.parse(fs.readFileSync(configFileName, 'utf8'));
|
||||
} catch (error) {
|
||||
Logger.warn("Couldn't get options from config file for Prometheus Middleware.", error);
|
||||
}
|
||||
|
||||
return express_prom_bundle(options);
|
||||
}
|
||||
116
backend/backend/src/notification/backend-transport.ts
Normal file
116
backend/backend/src/notification/backend-transport.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger, SMTP, Transport, VerifiableTransport} from '@openstapps/logger';
|
||||
|
||||
/**
|
||||
* Provides information if a transport is a verifiable transport
|
||||
* @param instance A transport that needs to be checked
|
||||
*/
|
||||
export function isTransportWithVerification(instance: Transport): instance is VerifiableTransport {
|
||||
return typeof (instance as VerifiableTransport).verify === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton for getting only one transport service
|
||||
*
|
||||
* In the future this may support more than loading SMTP as a transport.
|
||||
*/
|
||||
export class BackendTransport {
|
||||
/**
|
||||
* One (and only one) instance of the backend transport
|
||||
*/
|
||||
private static _instance?: BackendTransport;
|
||||
|
||||
/**
|
||||
* Stores information if transport is in state of waiting for the verification
|
||||
*/
|
||||
private waitingForVerification = false;
|
||||
|
||||
/**
|
||||
* A (SMTP) transport which includes settings for sending mails
|
||||
*/
|
||||
protected transport: SMTP | undefined;
|
||||
|
||||
/**
|
||||
* Destroys the singleton instance of the class (for unit test purposes)
|
||||
*/
|
||||
public static destroy() {
|
||||
delete BackendTransport._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides instance of a backend transport
|
||||
*/
|
||||
public static getInstance(): BackendTransport {
|
||||
if (BackendTransport._instance !== undefined) {
|
||||
return BackendTransport._instance;
|
||||
}
|
||||
|
||||
BackendTransport._instance = new BackendTransport();
|
||||
|
||||
return BackendTransport._instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an instance of a transport
|
||||
*/
|
||||
public static getTransportInstance(): SMTP | undefined {
|
||||
return BackendTransport.getInstance().transport;
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
// get SMTP instance for the time
|
||||
// in the future we may implement some other transport services which can be selected
|
||||
// via the configuration files
|
||||
try {
|
||||
this.transport = SMTP.getInstance();
|
||||
} catch (error) {
|
||||
if (process.env.ALLOW_NO_TRANSPORT === 'true') {
|
||||
Logger.warn('SMTP error was ignored.');
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.transport !== undefined && isTransportWithVerification(this.transport)) {
|
||||
void this.verifyTransport(this.transport);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the transport using its verification method
|
||||
*/
|
||||
private async verifyTransport(transport: VerifiableTransport): Promise<void> {
|
||||
this.waitingForVerification = true;
|
||||
try {
|
||||
const successful = await transport.verify();
|
||||
if (successful) {
|
||||
Logger.log('SMTP verification successful.');
|
||||
}
|
||||
} catch (error) {
|
||||
throw error;
|
||||
} finally {
|
||||
this.waitingForVerification = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides information if transport is in state of waiting for the verification
|
||||
*/
|
||||
public isWaitingForVerification(): boolean {
|
||||
return this.waitingForVerification;
|
||||
}
|
||||
}
|
||||
111
backend/backend/src/notification/mail-queue.ts
Normal file
111
backend/backend/src/notification/mail-queue.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.nse along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Logger, SMTP} from '@openstapps/logger';
|
||||
import {MailOptions} from 'nodemailer/lib/sendmail-transport';
|
||||
import Queue from 'promise-queue';
|
||||
/**
|
||||
* A queue that can send mails in serial
|
||||
*/
|
||||
export class MailQueue {
|
||||
/**
|
||||
* Number of allowed verification attempts after which the initialization of transport fails
|
||||
*/
|
||||
static readonly MAX_VERIFICATION_ATTEMPTS = 5;
|
||||
|
||||
/**
|
||||
* Number of milliseconds after which verification check should be repeated
|
||||
*/
|
||||
static readonly VERIFICATION_TIMEOUT = 5000;
|
||||
|
||||
/**
|
||||
* A queue that saves mails, before the transport is ready. When
|
||||
* the transport gets ready this mails are getting pushed in to
|
||||
* the normal queue.
|
||||
*/
|
||||
dryQueue: MailOptions[];
|
||||
|
||||
/**
|
||||
* A queue that saves mails, that are being sent in series
|
||||
*/
|
||||
queue: Queue;
|
||||
|
||||
/**
|
||||
* A counter for the number of verifications that failed
|
||||
*/
|
||||
verificationCounter: number;
|
||||
|
||||
/**
|
||||
* Creates a mail queue
|
||||
* @param transport Transport which is used for sending mails
|
||||
*/
|
||||
constructor(private readonly transport: SMTP) {
|
||||
this.queue = new Queue(1);
|
||||
|
||||
// this queue saves all request when the transport is not ready yet
|
||||
this.dryQueue = [];
|
||||
|
||||
this.verificationCounter = 0;
|
||||
|
||||
// if the transport can be verified it should check if it was done...
|
||||
this.checkForVerification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mail into the queue so it gets send when the queue is ready
|
||||
* @param mail Information required for sending a mail
|
||||
*/
|
||||
private async addToQueue(mail: MailOptions) {
|
||||
return this.queue.add<string>(() => this.transport.sendMail(mail));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the given transport
|
||||
*/
|
||||
private checkForVerification() {
|
||||
if (this.verificationCounter >= MailQueue.MAX_VERIFICATION_ATTEMPTS) {
|
||||
throw new Error('Failed to initialize the SMTP transport for the mail queue');
|
||||
}
|
||||
|
||||
if (this.transport.isVerified()) {
|
||||
Logger.ok('Transport for mail queue was verified. We can send mails now');
|
||||
// if the transport finally was verified send all our mails from the dry queue
|
||||
for (const mail of this.dryQueue) {
|
||||
void this.addToQueue(mail);
|
||||
}
|
||||
} else {
|
||||
this.verificationCounter++;
|
||||
setTimeout(() => {
|
||||
Logger.warn('Transport not verified yet. Trying to send mails here...');
|
||||
this.checkForVerification();
|
||||
}, MailQueue.VERIFICATION_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a mail into the queue so it gets send when the queue is ready
|
||||
* @param mail Information required for sending a mail
|
||||
*/
|
||||
public async push(mail: MailOptions) {
|
||||
if (this.transport.isVerified()) {
|
||||
await this.addToQueue(mail);
|
||||
} else {
|
||||
// the transport has verification, but is not verified yet
|
||||
// push to a dry queue which gets pushed to the real queue when the transport is verified
|
||||
this.dryQueue.push(mail);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
backend/backend/src/routes/bulk-add-route.ts
Normal file
45
backend/backend/src/routes/bulk-add-route.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCBulkAddRequest, SCBulkAddResponse, SCBulkAddRoute, SCNotFoundErrorResponse} from '@openstapps/core';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {isTestEnvironment} from '../common.js';
|
||||
import {BulkStorage} from '../storage/bulk-storage.js';
|
||||
import {createRoute} from './route.js';
|
||||
|
||||
/**
|
||||
* Contains information for using the route for adding bulks
|
||||
*/
|
||||
const bulkRouteModel = new SCBulkAddRoute();
|
||||
|
||||
/**
|
||||
* Implementation of the bulk add route (SCBulkAddRoute)
|
||||
*/
|
||||
export const bulkAddRouter = createRoute<SCBulkAddRequest, SCBulkAddResponse>(
|
||||
bulkRouteModel,
|
||||
async (request, app, parameters) => {
|
||||
const bulkMemory: BulkStorage = app.get('bulk');
|
||||
const bulk = bulkMemory.read(parameters.UID);
|
||||
|
||||
if (bulk === undefined) {
|
||||
Logger.warn(`Bulk with ${parameters.UID} not found.`);
|
||||
throw new SCNotFoundErrorResponse(isTestEnvironment);
|
||||
}
|
||||
|
||||
await bulkMemory.database.post(request, bulk);
|
||||
|
||||
return {};
|
||||
},
|
||||
);
|
||||
51
backend/backend/src/routes/bulk-done-route.ts
Normal file
51
backend/backend/src/routes/bulk-done-route.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
SCBulkDoneRequest,
|
||||
SCBulkDoneResponse,
|
||||
SCBulkDoneRoute,
|
||||
SCNotFoundErrorResponse,
|
||||
} from '@openstapps/core';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {isTestEnvironment} from '../common.js';
|
||||
import {BulkStorage} from '../storage/bulk-storage.js';
|
||||
import {createRoute} from './route.js';
|
||||
|
||||
/**
|
||||
* Contains information for using the route for closing bulks
|
||||
*/
|
||||
const bulkDoneRouteModel = new SCBulkDoneRoute();
|
||||
|
||||
/**
|
||||
* Implementation of the bulk done request route (SCBulkDoneRoute)
|
||||
*/
|
||||
export const bulkDoneRouter = createRoute<SCBulkDoneRequest, SCBulkDoneResponse>(
|
||||
bulkDoneRouteModel,
|
||||
async (_request, app, parameters) => {
|
||||
const bulkMemory: BulkStorage = app.get('bulk');
|
||||
const bulk = bulkMemory.read(parameters.UID);
|
||||
|
||||
if (bulk === undefined) {
|
||||
Logger.warn(`Bulk with ${parameters.UID} not found.`);
|
||||
throw new SCNotFoundErrorResponse(isTestEnvironment);
|
||||
}
|
||||
|
||||
bulk.state = 'done';
|
||||
await bulkMemory.markAsDone(bulk);
|
||||
|
||||
return {};
|
||||
},
|
||||
);
|
||||
32
backend/backend/src/routes/bulk-route.ts
Normal file
32
backend/backend/src/routes/bulk-route.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCBulkRequest, SCBulkResponse, SCBulkRoute} from '@openstapps/core';
|
||||
import {BulkStorage} from '../storage/bulk-storage.js';
|
||||
import {createRoute} from './route.js';
|
||||
|
||||
/**
|
||||
* Contains information for using the route for creating bulks
|
||||
*/
|
||||
const bulkRouteModel = new SCBulkRoute();
|
||||
|
||||
/**
|
||||
* Implementation of the bulk request route (SCBulkRoute)
|
||||
*/
|
||||
export const bulkRouter = createRoute<SCBulkRequest, SCBulkResponse>(bulkRouteModel, async (request, app) => {
|
||||
const bulkMemory: BulkStorage = app.get('bulk');
|
||||
|
||||
return bulkMemory.create(request);
|
||||
});
|
||||
53
backend/backend/src/routes/http-types.ts
Normal file
53
backend/backend/src/routes/http-types.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// the list provides option to easily implement "isHttpMethod" guard
|
||||
const httpVerbs = [
|
||||
'get',
|
||||
'post',
|
||||
'put',
|
||||
'delete',
|
||||
'patch',
|
||||
'options',
|
||||
'head',
|
||||
'checkout',
|
||||
'copy',
|
||||
'lock',
|
||||
'merge',
|
||||
'mkactivity',
|
||||
'mkcol',
|
||||
'move',
|
||||
'm-search',
|
||||
'notify',
|
||||
'purge',
|
||||
'report',
|
||||
'search',
|
||||
'subscribe',
|
||||
'trace',
|
||||
'unlock',
|
||||
'unsubscribe',
|
||||
] as const;
|
||||
/**
|
||||
* Strings that can be used as HTTP verbs (e.g. in requests): 'get' | 'post' | 'put' | 'delete' etc.
|
||||
*/
|
||||
export type HTTPVerb = (typeof httpVerbs)[number];
|
||||
|
||||
/**
|
||||
* Provides information if a text (representing a method) is an HTTP verb
|
||||
* @param method A text (representing a method) to check
|
||||
*/
|
||||
export function isHttpMethod(method: string): method is HTTPVerb {
|
||||
return (httpVerbs as unknown as string[]).includes(method);
|
||||
}
|
||||
37
backend/backend/src/routes/index-route.ts
Normal file
37
backend/backend/src/routes/index-route.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {SCIndexResponse, SCIndexRoute} from '@openstapps/core';
|
||||
import {createRoute} from './route.js';
|
||||
import {backendConfig} from '../config.js';
|
||||
|
||||
/**
|
||||
* Contains information for using the index route
|
||||
*/
|
||||
const indexRouteModel = new SCIndexRoute();
|
||||
|
||||
/**
|
||||
* Implementation of the index route (SCIndexRoute)
|
||||
*/
|
||||
export const indexRouter = createRoute<unknown, SCIndexResponse>(
|
||||
indexRouteModel,
|
||||
async (): Promise<SCIndexResponse> => {
|
||||
return {
|
||||
app: backendConfig.app,
|
||||
auth: backendConfig.auth,
|
||||
backend: backendConfig.backend,
|
||||
};
|
||||
},
|
||||
);
|
||||
59
backend/backend/src/routes/multi-search-route.ts
Normal file
59
backend/backend/src/routes/multi-search-route.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
SCMultiSearchRequest,
|
||||
SCMultiSearchResponse,
|
||||
SCMultiSearchRoute,
|
||||
SCSearchResponse,
|
||||
SCTooManyRequestsErrorResponse,
|
||||
} from '@openstapps/core';
|
||||
import {isTestEnvironment} from '../common.js';
|
||||
import {BulkStorage} from '../storage/bulk-storage.js';
|
||||
import {createRoute} from './route.js';
|
||||
import {backendConfig} from '../config.js';
|
||||
/**
|
||||
* Contains information for using the multi search route
|
||||
*/
|
||||
const multiSearchRouteModel = new SCMultiSearchRoute();
|
||||
|
||||
/**
|
||||
* Implementation of the multi search route (SCMultiSearchRoute)
|
||||
*/
|
||||
export const multiSearchRouter = createRoute<
|
||||
SCMultiSearchRequest,
|
||||
SCMultiSearchResponse | SCTooManyRequestsErrorResponse
|
||||
>(multiSearchRouteModel, async (request, app) => {
|
||||
const bulkMemory: BulkStorage = app.get('bulk');
|
||||
const queryNames = Object.keys(request);
|
||||
|
||||
if (queryNames.length > backendConfig.backend.maxMultiSearchRouteQueries) {
|
||||
throw new SCTooManyRequestsErrorResponse(isTestEnvironment);
|
||||
}
|
||||
|
||||
// get a map of promises for each query
|
||||
const searchRequests = queryNames.map(async queryName => {
|
||||
return bulkMemory.database.search(request[queryName]);
|
||||
});
|
||||
|
||||
const listOfSearchResponses = await Promise.all(searchRequests);
|
||||
|
||||
const response: {[queryName: string]: SCSearchResponse} = {};
|
||||
for (const [index, queryName] of queryNames.entries()) {
|
||||
response[queryName] = listOfSearchResponses[index];
|
||||
}
|
||||
|
||||
return response;
|
||||
});
|
||||
110
backend/backend/src/routes/plugin-register-route.ts
Normal file
110
backend/backend/src/routes/plugin-register-route.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
SCNotFoundErrorResponse,
|
||||
SCPluginAlreadyRegisteredErrorResponse,
|
||||
SCPluginMetaData,
|
||||
SCPluginRegisterRequest,
|
||||
SCPluginRegisterResponse,
|
||||
SCPluginRegisterRoute,
|
||||
} from '@openstapps/core';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {deepStrictEqual} from 'assert';
|
||||
import {isTestEnvironment, plugins} from '../common.js';
|
||||
import {createRoute} from './route.js';
|
||||
import {backendConfig} from '../config.js';
|
||||
|
||||
/**
|
||||
* Contains information for using the route for registering routes
|
||||
*/
|
||||
const pluginRegisterRouteModel = new SCPluginRegisterRoute();
|
||||
|
||||
/**
|
||||
* Implementation of the plugin registration route (SCPluginRegisterRoute)
|
||||
*/
|
||||
export const pluginRegisterRouter = createRoute(pluginRegisterRouteModel, pluginRegisterHandler);
|
||||
|
||||
/**
|
||||
* Handles requests on route for registering plugins
|
||||
* @param request Request received for registering or unregistering a plugin
|
||||
* @param _app Express application
|
||||
*/
|
||||
export async function pluginRegisterHandler(
|
||||
request: SCPluginRegisterRequest,
|
||||
_app: Express.Application,
|
||||
): Promise<SCPluginRegisterResponse> {
|
||||
switch (request.action) {
|
||||
case 'add': {
|
||||
return addPlugin(request.plugin);
|
||||
}
|
||||
case 'remove': {
|
||||
return removePlugin(request.route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a plugin to the list (map) of registered plugins
|
||||
* @param plugin Meta data of the plugin
|
||||
*/
|
||||
function addPlugin(plugin: SCPluginMetaData): SCPluginRegisterResponse {
|
||||
// check if plugin (its route) has already been registered
|
||||
if (plugins.has(plugin.route)) {
|
||||
const previouslyRegistered = plugins.get(plugin.route);
|
||||
try {
|
||||
deepStrictEqual(previouslyRegistered, plugin);
|
||||
|
||||
return {success: true};
|
||||
} catch {
|
||||
throw new SCPluginAlreadyRegisteredErrorResponse(
|
||||
'Plugin already registered',
|
||||
plugins.get(plugin.route)!,
|
||||
isTestEnvironment,
|
||||
);
|
||||
}
|
||||
}
|
||||
// it's a new plugin so it can be added to the map of plugins
|
||||
plugins.set(plugin.route, plugin);
|
||||
// add plugin info to app config
|
||||
if (backendConfig.app.features.plugins === undefined) {
|
||||
backendConfig.app.features.plugins = {};
|
||||
}
|
||||
backendConfig.app.features.plugins[plugin.name] = {urlPath: plugin.route};
|
||||
Logger.log(
|
||||
`Registered plugin (name: ${plugin.name}, address: ${plugin.address}) on the route "${plugin.route}".`,
|
||||
);
|
||||
|
||||
return {success: true};
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a plugin from the list (map) of registered plugins using the provided route
|
||||
* @param route Route of the plugin which needs to be unregistered
|
||||
*/
|
||||
function removePlugin(route: string): SCPluginRegisterResponse {
|
||||
if (!plugins.has(route)) {
|
||||
throw new SCNotFoundErrorResponse(isTestEnvironment);
|
||||
}
|
||||
if (plugins.has(route)) {
|
||||
const plugin = plugins.get(route)!;
|
||||
delete backendConfig.app.features.plugins?.[plugin.name];
|
||||
}
|
||||
// remove the plugin information using its route as a key
|
||||
plugins.delete(route);
|
||||
Logger.log(`Removed plugin that used the route "${route}".`);
|
||||
|
||||
return {success: true};
|
||||
}
|
||||
128
backend/backend/src/routes/route.ts
Normal file
128
backend/backend/src/routes/route.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
SCInternalServerErrorResponse,
|
||||
SCMethodNotAllowedErrorResponse,
|
||||
SCRoute,
|
||||
SCValidationErrorResponse,
|
||||
} from '@openstapps/core';
|
||||
import {ValidationError} from '@openstapps/core-tools/src/types/validator.js';
|
||||
import {Logger} from '@openstapps/logger';
|
||||
import {Application, Router} from 'express';
|
||||
import PromiseRouter from 'express-promise-router';
|
||||
import {isTestEnvironment, validator} from '../common.js';
|
||||
import {isHttpMethod} from './http-types.js';
|
||||
|
||||
/**
|
||||
* Creates a router from a route class and a handler function which implements the logic
|
||||
*
|
||||
* The given router performs a request and response validation, sets status codes and checks if the given handler
|
||||
* only returns errors that are allowed for the client to see
|
||||
* @param routeClass Model of a route
|
||||
* @param handler Implements the logic of the route
|
||||
*/
|
||||
export function createRoute<REQUESTTYPE, RETURNTYPE>(
|
||||
routeClass: SCRoute,
|
||||
handler: (
|
||||
validatedBody: REQUESTTYPE,
|
||||
app: Application,
|
||||
parameters: {[parameterName: string]: string},
|
||||
) => Promise<RETURNTYPE>,
|
||||
): Router {
|
||||
// create router
|
||||
const router = PromiseRouter({mergeParams: true});
|
||||
|
||||
// create route
|
||||
// the given type has no index signature so we have to cast to get the IRouteHandler when a HTTP method is given
|
||||
const route = router.route(routeClass.urlPath);
|
||||
|
||||
const verb = routeClass.method.toLowerCase();
|
||||
|
||||
// check if route has a valid http verb
|
||||
if (isHttpMethod(verb)) {
|
||||
// create a route handler for the given HTTP method
|
||||
route[verb](async (request, response) => {
|
||||
try {
|
||||
// validate request
|
||||
const requestValidation = validator.validate(request.body, routeClass.requestBodyName);
|
||||
|
||||
if (requestValidation.errors.length > 0) {
|
||||
const error = new SCValidationErrorResponse(requestValidation.errors, isTestEnvironment);
|
||||
response.status(error.statusCode);
|
||||
response.json(error);
|
||||
await Logger.error(error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// hand over request to handler with path parameters
|
||||
const handlerResponse = await handler(request.body, request.app, request.params);
|
||||
|
||||
// validate response generated by handler
|
||||
const responseErrors: ValidationError[] = validator.validate(
|
||||
handlerResponse,
|
||||
routeClass.responseBodyName,
|
||||
).errors;
|
||||
|
||||
if (responseErrors.length > 0) {
|
||||
const validationError = new SCValidationErrorResponse(responseErrors, isTestEnvironment);
|
||||
// The validation error is not caused by faulty user input, but through an error that originates somewhere in
|
||||
// the backend, therefore we use this "stacked" error.
|
||||
const internalServerError = new SCInternalServerErrorResponse(validationError, isTestEnvironment);
|
||||
response.status(internalServerError.statusCode);
|
||||
response.json(internalServerError);
|
||||
await Logger.error(internalServerError);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// set status code
|
||||
response.status(routeClass.statusCodeSuccess);
|
||||
|
||||
// respond
|
||||
response.json(handlerResponse);
|
||||
} catch (error) {
|
||||
// if the error response is allowed on the route
|
||||
if (routeClass.errorNames.some(constructorType => error instanceof constructorType)) {
|
||||
// respond with the error from the handler
|
||||
response.status(error.statusCode);
|
||||
response.json(error);
|
||||
await Logger.error(error);
|
||||
} else {
|
||||
// the error is not allowed so something went wrong
|
||||
const internalServerError = new SCInternalServerErrorResponse(error, isTestEnvironment);
|
||||
response.status(internalServerError.statusCode);
|
||||
response.json(internalServerError);
|
||||
await Logger.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Error(
|
||||
'Invalid HTTP verb in route definition. Please check route definitions in `@openstapps/core`',
|
||||
);
|
||||
}
|
||||
|
||||
// return a SCMethodNotAllowedErrorResponse on all other HTTP methods
|
||||
route.all((_request, response) => {
|
||||
const error = new SCMethodNotAllowedErrorResponse(isTestEnvironment);
|
||||
response.status(error.statusCode);
|
||||
response.json(error);
|
||||
Logger.warn(error);
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user