From 41bdbdcce710538e764e91b6fa38a043c829a579 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:01:36 +0200 Subject: [PATCH 01/25] Build improvements. --- .testrunsettings | 6 ++++++ Dockerfile | 7 +------ Dockerfile.build | 7 +------ 3 files changed, 8 insertions(+), 12 deletions(-) create mode 100644 .testrunsettings diff --git a/.testrunsettings b/.testrunsettings new file mode 100644 index 000000000..0082141a9 --- /dev/null +++ b/.testrunsettings @@ -0,0 +1,6 @@ + + + + 4 + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 86485f677..7b5213883 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,12 +19,7 @@ RUN cp -a /tmp/node_modules src/Squidex/ \ && npm run build # Test Backend -RUN dotnet restore \ - && dotnet test --filter Category!=Dependencies tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj \ - && dotnet test tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj +RUN dotnet restore && dotnet test -s ../../.testrunsettings --filter Category!=Dependencies # Publish RUN dotnet publish src/Squidex/Squidex.csproj --output /out/alpine --configuration Release -r alpine.3.7-x64 diff --git a/Dockerfile.build b/Dockerfile.build index 30a5d3091..f1468b1e0 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -16,12 +16,7 @@ RUN cp -a /tmp/node_modules src/Squidex/ \ && npm run build # Test Backend -RUN dotnet restore \ - && dotnet test --filter Category!=Dependencies tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj \ - && dotnet test tests/Squidex.Web.Tests/Squidex.Web.Tests.csproj +RUN dotnet restore && dotnet test -s ../../.testrunsettings --filter Category!=Dependencies # Publish RUN dotnet publish src/Squidex/Squidex.csproj --output /out/ --configuration Release \ No newline at end of file From 3502e679af697c94393419b38ae155369967d65f Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:14:43 +0200 Subject: [PATCH 02/25] Share nuget folder. --- .drone.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index bc95a8247..04d7f8979 100644 --- a/.drone.yml +++ b/.drone.yml @@ -28,6 +28,8 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker + - name: nuget + path: ~/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -51,6 +53,8 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker + - name: nuget + path: ~/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -73,6 +77,8 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker + - name: nuget + path: ~/.nuget/packages when: event: - tag @@ -154,4 +160,7 @@ volumes: path: /var/run/docker.sock - name: docker2 host: - path: /var/lib/docker \ No newline at end of file + path: /var/lib/docker + - name: nuget + host: + path: /var/lib/nuget \ No newline at end of file From 4e588c0d72b7c65b4c3fc3fe6c01ba4959f1c192 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:17:55 +0200 Subject: [PATCH 03/25] Test --- .testrunsettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.testrunsettings b/.testrunsettings index 0082141a9..69a779394 100644 --- a/.testrunsettings +++ b/.testrunsettings @@ -1,6 +1,6 @@ - 4 + 6 \ No newline at end of file From 42ce42502b894e90f0c0714031024a77e13cd24d Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:21:16 +0200 Subject: [PATCH 04/25] Another attempt. --- .drone.yml | 4 ++-- .testrunsettings | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.drone.yml b/.drone.yml index 04d7f8979..b9452ffb5 100644 --- a/.drone.yml +++ b/.drone.yml @@ -29,7 +29,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: ~/.nuget/packages + path: /home/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -54,7 +54,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: ~/.nuget/packages + path: /home/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME diff --git a/.testrunsettings b/.testrunsettings index 69a779394..0082141a9 100644 --- a/.testrunsettings +++ b/.testrunsettings @@ -1,6 +1,6 @@ - 6 + 4 \ No newline at end of file From 331e39a1e19a282c8e76b645d0d3256f3488b049 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:23:28 +0200 Subject: [PATCH 05/25] FF --- .testrunsettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.testrunsettings b/.testrunsettings index 0082141a9..69a779394 100644 --- a/.testrunsettings +++ b/.testrunsettings @@ -1,6 +1,6 @@ - 4 + 6 \ No newline at end of file From e71953030a121fe54a5d66d2912f295e5443de58 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:24:27 +0200 Subject: [PATCH 06/25] Pull Request fix. --- .drone.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.drone.yml b/.drone.yml index b9452ffb5..e0e7ab7f6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,6 +12,8 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker + - name: nuget + path: /home/.nuget/packages when: event: - pull_request From 6c791e4e80914d97fba3c0bcf4825516f19be2a5 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:25:43 +0200 Subject: [PATCH 07/25] T --- .testrunsettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.testrunsettings b/.testrunsettings index 69a779394..0082141a9 100644 --- a/.testrunsettings +++ b/.testrunsettings @@ -1,6 +1,6 @@ - 6 + 4 \ No newline at end of file From 311db4942cde17eb4b31057843e77b6435d2f1f4 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:28:33 +0200 Subject: [PATCH 08/25] Test --- .testrunsettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.testrunsettings b/.testrunsettings index 0082141a9..ef537d413 100644 --- a/.testrunsettings +++ b/.testrunsettings @@ -1,6 +1,6 @@ - 4 + 5 \ No newline at end of file From df80cfd57cee3e36385c6e3cd531b2d575557da0 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:34:41 +0200 Subject: [PATCH 09/25] Nuget cache extraction test #1 --- .drone.yml | 8 ++++---- .testrunsettings | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.drone.yml b/.drone.yml index e0e7ab7f6..92b954985 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,7 +13,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /home/.nuget/packages + path: /root/.nuget/packages/ when: event: - pull_request @@ -31,7 +31,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /home/.nuget/packages + path: /root/.nuget/packages/ environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -56,7 +56,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /home/.nuget/packages + path: /root/.nuget/packages/ environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -80,7 +80,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: ~/.nuget/packages + path: /root/.nuget/packages/ when: event: - tag diff --git a/.testrunsettings b/.testrunsettings index ef537d413..0082141a9 100644 --- a/.testrunsettings +++ b/.testrunsettings @@ -1,6 +1,6 @@ - 5 + 4 \ No newline at end of file From b68330af435a0178da4044111b9a46cd9d9aa0c7 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:51:45 +0200 Subject: [PATCH 10/25] Test --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 7b5213883..e6750cb62 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,8 @@ RUN cp -a /tmp/node_modules src/Squidex/ \ && cd src/Squidex \ && npm run test:coverage \ && npm run build + +RUN find / -name "*.nupkg" # Test Backend RUN dotnet restore && dotnet test -s ../../.testrunsettings --filter Category!=Dependencies From 16921870eb236b58b32589ecffcd30d4043ac0b1 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 18:58:09 +0200 Subject: [PATCH 11/25] A --- .drone.yml | 8 ++++---- Dockerfile | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 92b954985..26210c516 100644 --- a/.drone.yml +++ b/.drone.yml @@ -13,7 +13,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /root/.nuget/packages/ + path: /root/.nuget/packages when: event: - pull_request @@ -31,7 +31,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /root/.nuget/packages/ + path: /root/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -56,7 +56,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /root/.nuget/packages/ + path: /root/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -80,7 +80,7 @@ steps: - name: docker2 path: /var/lib/docker - name: nuget - path: /root/.nuget/packages/ + path: /root/.nuget/packages when: event: - tag diff --git a/Dockerfile b/Dockerfile index e6750cb62..54958061e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,10 @@ FROM squidex/dotnet:2.2-sdk-chromium-phantomjs-node as builder WORKDIR /src +COPY . . + +RUN dotnet restore + COPY src/Squidex/package*.json /tmp/ # Install Node packages @@ -17,8 +21,6 @@ RUN cp -a /tmp/node_modules src/Squidex/ \ && cd src/Squidex \ && npm run test:coverage \ && npm run build - -RUN find / -name "*.nupkg" # Test Backend RUN dotnet restore && dotnet test -s ../../.testrunsettings --filter Category!=Dependencies From 4dd3a56691ba135130a5ed0e64ae2719bb6f55bb Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 19:03:08 +0200 Subject: [PATCH 12/25] Reverted --- Dockerfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 54958061e..7b5213883 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,10 +5,6 @@ FROM squidex/dotnet:2.2-sdk-chromium-phantomjs-node as builder WORKDIR /src -COPY . . - -RUN dotnet restore - COPY src/Squidex/package*.json /tmp/ # Install Node packages From d9c05be89f3e56e6f1c39bd6fa5174dda5f18c55 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 18 Jun 2019 19:45:33 +0200 Subject: [PATCH 13/25] Reverted docker build volume. --- .drone.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.drone.yml b/.drone.yml index 26210c516..bc95a8247 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,8 +12,6 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker - - name: nuget - path: /root/.nuget/packages when: event: - pull_request @@ -30,8 +28,6 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker - - name: nuget - path: /root/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -55,8 +51,6 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker - - name: nuget - path: /root/.nuget/packages environment: DOCKER_USERNAME: from_secret: DOCKER_USERNAME @@ -79,8 +73,6 @@ steps: path: /var/run/docker.sock - name: docker2 path: /var/lib/docker - - name: nuget - path: /root/.nuget/packages when: event: - tag @@ -162,7 +154,4 @@ volumes: path: /var/run/docker.sock - name: docker2 host: - path: /var/lib/docker - - name: nuget - host: - path: /var/lib/nuget \ No newline at end of file + path: /var/lib/docker \ No newline at end of file From ab1fb499fdedc464a7f86001dde1f052a1645e2c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 18 Jun 2019 23:00:24 +0200 Subject: [PATCH 14/25] Simple fixes. --- Dockerfile | 12 +++++++++-- Dockerfile.build | 12 +++++++++-- src/Squidex/package-lock.json | 38 +++++++++++++++++++++-------------- src/Squidex/package.json | 16 ++++++++------- 4 files changed, 52 insertions(+), 26 deletions(-) diff --git a/Dockerfile b/Dockerfile index 86485f677..e57b35d67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,11 +5,20 @@ FROM squidex/dotnet:2.2-sdk-chromium-phantomjs-node as builder WORKDIR /src +# Copy Node project files. COPY src/Squidex/package*.json /tmp/ # Install Node packages RUN cd /tmp && npm install --loglevel=error +# Copy nuget project files. +COPY /**/**/*.csproj /tmp/ +# Copy nuget.config for package sources. +COPY NuGet.Config /tmp/ + +# Install nuget packages +RUN bash -c 'pushd /tmp; for p in *.csproj; do dotnet restore $p --verbosity quiet; true; done; popd' + COPY . . # Build Frontend @@ -19,8 +28,7 @@ RUN cp -a /tmp/node_modules src/Squidex/ \ && npm run build # Test Backend -RUN dotnet restore \ - && dotnet test --filter Category!=Dependencies tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj \ +RUN dotnet test tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj --filter Category!=Dependencies \ && dotnet test tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj \ && dotnet test tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj \ && dotnet test tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj \ diff --git a/Dockerfile.build b/Dockerfile.build index 30a5d3091..96debc8cd 100644 --- a/Dockerfile.build +++ b/Dockerfile.build @@ -2,11 +2,20 @@ FROM squidex/dotnet:2.2-sdk-chromium-phantomjs-node as builder WORKDIR /src +# Copy Node project files. COPY src/Squidex/package*.json /tmp/ # Install Node packages RUN cd /tmp && npm install --loglevel=error +# Copy Dotnet project files. +COPY /**/**/*.csproj /tmp/ +# Copy nuget.config for package sources. +COPY NuGet.Config /tmp/ + +# Install Dotnet packages +RUN bash -c 'pushd /tmp; for p in *.csproj; do dotnet restore $p --verbosity quiet; true; done; popd' + COPY . . # Build Frontend @@ -16,8 +25,7 @@ RUN cp -a /tmp/node_modules src/Squidex/ \ && npm run build # Test Backend -RUN dotnet restore \ - && dotnet test --filter Category!=Dependencies tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj \ +RUN dotnet test tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj --filter Category!=Dependencies \ && dotnet test tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj \ && dotnet test tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj \ && dotnet test tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj \ diff --git a/src/Squidex/package-lock.json b/src/Squidex/package-lock.json index 3051cf82b..b8073c031 100644 --- a/src/Squidex/package-lock.json +++ b/src/Squidex/package-lock.json @@ -3196,14 +3196,22 @@ } }, "browserslist": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.3.5.tgz", - "integrity": "sha512-z9ZhGc3d9e/sJ9dIx5NFXkKoaiQTnrvrMsN3R1fGb1tkWWNSz12UewJn9TNxGo1l7J23h0MRaPmk7jfeTZYs1w==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.3.tgz", + "integrity": "sha512-CNBqTCq22RKM8wKJNowcqihHJ4SkI8CGeK7KOR9tPboXUuS5Zk5lQgzzTbs4oxD8x+6HUshZUa2OyNI9lR93bQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000912", - "electron-to-chromium": "^1.3.86", - "node-releases": "^1.0.5" + "caniuse-lite": "^1.0.30000975", + "electron-to-chromium": "^1.3.164", + "node-releases": "^1.1.23" + }, + "dependencies": { + "caniuse-lite": { + "version": "1.0.30000975", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000975.tgz", + "integrity": "sha512-ZsXA9YWQX6ATu5MNg+Vx/cMQ+hM6vBBSqDeJs8ruk9z0ky4yIHML15MoxcFt088ST2uyjgqyUGRJButkptWf0w==", + "dev": true + } } }, "buffer": { @@ -3450,9 +3458,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000918", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000918.tgz", - "integrity": "sha512-CAZ9QXGViBvhHnmIHhsTPSWFBujDaelKnUj7wwImbyQRxmXynYqKGi3UaZTSz9MoVh+1EVxOS/DFIkrJYgR3aw==", + "version": "1.0.30000975", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000975.tgz", + "integrity": "sha512-ZsXA9YWQX6ATu5MNg+Vx/cMQ+hM6vBBSqDeJs8ruk9z0ky4yIHML15MoxcFt088ST2uyjgqyUGRJButkptWf0w==", "dev": true }, "canonical-path": { @@ -4950,9 +4958,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.90", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.90.tgz", - "integrity": "sha512-IjJZKRhFbWSOX1w0sdIXgp4CMRguu6UYcTckyFF/Gjtemsu/25eZ+RXwFlV+UWcIueHyQA1UnRJxocTpH5NdGA==", + "version": "1.3.164", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.164.tgz", + "integrity": "sha512-VLlalqUeduN4+fayVtRZvGP2Hl1WrRxlwzh2XVVMJym3IFrQUS29BFQ1GP/BxOJXJI1OFCrJ5BnFEsAe8NHtOg==", "dev": true }, "elliptic": { @@ -10755,9 +10763,9 @@ } }, "node-releases": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.1.tgz", - "integrity": "sha512-2UXrBr6gvaebo5TNF84C66qyJJ6r0kxBObgZIDX3D3/mt1ADKiHux3NJPWisq0wxvJJdkjECH+9IIKYViKj71Q==", + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.23.tgz", + "integrity": "sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==", "dev": true, "requires": { "semver": "^5.3.0" diff --git a/src/Squidex/package.json b/src/Squidex/package.json index 72f1ab671..09a66cd63 100644 --- a/src/Squidex/package.json +++ b/src/Squidex/package.json @@ -47,21 +47,23 @@ "zone.js": "0.9.1" }, "devDependencies": { - "@angular/compiler-cli": "7.2.14", "@angular/compiler": "7.2.14", + "@angular/compiler-cli": "7.2.14", "@ngtools/webpack": "7.3.8", "@types/core-js": "2.5.0", "@types/jasmine": "3.3.12", "@types/marked": "0.6.5", "@types/mousetrap": "1.6", "@types/node": "12.0.0", - "@types/react-dom": "16.8.4", "@types/react": "16.8.16", + "@types/react-dom": "16.8.4", "@types/sortablejs": "1.7.2", "angular-router-loader": "0.8.5", "angular2-template-loader": "0.6.2", "awesome-typescript-loader": "5.2.1", "babel-core": "6.26.3", + "browserslist": "^4.6.3", + "caniuse-lite": "^1.0.30000975", "circular-dependency-plugin": "5.0.2", "codelyzer": "5.0.1", "cpx": "1.5.0", @@ -72,16 +74,16 @@ "ignore-loader": "0.1.2", "istanbul-instrumenter-loader": "3.0.1", "jasmine-core": "3.4.0", + "karma": "4.1.0", "karma-chrome-launcher": "2.2.0", "karma-cli": "2.0.0", "karma-coverage-istanbul-reporter": "2.0.5", "karma-htmlfile-reporter": "0.3.8", - "karma-jasmine-html-reporter": "1.4.2", "karma-jasmine": "2.0.1", + "karma-jasmine-html-reporter": "1.4.2", "karma-mocha-reporter": "2.2.5", "karma-sourcemap-loader": "0.3.7", "karma-webpack": "3.0.5", - "karma": "4.1.0", "mini-css-extract-plugin": "0.6.0", "node-sass": "4.12.0", "optimize-css-assets-webpack-plugin": "5.0.1", @@ -93,15 +95,15 @@ "style-loader": "0.23.1", "ts-loader": "5.4.5", "tsconfig-paths-webpack-plugin": "3.2.0", - "tslint-webpack-plugin": "2.0.4", "tslint": "5.16.0", + "tslint-webpack-plugin": "2.0.4", "typemoq": "2.1.0", "typescript": "3.2.4", "uglifyjs-webpack-plugin": "2.1.2", "underscore": "1.9.1", + "webpack": "4.30.0", "webpack-cli": "3.3.1", "webpack-dev-server": "3.3.1", - "webpack-merge": "4.2.1", - "webpack": "4.30.0" + "webpack-merge": "4.2.1" } } From 36a4d2f1c033d8cc35e09304df2c50a45cd0a572 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Thu, 20 Jun 2019 09:11:05 +0200 Subject: [PATCH 15/25] Middleware to log resolver exceptions. --- .../Contents/GraphQL/CachingGraphQLService.cs | 11 +++-- .../Contents/GraphQL/GraphQLModel.cs | 4 +- .../Contents/GraphQL/LoggingMiddleware.cs | 42 +++++++++++++++++++ .../Contents/GraphQL/GraphQLTestBase.cs | 3 +- 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 src/Squidex.Domain.Apps.Entities/Contents/GraphQL/LoggingMiddleware.cs diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs index 2c57f06da..e56e28cb3 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/CachingGraphQLService.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Caching.Memory; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Infrastructure; +using Squidex.Infrastructure.Log; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL { @@ -20,6 +21,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10); private readonly IContentQueryService contentQuery; private readonly IGraphQLUrlGenerator urlGenerator; + private readonly ISemanticLog log; private readonly IAssetQueryService assetQuery; private readonly IAppProvider appProvider; @@ -28,18 +30,21 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL IAppProvider appProvider, IAssetQueryService assetQuery, IContentQueryService contentQuery, - IGraphQLUrlGenerator urlGenerator) + IGraphQLUrlGenerator urlGenerator, + ISemanticLog log) : base(cache) { Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(assetQuery, nameof(assetQuery)); Guard.NotNull(contentQuery, nameof(contentQuery)); Guard.NotNull(urlGenerator, nameof(urlGenerator)); + Guard.NotNull(log, nameof(log)); this.appProvider = appProvider; this.assetQuery = assetQuery; this.contentQuery = contentQuery; this.urlGenerator = urlGenerator; + this.log = log; } public async Task<(bool HasError, object Response)> QueryAsync(QueryContext context, params GraphQLQuery[] queries) @@ -70,14 +75,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return result; } - private static async Task<(bool HasError, object Response)> QueryInternalAsync(GraphQLModel model, GraphQLExecutionContext ctx, GraphQLQuery query) + private async Task<(bool HasError, object Response)> QueryInternalAsync(GraphQLModel model, GraphQLExecutionContext ctx, GraphQLQuery query) { if (string.IsNullOrWhiteSpace(query.Query)) { return (false, new { data = new object() }); } - var result = await model.ExecuteAsync(ctx, query); + var result = await model.ExecuteAsync(ctx, query, log); if (result.Errors?.Any() == true) { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index a07e8aca3..1373ee437 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -20,6 +20,7 @@ using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types; using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Utils; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; +using Squidex.Infrastructure.Log; using GraphQLSchema = GraphQL.Types.Schema; #pragma warning disable IDE0003 @@ -171,7 +172,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return contentTypes.GetOrAdd(schema, s => new ContentGraphType()); } - public async Task<(object Data, object[] Errors)> ExecuteAsync(GraphQLExecutionContext context, GraphQLQuery query) + public async Task<(object Data, object[] Errors)> ExecuteAsync(GraphQLExecutionContext context, GraphQLQuery query, ISemanticLog log) { Guard.NotNull(context, nameof(context)); @@ -179,6 +180,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL var result = await new DocumentExecuter().ExecuteAsync(options => { + options.FieldMiddleware.Use(LoggingMiddleware.Create(log)); options.OperationName = query.OperationName; options.UserContext = context; options.Schema = graphQLSchema; diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/LoggingMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/LoggingMiddleware.cs new file mode 100644 index 000000000..9db32cab0 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/LoggingMiddleware.cs @@ -0,0 +1,42 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using GraphQL.Instrumentation; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Log; + +namespace Squidex.Domain.Apps.Entities.Contents.GraphQL +{ + public static class LoggingMiddleware + { + public static Func Create(ISemanticLog log) + { + Guard.NotNull(log, nameof(log)); + + return new Func(next => + { + return async context => + { + try + { + return await next(context); + } + catch (Exception ex) + { + log.LogWarning(ex, w => w + .WriteProperty("action", "reolveField") + .WriteProperty("status", "failed") + .WriteProperty("field", context.FieldName)); + + throw ex; + } + }; + }); + } + } +} diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index d3f6b5ea1..53e155449 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -24,6 +24,7 @@ using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; +using Squidex.Infrastructure.Log; using Xunit; #pragma warning disable SA1311 // Static readonly fields must begin with upper-case letter @@ -96,7 +97,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL A.CallTo(() => appProvider.GetSchemasAsync(appId)).Returns(allSchemas); - sut = new CachingGraphQLService(cache, appProvider, assetQuery, contentQuery, new FakeUrlGenerator()); + sut = new CachingGraphQLService(cache, appProvider, assetQuery, contentQuery, new FakeUrlGenerator(), A.Fake()); } protected static IContentEntity CreateContent(Guid id, Guid refId, Guid assetId, NamedContentData data = null, NamedContentData dataDraft = null) From e1a75a8f6aab555b2800fba3de5f49118938668d Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Thu, 20 Jun 2019 18:16:35 +0200 Subject: [PATCH 16/25] Formatting fixes. --- .../IdentityServer/Views/Account/Login.cshtml | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml b/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml index 54b6042d0..dd23d6a95 100644 --- a/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml +++ b/src/Squidex/Areas/IdentityServer/Views/Account/Login.cshtml @@ -53,22 +53,22 @@ { if (Model.IsLogin) { - if (Model.IsFailed) - { -
Email or password not correct.
- } + if (Model.IsFailed) + { +
Email or password not correct.
+ } -
-
- -
+ +
+ +
-
- -
+
+ +
- -
+ + } else { @@ -95,7 +95,6 @@ else var redirectButtons = document.getElementsByClassName("redirect-button"); if (redirectButtons.length === 1) { - debugger; redirectButtons[0].click(); } From 8d4246ab828c86b4e22e54f1a7427ed65e6ebc39 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 14:58:57 +0200 Subject: [PATCH 17/25] Fixed content changed trigger. --- .../rules/triggers/content-changed-trigger.component.html | 8 ++++---- .../rules/triggers/content-changed-trigger.component.ts | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html b/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html index f1ae6a0f7..da925bae6 100644 --- a/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html +++ b/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.html @@ -22,13 +22,13 @@ - @@ -38,12 +38,12 @@
-
- +
diff --git a/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.ts b/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.ts index f169a8ff6..a3e1f140b 100644 --- a/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.ts +++ b/src/Squidex/app/features/rules/pages/rules/triggers/content-changed-trigger.component.ts @@ -29,9 +29,6 @@ export class ContentChangedTriggerComponent implements OnInit { @Input() public schemas: ImmutableArray; - @Input() - public isEditable: boolean; - @Input() public trigger: any; From 5c83dcec1649f2044d1d4dc7b09fd220230f0ad7 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 15:57:48 +0200 Subject: [PATCH 18/25] Fix tag names. --- .../Assets/AssetCommandMiddleware.cs | 64 ++++++++++---- .../Assets/AssetCreatedResult.cs | 11 ++- .../Assets/AssetResult.cs | 25 ++++++ .../Assets/Commands/CreateAsset.cs | 9 +- .../Assets/Commands/UpdateAsset.cs | 9 +- .../Assets/Commands/UploadAssetCommand.cs | 20 +++++ .../CollectionExtensions.cs | 8 ++ .../Controllers/Assets/AssetsController.cs | 6 +- .../Api/Controllers/Assets/Models/AssetDto.cs | 7 +- .../app/shared/services/assets.service.ts | 2 +- .../Assets/AssetCommandMiddlewareTests.cs | 84 ++++++++++++++++--- 11 files changed, 189 insertions(+), 56 deletions(-) create mode 100644 src/Squidex.Domain.Apps.Entities/Assets/AssetResult.cs create mode 100644 src/Squidex.Domain.Apps.Entities/Assets/Commands/UploadAssetCommand.cs diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs index b13c99f29..e45e02645 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetCommandMiddleware.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Security.Cryptography; using System.Threading.Tasks; using Orleans; +using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Tags; using Squidex.Infrastructure; @@ -24,25 +25,28 @@ namespace Squidex.Domain.Apps.Entities.Assets private readonly IAssetQueryService assetQuery; private readonly IAssetThumbnailGenerator assetThumbnailGenerator; private readonly IEnumerable> tagGenerators; + private readonly ITagService tagService; public AssetCommandMiddleware( IGrainFactory grainFactory, IAssetQueryService assetQuery, IAssetStore assetStore, IAssetThumbnailGenerator assetThumbnailGenerator, - IEnumerable> tagGenerators) + IEnumerable> tagGenerators, + ITagService tagService) : base(grainFactory) { Guard.NotNull(assetStore, nameof(assetStore)); Guard.NotNull(assetQuery, nameof(assetQuery)); Guard.NotNull(assetThumbnailGenerator, nameof(assetThumbnailGenerator)); Guard.NotNull(tagGenerators, nameof(tagGenerators)); + Guard.NotNull(tagService, nameof(tagService)); this.assetStore = assetStore; this.assetQuery = assetQuery; this.assetThumbnailGenerator = assetThumbnailGenerator; - this.tagGenerators = tagGenerators; + this.tagService = tagService; } public override async Task HandleAsync(CommandContext context, Func next) @@ -56,9 +60,8 @@ namespace Squidex.Domain.Apps.Entities.Assets createAsset.Tags = new HashSet(); } - createAsset.ImageInfo = await assetThumbnailGenerator.GetImageInfoAsync(createAsset.File.OpenRead()); - - createAsset.FileHash = await UploadAsync(context, createAsset.File); + await EnrichWithImageInfosAsync(createAsset); + await EnrichWithHashAndUploadAsync(createAsset, context); try { @@ -70,7 +73,9 @@ namespace Squidex.Domain.Apps.Entities.Assets { if (IsDuplicate(createAsset, existing)) { - result = new AssetCreatedResult(existing, true); + var denormalizedTags = await tagService.DenormalizeTagsAsync(createAsset.AppId.Id, TagGroups.Assets, existing.Tags); + + result = new AssetCreatedResult(existing, true, new HashSet(denormalizedTags.Values)); } break; @@ -85,7 +90,7 @@ namespace Squidex.Domain.Apps.Entities.Assets var asset = (IAssetEntity)await ExecuteCommandAsync(createAsset); - result = new AssetCreatedResult(asset, false); + result = new AssetCreatedResult(asset, false, createAsset.Tags); await assetStore.CopyAsync(context.ContextId.ToString(), createAsset.AssetId.ToString(), asset.FileVersion, null); } @@ -102,16 +107,16 @@ namespace Squidex.Domain.Apps.Entities.Assets case UpdateAsset updateAsset: { - updateAsset.ImageInfo = await assetThumbnailGenerator.GetImageInfoAsync(updateAsset.File.OpenRead()); + await EnrichWithImageInfosAsync(updateAsset); + await EnrichWithHashAndUploadAsync(updateAsset, context); - updateAsset.FileHash = await UploadAsync(context, updateAsset.File); try { - var result = (IAssetEntity)await ExecuteCommandAsync(updateAsset); + var result = (AssetResult)await ExecuteAndAdjustTagsAsync(updateAsset); context.Complete(result); - await assetStore.CopyAsync(context.ContextId.ToString(), updateAsset.AssetId.ToString(), result.FileVersion, null); + await assetStore.CopyAsync(context.ContextId.ToString(), updateAsset.AssetId.ToString(), result.Asset.FileVersion, null); } finally { @@ -121,29 +126,54 @@ namespace Squidex.Domain.Apps.Entities.Assets break; } + case AssetCommand command: + { + var result = await ExecuteAndAdjustTagsAsync(command); + + context.Complete(result); + + break; + } + default: await base.HandleAsync(context, next); + break; } } + private async Task ExecuteAndAdjustTagsAsync(AssetCommand command) + { + var result = await ExecuteCommandAsync(command); + + if (result is IAssetEntity asset) + { + var denormalizedTags = await tagService.DenormalizeTagsAsync(asset.AppId.Id, TagGroups.Assets, asset.Tags); + + return new AssetResult(asset, new HashSet(denormalizedTags.Values)); + } + + return result; + } + private static bool IsDuplicate(CreateAsset createAsset, IAssetEntity asset) { return asset != null && asset.FileName == createAsset.File.FileName && asset.FileSize == createAsset.File.FileSize; } - private async Task UploadAsync(CommandContext context, AssetFile file) + private async Task EnrichWithImageInfosAsync(UploadAssetCommand command) { - string hash; + command.ImageInfo = await assetThumbnailGenerator.GetImageInfoAsync(command.File.OpenRead()); + } - using (var hashStream = new HasherStream(file.OpenRead(), HashAlgorithmName.SHA256)) + private async Task EnrichWithHashAndUploadAsync(UploadAssetCommand command, CommandContext context) + { + using (var hashStream = new HasherStream(command.File.OpenRead(), HashAlgorithmName.SHA256)) { await assetStore.UploadAsync(context.ContextId.ToString(), hashStream); - hash = $"{hashStream.GetHashStringAndReset()}{file.FileName}{file.FileSize}".Sha256Base64(); + command.FileHash = $"{hashStream.GetHashStringAndReset()}{command.File.FileName}{command.File.FileSize}".Sha256Base64(); } - - return hash; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetCreatedResult.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetCreatedResult.cs index b1502786a..9ccc00763 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/AssetCreatedResult.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetCreatedResult.cs @@ -5,18 +5,17 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System.Collections.Generic; + namespace Squidex.Domain.Apps.Entities.Assets { - public sealed class AssetCreatedResult + public sealed class AssetCreatedResult : AssetResult { - public IAssetEntity Asset { get; } - public bool IsDuplicate { get; } - public AssetCreatedResult(IAssetEntity asset, bool isDuplicate) + public AssetCreatedResult(IAssetEntity asset, bool isDuplicate, HashSet tags) + : base(asset, tags) { - Asset = asset; - IsDuplicate = isDuplicate; } } diff --git a/src/Squidex.Domain.Apps.Entities/Assets/AssetResult.cs b/src/Squidex.Domain.Apps.Entities/Assets/AssetResult.cs new file mode 100644 index 000000000..b43713da5 --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Assets/AssetResult.cs @@ -0,0 +1,25 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Collections.Generic; + +namespace Squidex.Domain.Apps.Entities.Assets +{ + public class AssetResult + { + public IAssetEntity Asset { get; } + + public HashSet Tags { get; } + + public AssetResult(IAssetEntity asset, HashSet tags) + { + Asset = asset; + + Tags = tags; + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs b/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs index 9c49e67bd..8e869ba40 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/Commands/CreateAsset.cs @@ -8,22 +8,15 @@ using System; using System.Collections.Generic; using Squidex.Infrastructure; -using Squidex.Infrastructure.Assets; namespace Squidex.Domain.Apps.Entities.Assets.Commands { - public sealed class CreateAsset : AssetCommand, IAppCommand + public sealed class CreateAsset : UploadAssetCommand, IAppCommand { public NamedId AppId { get; set; } - public AssetFile File { get; set; } - - public ImageInfo ImageInfo { get; set; } - public HashSet Tags { get; set; } - public string FileHash { get; set; } - public CreateAsset() { AssetId = Guid.NewGuid(); diff --git a/src/Squidex.Domain.Apps.Entities/Assets/Commands/UpdateAsset.cs b/src/Squidex.Domain.Apps.Entities/Assets/Commands/UpdateAsset.cs index 1c998ac7a..16197164d 100644 --- a/src/Squidex.Domain.Apps.Entities/Assets/Commands/UpdateAsset.cs +++ b/src/Squidex.Domain.Apps.Entities/Assets/Commands/UpdateAsset.cs @@ -5,16 +5,9 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure.Assets; - namespace Squidex.Domain.Apps.Entities.Assets.Commands { - public sealed class UpdateAsset : AssetCommand + public sealed class UpdateAsset : UploadAssetCommand { - public AssetFile File { get; set; } - - public ImageInfo ImageInfo { get; set; } - - public string FileHash { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities/Assets/Commands/UploadAssetCommand.cs b/src/Squidex.Domain.Apps.Entities/Assets/Commands/UploadAssetCommand.cs new file mode 100644 index 000000000..5ef0652cd --- /dev/null +++ b/src/Squidex.Domain.Apps.Entities/Assets/Commands/UploadAssetCommand.cs @@ -0,0 +1,20 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure.Assets; + +namespace Squidex.Domain.Apps.Entities.Assets.Commands +{ + public abstract class UploadAssetCommand : AssetCommand + { + public AssetFile File { get; set; } + + public ImageInfo ImageInfo { get; set; } + + public string FileHash { get; set; } + } +} diff --git a/src/Squidex.Infrastructure/CollectionExtensions.cs b/src/Squidex.Infrastructure/CollectionExtensions.cs index 76be0fd06..cfe546a24 100644 --- a/src/Squidex.Infrastructure/CollectionExtensions.cs +++ b/src/Squidex.Infrastructure/CollectionExtensions.cs @@ -13,6 +13,14 @@ namespace Squidex.Infrastructure { public static class CollectionExtensions { + public static void AddRange(this ICollection target, IEnumerable source) + { + foreach (var value in source) + { + target.Add(value); + } + } + public static IEnumerable Shuffle(this IEnumerable enumerable) { var random = new Random(); diff --git a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs index 8f0f95fa2..965056fbe 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs @@ -182,7 +182,7 @@ namespace Squidex.Areas.Api.Controllers.Assets var context = await CommandBus.PublishAsync(command); var result = context.Result(); - var response = AssetDto.FromAsset(result.Asset, this, app, result.IsDuplicate); + var response = AssetDto.FromAsset(result.Asset, this, app, result.Tags, result.IsDuplicate); return CreatedAtAction(nameof(GetAsset), new { app, id = response.Id }, response); } @@ -267,8 +267,8 @@ namespace Squidex.Areas.Api.Controllers.Assets { var context = await CommandBus.PublishAsync(command); - var result = context.Result(); - var response = AssetDto.FromAsset(result, this, app); + var result = context.Result(); + var response = AssetDto.FromAsset(result.Asset, this, app, result.Tags); return response; } diff --git a/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs b/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs index f44c9d25a..ec0e68899 100644 --- a/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs @@ -118,10 +118,15 @@ namespace Squidex.Areas.Api.Controllers.Assets.Models [JsonProperty("_meta")] public AssetMetadata Metadata { get; set; } - public static AssetDto FromAsset(IAssetEntity asset, ApiController controller, string app, bool isDuplicate = false) + public static AssetDto FromAsset(IAssetEntity asset, ApiController controller, string app, HashSet tags = null, bool isDuplicate = false) { var response = SimpleMapper.Map(asset, new AssetDto { FileType = asset.FileName.FileType() }); + if (tags != null) + { + response.Tags = tags; + } + if (isDuplicate) { response.Metadata = new AssetMetadata { IsDuplicate = "true" }; diff --git a/src/Squidex/app/shared/services/assets.service.ts b/src/Squidex/app/shared/services/assets.service.ts index 429c225e7..8fd9e0fbd 100644 --- a/src/Squidex/app/shared/services/assets.service.ts +++ b/src/Squidex/app/shared/services/assets.service.ts @@ -242,7 +242,7 @@ export class AssetsService { tap(() => { this.analytics.trackEvent('Analytics', 'Updated', appName); }), - pretifyError('Failed to delete asset. Please reload.')); + pretifyError('Failed to update asset. Please reload.')); } public deleteAsset(appName: string, asset: Resource, version: Version): Observable> { diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs index 21df10911..00f6856ed 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetCommandMiddlewareTests.cs @@ -54,19 +54,23 @@ namespace Squidex.Domain.Apps.Entities.Assets A.CallTo(() => assetQuery.QueryByHashAsync(AppId, A.Ignored)) .Returns(new List()); - A.CallTo(() => tagService.NormalizeTagsAsync(AppId, TagGroups.Assets, A>.Ignored, A>.Ignored)) - .Returns(new Dictionary()); + A.CallTo(() => tagService.DenormalizeTagsAsync(AppId, TagGroups.Assets, A>.Ignored)) + .Returns(new Dictionary + { + ["1"] = "foundTag1", + ["2"] = "foundTag2" + }); A.CallTo(() => grainFactory.GetGrain(Id, null)) .Returns(asset); - sut = new AssetCommandMiddleware(grainFactory, assetQuery, assetStore, assetThumbnailGenerator, new[] { tagGenerator }); + sut = new AssetCommandMiddleware(grainFactory, assetQuery, assetStore, assetThumbnailGenerator, new[] { tagGenerator }, tagService); } [Fact] public async Task Create_should_create_domain_object() { - var command = new CreateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupTags(command); @@ -80,6 +84,8 @@ namespace Squidex.Domain.Apps.Entities.Assets Assert.Contains("tag1", command.Tags); Assert.Contains("tag2", command.Tags); + Assert.Equal(new HashSet { "tag1", "tag2" }, result.Tags); + AssertAssetHasBeenUploaded(0, context.ContextId); AssertAssetImageChecked(); } @@ -87,7 +93,7 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Create_should_calculate_hash() { - var command = new CreateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupImageInfo(); @@ -100,7 +106,7 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Create_should_return_duplicate_result_if_file_with_same_hash_found() { - var command = new CreateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupSameHashAsset(file.FileName, file.FileSize, out _); @@ -108,13 +114,15 @@ namespace Squidex.Domain.Apps.Entities.Assets await sut.HandleAsync(context); - Assert.True(context.Result().IsDuplicate); + var result = context.Result(); + + Assert.True(result.IsDuplicate); } [Fact] public async Task Create_should_not_return_duplicate_result_if_file_with_same_hash_but_other_name_found() { - var command = new CreateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupSameHashAsset("other-name", file.FileSize, out _); @@ -122,13 +130,31 @@ namespace Squidex.Domain.Apps.Entities.Assets await sut.HandleAsync(context); - Assert.False(context.Result().IsDuplicate); + var result = context.Result(); + + Assert.False(result.IsDuplicate); + } + + [Fact] + public async Task Create_should_resolve_tag_names_for_duplicate() + { + var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); + var context = CreateContextForCommand(command); + + SetupSameHashAsset(file.FileName, file.FileSize, out _); + SetupImageInfo(); + + await sut.HandleAsync(context); + + var result = context.Result(); + + Assert.Equal(new HashSet { "foundTag1", "foundTag2" }, result.Tags); } [Fact] public async Task Create_should_not_return_duplicate_result_if_file_with_same_hash_but_other_size_found() { - var command = new CreateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupSameHashAsset(file.FileName, 12345, out _); @@ -142,7 +168,7 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Update_should_update_domain_object() { - var command = new UpdateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupImageInfo(); @@ -158,7 +184,7 @@ namespace Squidex.Domain.Apps.Entities.Assets [Fact] public async Task Update_should_calculate_hash() { - var command = new UpdateAsset { AssetId = assetId, File = file }; + var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); var context = CreateContextForCommand(command); SetupImageInfo(); @@ -170,6 +196,40 @@ namespace Squidex.Domain.Apps.Entities.Assets Assert.True(command.FileHash.Length > 10); } + [Fact] + public async Task Update_should_resolve_tags() + { + var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); + var context = CreateContextForCommand(command); + + SetupImageInfo(); + + await ExecuteCreateAsync(); + + await sut.HandleAsync(context); + + var result = context.Result(); + + Assert.Equal(new HashSet { "foundTag1", "foundTag2" }, result.Tags); + } + + [Fact] + public async Task AnnotateAsset_should_resolve_tags() + { + var command = CreateCommand(new AnnotateAsset { AssetId = assetId, FileName = "newName" }); + var context = CreateContextForCommand(command); + + SetupImageInfo(); + + await ExecuteCreateAsync(); + + await sut.HandleAsync(context); + + var result = context.Result(); + + Assert.Equal(new HashSet { "foundTag1", "foundTag2" }, result.Tags); + } + private Task ExecuteCreateAsync() { return asset.ExecuteAsync(CreateCommand(new CreateAsset { AssetId = Id, File = file })); From ad0ab894fbda4d2d849be24b05417bfa21e4b7d0 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 17:01:58 +0200 Subject: [PATCH 19/25] Fix field form after "Create and Edit" --- .../features/schemas/pages/schema/field-wizard.component.html | 1 + src/Squidex/app/shared/components/schema-category.component.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html b/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html index 1b4866640..cf9681be6 100644 --- a/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html +++ b/src/Squidex/app/features/schemas/pages/schema/field-wizard.component.html @@ -65,6 +65,7 @@
implements if (query) { isOpen = true; } else { - isOpen = this.localStore.get(`schema-category.${this.name}`) !== 'false'; + isOpen = !this.localStore.getBoolean(this.configKey()); } this.next(s => ({ ...s, isOpen, schemasFiltered, schemasForCategory })); From c00305444905c2f575e1f4537259eda18b6e59a3 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 17:07:35 +0200 Subject: [PATCH 20/25] Fixed field deletion. --- .../Areas/Api/Controllers/Schemas/SchemaFieldsController.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs index 55e68584b..6c50117dc 100644 --- a/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs +++ b/src/Squidex/Areas/Api/Controllers/Schemas/SchemaFieldsController.cs @@ -513,9 +513,11 @@ namespace Squidex.Areas.Api.Controllers.Schemas [ApiCosts(1)] public async Task DeleteNestedField(string app, string name, long parentId, long id) { - await CommandBus.PublishAsync(new DeleteField { ParentFieldId = parentId, FieldId = id }); + var command = new DeleteField { ParentFieldId = parentId, FieldId = id }; - return NoContent(); + var response = await InvokeCommandAsync(app, command); + + return Ok(response); } private async Task InvokeCommandAsync(string app, ICommand command) From 2750c74b732852b24a300e173435d858cf4966ea Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 17:22:05 +0200 Subject: [PATCH 21/25] Fix cancel and enqueue rules. --- .../Controllers/Rules/Models/RuleEventDto.cs | 5 +- .../app/shared/services/rules.service.spec.ts | 67 ++++++++++--------- .../app/shared/services/rules.service.ts | 12 +++- .../shared/state/rule-events.state.spec.ts | 8 +-- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs index 201e3dadd..a513495ab 100644 --- a/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs @@ -80,7 +80,10 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models AddPutLink("update", controller.Url(x => nameof(x.PutEvent), values)); - AddDeleteLink("delete", controller.Url(x => nameof(x.DeleteEvent), values)); + if (NextAttempt.HasValue) + { + AddDeleteLink("delete", controller.Url(x => nameof(x.DeleteEvent), values)); + } return this; } diff --git a/src/Squidex/app/shared/services/rules.service.spec.ts b/src/Squidex/app/shared/services/rules.service.spec.ts index 399580e53..99c00490a 100644 --- a/src/Squidex/app/shared/services/rules.service.spec.ts +++ b/src/Squidex/app/shared/services/rules.service.spec.ts @@ -288,41 +288,15 @@ describe('RulesService', () => { req.flush({ total: 20, items: [ - { - id: 'id1', - created: '2017-12-12T10:10', - eventName: 'event1', - nextAttempt: '2017-12-12T12:10', - jobResult: 'Failed', - lastDump: 'dump1', - numCalls: 1, - description: 'url1', - result: 'Failed' - }, - { - id: 'id2', - created: '2017-12-13T10:10', - eventName: 'event2', - nextAttempt: '2017-12-13T12:10', - jobResult: 'Failed', - lastDump: 'dump2', - numCalls: 2, - description: 'url2', - result: 'Failed' - } + ruleEventResponse(1), + ruleEventResponse(2) ] }); expect(rules!).toEqual( new RuleEventsDto(20, [ - new RuleEventDto('id1', - DateTime.parseISO_UTC('2017-12-12T10:10'), - DateTime.parseISO_UTC('2017-12-12T12:10'), - 'event1', 'url1', 'dump1', 'Failed', 'Failed', 1), - new RuleEventDto('id2', - DateTime.parseISO_UTC('2017-12-13T10:10'), - DateTime.parseISO_UTC('2017-12-13T12:10'), - 'event2', 'url2', 'dump2', 'Failed', 'Failed', 2) + createRuleEvent(1), + createRuleEvent(2) ])); })); @@ -364,6 +338,23 @@ describe('RulesService', () => { req.flush({}); })); + function ruleEventResponse(id: number, suffix = '') { + return { + id: `id${id}`, + created: `${id % 1000 + 2000}-12-12T10:10:00`, + eventName: `event${id}${suffix}`, + nextAttempt: `${id % 1000 + 2000}-11-11T10:10`, + jobResult: `Failed${id}${suffix}`, + lastDump: `dump${id}${suffix}`, + numCalls: id, + description: `url${id}${suffix}`, + result: `Failed${id}${suffix}`, + _links: { + update: { method: 'PUT', href: `/rules/events/${id}` } + } + }; + } + function ruleResponse(id: number, suffix = '') { return { id: `id${id}`, @@ -390,6 +381,22 @@ describe('RulesService', () => { } }); +export function createRuleEvent(id: number, suffix = '') { + const links: ResourceLinks = { + update: { method: 'PUT', href: `/rules/events/${id}` } + }; + + return new RuleEventDto(links, `id${id}`, + DateTime.parseISO_UTC(`${id % 1000 + 2000}-12-12T10:10:00`), + DateTime.parseISO_UTC(`${id % 1000 + 2000}-11-11T10:10:00`), + `event${id}${suffix}`, + `url${id}${suffix}`, + `dump${id}${suffix}`, + `Failed${id}${suffix}`, + `Failed${id}${suffix}`, + id); +} + export function createRule(id: number, suffix = '') { const links: ResourceLinks = { update: { method: 'PUT', href: `/rules/${id}` } diff --git a/src/Squidex/app/shared/services/rules.service.ts b/src/Squidex/app/shared/services/rules.service.ts index bd44ae278..5c42f7dec 100644 --- a/src/Squidex/app/shared/services/rules.service.ts +++ b/src/Squidex/app/shared/services/rules.service.ts @@ -127,7 +127,10 @@ export class RuleEventsDto extends ResultSet { export class RuleEventDto extends Model { public readonly _links: ResourceLinks; - constructor( + public readonly canDelete: boolean; + public readonly canUpdate: boolean; + + constructor(links: ResourceLinks, public readonly id: string, public readonly created: DateTime, public readonly nextAttempt: DateTime | null, @@ -139,6 +142,11 @@ export class RuleEventDto extends Model { public readonly numCalls: number ) { super(); + + this._links = links; + + this.canDelete = hasAnyLink(links, 'delete'); + this.canUpdate = hasAnyLink(links, 'update'); } } @@ -287,7 +295,7 @@ export class RulesService { const items: any[] = body.items; const ruleEvents = new RuleEventsDto(body.total, items.map(item => - new RuleEventDto( + new RuleEventDto(item._links, item.id, DateTime.parseISO_UTC(item.created), item.nextAttempt ? DateTime.parseISO_UTC(item.nextAttempt) : null, diff --git a/src/Squidex/app/shared/state/rule-events.state.spec.ts b/src/Squidex/app/shared/state/rule-events.state.spec.ts index 5adcd6f4a..cd0ebcab6 100644 --- a/src/Squidex/app/shared/state/rule-events.state.spec.ts +++ b/src/Squidex/app/shared/state/rule-events.state.spec.ts @@ -9,14 +9,14 @@ import { of } from 'rxjs'; import { IMock, It, Mock, Times } from 'typemoq'; import { - DateTime, DialogService, - RuleEventDto, RuleEventsDto, RuleEventsState, RulesService } from '@app/shared/internal'; +import { createRuleEvent } from '../services/rules.service.spec'; + import { TestValues } from './_test-helpers'; describe('RuleEventsState', () => { @@ -26,8 +26,8 @@ describe('RuleEventsState', () => { } = TestValues; const oldRuleEvents = [ - new RuleEventDto('id1', DateTime.now(), null, 'event1', 'description', 'dump1', 'result1', 'result1', 1), - new RuleEventDto('id2', DateTime.now(), null, 'event2', 'description', 'dump2', 'result2', 'result2', 2) + createRuleEvent(1), + createRuleEvent(2) ]; let dialogs: IMock; From 85cd8f539d8de76249862c5e1b925374345bff79 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 17:26:39 +0200 Subject: [PATCH 22/25] Due time fixed. --- src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs b/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs index 9936e98ef..69c580518 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs @@ -22,17 +22,17 @@ namespace Squidex.Domain.Apps.Entities.Contents public Instant DueTime { get; } - public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant due) + public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant dueTime) { Id = id; ScheduledBy = scheduledBy; Status = status; - DueTime = due; + DueTime = dueTime; } - public static ScheduleJob Build(Status status, RefToken by, Instant due) + public static ScheduleJob Build(Status status, RefToken by, Instant dueTime) { - return new ScheduleJob(Guid.NewGuid(), status, by, due); + return new ScheduleJob(Guid.NewGuid(), status, by, dueTime); } } } From 362e8d71c63216bc61bf29a0da31a8b33fe9966d Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 21 Jun 2019 17:58:59 +0200 Subject: [PATCH 23/25] Fix for Create and Edit with nested field. --- .../app/shared/services/schemas.service.ts | 2 +- .../app/shared/state/schemas.state.spec.ts | 17 ++++++++++++++--- src/Squidex/app/shared/state/schemas.state.ts | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Squidex/app/shared/services/schemas.service.ts b/src/Squidex/app/shared/services/schemas.service.ts index e02391b2a..d2f6f7517 100644 --- a/src/Squidex/app/shared/services/schemas.service.ts +++ b/src/Squidex/app/shared/services/schemas.service.ts @@ -213,7 +213,7 @@ export class SchemaPropertiesDto { export interface AddFieldDto { readonly name: string; - readonly partitioning: string; + readonly partitioning?: string; readonly properties: FieldPropertiesDto; } diff --git a/src/Squidex/app/shared/state/schemas.state.spec.ts b/src/Squidex/app/shared/state/schemas.state.spec.ts index 4e8c74c74..0f0315218 100644 --- a/src/Squidex/app/shared/state/schemas.state.spec.ts +++ b/src/Squidex/app/shared/state/schemas.state.spec.ts @@ -13,6 +13,7 @@ import { SchemasState } from './schemas.state'; import { DialogService, + FieldDto, SchemaDetailsDto, SchemasService, UpdateSchemaCategoryDto, @@ -329,28 +330,38 @@ describe('SchemasState', () => { schemasService.setup(x => x.postField(app, schema1, It.isAny(), version)) .returns(() => of(updated)).verifiable(); - schemasState.addField(schema1, request).subscribe(); + let newField: FieldDto; + + schemasState.addField(schema1, request).subscribe(result => { + newField = result; + }); const schema1New = schemasState.snapshot.schemas.at(0); expect(schema1New).toEqual(updated); expect(schemasState.snapshot.selectedSchema).toEqual(updated); + expect(newField!).toBeDefined(); }); it('should update schema and selected schema when nested field added', () => { - const request = { ...schema.fields[0] }; + const request = { ...schema.fields[0].nested[0] }; const updated = createSchemaDetails(1, newVersion, '-new'); schemasService.setup(x => x.postField(app, schema.fields[0], It.isAny(), version)) .returns(() => of(updated)).verifiable(); - schemasState.addField(schema1, request, schema.fields[0]).subscribe(); + let newField: FieldDto; + + schemasState.addField(schema1, request, schema.fields[0]).subscribe(result => { + newField = result; + }); const schema1New = schemasState.snapshot.schemas.at(0); expect(schema1New).toEqual(updated); expect(schemasState.snapshot.selectedSchema).toEqual(updated); + expect(newField!).toBeDefined(); }); it('should update schema and selected schema when field removed', () => { diff --git a/src/Squidex/app/shared/state/schemas.state.ts b/src/Squidex/app/shared/state/schemas.state.ts index 68c3ea6d5..131fc1ad2 100644 --- a/src/Squidex/app/shared/state/schemas.state.ts +++ b/src/Squidex/app/shared/state/schemas.state.ts @@ -322,7 +322,7 @@ export class SchemasState extends State { function getField(x: SchemaDetailsDto, request: AddFieldDto, parent?: RootFieldDto): FieldDto { if (parent) { - return parent.nested.find(f => f.name === request.name)!; + return x.fields.find(f => f.fieldId === parent.fieldId)!.nested.find(f => f.name === request.name)!; } else { return x.fields.find(f => f.name === request.name)!; } From 880e8bf92dee27f01a26f001cf23ea6eb16bd017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Hlad=C3=ADk?= Date: Fri, 21 Jun 2019 19:50:08 +0200 Subject: [PATCH 24/25] Bad field name in GraphQL schema description (#370) * change nested field name source * nested field unique name * QueryGraphTypeVisitor property --- .../Contents/GraphQL/GraphQLModel.cs | 4 ++-- .../Contents/GraphQL/IGraphModel.cs | 2 +- .../Contents/GraphQL/Types/ContentDataGraphType.cs | 2 +- .../Contents/GraphQL/Types/NestedGraphType.cs | 10 +++++----- .../Contents/GraphQL/Types/QueryGraphTypeVisitor.cs | 6 ++++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs index 1373ee437..9cb3dc67e 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/GraphQLModel.cs @@ -136,9 +136,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL return partitionResolver(key); } - public (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field) + public (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field, string fieldName) { - return field.Accept(new QueryGraphTypeVisitor(schema, GetContentType, this, assetListType)); + return field.Accept(new QueryGraphTypeVisitor(schema, GetContentType, this, assetListType, fieldName)); } public IGraphType GetAssetType() diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs index f44c36b58..1ee303d6a 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/IGraphModel.cs @@ -35,6 +35,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL IGraphType GetContentDataType(Guid schemaId); - (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field); + (IGraphType ResolveType, ValueResolver Resolver) GetGraphType(ISchemaEntity schema, IField field, string fieldName); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs index 7dfd1480b..eb6ef19f5 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentDataGraphType.cs @@ -27,7 +27,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types foreach (var (field, fieldName, typeName) in schema.SchemaDef.Fields.SafeFields()) { - var (resolvedType, valueResolver) = model.GetGraphType(schema, field); + var (resolvedType, valueResolver) = model.GetGraphType(schema, field, fieldName); if (valueResolver != null) { diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs index 7f64227bb..2964ed201 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/NestedGraphType.cs @@ -16,18 +16,18 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types { public sealed class NestedGraphType : ObjectGraphType { - public NestedGraphType(IGraphModel model, ISchemaEntity schema, IArrayField field) + public NestedGraphType(IGraphModel model, ISchemaEntity schema, IArrayField field, string fieldName) { var schemaType = schema.TypeName(); var schemaName = schema.DisplayName(); - var fieldName = field.DisplayName(); + var fieldDisplayName = field.DisplayName(); Name = $"{schemaType}{fieldName}ChildDto"; foreach (var (nestedField, nestedName, _) in field.Fields.SafeFields()) { - var fieldInfo = model.GetGraphType(schema, nestedField); + var fieldInfo = model.GetGraphType(schema, nestedField, nestedName); if (fieldInfo.ResolveType != null) { @@ -38,12 +38,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types Name = nestedName, Resolver = resolver, ResolvedType = fieldInfo.ResolveType, - Description = $"The {fieldName}/{nestedField.DisplayName()} nested field." + Description = $"The {fieldDisplayName}/{nestedField.DisplayName()} nested field." }); } } - Description = $"The structure of the {schemaName}.{fieldName} nested schema."; + Description = $"The structure of the {schemaName}.{fieldDisplayName} nested schema."; } private static FuncFieldResolver ValueResolver(NestedField nestedField, (IGraphType ResolveType, ValueResolver Resolver) fieldInfo) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs index 32a9a308f..195eee1a7 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/QueryGraphTypeVisitor.cs @@ -22,13 +22,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types private readonly Func schemaResolver; private readonly IGraphModel model; private readonly IGraphType assetListType; + private readonly string fieldName; - public QueryGraphTypeVisitor(ISchemaEntity schema, Func schemaResolver, IGraphModel model, IGraphType assetListType) + public QueryGraphTypeVisitor(ISchemaEntity schema, Func schemaResolver, IGraphModel model, IGraphType assetListType, string fieldName) { this.model = model; this.assetListType = assetListType; this.schema = schema; this.schemaResolver = schemaResolver; + this.fieldName = fieldName; } public (IGraphType ResolveType, ValueResolver Resolver) Visit(IArrayField field) @@ -93,7 +95,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types private (IGraphType ResolveType, ValueResolver Resolver) ResolveNested(IArrayField field) { - var schemaFieldType = new ListGraphType(new NonNullGraphType(new NestedGraphType(model, schema, field))); + var schemaFieldType = new ListGraphType(new NonNullGraphType(new NestedGraphType(model, schema, field, this.fieldName))); return (schemaFieldType, NoopResolver); } From 4b7fa30f4aff2d9b8214e4862f89b885f5645bb5 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 21 Jun 2019 20:05:00 +0200 Subject: [PATCH 25/25] Fix for scheduling. --- .../Contents/ScheduleJob.cs | 11 ++++++----- .../Api/Controllers/Contents/Models/ScheduleJobDto.cs | 10 ++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs b/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs index 9936e98ef..4145dd954 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs @@ -1,4 +1,5 @@ -// ========================================================================== + +// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschraenkt) @@ -22,17 +23,17 @@ namespace Squidex.Domain.Apps.Entities.Contents public Instant DueTime { get; } - public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant due) + public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant dueTime) { Id = id; ScheduledBy = scheduledBy; Status = status; - DueTime = due; + DueTime = dueTime; } - public static ScheduleJob Build(Status status, RefToken by, Instant due) + public static ScheduleJob Build(Status status, RefToken scheduledBy, Instant dueTime) { - return new ScheduleJob(Guid.NewGuid(), status, by, due); + return new ScheduleJob(Guid.NewGuid(), status, scheduledBy, dueTime); } } } diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs b/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs index b0e7b34cb..ef7ebda7b 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.ComponentModel.DataAnnotations; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; @@ -25,13 +26,14 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models public Status Status { get; set; } /// - /// The user who schedule the content. + /// The target date and time when the content should be scheduled. /// - public RefToken ScheduledBy { get; set; } + public Instant DueTime { get; set; } /// - /// The target date and time when the content should be scheduled. + /// The user who schedule the content. /// - public Instant DueTime { get; set; } + [Required] + public RefToken ScheduledBy { get; set; } } }