Ver código fonte

Merge branch 'master' into next

Michael Bromley 4 anos atrás
pai
commit
2693174b3c

+ 14 - 0
CHANGELOG.md

@@ -1,3 +1,17 @@
+## <small>0.18.5 (2021-03-01)</small>
+
+
+#### Fixes
+
+* **admin-ui** Typing error on pt-Br i18n (#725) ([50aafb3](https://github.com/vendure-ecommerce/vendure/commit/50aafb3)), closes [#725](https://github.com/vendure-ecommerce/vendure/issues/725)
+* **core** Allow asset uploads with same major mime type ([070c5f2](https://github.com/vendure-ecommerce/vendure/commit/070c5f2)), closes [#727](https://github.com/vendure-ecommerce/vendure/issues/727)
+* **core** Fix list query sorting by non-default language with filters ([1e31828](https://github.com/vendure-ecommerce/vendure/commit/1e31828))
+* **core** Prevent Facet code conflicts ([bce3b59](https://github.com/vendure-ecommerce/vendure/commit/bce3b59)), closes [#715](https://github.com/vendure-ecommerce/vendure/issues/715)
+
+#### Features
+
+* **email-plugin** Support custom EmailGenerators and EmailSenders ([3e20624](https://github.com/vendure-ecommerce/vendure/commit/3e20624))
+
 ## <small>0.18.4 (2021-02-10)</small>
 
 

+ 7 - 12
docs/content/article/roadmap.md

@@ -6,18 +6,13 @@ showtoc: false
 
 ## Vendure beta ➡ v1.0
 
-Here is a list of some of the main outstanding tasks that are planned for the v1.0 release, at which point Vendure will come out of beta:
-
-* Complete the Channels implementation
-* ~~Back order handling~~ ✅
-* Administrator creation & editing of orders
-* ~~Custom authentication support~~ ✅
-* Improved promotions support
-* Improved tax calculation support
-* Improved support for running Vendure in cloud environments
-* Performance improvements
-
-We currently hope to **reach v1.0 by the end of 2020**. For an up-to-date overview of where we stand, refer to the [GitHub milestones page](https://github.com/vendure-ecommerce/vendure/milestones).
+Vendure is soon to enter the v1.0-beta phase. At that point no more breaking changes are planned. Non-breaking features and fixes will then be added over a period of one to several months while we progress from beta to release candidate. At that point, the final v1.0 state will be released. This is currently planned for around April 2021.
+
+ For an up-to-date overview of where we stand, refer to the [v1.0 milestone on GitHub](https://github.com/vendure-ecommerce/vendure/milestones/4).
+
+{{< alert "primary" >}}
+[Join our mailing list](https://mailchi.mp/17af21ad4b64/vendure-mailing-list) to be informed when the final v1.0 is released
+{{< /alert >}}
 
 ## Post v1.0
 

+ 2 - 0
docs/content/docs/developer-guide/authentication.md

@@ -9,6 +9,8 @@ Authentication is the process of determining the identity of a user. Common ways
 
 By default, Vendure uses a username/email address and password to authenticate users, but also supports a wide range of authentication methods via configurable AuthenticationStrategies.
 
+While developing a storefront, mobile app or server that implements authentication of Vendure further reading on [Managing Sessions]({{< relref "managing-sessions" >}}) is highly recommended.
+
 ## Adding support for external authentication
 
 This is done via the [`VendureConfig.authOptions` object]({{< relref "auth-options" >}}#shopauthenticationstrategy):

+ 4 - 0
docs/layouts/partials/top-bar.html

@@ -32,6 +32,10 @@
                         <img class="menu-icon" alt="icon" src="/svg/clr-icon-display.svg" />
                         Demo
                     </a>
+                    <a href="https://mailchi.mp/17af21ad4b64/vendure-mailing-list" target="_blank">
+                        <img src="/svg/clr-icon-email-light.svg" class="menu-icon" alt="email icon" />
+                        Mailing list
+                    </a>
                 </div>
             </div>
             <div class="submenu">

+ 1 - 1
lerna.json

@@ -2,7 +2,7 @@
   "packages": [
     "packages/*"
   ],
-  "version": "0.18.4",
+  "version": "0.18.5",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "command": {

+ 2 - 2
packages/admin-ui-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/admin-ui-plugin",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "files": [
@@ -20,7 +20,7 @@
     "@types/express": "^4.17.8",
     "@types/fs-extra": "^9.0.1",
     "@vendure/common": "^0.18.4",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "express": "^4.17.1",
     "rimraf": "^3.0.2",
     "typescript": "4.0.3"

+ 1 - 1
packages/admin-ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/admin-ui",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "license": "MIT",
   "scripts": {
     "ng": "ng",

+ 1 - 1
packages/admin-ui/src/lib/core/src/common/version.ts

@@ -1,2 +1,2 @@
 // Auto-generated by the set-version.js script.
-export const ADMIN_UI_VERSION = '0.18.4';
+export const ADMIN_UI_VERSION = '0.18.5';

+ 1 - 1
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -117,7 +117,7 @@
     "price-includes-tax-at": "Inclui { rate }% de imposto",
     "price-with-tax-in-default-zone": "Incuído { rate }% de imposto: { price }",
     "private": "Privado",
-    "product-details": "Dealhes do produto",
+    "product-details": "Detalhes do produto",
     "product-name": "Nome do produto",
     "product-variants": "Variações do produto",
     "public": "Público",

+ 2 - 2
packages/asset-server-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/asset-server-plugin",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "files": [
@@ -23,7 +23,7 @@
     "@types/node-fetch": "^2.5.7",
     "@types/sharp": "^0.26.0",
     "@vendure/common": "^0.18.4",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "aws-sdk": "^2.766.0",
     "express": "^4.17.1",
     "node-fetch": "^2.6.1",

+ 29 - 1
packages/core/e2e/asset.e2e-spec.ts

@@ -35,7 +35,7 @@ describe('Asset resolver', () => {
     const { server, adminClient } = createTestEnvironment(
         mergeConfig(testConfig, {
             assetOptions: {
-                permittedFileTypes: ['image/*', '.pdf'],
+                permittedFileTypes: ['image/*', '.pdf', '.zip'],
             },
         }),
     );
@@ -211,6 +211,34 @@ describe('Asset resolver', () => {
             ]);
         });
 
+        // https://github.com/vendure-ecommerce/vendure/issues/727
+        it('file extension with shared type', async () => {
+            const filesToUpload = [path.join(__dirname, 'fixtures/assets/dummy.zip')];
+            const { createAssets }: CreateAssets.Mutation = await adminClient.fileUploadMutation({
+                mutation: CREATE_ASSETS,
+                filePaths: filesToUpload,
+                mapVariables: filePaths => ({
+                    input: filePaths.map(p => ({ file: null })),
+                }),
+            });
+
+            expect(createAssets.length).toBe(1);
+
+            expect(isAsset(createAssets[0])).toBe(true);
+            const results = createAssets.filter(isAsset);
+            expect(results.map(a => omit(a, ['id']))).toEqual([
+                {
+                    fileSize: 1680,
+                    focalPoint: null,
+                    mimeType: 'application/zip',
+                    name: 'dummy.zip',
+                    preview: 'test-url/test-assets/dummy__preview.zip.png',
+                    source: 'test-url/test-assets/dummy.zip',
+                    type: 'BINARY',
+                },
+            ]);
+        });
+
         it('not permitted type', async () => {
             const filesToUpload = [path.join(__dirname, 'fixtures/assets/dummy.txt')];
             const { createAssets }: CreateAssets.Mutation = await adminClient.fileUploadMutation({

+ 39 - 0
packages/core/e2e/facet.e2e-spec.ts

@@ -578,6 +578,45 @@ describe('Facet resolver', () => {
             }, `No Facet with the id '1' could be found`),
         );
     });
+
+    // https://github.com/vendure-ecommerce/vendure/issues/715
+    describe('code conflicts', () => {
+        function createFacetWithCode(code: string) {
+            return adminClient.query<CreateFacet.Mutation, CreateFacet.Variables>(CREATE_FACET, {
+                input: {
+                    isPrivate: false,
+                    code,
+                    translations: [{ languageCode: LanguageCode.en, name: `Test Facet (${code})` }],
+                    values: [],
+                },
+            });
+        }
+
+        it('createFacet with conflicting slug gets renamed', async () => {
+            const { createFacet: result1 } = await createFacetWithCode('test');
+            expect(result1.code).toBe('test');
+
+            const { createFacet: result2 } = await createFacetWithCode('test');
+            expect(result2.code).toBe('test-2');
+        });
+
+        it('updateFacet with conflicting slug gets renamed', async () => {
+            const { createFacet } = await createFacetWithCode('foo');
+            expect(createFacet.code).toBe('foo');
+
+            const { updateFacet } = await adminClient.query<UpdateFacet.Mutation, UpdateFacet.Variables>(
+                UPDATE_FACET,
+                {
+                    input: {
+                        id: createFacet.id,
+                        code: 'test-2',
+                    },
+                },
+            );
+
+            expect(updateFacet.code).toBe('test-3');
+        });
+    });
 });
 
 export const GET_FACET_WITH_VALUES = gql`

BIN
packages/core/e2e/fixtures/assets/dummy.zip


+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/core",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "description": "A modern, headless ecommerce framework",
   "repository": {
     "type": "git",

+ 6 - 3
packages/core/src/service/services/asset.service.ts

@@ -537,9 +537,12 @@ export class AssetService {
 
     private validateMimeType(mimeType: string): boolean {
         const [type, subtype] = mimeType.split('/');
-        const typeMatch = this.permittedMimeTypes.find(t => t.type === type);
-        if (typeMatch) {
-            return typeMatch.subtype === subtype || typeMatch.subtype === '*';
+        const typeMatches = this.permittedMimeTypes.filter(t => t.type === type);
+
+        for (const match of typeMatches) {
+            if (match.subtype === subtype || match.subtype === '*') {
+                return true;
+            }
         }
         return false;
     }

+ 34 - 3
packages/core/src/service/services/facet.service.ts

@@ -6,12 +6,13 @@ import {
     LanguageCode,
     UpdateFacetInput,
 } from '@vendure/common/lib/generated-types';
+import { normalizeString } from '@vendure/common/lib/normalize-string';
 import { ID, PaginatedList } from '@vendure/common/lib/shared-types';
 
 import { RequestContext } from '../../api/common/request-context';
 import { ListQueryOptions } from '../../common/types/common-types';
 import { Translated } from '../../common/types/locale-types';
-import { assertFound } from '../../common/utils';
+import { assertFound, idsAreEqual } from '../../common/utils';
 import { ConfigService } from '../../config/config.service';
 import { FacetTranslation } from '../../entity/facet/facet-translation.entity';
 import { Facet } from '../../entity/facet/facet.entity';
@@ -96,8 +97,9 @@ export class FacetService {
             input,
             entityType: Facet,
             translationType: FacetTranslation,
-            beforeSave: newEntity => {
-                this.channelService.assignToCurrentChannel(newEntity, ctx);
+            beforeSave: async f => {
+                f.code = await this.ensureUniqueCode(ctx, f.code);
+                this.channelService.assignToCurrentChannel(f, ctx);
             },
         });
         await this.customFieldRelationService.updateRelations(ctx, Facet, input, facet);
@@ -110,6 +112,9 @@ export class FacetService {
             input,
             entityType: Facet,
             translationType: FacetTranslation,
+            beforeSave: async f => {
+                f.code = await this.ensureUniqueCode(ctx, f.code, f.id);
+            },
         });
         await this.customFieldRelationService.updateRelations(ctx, Facet, input, facet);
         return assertFound(this.findOne(ctx, facet.id));
@@ -154,4 +159,30 @@ export class FacetService {
             message,
         };
     }
+
+    /**
+     * Checks to ensure the Facet code is unique. If there is a conflict, then the code is suffixed
+     * with an incrementing integer.
+     */
+    private async ensureUniqueCode(ctx: RequestContext, code: string, id?: ID) {
+        let candidate = code;
+        let suffix = 1;
+        let match: Facet | undefined;
+        const alreadySuffixed = /-\d+$/;
+        do {
+            match = await this.connection.getRepository(ctx, Facet).findOne({ where: { code: candidate } });
+
+            const conflict = !!match && ((id != null && !idsAreEqual(match.id, id)) || id == null);
+            if (conflict) {
+                suffix++;
+                if (alreadySuffixed.test(candidate)) {
+                    candidate = candidate.replace(alreadySuffixed, `-${suffix}`);
+                } else {
+                    candidate = `${candidate}-${suffix}`;
+                }
+            }
+        } while (match);
+
+        return candidate;
+    }
 }

+ 2 - 2
packages/create/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/create",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "license": "MIT",
   "bin": {
     "create": "./index.js"
@@ -26,7 +26,7 @@
     "@types/handlebars": "^4.1.0",
     "@types/listr": "^0.14.2",
     "@types/semver": "^6.2.2",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "rimraf": "^3.0.2",
     "ts-node": "^9.0.0",
     "typescript": "4.0.3"

+ 8 - 8
packages/dev-server/package.json

@@ -1,6 +1,6 @@
 {
   "name": "dev-server",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "main": "index.js",
   "license": "MIT",
   "private": true,
@@ -14,18 +14,18 @@
     "load-test:100k": "node -r ts-node/register load-testing/run-load-test.ts 100000"
   },
   "dependencies": {
-    "@vendure/admin-ui-plugin": "^0.18.4",
-    "@vendure/asset-server-plugin": "^0.18.4",
+    "@vendure/admin-ui-plugin": "^0.18.5",
+    "@vendure/asset-server-plugin": "^0.18.5",
     "@vendure/common": "^0.18.4",
-    "@vendure/core": "^0.18.4",
-    "@vendure/elasticsearch-plugin": "^0.18.4",
-    "@vendure/email-plugin": "^0.18.4",
+    "@vendure/core": "^0.18.5",
+    "@vendure/elasticsearch-plugin": "^0.18.5",
+    "@vendure/email-plugin": "^0.18.5",
     "typescript": "4.0.3"
   },
   "devDependencies": {
     "@types/csv-stringify": "^3.1.0",
-    "@vendure/testing": "^0.18.4",
-    "@vendure/ui-devkit": "^0.18.4",
+    "@vendure/testing": "^0.18.5",
+    "@vendure/ui-devkit": "^0.18.5",
     "concurrently": "^5.0.0",
     "csv-stringify": "^5.3.3"
   }

+ 2 - 2
packages/elasticsearch-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/elasticsearch-plugin",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
@@ -23,7 +23,7 @@
   },
   "devDependencies": {
     "@vendure/common": "^0.18.4",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "rimraf": "^3.0.2",
     "typescript": "4.0.3"
   }

+ 2 - 2
packages/email-plugin/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/email-plugin",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
@@ -34,7 +34,7 @@
     "@types/mjml": "^4.0.4",
     "@types/nodemailer": "^6.4.0",
     "@vendure/common": "^0.18.4",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "rimraf": "^3.0.2",
     "typescript": "4.0.3"
   }

+ 2 - 2
packages/testing/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/testing",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "description": "End-to-end testing tools for Vendure projects",
   "keywords": [
     "vendure",
@@ -44,7 +44,7 @@
   "devDependencies": {
     "@types/mysql": "^2.15.15",
     "@types/pg": "^7.14.5",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "mysql": "^2.18.1",
     "pg": "^8.4.0",
     "rimraf": "^3.0.0",

+ 3 - 3
packages/ui-devkit/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@vendure/ui-devkit",
-  "version": "0.18.4",
+  "version": "0.18.5",
   "description": "A library for authoring Vendure Admin UI extensions",
   "keywords": [
     "vendure",
@@ -39,7 +39,7 @@
     "@angular/cli": "^10.1.4",
     "@angular/compiler": "^10.1.4",
     "@angular/compiler-cli": "^10.1.4",
-    "@vendure/admin-ui": "^0.18.4",
+    "@vendure/admin-ui": "^0.18.5",
     "@vendure/common": "^0.18.4",
     "chalk": "^4.1.0",
     "chokidar": "^3.4.2",
@@ -51,7 +51,7 @@
     "@rollup/plugin-node-resolve": "^9.0.0",
     "@types/fs-extra": "^9.0.1",
     "@types/glob": "^7.1.3",
-    "@vendure/core": "^0.18.4",
+    "@vendure/core": "^0.18.5",
     "rimraf": "^3.0.2",
     "rollup": "^2.28.2",
     "rollup-plugin-terser": "^7.0.2",