mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
Compare commits
232
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07687f132b | ||
|
|
6d1703d79f | ||
|
|
967abed4f9 | ||
|
|
e7ddd0ea61 | ||
|
|
f628081f90 | ||
|
|
cf70bc751e | ||
|
|
2e275a7489 | ||
|
|
27728c9283 | ||
|
|
6c10182c60 | ||
|
|
c7f50c7de6 | ||
|
|
a547af1de3 | ||
|
|
febe214af6 | ||
|
|
aaea099e48 | ||
|
|
fdeff3c174 | ||
|
|
652acede70 | ||
|
|
c9eff55f05 | ||
|
|
9554d5b910 | ||
|
|
441d275948 | ||
|
|
c2f191b43c | ||
|
|
7f1c095039 | ||
|
|
39971e0c30 | ||
|
|
6478184ead | ||
|
|
35b6bdc582 | ||
|
|
fd583d5bf0 | ||
|
|
25765f6a7d | ||
|
|
c133c1fdb8 | ||
|
|
26683c3ba3 | ||
|
|
57a060c793 | ||
|
|
cae6088557 | ||
|
|
bb025b29b2 | ||
|
|
6269f8e4ba | ||
|
|
a83e54034f | ||
|
|
5b4db4121b | ||
|
|
463e4d5034 | ||
|
|
629217a128 | ||
|
|
621c554523 | ||
|
|
7b107886b4 | ||
|
|
0f334b7932 | ||
|
|
d18da4336d | ||
|
|
dbdd5d4640 | ||
|
|
42f5226e09 | ||
|
|
24d6518898 | ||
|
|
f7b0755011 | ||
|
|
cee91bec80 | ||
|
|
9c409be818 | ||
|
|
fdbeeeba5d | ||
|
|
7317bd3e0c | ||
|
|
9e0bc1e5a6 | ||
|
|
a9b79d4a34 | ||
|
|
57fd623f64 | ||
|
|
7f1db9fdaf | ||
|
|
950cbe7ff1 | ||
|
|
5b6922d4bc | ||
|
|
363e8b8f61 | ||
|
|
5142417020 | ||
|
|
85859805e0 | ||
|
|
1dab731bd8 | ||
|
|
5c56d03656 | ||
|
|
845bccfec5 | ||
|
|
412a1a539f | ||
|
|
e3175676c1 | ||
|
|
76dfd21949 | ||
|
|
c03df586d6 | ||
|
|
afaab641b1 | ||
|
|
51454a08d7 | ||
|
|
550272502e | ||
|
|
4a87f36ef3 | ||
|
|
a25f82a606 | ||
|
|
5f6d248502 | ||
|
|
c6aab19393 | ||
|
|
b760ab7be1 | ||
|
|
42e7969f42 | ||
|
|
7f1c0fdd4d | ||
|
|
18be9f31d2 | ||
|
|
ed65373e74 | ||
|
|
15f99aa8c5 | ||
|
|
59984b59c0 | ||
|
|
eeb61a3a2f | ||
|
|
68bf77cbad | ||
|
|
9a511efdd8 | ||
|
|
41b78a87e0 | ||
|
|
502eedffbd | ||
|
|
a06480439b | ||
|
|
7fce14beb7 | ||
|
|
f99a364148 | ||
|
|
1bd06b6c4b | ||
|
|
9f3236cc92 | ||
|
|
69b5ba751d | ||
|
|
ad45c80c3a | ||
|
|
43b195baa9 | ||
|
|
e3ebaca4b6 | ||
|
|
236ceb60de | ||
|
|
6fe766097b | ||
|
|
acd3c256cd | ||
|
|
6547ffbb46 | ||
|
|
3fbae278e6 | ||
|
|
d8fe1bd10c | ||
|
|
c704b9e04a | ||
|
|
637f66a91c | ||
|
|
8a71e33174 | ||
|
|
7f9358f358 | ||
|
|
00fa3a2082 | ||
|
|
47fe923883 | ||
|
|
cc562f6314 | ||
|
|
71c76e10d6 | ||
|
|
fdaed06adc | ||
|
|
371a736408 | ||
|
|
b7c5088603 | ||
|
|
07cf12a3ec | ||
|
|
61591cd2e7 | ||
|
|
db1c746cc2 | ||
|
|
55e24c3158 | ||
|
|
90ca6f6666 | ||
|
|
3c031dc7a0 | ||
|
|
baad2fabd4 | ||
|
|
bfd93d1071 | ||
|
|
2a8b0bef67 | ||
|
|
e0050414d6 | ||
|
|
35dac5f76e | ||
|
|
c9f28472fe | ||
|
|
cc6ec7eb6e | ||
|
|
72c739283e | ||
|
|
edc66f8722 | ||
|
|
e1c746aa68 | ||
|
|
32ee132dd9 | ||
|
|
0325f4c519 | ||
|
|
fae9cef1e4 | ||
|
|
2b78561654 | ||
|
|
5b8db1ddef | ||
|
|
d0f96f6587 | ||
|
|
a6a32d6d58 | ||
|
|
c8bb029509 | ||
|
|
c0c5bbd960 | ||
|
|
1f6f83f5c3 | ||
|
|
28ad3b03b7 | ||
|
|
33b8f27097 | ||
|
|
a6c98365d9 | ||
|
|
1b553c0455 | ||
|
|
9fd0d644cf | ||
|
|
c645215afc | ||
|
|
2c54574377 | ||
|
|
4fb8608908 | ||
|
|
75f7f82a3f | ||
|
|
5dd2c425ac | ||
|
|
9034e81c9b | ||
|
|
907f5a969a | ||
|
|
bbf5586935 | ||
|
|
1e03046d68 | ||
|
|
6c9b4aa498 | ||
|
|
02d9c344f2 | ||
|
|
4a635d7599 | ||
|
|
a038e4b3a2 | ||
|
|
3e29ce839f | ||
|
|
13bc31cf25 | ||
|
|
f536b39b03 | ||
|
|
0fab15c58e | ||
|
|
29c8717b60 | ||
|
|
255a6242cb | ||
|
|
a8b4f2dc55 | ||
|
|
795ba4cd41 | ||
|
|
fe52c3df12 | ||
|
|
c625ce428e | ||
|
|
7ce1e0bd48 | ||
|
|
c6a46fbdad | ||
|
|
81f85293f2 | ||
|
|
1cc18dd0f0 | ||
|
|
6b084424b5 | ||
|
|
006b30c441 | ||
|
|
5cd4447cbf | ||
|
|
88267716a3 | ||
|
|
23dca72cd3 | ||
|
|
b1ed38c2d0 | ||
|
|
3be2f320f8 | ||
|
|
d75ef19bbf | ||
|
|
e0cfb07f60 | ||
|
|
a53b164b45 | ||
|
|
63a605484c | ||
|
|
ef05288f81 | ||
|
|
7ee385fe45 | ||
|
|
80218df85e | ||
|
|
0371ba46f6 | ||
|
|
0883e0fec0 | ||
|
|
f7b1ccae9a | ||
|
|
bc9c85019f | ||
|
|
e5f712a857 | ||
|
|
d6e55f81ff | ||
|
|
ea1871b0df | ||
|
|
b570078223 | ||
|
|
5f79c2dd10 | ||
|
|
106dd1b07b | ||
|
|
a3036730b4 | ||
|
|
ad9b28af18 | ||
|
|
a7a3ccdb71 | ||
|
|
bd8a156908 | ||
|
|
62c2523aec | ||
|
|
95e0a88bbb | ||
|
|
1dfe6e60b3 | ||
|
|
6613ef2f18 | ||
|
|
b04fea4726 | ||
|
|
0d004926e6 | ||
|
|
fb9ebfcc10 | ||
|
|
a14971b790 | ||
|
|
51fc266bc2 | ||
|
|
6323fddbd8 | ||
|
|
7035a2e025 | ||
|
|
e1226515f6 | ||
|
|
8f07308342 | ||
|
|
d44e862a0c | ||
|
|
6bc9f1dae4 | ||
|
|
bf22bf9eed | ||
|
|
8ef463f8b0 | ||
|
|
9fae908602 | ||
|
|
8e8804a318 | ||
|
|
e1881a7645 | ||
|
|
f40cebf60b | ||
|
|
6f9b7031f4 | ||
|
|
be4108a573 | ||
|
|
0778a0e4d3 | ||
|
|
1f28eaecdb | ||
|
|
f2ebe46506 | ||
|
|
cb9e834a1f | ||
|
|
b11027d58f | ||
|
|
d22cea01ce | ||
|
|
b7946791f4 | ||
|
|
481a0b1da9 | ||
|
|
7096b0f8a3 | ||
|
|
b85702f169 | ||
|
|
69ec7cdeb6 | ||
|
|
b7f984fc8d | ||
|
|
efd12c8feb | ||
|
|
ed166a7291 | ||
|
|
8ccdc0fbc4 |
@@ -4,3 +4,8 @@
|
|||||||
# user defined files
|
# user defined files
|
||||||
.env
|
.env
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
# local-only agent docs + plan notes (never track: they hold credentials/creds refs)
|
||||||
|
references/
|
||||||
|
AGENTS.md
|
||||||
|
todo.md
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/access-token-encryptor monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/access-token-encryptor
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/access-token-encryptor
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/access-token-encryptor
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ access-token-encryptor
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/access-token-encryptor
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/fetch-utils monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/fetch-utils
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/fetch-utils
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/fetch-utils
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ fetch-utils
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/fetch-utils
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/logger monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/logger
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/logger
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/logger
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ logger
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/logger
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/metrics monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/metrics
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/metrics
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/metrics
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ metrics
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/metrics
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/mongo-utils monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/mongo-utils
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/mongo-utils
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/mongo-utils
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,7 +5,6 @@ mongo-utils
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/mongo-utils
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
--tsconfig-no-implicit-any=True
|
--tsconfig-no-implicit-any=True
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/o-error monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/o-error
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/o-error
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/o-error
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ o-error
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/o-error
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/object-persistor monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/object-persistor
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/object-persistor
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/object-persistor
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,7 +5,6 @@ object-persistor
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/object-persistor
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
--tsconfig-no-implicit-any=True
|
--tsconfig-no-implicit-any=True
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/overleaf-editor-core monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/overleaf-editor-core
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/overleaf-editor-core
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/overleaf-editor-core
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ overleaf-editor-core
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=overleaf-editor-core
|
|
||||||
--pipeline-owner=44
|
--pipeline-owner=44
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ class TrackedChange {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
this.tracking.type === other.tracking.type &&
|
this.tracking.canMergeWith(other.tracking) &&
|
||||||
this.tracking.userId === other.tracking.userId &&
|
|
||||||
this.range.touches(other.range) &&
|
this.range.touches(other.range) &&
|
||||||
this.range.canMerge(other.range)
|
this.range.canMerge(other.range)
|
||||||
)
|
)
|
||||||
@@ -75,13 +74,7 @@ class TrackedChange {
|
|||||||
}
|
}
|
||||||
return new TrackedChange(
|
return new TrackedChange(
|
||||||
this.range.merge(other.range),
|
this.range.merge(other.range),
|
||||||
new TrackingProps(
|
this.tracking.mergeWith(other.tracking)
|
||||||
this.tracking.type,
|
|
||||||
this.tracking.userId,
|
|
||||||
this.tracking.ts.getTime() > other.tracking.ts.getTime()
|
|
||||||
? this.tracking.ts
|
|
||||||
: other.tracking.ts
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -405,6 +405,49 @@ describe('TextOperation', function () {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it(
|
||||||
|
'compose associativity (randomised)',
|
||||||
|
random.test(numTrials, () => {
|
||||||
|
const str = random.string(20)
|
||||||
|
const comments = random.comments(6)
|
||||||
|
|
||||||
|
const a = randomOperation(str, comments.ids)
|
||||||
|
const afterA = new StringFileData(str, comments.comments)
|
||||||
|
a.apply(afterA)
|
||||||
|
|
||||||
|
const b = randomOperation(afterA.getContent(), comments.ids)
|
||||||
|
const afterB = new StringFileData(
|
||||||
|
afterA.getContent(),
|
||||||
|
comments.comments
|
||||||
|
)
|
||||||
|
b.apply(afterB)
|
||||||
|
|
||||||
|
const c = randomOperation(afterB.getContent(), comments.ids)
|
||||||
|
|
||||||
|
const ab = a.compose(b)
|
||||||
|
const ab_c = ab.compose(c)
|
||||||
|
|
||||||
|
const bc = b.compose(c)
|
||||||
|
const a_bc = a.compose(bc)
|
||||||
|
|
||||||
|
const ab_c_file = new StringFileData(str, comments.comments)
|
||||||
|
ab_c.apply(ab_c_file)
|
||||||
|
|
||||||
|
const a_bc_file = new StringFileData(str, comments.comments)
|
||||||
|
a_bc.apply(a_bc_file)
|
||||||
|
|
||||||
|
const fuzzingError = fuzzingErrorMessage({
|
||||||
|
str,
|
||||||
|
comments,
|
||||||
|
a: a.toJSON(),
|
||||||
|
b: b.toJSON(),
|
||||||
|
c: c.toJSON(),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ab_c_file.toRaw()).to.deep.equal(a_bc_file.toRaw(), fuzzingError)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
it('composes two operations with comments', function () {
|
it('composes two operations with comments', function () {
|
||||||
expect(
|
expect(
|
||||||
compose(
|
compose(
|
||||||
@@ -625,11 +668,54 @@ describe('TextOperation', function () {
|
|||||||
a: a.toJSON(),
|
a: a.toJSON(),
|
||||||
b: b.toJSON(),
|
b: b.toJSON(),
|
||||||
})
|
})
|
||||||
expect(abPrime.equals(baPrime)).to.be.equal(true, fuzzingError)
|
// The composition of ab' and ba' is not guaranteed to be equal, but
|
||||||
|
// should converge to the same file contents + ranges.
|
||||||
expect(abFile.toRaw()).to.deep.equal(baFile.toRaw(), fuzzingError)
|
expect(abFile.toRaw()).to.deep.equal(baFile.toRaw(), fuzzingError)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it('chooses lower tracked change timestamp', function () {
|
||||||
|
const ts1 = '2024-01-01T01:00:00.000Z'
|
||||||
|
const ts2 = '2024-01-01T02:00:00.000Z'
|
||||||
|
const str = 'abcde'
|
||||||
|
const comments = []
|
||||||
|
|
||||||
|
const a = new TextOperation()
|
||||||
|
.retain(2, {
|
||||||
|
tracking: TrackingProps.fromRaw({
|
||||||
|
ts: ts1,
|
||||||
|
type: 'insert',
|
||||||
|
userId: 'user1',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.retain(1)
|
||||||
|
.retain(2, {
|
||||||
|
tracking: TrackingProps.fromRaw({
|
||||||
|
ts: ts2,
|
||||||
|
type: 'insert',
|
||||||
|
userId: 'user1',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const b = new TextOperation().retain(1).remove(3).retain(1)
|
||||||
|
|
||||||
|
const [aPrime, bPrime] = TextOperation.transform(a, b)
|
||||||
|
const aComposeBPrime = a.compose(bPrime)
|
||||||
|
const bComposeAPrime = b.compose(aPrime)
|
||||||
|
|
||||||
|
const aBPFile = new StringFileData(str, comments)
|
||||||
|
aComposeBPrime.apply(aBPFile)
|
||||||
|
|
||||||
|
const bAPFile = new StringFileData(str, comments)
|
||||||
|
bComposeAPrime.apply(bAPFile)
|
||||||
|
|
||||||
|
expect(aBPFile.toRaw()).to.deep.equal(bAPFile.toRaw())
|
||||||
|
expect(aBPFile.trackedChanges.length).to.equal(1)
|
||||||
|
expect(
|
||||||
|
aBPFile.trackedChanges.asSorted()[0].tracking.ts.toISOString()
|
||||||
|
).to.equal(ts1)
|
||||||
|
})
|
||||||
|
|
||||||
it('adds a tracked change from operation 1', function () {
|
it('adds a tracked change from operation 1', function () {
|
||||||
expect(
|
expect(
|
||||||
transform(
|
transform(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { expect } = require('chai')
|
|||||||
describe('TrackedChangeList', function () {
|
describe('TrackedChangeList', function () {
|
||||||
describe('applyInsert', function () {
|
describe('applyInsert', function () {
|
||||||
describe('with same author', function () {
|
describe('with same author', function () {
|
||||||
it('should merge consecutive tracked changes and use the latest timestamp', function () {
|
it('should merge consecutive tracked changes and use the earliest timestamp', function () {
|
||||||
const trackedChanges = TrackedChangeList.fromRaw([
|
const trackedChanges = TrackedChangeList.fromRaw([
|
||||||
{
|
{
|
||||||
range: { pos: 0, length: 3 },
|
range: { pos: 0, length: 3 },
|
||||||
@@ -33,7 +33,7 @@ describe('TrackedChangeList', function () {
|
|||||||
tracking: {
|
tracking: {
|
||||||
type: 'insert',
|
type: 'insert',
|
||||||
userId: 'user1',
|
userId: 'user1',
|
||||||
ts: '2024-01-01T00:00:00.000Z',
|
ts: '2023-01-01T00:00:00.000Z',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -699,7 +699,7 @@ describe('TrackedChangeList', function () {
|
|||||||
tracking: {
|
tracking: {
|
||||||
type: 'insert',
|
type: 'insert',
|
||||||
userId: 'user1',
|
userId: 'user1',
|
||||||
ts: '2024-01-01T00:00:00.000Z',
|
ts: '2023-01-01T00:00:00.000Z',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/promise-utils monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/promise-utils
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/promise-utils
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/promise-utils
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ promise-utils
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/promise-utils
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/ranges-tracker monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/ranges-tracker
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/ranges-tracker
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/ranges-tracker
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ ranges-tracker
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/ranges-tracker
|
|
||||||
--pipeline-owner=44
|
--pipeline-owner=44
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ class RangesTracker {
|
|||||||
offset = opStart - changeStart
|
offset = opStart - changeStart
|
||||||
change.op.i =
|
change.op.i =
|
||||||
change.op.i.slice(0, offset) + op.i + change.op.i.slice(offset)
|
change.op.i.slice(0, offset) + op.i + change.op.i.slice(offset)
|
||||||
change.metadata.ts = metadata.ts
|
change.metadata.ts = pickTimestamp(change.metadata, metadata)
|
||||||
alreadyMerged = true
|
alreadyMerged = true
|
||||||
movedChanges.push(change)
|
movedChanges.push(change)
|
||||||
} else if (opStart <= changeStart) {
|
} else if (opStart <= changeStart) {
|
||||||
@@ -728,6 +728,10 @@ class RangesTracker {
|
|||||||
) {
|
) {
|
||||||
removeChanges.push(change)
|
removeChanges.push(change)
|
||||||
previousChange.op.i += change.op.i
|
previousChange.op.i += change.op.i
|
||||||
|
previousChange.metadata.ts = pickTimestamp(
|
||||||
|
previousChange.metadata,
|
||||||
|
change.metadata
|
||||||
|
)
|
||||||
movedChanges.push(previousChange)
|
movedChanges.push(previousChange)
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
@@ -790,4 +794,15 @@ class RangesTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pickTimestamp(oldMetadata, newMetadata) {
|
||||||
|
// Make sure null values don't get treated as 1970-01-01 dates in the
|
||||||
|
// comparison below.
|
||||||
|
if (oldMetadata.ts == null) return newMetadata.ts
|
||||||
|
if (newMetadata.ts == null) return oldMetadata.ts
|
||||||
|
|
||||||
|
return new Date(oldMetadata.ts) < new Date(newMetadata.ts)
|
||||||
|
? oldMetadata.ts
|
||||||
|
: newMetadata.ts
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = RangesTracker
|
module.exports = RangesTracker
|
||||||
|
|||||||
@@ -222,4 +222,114 @@ describe('RangesTracker', function () {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('merging tracked inserts from the same user', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
this.comments = []
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps the earlier timestamp when the existing insert is older', function () {
|
||||||
|
this.rangesTracker = new RangesTracker(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'id1',
|
||||||
|
op: { p: 10, i: 'foo' },
|
||||||
|
metadata: { user_id: 'user-1', ts: '2024-01-01T00:00:00.000Z' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
this.comments
|
||||||
|
)
|
||||||
|
this.rangesTracker.track_changes = true
|
||||||
|
this.rangesTracker.applyOp(
|
||||||
|
{ p: 13, i: 'bar' },
|
||||||
|
{ user_id: 'user-1', ts: new Date('2024-06-01T00:00:00.000Z') }
|
||||||
|
)
|
||||||
|
expect(this.rangesTracker.changes).to.have.length(1)
|
||||||
|
const [change] = this.rangesTracker.changes
|
||||||
|
expect(change.op).to.deep.equal({ p: 10, i: 'foobar' })
|
||||||
|
expect(change.metadata.user_id).to.equal('user-1')
|
||||||
|
expect(new Date(change.metadata.ts).toISOString()).to.equal(
|
||||||
|
'2024-01-01T00:00:00.000Z'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps the earlier timestamp when the incoming insert is older', function () {
|
||||||
|
this.rangesTracker = new RangesTracker(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'id1',
|
||||||
|
op: { p: 10, i: 'foo' },
|
||||||
|
metadata: { user_id: 'user-1', ts: '2024-06-01T00:00:00.000Z' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
this.comments
|
||||||
|
)
|
||||||
|
this.rangesTracker.track_changes = true
|
||||||
|
this.rangesTracker.applyOp(
|
||||||
|
{ p: 13, i: 'bar' },
|
||||||
|
{ user_id: 'user-1', ts: new Date('2024-01-01T00:00:00.000Z') }
|
||||||
|
)
|
||||||
|
expect(this.rangesTracker.changes).to.have.length(1)
|
||||||
|
const [change] = this.rangesTracker.changes
|
||||||
|
expect(change.op).to.deep.equal({ p: 10, i: 'foobar' })
|
||||||
|
expect(change.metadata.user_id).to.equal('user-1')
|
||||||
|
expect(new Date(change.metadata.ts).toISOString()).to.equal(
|
||||||
|
'2024-01-01T00:00:00.000Z'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses the defined timestamp when the existing insert has a null timestamp', function () {
|
||||||
|
this.rangesTracker = new RangesTracker(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'id1',
|
||||||
|
op: { p: 10, i: 'foo' },
|
||||||
|
metadata: { user_id: 'user-1', ts: null },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
this.comments
|
||||||
|
)
|
||||||
|
this.rangesTracker.track_changes = true
|
||||||
|
this.rangesTracker.applyOp(
|
||||||
|
{ p: 13, i: 'bar' },
|
||||||
|
{ user_id: 'user-1', ts: new Date('2024-01-01T00:00:00.000Z') }
|
||||||
|
)
|
||||||
|
expect(this.rangesTracker.changes).to.have.length(1)
|
||||||
|
const [change] = this.rangesTracker.changes
|
||||||
|
expect(new Date(change.metadata.ts).toISOString()).to.equal(
|
||||||
|
'2024-01-01T00:00:00.000Z'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('keeps the earlier timestamp when re-merging inserts after a deletion', function () {
|
||||||
|
this.rangesTracker = new RangesTracker(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'id1',
|
||||||
|
op: { p: 10, i: 'aaa' },
|
||||||
|
metadata: { user_id: 'user-1', ts: '2024-03-01T00:00:00.000Z' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'id2',
|
||||||
|
op: { p: 13, i: 'bb' },
|
||||||
|
metadata: { user_id: 'user-2', ts: '2024-02-01T00:00:00.000Z' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'id3',
|
||||||
|
op: { p: 15, i: 'ccc' },
|
||||||
|
metadata: { user_id: 'user-1', ts: '2024-01-01T00:00:00.000Z' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
this.comments
|
||||||
|
)
|
||||||
|
this.rangesTracker.applyOp({ p: 13, d: 'bb' })
|
||||||
|
expect(this.rangesTracker.changes).to.have.length(1)
|
||||||
|
const [change] = this.rangesTracker.changes
|
||||||
|
expect(change.op).to.deep.equal({ p: 10, i: 'aaaccc' })
|
||||||
|
expect(change.metadata.user_id).to.equal('user-1')
|
||||||
|
expect(new Date(change.metadata.ts).toISOString()).to.equal(
|
||||||
|
'2024-01-01T00:00:00.000Z'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/redis-wrapper monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/redis-wrapper
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/redis-wrapper
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/redis-wrapper
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ redis-wrapper
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/redis-wrapper
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/settings monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/settings
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/settings
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/settings
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ settings
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/settings
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/stream-utils monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/stream-utils
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/stream-utils
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/stream-utils
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,6 +5,5 @@ stream-utils
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/stream-utils
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Run the test commands in the scope of the monorepo.
|
||||||
|
# Eslint and prettier (plus some configs) are on the root.
|
||||||
|
RUN_LINTING = ../../bin/run -w /overleaf/libraries/validation-tools monorepo yarn run --silent
|
||||||
|
RUN_LINTING_MONOREPO = ../../bin/run monorepo yarn run --silent
|
||||||
|
|
||||||
|
WITH_CACHE_FOLDER = \
|
||||||
|
lint \
|
||||||
|
lint_ci \
|
||||||
|
lint_fix \
|
||||||
|
format \
|
||||||
|
format_ci \
|
||||||
|
format_fix \
|
||||||
|
typecheck \
|
||||||
|
typecheck_ci \
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/prettier/
|
||||||
|
../../node_modules/.cache/prettier/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
$(WITH_CACHE_FOLDER): ../../node_modules/.cache/eslint/
|
||||||
|
../../node_modules/.cache/eslint/:
|
||||||
|
mkdir -p $@
|
||||||
|
|
||||||
|
format:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/validation-tools
|
||||||
|
|
||||||
|
format_ci:
|
||||||
|
$(RUN_LINTING_MONOREPO) format libraries/validation-tools
|
||||||
|
|
||||||
|
format_fix:
|
||||||
|
$(RUN_LINTING_MONOREPO) format:fix libraries/validation-tools
|
||||||
|
|
||||||
|
lint:
|
||||||
|
$(RUN_LINTING) lint
|
||||||
|
|
||||||
|
lint_ci:
|
||||||
|
-$(RUN_LINTING) lint --format json --output-file reports/eslint.json
|
||||||
|
sed -i 's_"filePath":"/overleaf_"filePath":"$(MONOREPO)_g' reports/eslint.json
|
||||||
|
|
||||||
|
lint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
|
typecheck:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
typecheck_ci:
|
||||||
|
$(RUN_LINTING) types:check
|
||||||
|
|
||||||
|
test: test_unit
|
||||||
|
test_unit:
|
||||||
|
ifneq (,$(wildcard test/unit))
|
||||||
|
$(RUN_LINTING) test:unit
|
||||||
|
endif
|
||||||
|
|
||||||
|
test: test_acceptance
|
||||||
|
test_acceptance:
|
||||||
|
ifneq (,$(wildcard test/acceptance))
|
||||||
|
$(RUN_LINTING) test:acceptance
|
||||||
|
endif
|
||||||
@@ -5,7 +5,6 @@ validation-tools
|
|||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--is-library=True
|
--is-library=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/validation-tools
|
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
--test-acceptance-vitest=True
|
--test-acceptance-vitest=True
|
||||||
--test-unit-vitest=True
|
--test-unit-vitest=True
|
||||||
|
|||||||
+8
-5
@@ -41,12 +41,13 @@
|
|||||||
"sandboxed-module": "patch:sandboxed-module@npm%3A2.0.4#~/.yarn/patches/sandboxed-module-npm-2.0.4-f8b45aacc9.patch",
|
"sandboxed-module": "patch:sandboxed-module@npm%3A2.0.4#~/.yarn/patches/sandboxed-module-npm-2.0.4-f8b45aacc9.patch",
|
||||||
"request/tough-cookie": "5.1.2",
|
"request/tough-cookie": "5.1.2",
|
||||||
"request/form-data": "2.5.5",
|
"request/form-data": "2.5.5",
|
||||||
"request/qs": "6.14.1",
|
"request/qs": "6.15.2",
|
||||||
"@cypress/request/qs": "6.14.1",
|
"@cypress/request/qs": "6.15.2",
|
||||||
|
"qs": "6.15.2",
|
||||||
"@opentelemetry/api": "1.9.0",
|
"@opentelemetry/api": "1.9.0",
|
||||||
"mocha/serialize-javascript": "7.0.5",
|
"mocha/serialize-javascript": "7.0.5",
|
||||||
"pprof/protobufjs": "7.5.5",
|
"protobufjs": "7.6.3",
|
||||||
"@google-cloud/profiler/protobufjs": "7.5.5",
|
"@protobufjs/utf8": "1.1.1",
|
||||||
"mocha-multi-reporters": "patch:mocha-multi-reporters@npm%3A1.5.1#~/.yarn/patches/mocha-multi-reporters-npm-1.5.1-0a1088aed5.patch",
|
"mocha-multi-reporters": "patch:mocha-multi-reporters@npm%3A1.5.1#~/.yarn/patches/mocha-multi-reporters-npm-1.5.1-0a1088aed5.patch",
|
||||||
"pdfjs-dist": "patch:pdfjs-dist@npm%3A5.1.91#~/.yarn/patches/pdfjs-dist-npm-5.1.91.patch",
|
"pdfjs-dist": "patch:pdfjs-dist@npm%3A5.1.91#~/.yarn/patches/pdfjs-dist-npm-5.1.91.patch",
|
||||||
"referer-parser": "patch:referer-parser@npm%3A0.0.3#~/.yarn/patches/referer-parser-npm-0.0.3.patch",
|
"referer-parser": "patch:referer-parser@npm%3A0.0.3#~/.yarn/patches/referer-parser-npm-0.0.3.patch",
|
||||||
@@ -101,11 +102,12 @@
|
|||||||
"cluster-key-slot": "1.1.0",
|
"cluster-key-slot": "1.1.0",
|
||||||
"@octokit/request": "9.2.2",
|
"@octokit/request": "9.2.2",
|
||||||
"randomstring": "1.2.2",
|
"randomstring": "1.2.2",
|
||||||
"vite": "7.3.1",
|
"vite": "7.3.5",
|
||||||
"isomorphic-git": "1.33.1",
|
"isomorphic-git": "1.33.1",
|
||||||
"http-status": "1.5.0",
|
"http-status": "1.5.0",
|
||||||
"knex": "2.4.0",
|
"knex": "2.4.0",
|
||||||
"utf-8-validate": "5.0.8",
|
"utf-8-validate": "5.0.8",
|
||||||
|
"ws@npm:^8": "8.21.0",
|
||||||
"samlp": "7.0.2",
|
"samlp": "7.0.2",
|
||||||
"compression": "1.7.4",
|
"compression": "1.7.4",
|
||||||
"cookie-parser": "1.4.6",
|
"cookie-parser": "1.4.6",
|
||||||
@@ -198,6 +200,7 @@
|
|||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"jobs/mirror-documentation",
|
"jobs/mirror-documentation",
|
||||||
|
"jobs/wiki-algolia",
|
||||||
"libraries/*",
|
"libraries/*",
|
||||||
"server-ce/test",
|
"server-ce/test",
|
||||||
"services/analytics",
|
"services/analytics",
|
||||||
|
|||||||
@@ -8,3 +8,13 @@ server-ce/test
|
|||||||
services/web/scripts/plan-prices
|
services/web/scripts/plan-prices
|
||||||
services/web/scripts/translations
|
services/web/scripts/translations
|
||||||
services/web/scripts/ukamf
|
services/web/scripts/ukamf
|
||||||
|
|
||||||
|
# dev-environment node_modules symlinks must never enter the image:
|
||||||
|
# BuildKit cannot replace a directory already present in the base/cache
|
||||||
|
# layer (overleaf/services/web/node_modules) with a file/symlink
|
||||||
|
node_modules
|
||||||
|
services/web/node_modules
|
||||||
|
libraries/*/node_modules
|
||||||
|
services/*/node_modules
|
||||||
|
services/web/modules/*/node_modules
|
||||||
|
tools/migrations/node_modules
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import {
|
|||||||
createNewFile,
|
createNewFile,
|
||||||
createProjectAndOpenInNewEditor,
|
createProjectAndOpenInNewEditor,
|
||||||
openProjectById,
|
openProjectById,
|
||||||
|
openProjectByName,
|
||||||
|
shareProjectByEmailAndAcceptInviteViaDash,
|
||||||
testNewFileUpload,
|
testNewFileUpload,
|
||||||
} from './helpers/project'
|
} from './helpers/project'
|
||||||
import { isExcludedBySharding, startWith } from './helpers/config'
|
import { isExcludedBySharding, startWith } from './helpers/config'
|
||||||
@@ -321,6 +323,124 @@ describe('editor', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('editing mode', function () {
|
||||||
|
if (isExcludedBySharding('PRO_DEFAULT_1')) return
|
||||||
|
startWith({ pro: true })
|
||||||
|
|
||||||
|
const OWNER = USER
|
||||||
|
const EDITOR = COLLABORATOR
|
||||||
|
const REVIEWER = 'reviewer@example.com'
|
||||||
|
const VIEWER = 'viewer@example.com'
|
||||||
|
ensureUserExists({ email: OWNER })
|
||||||
|
ensureUserExists({ email: EDITOR })
|
||||||
|
ensureUserExists({ email: REVIEWER })
|
||||||
|
ensureUserExists({ email: VIEWER })
|
||||||
|
|
||||||
|
let projectName: string
|
||||||
|
|
||||||
|
function openEditingModeMenu() {
|
||||||
|
cy.findByRole('button', { name: 'View' }).click()
|
||||||
|
cy.findByRole('menuitem', { name: 'Editing mode' }).click()
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeWithReRunOnTestRetry(() => {
|
||||||
|
projectName = `project-${uuid()}`
|
||||||
|
login(OWNER)
|
||||||
|
createProjectAndOpenInNewEditor(projectName, { type: 'Example project' })
|
||||||
|
|
||||||
|
shareProjectByEmailAndAcceptInviteViaDash(
|
||||||
|
projectName,
|
||||||
|
EDITOR,
|
||||||
|
'Editor',
|
||||||
|
true
|
||||||
|
)
|
||||||
|
login(OWNER)
|
||||||
|
shareProjectByEmailAndAcceptInviteViaDash(
|
||||||
|
projectName,
|
||||||
|
REVIEWER,
|
||||||
|
'Reviewer',
|
||||||
|
true
|
||||||
|
)
|
||||||
|
login(OWNER)
|
||||||
|
shareProjectByEmailAndAcceptInviteViaDash(
|
||||||
|
projectName,
|
||||||
|
VIEWER,
|
||||||
|
'Viewer',
|
||||||
|
true
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('lets an editor switch between editing and reviewing', function () {
|
||||||
|
login(EDITOR)
|
||||||
|
openProjectByName(projectName, true)
|
||||||
|
|
||||||
|
openEditingModeMenu()
|
||||||
|
cy.findByRole('menuitem', { name: 'Editing' })
|
||||||
|
.should('have.attr', 'aria-selected', 'true')
|
||||||
|
.and('not.have.attr', 'aria-disabled')
|
||||||
|
cy.findByRole('menuitem', { name: 'Reviewing' })
|
||||||
|
.should('have.attr', 'aria-selected', 'false')
|
||||||
|
.and('not.have.attr', 'aria-disabled')
|
||||||
|
cy.findByRole('menuitem', { name: 'Viewing' }).should('not.exist')
|
||||||
|
|
||||||
|
cy.findByRole('menuitem', { name: 'Reviewing' }).click()
|
||||||
|
cy.findByRole('button', { name: 'Reviewing' }).should('exist')
|
||||||
|
|
||||||
|
openEditingModeMenu()
|
||||||
|
cy.findByRole('menuitem', { name: 'Reviewing' }).should(
|
||||||
|
'have.attr',
|
||||||
|
'aria-selected',
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
cy.findByRole('menuitem', { name: 'Editing' }).should(
|
||||||
|
'have.attr',
|
||||||
|
'aria-selected',
|
||||||
|
'false'
|
||||||
|
)
|
||||||
|
|
||||||
|
cy.findByRole('menuitem', { name: 'Editing' }).click()
|
||||||
|
cy.findByRole('button', { name: 'Editing' }).should('exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows a reviewer in reviewing mode with editing disabled', function () {
|
||||||
|
login(REVIEWER)
|
||||||
|
openProjectByName(projectName, true)
|
||||||
|
|
||||||
|
openEditingModeMenu()
|
||||||
|
cy.findByRole('menuitem', { name: 'Reviewing' })
|
||||||
|
.should('have.attr', 'aria-selected', 'true')
|
||||||
|
.and('not.have.attr', 'aria-disabled')
|
||||||
|
cy.findByRole('menuitem', { name: 'Editing' }).should(
|
||||||
|
'have.attr',
|
||||||
|
'aria-disabled',
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
cy.findByRole('menuitem', { name: 'Viewing' }).should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows a viewer in viewing mode with editing and reviewing disabled', function () {
|
||||||
|
login(VIEWER)
|
||||||
|
openProjectByName(projectName, true)
|
||||||
|
|
||||||
|
openEditingModeMenu()
|
||||||
|
cy.findByRole('menuitem', { name: 'Viewing' }).should(
|
||||||
|
'have.attr',
|
||||||
|
'aria-selected',
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
cy.findByRole('menuitem', { name: 'Editing' }).should(
|
||||||
|
'have.attr',
|
||||||
|
'aria-disabled',
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
cy.findByRole('menuitem', { name: 'Reviewing' }).should(
|
||||||
|
'have.attr',
|
||||||
|
'aria-disabled',
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
function createRandomLetterString() {
|
function createRandomLetterString() {
|
||||||
const chars = 'abcdefghijklmnopqrstuvwxyz'
|
const chars = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
let result = ''
|
let result = ''
|
||||||
|
|||||||
@@ -256,7 +256,12 @@ describe('filestore migration', function () {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// 5.x
|
// 5.x
|
||||||
startWith({ version: '5.5.5', pro: true, withDataDir: true })
|
startWith({
|
||||||
|
version: '5.5.5',
|
||||||
|
pro: true,
|
||||||
|
withDataDir: true,
|
||||||
|
resetData: true,
|
||||||
|
})
|
||||||
defaultImage = 'frog.jpg'
|
defaultImage = 'frog.jpg'
|
||||||
ensureUserExists({ email })
|
ensureUserExists({ email })
|
||||||
before(function () {
|
before(function () {
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ export function openProjectViaInviteNotification(
|
|||||||
function shareProjectByEmail(
|
function shareProjectByEmail(
|
||||||
projectName: string,
|
projectName: string,
|
||||||
email: string,
|
email: string,
|
||||||
level: 'Viewer' | 'Editor',
|
level: 'Viewer' | 'Editor' | 'Reviewer',
|
||||||
newEditor: boolean = false
|
newEditor: boolean = false
|
||||||
) {
|
) {
|
||||||
openProjectByName(projectName, newEditor)
|
openProjectByName(projectName, newEditor)
|
||||||
@@ -231,7 +231,7 @@ function shareProjectByEmail(
|
|||||||
export function shareProjectByEmailAndAcceptInviteViaDash(
|
export function shareProjectByEmailAndAcceptInviteViaDash(
|
||||||
projectName: string,
|
projectName: string,
|
||||||
email: string,
|
email: string,
|
||||||
level: 'Viewer' | 'Editor',
|
level: 'Viewer' | 'Editor' | 'Reviewer',
|
||||||
newEditor: boolean = false
|
newEditor: boolean = false
|
||||||
) {
|
) {
|
||||||
shareProjectByEmail(projectName, email, level, newEditor)
|
shareProjectByEmail(projectName, email, level, newEditor)
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry
|
|||||||
|
|
||||||
describe('Project Sharing', function () {
|
describe('Project Sharing', function () {
|
||||||
if (isExcludedBySharding('PRO_CUSTOM_4')) return
|
if (isExcludedBySharding('PRO_CUSTOM_4')) return
|
||||||
|
startWith({ withDataDir: true, pro: true, resetData: true })
|
||||||
ensureUserExists({ email: 'user@example.com' })
|
ensureUserExists({ email: 'user@example.com' })
|
||||||
startWith({ withDataDir: true, pro: true })
|
|
||||||
|
|
||||||
let projectName: string
|
let projectName: string
|
||||||
let recompile: () => void
|
let recompile: () => void
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = chat
|
export PROJECT_NAME = chat
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -28,13 +28,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/tools/migrations/package.json \
|
$(MONOREPO)/tools/migrations/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ chat
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/chat
|
|
||||||
--pipeline-owner=44
|
--pipeline-owner=44
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/chat/reports
|
- ./reports:/overleaf/services/chat/reports
|
||||||
@@ -21,7 +21,7 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -42,7 +42,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ before('run migrations', async function () {
|
|||||||
this.timeout(60_000)
|
this.timeout(60_000)
|
||||||
|
|
||||||
await promisify(exec)(
|
await promisify(exec)(
|
||||||
`cd ../../tools/migrations && npm run migrations -- migrate -t server-ce`
|
`cd ../../tools/migrations && yarn run migrations migrate -t 'server-ce & !nonblocking'`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
compiles
|
compiles
|
||||||
output
|
output
|
||||||
cache
|
cache
|
||||||
uploads
|
uploads
|
||||||
|
sharded
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = clsi
|
export PROJECT_NAME = clsi
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -29,13 +29,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/services/clsi/package.json \
|
$(MONOREPO)/services/clsi/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -192,6 +192,11 @@ async function doCompile(request, stats, timings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass through checkpoint setting
|
||||||
|
if (request.enableCheckpoint) {
|
||||||
|
env.ENABLE_CHECKPOINT = '1'
|
||||||
|
}
|
||||||
|
|
||||||
const compileStart = Date.now()
|
const compileStart = Date.now()
|
||||||
|
|
||||||
const compileName = getCompileName(request.project_id, request.user_id)
|
const compileName = getCompileName(request.project_id, request.user_id)
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ const LATEX_EXPORT_CONFIGS = {
|
|||||||
'--to',
|
'--to',
|
||||||
'html',
|
'html',
|
||||||
'--standalone',
|
'--standalone',
|
||||||
|
'--mathml',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ function parse(body, callback) {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
response.enableCheckpoint = _parseAttribute(
|
||||||
|
'enableCheckpoint',
|
||||||
|
compile.options.enableCheckpoint,
|
||||||
|
{ default: false, type: 'boolean' }
|
||||||
|
)
|
||||||
response.timeout = _parseAttribute('timeout', compile.options.timeout, {
|
response.timeout = _parseAttribute('timeout', compile.options.timeout, {
|
||||||
default: MAX_TIMEOUT,
|
default: MAX_TIMEOUT,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
|||||||
@@ -23,9 +23,15 @@ import Metrics from '@overleaf/metrics'
|
|||||||
import logger from '@overleaf/logger'
|
import logger from '@overleaf/logger'
|
||||||
import settings from '@overleaf/settings'
|
import settings from '@overleaf/settings'
|
||||||
import ClsiMetrics from './Metrics.js'
|
import ClsiMetrics from './Metrics.js'
|
||||||
|
import { Minimatch } from 'minimatch'
|
||||||
|
|
||||||
const { shouldSkipMetrics } = ClsiMetrics
|
const { shouldSkipMetrics } = ClsiMetrics
|
||||||
|
|
||||||
|
// Additional file patterns to keep between compiles
|
||||||
|
const preciousFileMatcher = new Minimatch(settings.preciousFilePattern, {
|
||||||
|
dot: true,
|
||||||
|
})
|
||||||
|
|
||||||
let ResourceWriter
|
let ResourceWriter
|
||||||
|
|
||||||
const parallelFileDownloads = settings.parallelFileDownloads || 1
|
const parallelFileDownloads = settings.parallelFileDownloads || 1
|
||||||
@@ -265,6 +271,10 @@ export default ResourceWriter = {
|
|||||||
// Epstopdf generated files
|
// Epstopdf generated files
|
||||||
shouldDelete = false
|
shouldDelete = false
|
||||||
}
|
}
|
||||||
|
// Keep additional precious files and directories
|
||||||
|
if (shouldDelete && preciousFileMatcher.match(path)) {
|
||||||
|
shouldDelete = false
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
path === 'output.tar.gz' ||
|
path === 'output.tar.gz' ||
|
||||||
path === 'output.synctex.gz' ||
|
path === 'output.synctex.gz' ||
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ clsi
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/clsi
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=True
|
--public-repo=True
|
||||||
--test-unit-vitest=True
|
--test-unit-vitest=True
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ module.exports = {
|
|||||||
process.env.PDFTOCAIRO_IMAGE || 'quay.io/sharelatex/pdftocairo:24.02',
|
process.env.PDFTOCAIRO_IMAGE || 'quay.io/sharelatex/pdftocairo:24.02',
|
||||||
enablePdfConversions: process.env.ENABLE_PDF_CONVERSIONS === 'true',
|
enablePdfConversions: process.env.ENABLE_PDF_CONVERSIONS === 'true',
|
||||||
maxUploadSize: 50 * 1024 * 1024,
|
maxUploadSize: 50 * 1024 * 1024,
|
||||||
|
preciousFilePattern: process.env.PRECIOUS_FILE_PATTERN || '',
|
||||||
|
|
||||||
internal: {
|
internal: {
|
||||||
clsi: {
|
clsi: {
|
||||||
@@ -202,6 +203,16 @@ if ((process.env.DOCKER_RUNNER || process.env.SANDBOXED_COMPILES) === 'true') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.NEW_APPARMOR_PROFILE) {
|
||||||
|
try {
|
||||||
|
module.exports.clsi.docker.new_apparmor_profile =
|
||||||
|
process.env.NEW_APPARMOR_PROFILE
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error, 'could not apply new apparmor profile setting')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.ALLOWED_IMAGES) {
|
if (process.env.ALLOWED_IMAGES) {
|
||||||
try {
|
try {
|
||||||
module.exports.clsi.docker.allowedImages =
|
module.exports.clsi.docker.allowedImages =
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/clsi/reports
|
- ./reports:/overleaf/services/clsi/reports
|
||||||
- ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json
|
- ../../tsconfig.backend.json:/overleaf/tsconfig.backend.json
|
||||||
@@ -17,7 +17,7 @@ services:
|
|||||||
VITEST_NO_CACHE: true
|
VITEST_NO_CACHE: true
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -51,7 +51,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"dockerode": "^4.0.9",
|
"dockerode": "^4.0.9",
|
||||||
"express": "4.22.1",
|
"express": "4.22.1",
|
||||||
"lodash": "^4.18.1",
|
"lodash": "^4.18.1",
|
||||||
|
"minimatch": "^10.2.5",
|
||||||
"multer": "2.1.1",
|
"multer": "2.1.1",
|
||||||
"overleaf-editor-core": "workspace:*",
|
"overleaf-editor-core": "workspace:*",
|
||||||
"p-limit": "^3.1.0",
|
"p-limit": "^3.1.0",
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ const LATEX_TO_DOCUMENT_CASES = [
|
|||||||
'--to',
|
'--to',
|
||||||
'html',
|
'html',
|
||||||
'--standalone',
|
'--standalone',
|
||||||
|
'--mathml',
|
||||||
'--resource-path=..',
|
'--resource-path=..',
|
||||||
'--extract-media=.',
|
'--extract-media=.',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ describe('ResourceWriter', () => {
|
|||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
vi.doMock('@overleaf/settings', () => ({
|
||||||
|
default: (ctx.settings = {
|
||||||
|
preciousFilePattern: '{keepdir/**,.other/keepdir/**}',
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
vi.doMock('../../../app/js/ResourceStateManager', () => ({
|
vi.doMock('../../../app/js/ResourceStateManager', () => ({
|
||||||
default: (ctx.ResourceStateManager = {}),
|
default: (ctx.ResourceStateManager = {}),
|
||||||
}))
|
}))
|
||||||
@@ -246,6 +252,12 @@ describe('ResourceWriter', () => {
|
|||||||
{
|
{
|
||||||
path: 'output.stderr',
|
path: 'output.stderr',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'keepdir/file',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '.other/keepdir/.subdir/file',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
ctx.resources = 'mock-resources'
|
ctx.resources = 'mock-resources'
|
||||||
ctx.request = {
|
ctx.request = {
|
||||||
@@ -297,6 +309,18 @@ describe('ResourceWriter', () => {
|
|||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not delete additionally specified files', ctx => {
|
||||||
|
return ctx.ResourceWriter._deleteFileIfNotDirectory
|
||||||
|
.calledWith(path.join(ctx.basePath, 'keepdir/file'))
|
||||||
|
.should.equal(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not delete additionally specified hidden files', ctx => {
|
||||||
|
return ctx.ResourceWriter._deleteFileIfNotDirectory
|
||||||
|
.calledWith(path.join(ctx.basePath, '.other/keepdir/.subdir/file'))
|
||||||
|
.should.equal(false)
|
||||||
|
})
|
||||||
|
|
||||||
it('should not delete the extra aux files', ctx => {
|
it('should not delete the extra aux files', ctx => {
|
||||||
return ctx.ResourceWriter._deleteFileIfNotDirectory
|
return ctx.ResourceWriter._deleteFileIfNotDirectory
|
||||||
.calledWith(path.join(ctx.basePath, 'extra.aux'))
|
.calledWith(path.join(ctx.basePath, 'extra.aux'))
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ COPY libraries/object-persistor/package.json /overleaf/libraries/object-persisto
|
|||||||
COPY libraries/promise-utils/package.json /overleaf/libraries/promise-utils/package.json
|
COPY libraries/promise-utils/package.json /overleaf/libraries/promise-utils/package.json
|
||||||
COPY libraries/settings/package.json /overleaf/libraries/settings/package.json
|
COPY libraries/settings/package.json /overleaf/libraries/settings/package.json
|
||||||
COPY libraries/stream-utils/package.json /overleaf/libraries/stream-utils/package.json
|
COPY libraries/stream-utils/package.json /overleaf/libraries/stream-utils/package.json
|
||||||
|
COPY libraries/validation-tools/package.json /overleaf/libraries/validation-tools/package.json
|
||||||
COPY services/docstore/package.json /overleaf/services/docstore/package.json
|
COPY services/docstore/package.json /overleaf/services/docstore/package.json
|
||||||
COPY tools/migrations/package.json /overleaf/tools/migrations/package.json
|
COPY tools/migrations/package.json /overleaf/tools/migrations/package.json
|
||||||
COPY .yarn/patches/ /overleaf/.yarn/patches/
|
COPY .yarn/patches/ /overleaf/.yarn/patches/
|
||||||
@@ -45,6 +46,7 @@ COPY libraries/object-persistor/ /overleaf/libraries/object-persistor/
|
|||||||
COPY libraries/promise-utils/ /overleaf/libraries/promise-utils/
|
COPY libraries/promise-utils/ /overleaf/libraries/promise-utils/
|
||||||
COPY libraries/settings/ /overleaf/libraries/settings/
|
COPY libraries/settings/ /overleaf/libraries/settings/
|
||||||
COPY libraries/stream-utils/ /overleaf/libraries/stream-utils/
|
COPY libraries/stream-utils/ /overleaf/libraries/stream-utils/
|
||||||
|
COPY libraries/validation-tools/ /overleaf/libraries/validation-tools/
|
||||||
COPY services/docstore/ /overleaf/services/docstore/
|
COPY services/docstore/ /overleaf/services/docstore/
|
||||||
COPY tools/migrations/ /overleaf/tools/migrations/
|
COPY tools/migrations/ /overleaf/tools/migrations/
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = docstore
|
export PROJECT_NAME = docstore
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -26,17 +26,15 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/libraries/promise-utils/package.json \
|
$(MONOREPO)/libraries/promise-utils/package.json \
|
||||||
$(MONOREPO)/libraries/settings/package.json \
|
$(MONOREPO)/libraries/settings/package.json \
|
||||||
$(MONOREPO)/libraries/stream-utils/package.json \
|
$(MONOREPO)/libraries/stream-utils/package.json \
|
||||||
|
$(MONOREPO)/libraries/validation-tools/package.json \
|
||||||
$(MONOREPO)/services/docstore/package.json \
|
$(MONOREPO)/services/docstore/package.json \
|
||||||
$(MONOREPO)/tools/migrations/package.json \
|
$(MONOREPO)/tools/migrations/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -7,11 +7,7 @@ import Settings from '@overleaf/settings'
|
|||||||
import logger from '@overleaf/logger'
|
import logger from '@overleaf/logger'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import bodyParser from 'body-parser'
|
import bodyParser from 'body-parser'
|
||||||
import {
|
import { handleValidationError } from '@overleaf/validation-tools'
|
||||||
celebrate as validate,
|
|
||||||
Joi,
|
|
||||||
errors as handleValidationErrors,
|
|
||||||
} from 'celebrate'
|
|
||||||
import mongodb from './app/js/mongodb.js'
|
import mongodb from './app/js/mongodb.js'
|
||||||
import Errors from './app/js/Errors.js'
|
import Errors from './app/js/Errors.js'
|
||||||
import HttpController from './app/js/HttpController.js'
|
import HttpController from './app/js/HttpController.js'
|
||||||
@@ -79,13 +75,6 @@ app.post(
|
|||||||
app.patch(
|
app.patch(
|
||||||
'/project/:project_id/doc/:doc_id',
|
'/project/:project_id/doc/:doc_id',
|
||||||
bodyParser.json(),
|
bodyParser.json(),
|
||||||
validate({
|
|
||||||
body: {
|
|
||||||
deleted: Joi.boolean(),
|
|
||||||
name: Joi.string().when('deleted', { is: true, then: Joi.required() }),
|
|
||||||
deletedAt: Joi.date().when('deleted', { is: true, then: Joi.required() }),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
HttpController.patchDoc
|
HttpController.patchDoc
|
||||||
)
|
)
|
||||||
app.delete('/project/:project_id/doc/:doc_id', (req, res) => {
|
app.delete('/project/:project_id/doc/:doc_id', (req, res) => {
|
||||||
@@ -101,7 +90,7 @@ app.get('/health_check', HttpController.healthCheck)
|
|||||||
|
|
||||||
app.get('/status', (req, res) => res.send('docstore is alive'))
|
app.get('/status', (req, res) => res.send('docstore is alive'))
|
||||||
|
|
||||||
app.use(handleValidationErrors())
|
app.use(handleValidationError)
|
||||||
app.use(function (error, req, res, next) {
|
app.use(function (error, req, res, next) {
|
||||||
if (error instanceof Errors.NotFoundError) {
|
if (error instanceof Errors.NotFoundError) {
|
||||||
logger.warn({ req }, 'not found')
|
logger.warn({ req }, 'not found')
|
||||||
|
|||||||
@@ -5,6 +5,17 @@ import HealthChecker from './HealthChecker.js'
|
|||||||
import Errors from './Errors.js'
|
import Errors from './Errors.js'
|
||||||
import Settings from '@overleaf/settings'
|
import Settings from '@overleaf/settings'
|
||||||
import { expressify } from '@overleaf/promise-utils'
|
import { expressify } from '@overleaf/promise-utils'
|
||||||
|
import { parseReq, z } from '@overleaf/validation-tools'
|
||||||
|
|
||||||
|
const patchDocSchema = z.object({
|
||||||
|
body: z
|
||||||
|
.object({
|
||||||
|
deleted: z.literal(true),
|
||||||
|
deletedAt: z.coerce.date(),
|
||||||
|
name: z.string(),
|
||||||
|
})
|
||||||
|
.strict(),
|
||||||
|
})
|
||||||
|
|
||||||
async function getDoc(req, res) {
|
async function getDoc(req, res) {
|
||||||
const { doc_id: docId, project_id: projectId } = req.params
|
const { doc_id: docId, project_id: projectId } = req.params
|
||||||
@@ -182,18 +193,9 @@ async function updateDoc(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function patchDoc(req, res) {
|
async function patchDoc(req, res) {
|
||||||
|
const { body: meta } = parseReq(req, patchDocSchema)
|
||||||
const { doc_id: docId, project_id: projectId } = req.params
|
const { doc_id: docId, project_id: projectId } = req.params
|
||||||
logger.debug({ projectId, docId }, 'patching doc')
|
logger.debug({ projectId, docId }, 'patching doc')
|
||||||
|
|
||||||
const allowedFields = ['deleted', 'deletedAt', 'name']
|
|
||||||
const meta = {}
|
|
||||||
Object.entries(req.body).forEach(([field, value]) => {
|
|
||||||
if (allowedFields.includes(field)) {
|
|
||||||
meta[field] = value
|
|
||||||
} else {
|
|
||||||
logger.fatal({ field }, 'joi validation for pathDoc is broken')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await DocManager.patchDoc(projectId, docId, meta)
|
await DocManager.patchDoc(projectId, docId, meta)
|
||||||
res.sendStatus(204)
|
res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ docstore
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/docstore
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=True
|
--public-repo=True
|
||||||
--test-unit-vitest=True
|
--test-unit-vitest=True
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/docstore/reports
|
- ./reports:/overleaf/services/docstore/reports
|
||||||
@@ -23,7 +23,7 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -49,7 +49,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -25,10 +25,10 @@
|
|||||||
"@overleaf/promise-utils": "workspace:*",
|
"@overleaf/promise-utils": "workspace:*",
|
||||||
"@overleaf/settings": "workspace:*",
|
"@overleaf/settings": "workspace:*",
|
||||||
"@overleaf/stream-utils": "^0.1.0",
|
"@overleaf/stream-utils": "^0.1.0",
|
||||||
|
"@overleaf/validation-tools": "workspace:*",
|
||||||
"async": "^3.2.5",
|
"async": "^3.2.5",
|
||||||
"body-parser": "1.20.4",
|
"body-parser": "1.20.4",
|
||||||
"bunyan": "^1.8.15",
|
"bunyan": "^1.8.15",
|
||||||
"celebrate": "^15.0.3",
|
|
||||||
"express": "4.22.1",
|
"express": "4.22.1",
|
||||||
"lodash": "^4.18.1",
|
"lodash": "^4.18.1",
|
||||||
"mongodb-legacy": "6.1.3",
|
"mongodb-legacy": "6.1.3",
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ before('run migrations', async function () {
|
|||||||
this.timeout(60_000)
|
this.timeout(60_000)
|
||||||
|
|
||||||
await promisify(exec)(
|
await promisify(exec)(
|
||||||
`cd ../../tools/migrations && npm run migrations -- migrate -t server-ce`
|
`cd ../../tools/migrations && yarn run migrations migrate -t 'server-ce & !nonblocking'`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -486,7 +486,11 @@ describe('HttpController', () => {
|
|||||||
project_id: ctx.projectId,
|
project_id: ctx.projectId,
|
||||||
doc_id: ctx.docId,
|
doc_id: ctx.docId,
|
||||||
}
|
}
|
||||||
ctx.req.body = { name: 'foo.tex' }
|
ctx.req.body = {
|
||||||
|
deleted: true,
|
||||||
|
deletedAt: '2026-06-15T00:00:00Z',
|
||||||
|
name: 'foo.tex',
|
||||||
|
}
|
||||||
ctx.DocManager.patchDoc = sinon.stub().resolves()
|
ctx.DocManager.patchDoc = sinon.stub().resolves()
|
||||||
await ctx.HttpController.patchDoc(ctx.req, ctx.res, ctx.next)
|
await ctx.HttpController.patchDoc(ctx.req, ctx.res, ctx.next)
|
||||||
})
|
})
|
||||||
@@ -494,7 +498,12 @@ describe('HttpController', () => {
|
|||||||
it('should delete the document', ctx => {
|
it('should delete the document', ctx => {
|
||||||
expect(ctx.DocManager.patchDoc).to.have.been.calledWith(
|
expect(ctx.DocManager.patchDoc).to.have.been.calledWith(
|
||||||
ctx.projectId,
|
ctx.projectId,
|
||||||
ctx.docId
|
ctx.docId,
|
||||||
|
{
|
||||||
|
deleted: true,
|
||||||
|
deletedAt: new Date('2026-06-15T00:00:00Z'),
|
||||||
|
name: 'foo.tex',
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -510,19 +519,13 @@ describe('HttpController', () => {
|
|||||||
await ctx.HttpController.patchDoc(ctx.req, ctx.res, ctx.next)
|
await ctx.HttpController.patchDoc(ctx.req, ctx.res, ctx.next)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should log a message', ctx => {
|
it('should pass a validation error to next', ctx => {
|
||||||
expect(ctx.logger.fatal).to.have.been.calledWith(
|
expect(ctx.next).to.have.been.calledOnce
|
||||||
{ field: 'cannot' },
|
expect(ctx.next.firstCall.args[0].name).to.equal('InvalidRequestError')
|
||||||
'joi validation for pathDoc is broken'
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not pass the invalid field along', ctx => {
|
it('should not patch the document', ctx => {
|
||||||
expect(ctx.DocManager.patchDoc).to.have.been.calledWith(
|
expect(ctx.DocManager.patchDoc).not.to.have.been.called
|
||||||
ctx.projectId,
|
|
||||||
ctx.docId,
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = document-updater
|
export PROJECT_NAME = document-updater
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -31,13 +31,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/tools/migrations/package.json \
|
$(MONOREPO)/tools/migrations/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ document-updater
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/document-updater
|
|
||||||
--pipeline-owner=44
|
--pipeline-owner=44
|
||||||
--public-repo=True
|
--public-repo=True
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/document-updater/reports
|
- ./reports:/overleaf/services/document-updater/reports
|
||||||
@@ -28,7 +28,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ before('run migrations', async function () {
|
|||||||
this.timeout(60_000)
|
this.timeout(60_000)
|
||||||
|
|
||||||
await promisify(exec)(
|
await promisify(exec)(
|
||||||
`cd ../../tools/migrations && npm run migrations -- migrate -t server-ce`
|
`cd ../../tools/migrations && yarn run migrations migrate -t 'server-ce & !nonblocking'`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = filestore
|
export PROJECT_NAME = filestore
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -27,13 +27,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/services/filestore/package.json \
|
$(MONOREPO)/services/filestore/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ filestore
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/filestore
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=True
|
--public-repo=True
|
||||||
--test-acceptance-shards=SHARD_01_,SHARD_02_,SHARD_03_
|
--test-acceptance-shards=SHARD_01_,SHARD_02_,SHARD_03_
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ volumes:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/filestore/reports
|
- ./reports:/overleaf/services/filestore/reports
|
||||||
@@ -21,7 +21,7 @@ services:
|
|||||||
VITEST_NO_CACHE: true
|
VITEST_NO_CACHE: true
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -65,7 +65,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ MVN_TARGET := target/writelatex-git-bridge-1.0-SNAPSHOT-jar-with-dependencies.ja
|
|||||||
|
|
||||||
export BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
export COMMIT_SHA ?= $(shell git rev-parse HEAD)
|
export COMMIT_SHA ?= $(shell git rev-parse HEAD)
|
||||||
PROJECT_NAME = git-bridge
|
PROJECT_NAME = git-bridge
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
<commons.compress.version>1.28.0</commons.compress.version>
|
<commons.compress.version>1.28.0</commons.compress.version>
|
||||||
<simpleclient.version>0.10.0</simpleclient.version>
|
<simpleclient.version>0.10.0</simpleclient.version>
|
||||||
<bouncycastle.crypto.version>1.84</bouncycastle.crypto.version>
|
<bouncycastle.crypto.version>1.84</bouncycastle.crypto.version>
|
||||||
<netty.version>4.1.132.Final</netty.version>
|
<netty.version>4.1.135.Final</netty.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = history-v1
|
export PROJECT_NAME = history-v1
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -33,13 +33,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/tools/migrations/package.json \
|
$(MONOREPO)/tools/migrations/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ history-v1
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=overleaf-editor
|
|
||||||
--pipeline-owner=44
|
--pipeline-owner=44
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
--tsconfig-extra-includes=backup-deletion-app.mjs,backup-verifier-app.mjs,backup-worker-app.mjs,api/**/*,migrations/**/*,storage/**/*
|
--tsconfig-extra-includes=backup-deletion-app.mjs,backup-verifier-app.mjs,backup-worker-app.mjs,api/**/*,migrations/**/*,storage/**/*
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ volumes:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/history-v1/reports
|
- ./reports:/overleaf/services/history-v1/reports
|
||||||
@@ -31,7 +31,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -80,7 +80,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function setupMongoDatabase() {
|
|||||||
this.timeout(60_000)
|
this.timeout(60_000)
|
||||||
await promisify(exec)(
|
await promisify(exec)(
|
||||||
// Run saas migrations for backup indexes
|
// Run saas migrations for backup indexes
|
||||||
`cd ../../tools/migrations && npm run migrations -- migrate -t saas`
|
`cd ../../tools/migrations && yarn run migrations migrate -t 'saas & !nonblocking'`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = notifications
|
export PROJECT_NAME = notifications
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -29,13 +29,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/tools/migrations/package.json \
|
$(MONOREPO)/tools/migrations/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ notifications
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/notifications
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=True
|
--public-repo=True
|
||||||
--test-acceptance-vitest=True
|
--test-acceptance-vitest=True
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/notifications/reports
|
- ./reports:/overleaf/services/notifications/reports
|
||||||
@@ -23,7 +23,7 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -45,7 +45,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ import { promisify } from 'node:util'
|
|||||||
|
|
||||||
beforeAll(async function () {
|
beforeAll(async function () {
|
||||||
await promisify(exec)(
|
await promisify(exec)(
|
||||||
`cd ../../tools/migrations && npm run migrations -- migrate -t server-ce`
|
`cd ../../tools/migrations && yarn run migrations migrate -t 'server-ce & !nonblocking'`
|
||||||
)
|
)
|
||||||
}, 60_000)
|
}, 60_000)
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = project-history
|
export PROJECT_NAME = project-history
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -32,13 +32,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/tools/migrations/package.json \
|
$(MONOREPO)/tools/migrations/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Metrics from '@overleaf/metrics'
|
import Metrics from '@overleaf/metrics'
|
||||||
import logger from '@overleaf/logger'
|
import logger from '@overleaf/logger'
|
||||||
|
import OError from '@overleaf/o-error'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import bodyParser from 'body-parser'
|
import bodyParser from 'body-parser'
|
||||||
import * as Errors from './Errors.js'
|
import * as Errors from './Errors.js'
|
||||||
@@ -54,6 +55,13 @@ app.use(function (error, req, res, next) {
|
|||||||
res.sendStatus(422)
|
res.sendStatus(422)
|
||||||
} else if (error instanceof Errors.TooManyRequestsError) {
|
} else if (error instanceof Errors.TooManyRequestsError) {
|
||||||
res.status(429).set('Retry-After', 300).end()
|
res.status(429).set('Retry-After', 300).end()
|
||||||
|
} else if (
|
||||||
|
error instanceof OError &&
|
||||||
|
error.message === 'Timeout' &&
|
||||||
|
error.info?.key
|
||||||
|
) {
|
||||||
|
logger.warn({ error, req }, error.message)
|
||||||
|
res.status(423).json({ message: 'redis lock is taken' })
|
||||||
} else {
|
} else {
|
||||||
logger.error({ err: error, req }, error.message)
|
logger.error({ err: error, req }, error.message)
|
||||||
res.status(500).json({ message: 'an internal error occurred' })
|
res.status(500).json({ message: 'an internal error occurred' })
|
||||||
|
|||||||
@@ -5,6 +5,5 @@ project-history
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=True
|
--esmock-loader=True
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/project-history
|
|
||||||
--pipeline-owner=44
|
--pipeline-owner=44
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/project-history/reports
|
- ./reports:/overleaf/services/project-history/reports
|
||||||
@@ -28,7 +28,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ import { expect } from 'chai'
|
|||||||
import { fetchNothing, fetchJsonWithResponse } from '@overleaf/fetch-utils'
|
import { fetchNothing, fetchJsonWithResponse } from '@overleaf/fetch-utils'
|
||||||
import assert from 'node:assert'
|
import assert from 'node:assert'
|
||||||
import mongodb from 'mongodb-legacy'
|
import mongodb from 'mongodb-legacy'
|
||||||
|
import RedisWrapper from '@overleaf/redis-wrapper'
|
||||||
import * as ProjectHistoryClient from './helpers/ProjectHistoryClient.js'
|
import * as ProjectHistoryClient from './helpers/ProjectHistoryClient.js'
|
||||||
import * as ProjectHistoryApp from './helpers/ProjectHistoryApp.js'
|
import * as ProjectHistoryApp from './helpers/ProjectHistoryApp.js'
|
||||||
import Settings from '@overleaf/settings'
|
import Settings from '@overleaf/settings'
|
||||||
const { ObjectId } = mongodb
|
const { ObjectId } = mongodb
|
||||||
|
const LockKey = Settings.redis.lock.key_schema
|
||||||
|
const lockRClient = RedisWrapper.createClient(Settings.redis.lock)
|
||||||
|
|
||||||
const MockHistoryStore = () => nock('http://127.0.0.1:3100')
|
const MockHistoryStore = () => nock('http://127.0.0.1:3100')
|
||||||
const MockWeb = () => nock('http://127.0.0.1:3000')
|
const MockWeb = () => nock('http://127.0.0.1:3000')
|
||||||
@@ -150,6 +153,22 @@ describe('Flushing old queues', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when the project lock is already held', function () {
|
||||||
|
it('returns 423', async function () {
|
||||||
|
const key = LockKey.projectHistoryLock({ project_id: this.projectId })
|
||||||
|
await lockRClient.set(key, 'taken')
|
||||||
|
try {
|
||||||
|
const { statusCode } = await ProjectHistoryClient.flushProject(
|
||||||
|
this.projectId,
|
||||||
|
{ allowErrors: true }
|
||||||
|
)
|
||||||
|
expect(statusCode).to.equal(423)
|
||||||
|
} finally {
|
||||||
|
await lockRClient.del(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('when the update is newer than the cutoff and project has short queue', function () {
|
describe('when the update is newer than the cutoff and project has short queue', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
Settings.shortHistoryQueues.push(this.projectId)
|
Settings.shortHistoryQueues.push(this.projectId)
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ before('run migrations', async function () {
|
|||||||
this.timeout(60_000)
|
this.timeout(60_000)
|
||||||
|
|
||||||
await promisify(exec)(
|
await promisify(exec)(
|
||||||
`cd ../../tools/migrations && npm run migrations -- migrate -t server-ce`
|
`cd ../../tools/migrations && yarn run migrations migrate -t 'server-ce & !nonblocking'`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,13 @@ import sinon from 'sinon'
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import mongodb from 'mongodb-legacy'
|
import mongodb from 'mongodb-legacy'
|
||||||
import tk from 'timekeeper'
|
import tk from 'timekeeper'
|
||||||
import { File, Comment, TrackedChange, Range } from 'overleaf-editor-core'
|
import {
|
||||||
|
File,
|
||||||
|
Comment,
|
||||||
|
TrackedChange,
|
||||||
|
Range,
|
||||||
|
TrackingProps,
|
||||||
|
} from 'overleaf-editor-core'
|
||||||
import { UnprocessableError } from 'overleaf-editor-core/lib/errors.js'
|
import { UnprocessableError } from 'overleaf-editor-core/lib/errors.js'
|
||||||
import { strict as esmock } from 'esmock'
|
import { strict as esmock } from 'esmock'
|
||||||
import { FileContentEmptyError } from '../../../../app/js/Errors.js'
|
import { FileContentEmptyError } from '../../../../app/js/Errors.js'
|
||||||
@@ -2013,32 +2019,44 @@ describe('SyncManager', function () {
|
|||||||
describe('syncing tracked changes', function () {
|
describe('syncing tracked changes', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.loadedSnapshotDoc.getTrackedChanges().add(
|
this.loadedSnapshotDoc.getTrackedChanges().add(
|
||||||
new TrackedChange(new Range(4, 6), {
|
new TrackedChange(
|
||||||
type: 'delete',
|
new Range(4, 6),
|
||||||
userId: USER_ID,
|
TrackingProps.fromRaw({
|
||||||
ts: new Date(TIMESTAMP),
|
type: 'delete',
|
||||||
})
|
userId: USER_ID,
|
||||||
|
ts: new Date(TIMESTAMP).toISOString(),
|
||||||
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
this.loadedSnapshotDoc.getTrackedChanges().add(
|
this.loadedSnapshotDoc.getTrackedChanges().add(
|
||||||
new TrackedChange(new Range(10, 6), {
|
new TrackedChange(
|
||||||
type: 'insert',
|
new Range(10, 6),
|
||||||
userId: USER_ID,
|
TrackingProps.fromRaw({
|
||||||
ts: new Date(TIMESTAMP),
|
type: 'insert',
|
||||||
})
|
userId: USER_ID,
|
||||||
|
ts: new Date(TIMESTAMP).toISOString(),
|
||||||
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
this.loadedSnapshotDoc.getTrackedChanges().add(
|
this.loadedSnapshotDoc.getTrackedChanges().add(
|
||||||
new TrackedChange(new Range(20, 6), {
|
new TrackedChange(
|
||||||
type: 'delete',
|
new Range(20, 6),
|
||||||
userId: USER_ID,
|
TrackingProps.fromRaw({
|
||||||
ts: new Date(TIMESTAMP),
|
type: 'delete',
|
||||||
})
|
userId: USER_ID,
|
||||||
|
ts: new Date(TIMESTAMP).toISOString(),
|
||||||
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
this.loadedSnapshotDoc.getTrackedChanges().add(
|
this.loadedSnapshotDoc.getTrackedChanges().add(
|
||||||
new TrackedChange(new Range(40, 3), {
|
new TrackedChange(
|
||||||
type: 'insert',
|
new Range(40, 3),
|
||||||
userId: USER_ID,
|
TrackingProps.fromRaw({
|
||||||
ts: new Date(TIMESTAMP),
|
type: 'insert',
|
||||||
})
|
userId: USER_ID,
|
||||||
|
ts: new Date(TIMESTAMP).toISOString(),
|
||||||
|
})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
this.changes = [
|
this.changes = [
|
||||||
makeTrackedChange('td1', { p: 4, d: 'quick ' }),
|
makeTrackedChange('td1', { p: 4, d: 'quick ' }),
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
# Instead run bin/update_build_scripts from
|
# Instead run bin/update_build_scripts from
|
||||||
# https://github.com/overleaf/internal/
|
# https://github.com/overleaf/internal/
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE = $(shell echo $(BRANCH_NAME) | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
PROJECT_NAME = real-time
|
export PROJECT_NAME = real-time
|
||||||
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]')
|
||||||
HERE=$(shell pwd)
|
HERE=$(shell pwd)
|
||||||
export MONOREPO ?= $(shell cd ../../ && pwd)
|
export MONOREPO ?= $(shell cd ../../ && pwd)
|
||||||
@@ -28,13 +28,10 @@ IMAGE_CACHE ?= $(IMAGE_REPO):cache-$(shell cat \
|
|||||||
$(MONOREPO)/services/real-time/package.json \
|
$(MONOREPO)/services/real-time/package.json \
|
||||||
$(MONOREPO)/.yarn/patches/* \
|
$(MONOREPO)/.yarn/patches/* \
|
||||||
| sha256sum | cut -d '-' -f1)
|
| sha256sum | cut -d '-' -f1)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ real-time
|
|||||||
--env-pass-through=
|
--env-pass-through=
|
||||||
--esmock-loader=False
|
--esmock-loader=False
|
||||||
--node-version=24.14.1
|
--node-version=24.14.1
|
||||||
--package-name=@overleaf/real-time
|
|
||||||
--pipeline-owner=32
|
--pipeline-owner=32
|
||||||
--public-repo=False
|
--public-repo=False
|
||||||
--test-unit-vitest=True
|
--test-unit-vitest=True
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
test_unit:
|
test_unit:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
user: node
|
user: node
|
||||||
volumes:
|
volumes:
|
||||||
- ./reports:/overleaf/services/real-time/reports
|
- ./reports:/overleaf/services/real-time/reports
|
||||||
@@ -26,7 +26,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
test_acceptance:
|
test_acceptance:
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
environment:
|
environment:
|
||||||
CI:
|
CI:
|
||||||
RETRIES:
|
RETRIES:
|
||||||
@@ -50,7 +50,7 @@ services:
|
|||||||
|
|
||||||
tar:
|
tar:
|
||||||
build: .
|
build: .
|
||||||
image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
image: ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/tmp/build/
|
- ./:/tmp/build/
|
||||||
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs .
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export default defineMain({
|
|||||||
...storybookConfig.resolve?.alias,
|
...storybookConfig.resolve?.alias,
|
||||||
// custom prefixes for import paths
|
// custom prefixes for import paths
|
||||||
'@': path.join(rootDir, 'frontend/js/'),
|
'@': path.join(rootDir, 'frontend/js/'),
|
||||||
|
'@modules': path.join(rootDir, 'modules/'),
|
||||||
'@ol-types': path.join(rootDir, 'types/'),
|
'@ol-types': path.join(rootDir, 'types/'),
|
||||||
'@ol-storybook': path.join(rootDir, '.storybook/'),
|
'@ol-storybook': path.join(rootDir, '.storybook/'),
|
||||||
'@wf': path.join(
|
'@wf': path.join(
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
ARG PROJECT_NAME
|
ARG PROJECT_NAME
|
||||||
ARG BRANCH_NAME
|
ARG BRANCH_NAME_TAG_SAFE
|
||||||
ARG BUILD_NUMBER
|
ARG BUILD_NUMBER
|
||||||
|
|
||||||
FROM ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER
|
FROM ci/$PROJECT_NAME:$BRANCH_NAME_TAG_SAFE-$BUILD_NUMBER
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
|
|||||||
+12
-10
@@ -1,11 +1,11 @@
|
|||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
export RETRIES ?= $(if $(CI),3,0)
|
export RETRIES ?= $(if $(CI),3,0)
|
||||||
|
|
||||||
BUILD_NUMBER ?= local
|
export BUILD_NUMBER ?= local
|
||||||
ifeq ($(BRANCH_NAME),)
|
ifeq ($(BRANCH_NAME),)
|
||||||
export BRANCH_NAME := $(shell git rev-parse --abbrev-ref HEAD)
|
export BRANCH_NAME := $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
endif
|
endif
|
||||||
BRANCH_NAME_TAG_SAFE := $(shell echo "$(BRANCH_NAME)" | sed 's/\//\-\-/g' | cut -c1-96)
|
export BRANCH_NAME_TAG_SAFE := $(shell echo "$(BRANCH_NAME)" | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
|
|
||||||
.PHONY: print-branch-tag-safe
|
.PHONY: print-branch-tag-safe
|
||||||
print-branch-tag-safe:
|
print-branch-tag-safe:
|
||||||
@@ -14,7 +14,7 @@ print-branch-tag-safe:
|
|||||||
ifeq ($(COMMIT_SHA),)
|
ifeq ($(COMMIT_SHA),)
|
||||||
export COMMIT_SHA := $(shell git rev-parse HEAD)
|
export COMMIT_SHA := $(shell git rev-parse HEAD)
|
||||||
endif
|
endif
|
||||||
PROJECT_NAME = web
|
export PROJECT_NAME = web
|
||||||
BUILD_DIR_NAME := web
|
BUILD_DIR_NAME := web
|
||||||
PWD := $(shell pwd)
|
PWD := $(shell pwd)
|
||||||
ifeq ($(MONOREPO),)
|
ifeq ($(MONOREPO),)
|
||||||
@@ -28,11 +28,8 @@ CFG_SAAS=/overleaf/services/web/test/acceptance/config/settings.test.saas.js
|
|||||||
CFG_SERVER_CE=/overleaf/services/web/test/acceptance/config/settings.test.server-ce.js
|
CFG_SERVER_CE=/overleaf/services/web/test/acceptance/config/settings.test.server-ce.js
|
||||||
CFG_SERVER_PRO=/overleaf/services/web/test/acceptance/config/settings.test.server-pro.js
|
CFG_SERVER_PRO=/overleaf/services/web/test/acceptance/config/settings.test.server-pro.js
|
||||||
|
|
||||||
DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \
|
export MOCHA_GREP ?=
|
||||||
BRANCH_NAME=$(BRANCH_NAME_TAG_SAFE) \
|
DOCKER_COMPOSE := docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
# Common flags for docker compose run.
|
# Common flags for docker compose run.
|
||||||
# --rm Tear down test runner container
|
# --rm Tear down test runner container
|
||||||
@@ -154,7 +151,7 @@ MOCHA_CMD_LINE = \
|
|||||||
mocha \
|
mocha \
|
||||||
--exit \
|
--exit \
|
||||||
--file test/unit/bootstrap.js \
|
--file test/unit/bootstrap.js \
|
||||||
--grep=${MOCHA_GREP} \
|
--grep="${MOCHA_GREP}" \
|
||||||
--reporter spec \
|
--reporter spec \
|
||||||
--timeout 25000 \
|
--timeout 25000 \
|
||||||
|
|
||||||
@@ -178,7 +175,7 @@ test_unit_module: mongo_migrations_for_tests
|
|||||||
$(MAKE) modules/$(MODULE_NAME)/test_unit
|
$(MAKE) modules/$(MODULE_NAME)/test_unit
|
||||||
|
|
||||||
mongo_migrations_for_tests:
|
mongo_migrations_for_tests:
|
||||||
$(DOCKER_COMPOSE) run $(DC_RUN_FLAGS) --workdir /overleaf/tools/migrations test_unit yarn run migrations migrate -t saas
|
$(DOCKER_COMPOSE) run $(DC_RUN_FLAGS) --workdir /overleaf/tools/migrations test_unit yarn run migrations migrate -t 'saas & !nonblocking'
|
||||||
|
|
||||||
#
|
#
|
||||||
# Frontend tests
|
# Frontend tests
|
||||||
@@ -550,6 +547,10 @@ else
|
|||||||
$(RUN_LINTING) lint
|
$(RUN_LINTING) lint
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
lint_fix: lint_eslint_fix
|
||||||
|
lint_eslint_fix:
|
||||||
|
$(RUN_LINTING) lint:fix
|
||||||
|
|
||||||
lint: lint_stylelint
|
lint: lint_stylelint
|
||||||
lint_stylelint:
|
lint_stylelint:
|
||||||
ifeq ($(CI),true)
|
ifeq ($(CI),true)
|
||||||
@@ -559,6 +560,7 @@ else
|
|||||||
$(RUN_LINTING) lint:styles
|
$(RUN_LINTING) lint:styles
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
lint_fix: lint_stylelint_fix
|
||||||
lint_stylelint_fix:
|
lint_stylelint_fix:
|
||||||
$(RUN_LINTING) lint:styles:fix
|
$(RUN_LINTING) lint:styles:fix
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
BUILD_DIR_NAME ?= web
|
BUILD_DIR_NAME ?= web
|
||||||
|
ifeq ($(BRANCH_NAME),)
|
||||||
|
export BRANCH_NAME := $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
endif
|
||||||
|
export BRANCH_NAME_TAG_SAFE := $(shell echo "$(BRANCH_NAME)" | sed 's/\//\-\-/g' | cut -c1-96)
|
||||||
export MODULE_NAME := $(notdir $(shell pwd))
|
export MODULE_NAME := $(notdir $(shell pwd))
|
||||||
MODULE_DIR := modules/$(MODULE_NAME)
|
export MODULE_DIR := modules/$(MODULE_NAME)
|
||||||
PROJECT_NAME = web
|
export PROJECT_NAME = web
|
||||||
export RETRIES ?= $(if $(CI),3,0)
|
export RETRIES ?= $(if $(CI),3,0)
|
||||||
|
export MOCHA_GREP ?=
|
||||||
|
|
||||||
export OVERLEAF_CONFIG = /overleaf/services/web/$(MODULE_DIR)/test/acceptance/config/settings.test.js
|
export OVERLEAF_CONFIG = /overleaf/services/web/$(MODULE_DIR)/test/acceptance/config/settings.test.js
|
||||||
export BASE_CONFIG ?= /overleaf/services/web/test/acceptance/config/settings.test.saas.js
|
export BASE_CONFIG ?= /overleaf/services/web/test/acceptance/config/settings.test.saas.js
|
||||||
@@ -12,13 +17,7 @@ CFG_SERVER_CE=/overleaf/services/web/test/acceptance/config/settings.test.server
|
|||||||
CFG_SERVER_PRO=/overleaf/services/web/test/acceptance/config/settings.test.server-pro.js
|
CFG_SERVER_PRO=/overleaf/services/web/test/acceptance/config/settings.test.server-pro.js
|
||||||
|
|
||||||
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml
|
||||||
DOCKER_COMPOSE := cd ../../ && \
|
DOCKER_COMPOSE := cd ../../ && docker compose ${DOCKER_COMPOSE_FLAGS}
|
||||||
MODULE_DIR=$(MODULE_DIR) \
|
|
||||||
BUILD_NUMBER=$(BUILD_NUMBER) \
|
|
||||||
BRANCH_NAME=$(BRANCH_NAME) \
|
|
||||||
PROJECT_NAME=$(PROJECT_NAME) \
|
|
||||||
MOCHA_GREP=${MOCHA_GREP} \
|
|
||||||
docker compose ${DOCKER_COMPOSE_FLAGS}
|
|
||||||
|
|
||||||
ifeq (,$(wildcard test/unit))
|
ifeq (,$(wildcard test/unit))
|
||||||
test_unit:
|
test_unit:
|
||||||
@@ -26,7 +25,7 @@ test_unit:
|
|||||||
else
|
else
|
||||||
test_unit: export COMPOSE_PROJECT_NAME=unit_test_$(BUILD_DIR_NAME)_$(MODULE_NAME)
|
test_unit: export COMPOSE_PROJECT_NAME=unit_test_$(BUILD_DIR_NAME)_$(MODULE_NAME)
|
||||||
test_unit:
|
test_unit:
|
||||||
${DOCKER_COMPOSE} run --rm test_unit yarn test:unit:run_dir -- ${MOCHA_ARGS} $(MODULE_DIR)/test/unit/src
|
${DOCKER_COMPOSE} run --rm test_unit yarn test:unit:run_dir ${MOCHA_ARGS} $(MODULE_DIR)/test/unit/src
|
||||||
${DOCKER_COMPOSE} down
|
${DOCKER_COMPOSE} down
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ async function recordEventForUser(userId, event, segmentation) {
|
|||||||
userId,
|
userId,
|
||||||
event,
|
event,
|
||||||
segmentation,
|
segmentation,
|
||||||
isLabsUser: Boolean(labsProgram),
|
isLabsUser: labsProgram,
|
||||||
isLoggedIn: true,
|
isLoggedIn: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -97,6 +97,31 @@ function recordEventForUserInBackground(userId, event, segmentation) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function recordEventForMongoUser(user, event, segmentation) {
|
||||||
|
const { userId, analyticsId, labsProgram } = _getIdsFromMongoUser(user)
|
||||||
|
if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_recordEvent({
|
||||||
|
analyticsId,
|
||||||
|
userId,
|
||||||
|
event,
|
||||||
|
segmentation,
|
||||||
|
isLabsUser: labsProgram,
|
||||||
|
isLoggedIn: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordEventForMongoUserInBackground(user, event, segmentation) {
|
||||||
|
const { userId } = _getIdsFromMongoUser(user) // throw before going into the background.
|
||||||
|
recordEventForMongoUser(user, event, segmentation).catch(err => {
|
||||||
|
logger.warn(
|
||||||
|
{ err, userId, event, segmentation },
|
||||||
|
'failed to record event for user'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function recordEventForSession(session, event, segmentation) {
|
function recordEventForSession(session, event, segmentation) {
|
||||||
const { analyticsId, userId } = getIdsFromSession(session)
|
const { analyticsId, userId } = getIdsFromSession(session)
|
||||||
if (!analyticsId) {
|
if (!analyticsId) {
|
||||||
@@ -142,7 +167,7 @@ async function setUserPropertyForUser(userId, propertyName, propertyValue) {
|
|||||||
if (analyticsId) {
|
if (analyticsId) {
|
||||||
await _setUserProperty({
|
await _setUserProperty({
|
||||||
analyticsId,
|
analyticsId,
|
||||||
isLabsUser: Boolean(labsProgram),
|
isLabsUser: labsProgram,
|
||||||
propertyName,
|
propertyName,
|
||||||
propertyValue,
|
propertyValue,
|
||||||
})
|
})
|
||||||
@@ -158,6 +183,41 @@ function setUserPropertyForUserInBackground(userId, property, value) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{_id: ObjectId, analyticsId: string, labsProgram: boolean}} user
|
||||||
|
* @param {string} propertyName
|
||||||
|
* @param {any} propertyValue
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
async function setUserPropertyForMongoUser(user, propertyName, propertyValue) {
|
||||||
|
const { userId, analyticsId, labsProgram } = _getIdsFromMongoUser(user)
|
||||||
|
if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_checkPropertyValue(propertyValue)
|
||||||
|
await _setUserProperty({
|
||||||
|
analyticsId,
|
||||||
|
isLabsUser: labsProgram,
|
||||||
|
propertyName,
|
||||||
|
propertyValue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{_id: ObjectId, analyticsId: string, labsProgram: boolean}} user
|
||||||
|
* @param {string} property
|
||||||
|
* @param {any} value
|
||||||
|
*/
|
||||||
|
function setUserPropertyForMongoUserInBackground(user, property, value) {
|
||||||
|
const { userId } = _getIdsFromMongoUser(user) // throw before going into the background.
|
||||||
|
setUserPropertyForMongoUser(user, property, value).catch(err => {
|
||||||
|
logger.warn(
|
||||||
|
{ err, userId, property, value },
|
||||||
|
'failed to set user property for user'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function setUserPropertyForAnalyticsId(
|
async function setUserPropertyForAnalyticsId(
|
||||||
analyticsId,
|
analyticsId,
|
||||||
propertyName,
|
propertyName,
|
||||||
@@ -192,8 +252,8 @@ async function setUserPropertyForSession(session, propertyName, propertyValue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setUserPropertyForSessionInBackground(session, property, value) {
|
function setUserPropertyForSessionInBackground(session, property, value) {
|
||||||
|
const { analyticsId, userId } = getIdsFromSession(session) // throw before going into the background.
|
||||||
setUserPropertyForSession(session, property, value).catch(err => {
|
setUserPropertyForSession(session, property, value).catch(err => {
|
||||||
const { analyticsId, userId } = getIdsFromSession(session)
|
|
||||||
logger.warn(
|
logger.warn(
|
||||||
{ err, analyticsId, userId, property, value },
|
{ err, analyticsId, userId, property, value },
|
||||||
'failed to set user property for session'
|
'failed to set user property for session'
|
||||||
@@ -452,6 +512,26 @@ function _isAnalyticsDisabled() {
|
|||||||
return !(Settings.analytics && Settings.analytics.enabled)
|
return !(Settings.analytics && Settings.analytics.enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{_id: ObjectId, analyticsId: string, labsProgram: boolean}} user
|
||||||
|
* @return {{userId: string, analyticsId: string, labsProgram: boolean}}
|
||||||
|
*/
|
||||||
|
function _getIdsFromMongoUser(user) {
|
||||||
|
const userId = user?._id?.toString()
|
||||||
|
if (!userId) {
|
||||||
|
throw new Error('bug: include db.users._id in projection')
|
||||||
|
}
|
||||||
|
const analyticsId = user?.analyticsId
|
||||||
|
if (!analyticsId) {
|
||||||
|
throw new Error('bug: include db.users.analyticsId in projection')
|
||||||
|
}
|
||||||
|
const labsProgram = user?.labsProgram
|
||||||
|
if (typeof labsProgram !== 'boolean') {
|
||||||
|
throw new Error('bug: include db.users.labsProgram in projection')
|
||||||
|
}
|
||||||
|
return { userId, analyticsId, labsProgram }
|
||||||
|
}
|
||||||
|
|
||||||
function _checkPropertyValue(propertyValue) {
|
function _checkPropertyValue(propertyValue) {
|
||||||
if (propertyValue === undefined) {
|
if (propertyValue === undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -498,13 +578,15 @@ async function analyticsIdMiddleware(req, res, next) {
|
|||||||
if (sessionUser) {
|
if (sessionUser) {
|
||||||
// For old sessions, session.analyticsId is the anon id immediately after login. Do not use it!
|
// For old sessions, session.analyticsId is the anon id immediately after login. Do not use it!
|
||||||
session.analyticsId = sessionUser.analyticsId
|
session.analyticsId = sessionUser.analyticsId
|
||||||
if (!session.analyticsId) {
|
if (!session.analyticsId || typeof sessionUser.labsProgram !== 'boolean') {
|
||||||
session.analyticsId = sessionUser.analyticsId =
|
const { analyticsId, labsProgram } =
|
||||||
await UserAnalyticsDataCache.getAnalyticsId(
|
await UserAnalyticsDataCache.getAnalyticsData(
|
||||||
sessionUser._id,
|
sessionUser._id,
|
||||||
// Do not drill down further, this middleware is on all endpoints.
|
// Do not drill down further, this middleware is on all endpoints.
|
||||||
'analyticsIdMiddleware'
|
'analyticsIdMiddleware'
|
||||||
)
|
)
|
||||||
|
session.analyticsId = sessionUser.analyticsId = analyticsId
|
||||||
|
sessionUser.labsProgram = labsProgram
|
||||||
}
|
}
|
||||||
} else if (!session.analyticsId) {
|
} else if (!session.analyticsId) {
|
||||||
// generate an `analyticsId` if needed
|
// generate an `analyticsId` if needed
|
||||||
@@ -521,9 +603,13 @@ export default {
|
|||||||
recordEventForSession,
|
recordEventForSession,
|
||||||
recordEventForUser,
|
recordEventForUser,
|
||||||
recordEventForUserInBackground,
|
recordEventForUserInBackground,
|
||||||
|
recordEventForMongoUser,
|
||||||
|
recordEventForMongoUserInBackground,
|
||||||
emitPackageUsage,
|
emitPackageUsage,
|
||||||
setUserPropertyForUser,
|
setUserPropertyForUser,
|
||||||
setUserPropertyForUserInBackground,
|
setUserPropertyForUserInBackground,
|
||||||
|
setUserPropertyForMongoUser,
|
||||||
|
setUserPropertyForMongoUserInBackground,
|
||||||
setUserPropertyForSession,
|
setUserPropertyForSession,
|
||||||
setUserPropertyForSessionInBackground,
|
setUserPropertyForSessionInBackground,
|
||||||
setUserPropertyForAnalyticsId,
|
setUserPropertyForAnalyticsId,
|
||||||
|
|||||||
@@ -25,32 +25,32 @@ function clearInbound(session) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addUserProperties(userId, session) {
|
function addUserProperties(user, session) {
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session.required_login_from_product_medium) {
|
if (session.required_login_from_product_medium) {
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-product-medium`,
|
`registered-from-product-medium`,
|
||||||
session.required_login_from_product_medium
|
session.required_login_from_product_medium
|
||||||
)
|
)
|
||||||
if (session.required_login_from_product_source) {
|
if (session.required_login_from_product_source) {
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-product-source`,
|
`registered-from-product-source`,
|
||||||
session.required_login_from_product_source
|
session.required_login_from_product_source
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if (session.referal_id) {
|
} else if (session.referal_id) {
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-bonus-scheme`,
|
`registered-from-bonus-scheme`,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-product-medium`,
|
`registered-from-product-medium`,
|
||||||
'bonus-scheme'
|
'bonus-scheme'
|
||||||
)
|
)
|
||||||
@@ -58,16 +58,16 @@ function addUserProperties(userId, session) {
|
|||||||
|
|
||||||
if (session.inbound) {
|
if (session.inbound) {
|
||||||
if (session.inbound.referrer && session.inbound.referrer.medium) {
|
if (session.inbound.referrer && session.inbound.referrer.medium) {
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-referrer-medium`,
|
`registered-from-referrer-medium`,
|
||||||
`${session.inbound.referrer.medium
|
`${session.inbound.referrer.medium
|
||||||
.charAt(0)
|
.charAt(0)
|
||||||
.toUpperCase()}${session.inbound.referrer.medium.slice(1)}`
|
.toUpperCase()}${session.inbound.referrer.medium.slice(1)}`
|
||||||
)
|
)
|
||||||
if (session.inbound.referrer.source) {
|
if (session.inbound.referrer.source) {
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-referrer-source`,
|
`registered-from-referrer-source`,
|
||||||
session.inbound.referrer.source
|
session.inbound.referrer.source
|
||||||
)
|
)
|
||||||
@@ -77,8 +77,8 @@ function addUserProperties(userId, session) {
|
|||||||
if (session.inbound.utm) {
|
if (session.inbound.utm) {
|
||||||
for (const utmKey of RequestHelper.REGISTRATION_UTM_KEYS) {
|
for (const utmKey of RequestHelper.REGISTRATION_UTM_KEYS) {
|
||||||
if (session.inbound.utm[utmKey]) {
|
if (session.inbound.utm[utmKey]) {
|
||||||
AnalyticsManager.setUserPropertyForUserInBackground(
|
AnalyticsManager.setUserPropertyForMongoUserInBackground(
|
||||||
userId,
|
user,
|
||||||
`registered-from-${utmKey.replace('_', '-')}`,
|
`registered-from-${utmKey.replace('_', '-')}`,
|
||||||
session.inbound.utm[utmKey]
|
session.inbound.utm[utmKey]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -685,7 +685,7 @@ function _loginAsyncHandlers(req, user, anonymousAnalyticsId, isNewUser) {
|
|||||||
LoginRateLimiter.recordSuccessfulLogin(user.email, () => {})
|
LoginRateLimiter.recordSuccessfulLogin(user.email, () => {})
|
||||||
AuthenticationController._recordSuccessfulLogin(user._id, () => {})
|
AuthenticationController._recordSuccessfulLogin(user._id, () => {})
|
||||||
AuthenticationController.ipMatchCheck(req, user)
|
AuthenticationController.ipMatchCheck(req, user)
|
||||||
Analytics.recordEventForUserInBackground(user._id, 'user-logged-in', {
|
Analytics.recordEventForMongoUserInBackground(user, 'user-logged-in', {
|
||||||
source: req.session.saml
|
source: req.session.saml
|
||||||
? 'saml'
|
? 'saml'
|
||||||
: req.user_info?.auth_provider || 'email-password',
|
: req.user_info?.auth_provider || 'email-password',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { expressify } from '@overleaf/promise-utils'
|
|||||||
|
|
||||||
async function optIn(req, res) {
|
async function optIn(req, res) {
|
||||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||||
await BetaProgramHandler.promises.optIn(userId)
|
await BetaProgramHandler.promises.optIn(req.session, userId)
|
||||||
try {
|
try {
|
||||||
await SplitTestSessionHandler.promises.sessionMaintenance(req, null)
|
await SplitTestSessionHandler.promises.sessionMaintenance(req, null)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -22,7 +22,7 @@ async function optIn(req, res) {
|
|||||||
|
|
||||||
async function optOut(req, res) {
|
async function optOut(req, res) {
|
||||||
const userId = SessionManager.getLoggedInUserId(req.session)
|
const userId = SessionManager.getLoggedInUserId(req.session)
|
||||||
await BetaProgramHandler.promises.optOut(userId)
|
await BetaProgramHandler.promises.optOut(req.session, userId)
|
||||||
try {
|
try {
|
||||||
await SplitTestSessionHandler.promises.sessionMaintenance(req, null)
|
await SplitTestSessionHandler.promises.sessionMaintenance(req, null)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user