From 49618755beb3e92621e2f8a6780ca29594417783 Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Tue, 17 Oct 2023 10:03:05 +0200 Subject: [PATCH 1/8] feat(core): Add `cbqc` named export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This exports the constant `0.55342686` which is the value to best approximate a (quarter) circle with a cubic Bézier curve. See: https://spencermortensen.com/articles/bezier-circle/ --- CHANGELOG.md | 1 + config/changelog.yaml | 1 + packages/core/src/index.mjs | 2 ++ packages/core/src/utils.mjs | 10 ++++++++++ 4 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f7953442e8..3b5e678b148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -136,6 +136,7 @@ #### Added - Allow plugins to provide their own packing implementation + - Added named export `cbqc` which exports the constant to approximate a circle with Cubic Bézier curves #### Fixed diff --git a/config/changelog.yaml b/config/changelog.yaml index af9c4c82c67..313da9509d7 100644 --- a/config/changelog.yaml +++ b/config/changelog.yaml @@ -2,6 +2,7 @@ Unreleased: Added: core: - Allow plugins to provide their own packing implementation + - Added named export `cbqc` which exports the constant to approximate a circle with Cubic Bézier curves plugin-bin-pack: - First release of the plugin providing the default packing implementation plugin-ringsector: diff --git a/packages/core/src/index.mjs b/packages/core/src/index.mjs index 06fc80c1a23..3bc982451aa 100644 --- a/packages/core/src/index.mjs +++ b/packages/core/src/index.mjs @@ -15,6 +15,7 @@ import { beamsIntersect, beamIntersectsCurve, capitalize, + cbqc, circlesIntersect, curveEdge, curveIntersectsX, @@ -62,6 +63,7 @@ export { beamsIntersect, beamIntersectsCurve, capitalize, + cbqc, circlesIntersect, curveEdge, curveIntersectsX, diff --git a/packages/core/src/utils.mjs b/packages/core/src/utils.mjs index b24148a9fcb..23d39930a8a 100644 --- a/packages/core/src/utils.mjs +++ b/packages/core/src/utils.mjs @@ -2,8 +2,18 @@ import { Bezier } from 'bezier-js' import { Path } from './path.mjs' import { Point } from './point.mjs' +/* + * See: https://en.wikipedia.org/wiki/Golden_ratio + */ export const goldenRatio = 1.618034 +/* + * cbqc = Cubic Bezier Quarter Circle + * The value to best approximate a (quarter) circle with cubic Bézier curves + * See: https://spencermortensen.com/articles/bezier-circle/ + */ +export const cbqc = 0.55191502449351 + ////////////////////////////////////////////// // PUBLIC METHODS // ////////////////////////////////////////////// From b0b3dee005bc88dd7a9843c84a502023ef93ea6c Mon Sep 17 00:00:00 2001 From: FreeSewing bot Date: Tue, 17 Oct 2023 15:49:55 +0200 Subject: [PATCH 2/8] feat: New showcase post simone-by-gaelle by Natalia --- markdown/org/showcase/simone-by-gaelle/en.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 markdown/org/showcase/simone-by-gaelle/en.md diff --git a/markdown/org/showcase/simone-by-gaelle/en.md b/markdown/org/showcase/simone-by-gaelle/en.md new file mode 100644 index 00000000000..366b654f25b --- /dev/null +++ b/markdown/org/showcase/simone-by-gaelle/en.md @@ -0,0 +1,19 @@ +--- +title: "Simone by Gaëlle" +caption: "A lovely Simone shirt with beautiful details" +date: 20231017 +intro: "This Simone shirt features beautiful details, including coordinated buttons and custom labels." +designs: ["simone"] +maker: Natalia +--- + +The talented Gaëlle shared this Simone shirt. Don't miss the the detail photos. + +![Another view of the front](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-simone-by-gaelle-1/public "Another view of the front") + +![Collar details](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-simone-by-gaelle-2/public "Collar details") + +![Cuff button details](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-simone-by-gaelle-4/public "Cuff button details") + +![Custom label tags](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-simone-by-gaelle-5/public "Custom label tags") + From 0c8a26f94753ca7a610a4549698926deb14f6083 Mon Sep 17 00:00:00 2001 From: FreeSewing bot Date: Tue, 17 Oct 2023 15:55:56 +0200 Subject: [PATCH 3/8] feat: New showcase post breanna-dress-by-andrea-cretu by Natalia --- .../breanna-dress-by-andrea-cretu/en.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 markdown/org/showcase/breanna-dress-by-andrea-cretu/en.md diff --git a/markdown/org/showcase/breanna-dress-by-andrea-cretu/en.md b/markdown/org/showcase/breanna-dress-by-andrea-cretu/en.md new file mode 100644 index 00000000000..d60d5eb7fae --- /dev/null +++ b/markdown/org/showcase/breanna-dress-by-andrea-cretu/en.md @@ -0,0 +1,17 @@ +--- +title: "Breanna dress by Andrea Cretu" +caption: "Andrea made this lovely dress based on the Breanna block" +date: 20231017 +intro: "Andrea added a circle skirt to the Breanna block to make this charming dress." +designs: ["breanna"] +maker: Natalia +--- + +Andrea added a circle skirt to the Breanna block to make this charming dress. We love the choice of fabric and buttons! + +Andrea shared these helpful details: + +> Made a dress based on the Breanna body block, with a circle skirt. Next iteration I'll scoop out the armholes and neck and add length to the bottom, so the skirt starts a little lower. Also will make the darts end earlier on the bust and later on the back. + +Andrea is a talented creator, and the owner at [Yarnandy.com](Yarnandy.com). + From 47b43afb3798d51ffbce9948937c7bac8c48ef36 Mon Sep 17 00:00:00 2001 From: FreeSewing bot Date: Tue, 17 Oct 2023 16:06:50 +0200 Subject: [PATCH 4/8] feat: New showcase post four-versions-of-otis-and-a-bonus-bob by Natalia --- .../en.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 markdown/org/showcase/four-versions-of-otis-and-a-bonus-bob/en.md diff --git a/markdown/org/showcase/four-versions-of-otis-and-a-bonus-bob/en.md b/markdown/org/showcase/four-versions-of-otis-and-a-bonus-bob/en.md new file mode 100644 index 00000000000..771073a3a20 --- /dev/null +++ b/markdown/org/showcase/four-versions-of-otis-and-a-bonus-bob/en.md @@ -0,0 +1,23 @@ +--- +title: "Four versions of Otis and a bonus Bob" +caption: "An Otis baby romper and Bob bib" +date: 20231017 +intro: "Wouter made four versions of Otis for newborn Otis, and a Bob to complete the ensemble." +designs: ["otis", "bob"] +maker: Natalia +--- + +Wouter, the designer, made these: + +> Four versions of otis. One with long sleeves, and one that is reversible (don’t try this; figuring out how seams go together and in which sequence causes headaches). + +We are head over heels for his adorable fabric choices. The cute baby doesn't hurt. + +![Otis on Otis](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-four-versions-of-otis-and-a-bonus-bob-1/public "Otis on Otis") + +![A polka dot Otis](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-four-versions-of-otis-and-a-bonus-bob-2/public "A polka dot Otis") + +![This Otis is out of this world](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-four-versions-of-otis-and-a-bonus-bob-3/public "This Otis is out of this world") + +![A view of the reverse](https://imagedelivery.net/ouSuR9yY1bHt-fuAokSA5Q/showcase-four-versions-of-otis-and-a-bonus-bob-4/public "A view of the reverse") + From 37d6959cb2a8f2b266578475079a490a141ab833 Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Tue, 17 Oct 2023 17:41:28 +0200 Subject: [PATCH 5/8] chore(backend): Remove (c)set from patterns, img from users This removes some fields from the database and the logic for handling them. Specifically: - Do not keep a set or cset reference for patterns. Doing so will only raise expectations for users as a link between (c)set and pattern might signal that changes to the (c)set would somehow also update the pattern. Once a pattern is saved, it is what it is, so no point keeping a link to the (c)set. We may want to look at how to add a note about which (c)set the pattern was generated for, but I don't think that's crucial. - Do not keep an img field in the user account, cset, or open pack, since they have a deterministic image ID anyway. This also adds and info field to cset and option pack which is an internal field allowing us to keep (non-public) notes about where the record comes from. This will be important when we add a new mesurement and we have to contqct all these people for that extra measurement (for example). --- sites/backend/prisma/schema.prisma | 12 +- sites/backend/src/models/curated-set.mjs | 44 ++--- sites/backend/src/models/option-pack.mjs | 16 +- sites/backend/src/models/pattern.mjs | 235 +---------------------- sites/backend/src/models/set.mjs | 76 -------- sites/backend/src/models/subscriber.mjs | 39 ---- sites/backend/src/models/user.mjs | 156 +-------------- sites/backend/src/routes/imports.mjs | 21 -- sites/backend/src/routes/index.mjs | 2 - sites/backend/tests/account.mjs | 5 - sites/backend/tests/curated-set.mjs | 5 +- sites/backend/tests/option-pack.mjs | 3 +- sites/backend/tests/pattern.mjs | 25 --- 13 files changed, 47 insertions(+), 592 deletions(-) delete mode 100644 sites/backend/src/routes/imports.mjs diff --git a/sites/backend/prisma/schema.prisma b/sites/backend/prisma/schema.prisma index fa09aa98fc8..22814ce5da0 100644 --- a/sites/backend/prisma/schema.prisma +++ b/sites/backend/prisma/schema.prisma @@ -64,7 +64,6 @@ model User { ehash String @unique email String ihash String - img String? initial String imperial Boolean @default(false) jwtCalls Int @default(0) @@ -94,17 +93,13 @@ model Pattern { img String? name String @default("") notes String - set Set? @relation(fields: [setId], references: [id]) - setId Int? - cset CuratedSet? @relation(fields: [csetId], references: [id]) - csetId Int? public Boolean @default(false) settings String user User @relation(fields: [userId], references: [id]) userId Int updatedAt DateTime @updatedAt - @@index([userId, setId]) + @@index([userId, design]) } model Set { @@ -117,7 +112,6 @@ model Set { user User @relation(fields: [userId], references: [id]) userId Int measies String @default("{}") - patterns Pattern[] public Boolean @default(false) updatedAt DateTime @updatedAt @@ -127,7 +121,7 @@ model Set { model CuratedSet { id Int @id @default(autoincrement()) createdAt DateTime @default(now()) - img String? + info String @default("") nameDe String @default("") nameEn String @default("") nameEs String @default("") @@ -142,7 +136,6 @@ model CuratedSet { notesUk String @default("") tags String @default("{}") measies String @default("[]") - patterns Pattern[] updatedAt DateTime @updatedAt published Boolean @default(false) } @@ -152,6 +145,7 @@ model OptionPack { createdAt DateTime @default(now()) design String @default("") img String? + info String @default("") nameDe String @default("") nameEn String @default("") nameEs String @default("") diff --git a/sites/backend/src/models/curated-set.mjs b/sites/backend/src/models/curated-set.mjs index b0ed1510cb5..13a744791dc 100644 --- a/sites/backend/src/models/curated-set.mjs +++ b/sites/backend/src/models/curated-set.mjs @@ -58,9 +58,9 @@ CuratedSetModel.prototype.guardedCreate = async function ({ body, user }) { else data.measies = '{}' /* - * Set an initial img as we need the record ID to store an image on cloudflare + * Add the info */ - data.img = this.config.avatars.set + if (body.info) data.info = body.info /* * Create the database record @@ -68,9 +68,9 @@ CuratedSetModel.prototype.guardedCreate = async function ({ body, user }) { await this.createRecord(data) /* - * Now that we have a record and ID, we can update the image after uploading it to cloudflare + * Now that we have a record and ID, we can upload the image to cloudflare and set its id */ - const img = await storeImage( + await storeImage( { id: `cset-${this.record.id}`, metadata: { user: user.uid }, @@ -79,14 +79,6 @@ CuratedSetModel.prototype.guardedCreate = async function ({ body, user }) { this.isTest(body) ) - /* - * If an image was uploaded, update the record with the image ID - */ - if (img) await this.update({ img }) - /* - * If not, just read the record from the datbasa - */ else await this.read({ id: this.record.id }) - /* * Record created, return data in the proper format */ @@ -147,6 +139,7 @@ CuratedSetModel.prototype.allCuratedSets = async function () { */ asPojo.measies = JSON.parse(asPojo.measies) asPojo.tags = JSON.parse(asPojo.tags) + delete asPojo.info list.push(asPojo) } @@ -229,6 +222,11 @@ CuratedSetModel.prototype.guardedUpdate = async function ({ params, body, user } */ if ([true, false].includes(body.published)) data.published = body.published + /* + * Handle the info field + */ + if (typeof body.info === 'string') data.info = body.info + /* * Unlike a regular set, curated set have notes and name in each language */ @@ -263,7 +261,6 @@ CuratedSetModel.prototype.guardedUpdate = async function ({ params, body, user } }, this.isTest(body) ) - data.img = img } /* @@ -365,10 +362,7 @@ CuratedSetModel.prototype.suggest = async function ({ body, user }) { /* * If an image was uploaded, update the record with the image ID */ - if (img) { - data.img = img - await this.Confirmation.update({ data }) - } + if (img) await this.Confirmation.update({ data }) /* * Return id @@ -438,8 +432,6 @@ CuratedSetModel.prototype.fromSuggestion = async function ({ params, user }) { * Now create the curated set */ await this.createRecord({ - // This image will need to be replaced - img: this.Confirmation.clear.data.img, nameDe: name, nameEn: name, nameEs: name, @@ -476,13 +468,14 @@ CuratedSetModel.prototype.fromSuggestion = async function ({ params, user }) { * @returns {curatedSet} object - The Cureated Set as a plain object */ CuratedSetModel.prototype.asCuratedSet = function () { - return { - ...this.record, - measies: - typeof this.record.measies === 'string' - ? JSON.parse(this.record.measies) - : this.record.measies, + const data = { ...this.record } + for (const field of this.jsonFields) { + data[field] = + typeof this.record[field] === 'string' ? JSON.parse(this.record[field]) : this.record[field] } + delete data.info + + return data } /* @@ -499,6 +492,7 @@ CuratedSetModel.prototype.asData = function () { } data.measurements = data.measies delete data.measies + delete data.info return data } diff --git a/sites/backend/src/models/option-pack.mjs b/sites/backend/src/models/option-pack.mjs index 2e21d7484fe..331ab63451c 100644 --- a/sites/backend/src/models/option-pack.mjs +++ b/sites/backend/src/models/option-pack.mjs @@ -35,6 +35,7 @@ OptionPackModel.prototype.guardedCreate = async function ({ body, user }) { * Is design set? */ if (!body.design || typeof body.design !== 'string') return this.setResponse(400, 'designMissing') + /* * Is nameEn set? */ @@ -57,6 +58,11 @@ OptionPackModel.prototype.guardedCreate = async function ({ body, user }) { } if (body.tags && Array.isArray(body.tags)) data.tags = JSON.stringify(body.tags) + /* + * Add the info + */ + if (body.info) data.info = body.info + /* * Add the options if there are any */ @@ -187,6 +193,11 @@ OptionPackModel.prototype.guardedUpdate = async function ({ params, body, user } } } + /* + * Handle the info field + */ + if (typeof body.info === 'string') data.info = body.info + /* * Handle the options */ @@ -305,7 +316,10 @@ OptionPackModel.prototype.suggest = async function ({ body, user }) { * @returns {optionPack} object - The Option Pack as a plain object */ OptionPackModel.prototype.asOptionPack = function () { - return this.record + const data = { ...this.record } + delete data.info + + return data } /* diff --git a/sites/backend/src/models/pattern.mjs b/sites/backend/src/models/pattern.mjs index e4a75769db1..63d586922a3 100644 --- a/sites/backend/src/models/pattern.mjs +++ b/sites/backend/src/models/pattern.mjs @@ -10,7 +10,6 @@ export function PatternModel(tools) { name: 'pattern', encryptedFields: ['data', 'name', 'notes', 'settings'], jsonFields: ['data'], - models: ['set'], }) } @@ -33,10 +32,6 @@ PatternModel.prototype.userPatterns = async function (uid) { try { patterns = await this.prisma.pattern.findMany({ where: { userId: uid }, - include: { - set: true, - cset: true, - }, }) } catch (err) { log.warn(`Failed to search patterns for user ${uid}: ${err}`) @@ -95,11 +90,9 @@ PatternModel.prototype.guardedCreate = async function ({ body, user }) { * Create initial record */ await this.createRecord({ - csetId: body.cset ? body.cset : null, data: typeof body.data === 'object' ? body.data : {}, design: body.design, img: this.config.avatars.pattern, - setId: body.set ? body.set : null, settings: { ...body.settings, measurements: @@ -129,7 +122,7 @@ PatternModel.prototype.guardedCreate = async function ({ body, user }) { * If not, just update the record from the database */ await this.update({ img }) - } else await this.read({ id: this.record.id }, { set: true, cset: true }) + } else await this.read({ id: this.record.id }) /* * Now return 201 and the record data @@ -147,7 +140,7 @@ PatternModel.prototype.publicRead = async function ({ params }) { /* * Attempt to read the database record */ - await this.read({ id: parseInt(params.id) }, { set: true, cset: true }) + await this.read({ id: parseInt(params.id) }) /* * Ensure it is public and if it is not public, return 404 @@ -184,7 +177,7 @@ PatternModel.prototype.guardedRead = async function ({ params, user }) { /* * Attempt to read record from database */ - await this.read({ id: parseInt(params.id) }, { set: true, cset: true }) + await this.read({ id: parseInt(params.id) }) /* * Return 404 if it cannot be found @@ -272,7 +265,7 @@ PatternModel.prototype.guardedUpdate = async function ({ params, body, user }) { /* * Attempt to read record from the database */ - await this.read({ id: parseInt(params.id) }, { set: true, cset: true }) + await this.read({ id: parseInt(params.id) }) /* * Only admins can update other people's patterns @@ -322,7 +315,7 @@ PatternModel.prototype.guardedUpdate = async function ({ params, body, user }) { /* * Now update the record */ - await this.update(data, { set: true, cset: true }) + await this.update(data) /* * Return 200 and the data @@ -391,8 +384,6 @@ PatternModel.prototype.revealPattern = function (pattern) { //console.log(err) } } - if (pattern.set) delete pattern.set.measies - if (pattern.cset) delete pattern.cset.measies return { ...pattern, ...clear } } @@ -410,219 +401,3 @@ PatternModel.prototype.asPublicPattern = function () { return data } - -/* - * - * Everything below this comment is v2 => v3 migration code - * And can be removed after the migration - */ - -const migratePattern = (v2, userId) => ({ - createdAt: new Date(v2.created ? v2.created : v2.createdAt), - data: { version: v2.data.version, notes: ['Migrated from version 2'] }, - design: v2.design || v2.data.design, - name: v2.name || '--', - notes: v2.notes ? v2.notes + '\n\nMigrated from v2' : 'Migrated from v2', - settings: v2.data.settings, - userId, -}) - -const v2lut = { - 'size 28, with breasts': 1, - 'size 30, with breasts': 2, - 'size 32, with breasts': 3, - 'size 34, with breasts': 4, - 'size 36, with breasts': 5, - 'size 38, with breasts': 6, - 'size 40, with breasts': 7, - 'size 42, with breasts': 8, - 'size 44, with breasts': 9, - 'size 46, with breasts': 10, - 'size-28-b': 1, - 'size-30-b': 2, - 'size-32-b': 3, - 'size-34-b': 4, - 'size-36-b': 5, - 'size-38-b': 6, - 'size-40-b': 7, - 'size-42-b': 8, - 'size-44-b': 9, - 'size-46-b': 10, - 'size-28-with-breasts': 1, - 'size-30-with-breasts': 2, - 'size-32-with-breasts': 3, - 'size-34-with-breasts': 4, - 'size-36-with-breasts': 5, - 'size-38-with-breasts': 6, - 'size-40-with-breasts': 7, - 'size-42-with-breasts': 8, - 'size-44-with-breasts': 9, - 'size-46-with-breasts': 10, - 'größe 28, mit brüsten': 1, - 'größe 30, mit brüsten': 2, - 'größe 32, mit brüsten': 3, - 'größe 34, mit brüsten': 4, - 'größe 36, mit brüsten': 5, - 'größe 38, mit brüsten': 6, - 'größe 40, mit brüsten': 7, - 'größe 42, mit brüsten': 8, - 'größe 44, mit brüsten': 9, - 'größe 46, mit brüsten': 10, - 'maat 28, met borsten': 1, - 'maat 30, met borsten': 2, - 'maat 32, met borsten': 3, - 'maat 34, met borsten': 4, - 'maat 36, met borsten': 5, - 'maat 38, met borsten': 6, - 'maat 40, met borsten': 7, - 'maat 42, met borsten': 8, - 'maat 44, met borsten': 9, - 'maat 46, met borsten': 10, - 'taille 28, avec des seins': 1, - 'taille 30, avec des seins': 2, - 'taille 32, avec des seins': 3, - 'taille 34, avec des seins': 4, - 'taille 36, avec des seins': 5, - 'taille 38, avec des seins': 6, - 'taille 40, avec des seins': 7, - 'taille 42, avec des seins': 8, - 'taille 44, avec des seins': 9, - 'taille 46, avec des seins': 10, - 'size 28, avec des seins': 1, - 'size 30, avec des seins': 2, - 'size 32, avec des seins': 3, - 'size 34, avec des seins': 4, - 'size 36, avec des seins': 5, - 'size 38, avec des seins': 6, - 'size 40, avec des seins': 7, - 'size 42, avec des seins': 8, - 'size 44, avec des seins': 9, - 'size 46, avec des seins': 10, - 'tamaño 28, con pechos': 1, - 'tamaño 30, con pechos': 2, - 'tamaño 32, con pechos': 3, - 'tamaño 34, con pechos': 4, - 'tamaño 36, con pechos': 5, - 'tamaño 38, con pechos': 6, - 'tamaño 40, con pechos': 7, - 'tamaño 42, con pechos': 8, - 'tamaño 44, con pechos': 9, - 'tamaño 46, con pechos': 10, - - 'size 32, without breasts': 11, - 'size 34, without breasts': 12, - 'size 36, without breasts': 13, - 'size 38, without breasts': 14, - 'size 40, without breasts': 15, - 'size 42, without breasts': 16, - 'size 44, without breasts': 17, - 'size 46, without breasts': 18, - 'size 48, without breasts': 19, - 'size 50, without breasts': 20, - 'taille 32, sans seins': 11, - 'taille 34, sans seins': 12, - 'taille 36, sans seins': 13, - 'taille 38, sans seins': 14, - 'taille 40, sans seins': 15, - 'taille 42, sans seins': 16, - 'taille 44, sans seins': 17, - 'taille 46, sans seins': 18, - 'taille 48, sans seins': 19, - 'taille 50, sans seins': 20, - 'size 32, sans seins': 11, - 'size 34, sans seins': 12, - 'size 36, sans seins': 13, - 'size 38, sans seins': 14, - 'size 40, sans seins': 15, - 'size 42, sans seins': 16, - 'size 44, sans seins': 17, - 'size 46, sans seins': 18, - 'size 48, sans seins': 19, - 'size 50, sans seins': 20, - 'size-28-without-breasts': 11, - 'size-30-without-breasts': 12, - 'size-32-without-breasts': 13, - 'size-34-without-breasts': 14, - 'size-36-without-breasts': 15, - 'size-38-without-breasts': 16, - 'size-40-without-breasts': 17, - 'size-42-without-breasts': 18, - 'size-44-without-breasts': 19, - 'size-46-without-breasts': 20, - 'size-32-a': 11, - 'size-34-a': 12, - 'size-36-a': 13, - 'size-38-a': 14, - 'size-40-a': 15, - 'size-42-a': 16, - 'size-44-a': 17, - 'size-46-a': 18, - 'size-48-a': 19, - 'size-50-a': 20, - 'maat 32, zonder borsten': 11, - 'maat 34, zonder borsten': 12, - 'maat 36, zonder borsten': 13, - 'maat 38, zonder borsten': 14, - 'maat 40, zonder borsten': 15, - 'maat 42, zonder borsten': 16, - 'maat 44, zonder borsten': 17, - 'maat 46, zonder borsten': 18, - 'maat 48, zonder borsten': 19, - 'maat 50, zonder borsten': 20, - 'größe 32, ohne brüste': 11, - 'größe 34, ohne brüste': 12, - 'größe 36, ohne brüste': 13, - 'größe 38, ohne brüste': 14, - 'größe 40, ohne brüste': 15, - 'größe 42, ohne brüste': 16, - 'größe 44, ohne brüste': 17, - 'größe 46, ohne brüste': 18, - 'größe 48, ohne brüste': 19, - 'größe 50, ohne brüste': 20, - 'grösse 32, ohne brüste': 11, - 'grösse 34, ohne brüste': 12, - 'grösse 36, ohne brüste': 13, - 'grösse 38, ohne brüste': 14, - 'grösse 40, ohne brüste': 15, - 'grösse 42, ohne brüste': 16, - 'grösse 44, ohne brüste': 17, - 'grösse 46, ohne brüste': 18, - 'grösse 48, ohne brüste': 19, - 'grösse 50, ohne brüste': 20, - 'tamaño 32, sin pechos': 11, - 'tamaño 34, sin pechos': 12, - 'tamaño 36, sin pechos': 13, - 'tamaño 38, sin pechos': 14, - 'tamaño 40, sin pechos': 15, - 'tamaño 42, sin pechos': 16, - 'tamaño 44, sin pechos': 17, - 'tamaño 46, sin pechos': 18, - 'tamaño 48, sin pechos': 19, - 'tamaño 50, sin pechos': 20, -} -/* - * This is a special route not available for API users - */ -PatternModel.prototype.import = async function (v2user, lut, userId) { - for (const pattern of Object.values(v2user.patterns)) { - let skip = false - const data = { ...migratePattern(pattern, userId), userId } - if (lut[pattern.person]) data.setId = lut[pattern.person] - else if (v2lut[pattern.person]) data.csetId = v2lut[pattern.person] - else if (pattern.person.length !== 5 && !['any', 'original'].includes(pattern.person)) { - console.log(`Cannot find ${pattern.person}`, pattern, { lut, v2lut }) - process.exit() - } - if (!data.design || ['theo', 'ursula', 'unice'].includes(data.design)) skip = true - if (!skip) { - // V2 does not support images for patterns - data.img = 'default-avatar' - try { - this.createRecord(data) - } catch (err) { - log.warn(err, 'Could not create pattern') - console.log(data) - } - } - } -} diff --git a/sites/backend/src/models/set.mjs b/sites/backend/src/models/set.mjs index 80e0a7aa8ce..26fcee2325d 100644 --- a/sites/backend/src/models/set.mjs +++ b/sites/backend/src/models/set.mjs @@ -386,79 +386,3 @@ SetModel.prototype.asPublicSet = function () { return data } - -/* - * - * Everything below this comment is part of the v2 => v3 migration code - * and can be removed once that migration is complete - */ - -const migratePerson = (v2) => ({ - createdAt: new Date(v2.created ? v2.created : v2.createdAt), - imperial: v2.units === 'imperial', - name: v2.name || '--', // Encrypted, so always set _some_ value - notes: v2.notes || '--', // Encrypted, so always set _some_ value - measies: v2.measurements || {}, // Encrypted, so always set _some_ value - updatedAt: new Date(v2.updatedAt), -}) - -/* - * This is a special import route - */ -SetModel.prototype.migrate = async function (v2user, userId) { - const lut = {} // lookup tabel for v2 handle to v3 id - for (const [handle, person] of Object.entries(v2user.people)) { - const data = { ...migratePerson(person), userId } - data.img = 'default-avatar' - try { - await this.createRecord(data) - lut[handle] = this.record.id - } catch (err) { - log.warn(err, 'Could not create set') - console.log(person) - } - } - - return lut -} -/* - * This is a special route not available for API users - */ -SetModel.prototype.import = async function (v2user, userId) { - const lut = {} // lookup tabel for v2 handle to v3 id - for (const [handle, person] of Object.entries(v2user.people)) { - const data = { ...migratePerson(person), userId } - await this.createRecord(data) - // Now that we have an ID, we can handle the image - if (person.picture && person.picture.slice(-4) !== '.svg') { - const imgId = `set-${this.record.id}` - const imgUrl = - 'https://static.freesewing.org/users/' + - encodeURIComponent(v2user.handle.slice(0, 1)) + - '/' + - encodeURIComponent(v2user.handle) + - '/people/' + - encodeURIComponent(person.handle) + - '/' + - encodeURIComponent(person.picture) - data.img = await importImage({ - id: imgId, - metadata: { - user: userId, - v2PersonHandle: handle, - }, - url: imgUrl, - }) - data.img = imgId - } else data.img = 'default-avatar' - try { - await this.createRecord(data) - lut[handle] = this.record.id - } catch (err) { - log.warn(err, 'Could not create set') - console.log(person) - } - } - - return lut -} diff --git a/sites/backend/src/models/subscriber.mjs b/sites/backend/src/models/subscriber.mjs index fd46b8a7a64..b29479fec33 100644 --- a/sites/backend/src/models/subscriber.mjs +++ b/sites/backend/src/models/subscriber.mjs @@ -192,42 +192,3 @@ SubscriberModel.prototype.verifySubscription = async function (body) { return this } - -/* - * - * Anything below this comment is migration code for the v2 => v3 migration - * and can be safely removed after the migration is done - */ - -/* - * This is a special route not available for API users - */ -SubscriberModel.prototype.import = async function (list) { - let created = 0 - for (const sub of list) { - const email = clean(sub) - const ehash = hash(email) - await this.read({ ehash }) - - if (!this.record) { - const data = await this.cloak({ - ehash, - email, - language: 'en', - active: true, - }) - try { - this.record = await this.prisma.subscriber.create({ data }) - created++ - } catch (err) { - log.warn(err, 'Could not create subscriber record') - return this.setResponse(500, 'createSubscriberFailed') - } - } - } - - return this.setResponse(200, 'success', { - total: list.length, - imported: created, - }) -} diff --git a/sites/backend/src/models/user.mjs b/sites/backend/src/models/user.mjs index 72267111b13..2284ff90830 100644 --- a/sites/backend/src/models/user.mjs +++ b/sites/backend/src/models/user.mjs @@ -176,13 +176,11 @@ UserModel.prototype.oauthSignIn = async function ({ body }) { metadata: { ihash }, url: oauthData.img, }) - if (img) data.img = this.encrypt(img) - else data.img = this.encrypt(this.config.avatars.user) } catch (err) { log.info(err, `Unable to update image post-oauth signup for user ${email}`) return this.setResponse(500, 'createAccountFailed') } - } else data.img = this.config.avatars.user + } /* * Now attempt to create the record in the database @@ -763,7 +761,6 @@ UserModel.prototype.guardedCreate = async function ({ body }) { */ data: this.encrypt({}), bio: this.encrypt(''), - img: this.config.avatars.user, } /* * During tests, users can set their own permission level so you can test admin stuff @@ -1295,7 +1292,7 @@ UserModel.prototype.guardedUpdate = async function ({ body, user }) { * Image (img) */ if (typeof body.img === 'string') - data.img = await replaceImage({ + await replaceImage({ id: `uid-${this.record.ihash}`, data: body.img, }) @@ -1593,7 +1590,6 @@ UserModel.prototype.asProfile = function () { return { id: this.record.id, bio: this.clear.bio, - img: this.record.img, ihash: this.record.ihash, patron: this.record.patron, role: this.record.role, @@ -1620,7 +1616,6 @@ UserModel.prototype.asAccount = function () { email: this.clear.email, data: this.clear.data, ihash: this.record.ihash, - img: this.record.img, imperial: this.record.imperial, initial: this.clear.initial, jwtCalls: this.record.jwtCalls, @@ -1901,150 +1896,3 @@ UserModel.prototype.papersPlease = async function (id, type, payload) { */ return [true, false] } - -/* - * Everything below this comment is migration code. - * This can all be removed after v3 is in production and all users have been migrated. - */ -const migrateUser = (v2) => { - const email = clean(v2.email) - const initial = v2.initial ? clean(v2.initial) : email - const data = { - bio: v2.bio || '--', - consent: 0, - createdAt: v2.time?.created ? new Date(v2.time.created) : new Date(), - email, - ehash: hash(email), - data: {}, - ihash: hash(initial), - img: 'default-avatar', - initial, - imperial: v2.settings.units === 'imperial', - language: v2.settings.language, - lastSeen: new Date(), - lusername: v2.username.toLowerCase(), - mfaEnabled: false, - newsletter: v2.newsletter === true ? true : false, - patron: v2.patron, - role: v2._id === '5d62aa44ce141a3b816a3dd9' ? 'admin' : 'user', - status: v2.status === 'active' ? 1 : 0, - username: v2.username, - } - if (data.consent.profile) data.consent++ - if (data.consent.measurements) data.consent++ - if (data.consent.openData) data.consent++ - - return data -} - -/* - * This is a special migration route - */ -UserModel.prototype.migrate = async function ({ password, v2 }) { - //let lut = false - const data = migrateUser(v2.account) - if (v2.account.consent.profile && (v2.account.consent.model || v2.account.consent.measurements)) { - data.consent++ - if (v2.account.consent.openData) v2.account.consent++ - } - data.password = password - await this.read({ ehash: data.ehash }) - if (!this.record) { - /* - * Skip images for now - */ - data.img = 'default-avatar' - let available = await this.isLusernameAvailable(data.lusername) - while (!available) { - data.username += '+' - data.lusername += '+' - available = await this.isLusernameAvailable(data.lusername) - } - try { - await this.createRecord(data) - } catch (err) { - log.warn(err, 'Could not create user record') - return this.setResponse(500, 'createUserFailed') - } - // That's the user, now load their people as sets - const user = { - ...v2.account, - people: v2.people, - patterns: v2.patterns, - } - if (user.people) await this.Set.migrate(user, this.record.id) - //if (user.people) lut = await this.Set.migrate(user, this.record.id) - //if (user.patterns) await this.Pattern.import(user, lut, this.record.id) - } else { - return this.setResponse(400, 'userExists') - } - - /* - * Decrypt data so we can return it - */ - await this.reveal() - - /* - * Looks like the migration was a success. Return a passwordless sign in - */ - return this.signInOk() -} -/* - * This is a special route not available for API users - */ -UserModel.prototype.import = async function (user) { - if (user.status === 'active') { - const data = migrateUser(user) - if (user.consent.profile && (user.consent.model || user.consent.measurements)) { - data.consent++ - if (user.consent.openData) data.consent++ - } - - await this.read({ ehash: data.ehash }) - if (!this.record) { - /* - * Skip images for now - */ - if (data.img) { - /* - * Figure out what image to grab from the FreeSewing v2 backend server - */ - const imgId = `user-${data.ihash}` - const imgUrl = - 'https://static.freesewing.org/users/' + - encodeURIComponent(user.handle.slice(0, 1)) + - '/' + - encodeURIComponent(user.handle) + - '/' + - encodeURIComponent(data.img) - data.img = await importImage({ - id: imgId, - metadata: { - user: `v2-${user.handle}`, - ihash: data.ihash, - }, - url: imgUrl, - }) - data.img = imgId - } else data.img = 'default-avatar' - let available = await this.isLusernameAvailable(data.lusername) - while (!available) { - data.username += '+' - data.lusername += '+' - available = await this.isLusernameAvailable(data.lusername) - } - try { - await this.createRecord(data) - } catch (err) { - log.warn(err, 'Could not create user record') - return this.setResponse(500, 'createUserFailed') - } - // That's the user, now load their people as sets - let lut = false - if (user.people) lut = await this.Set.import(user, this.record.id) - if (user.patterns) await this.Pattern.import(user, lut, this.record.id) - } - } - - return this.setResponse200() -} diff --git a/sites/backend/src/routes/imports.mjs b/sites/backend/src/routes/imports.mjs deleted file mode 100644 index 7c8bf060787..00000000000 --- a/sites/backend/src/routes/imports.mjs +++ /dev/null @@ -1,21 +0,0 @@ -import { ImportsController } from '../controllers/imports.mjs' - -const Import = new ImportsController() - -export function importsRoutes(tools) { - const { app } = tools - - /* - * All these routes use hard-coded credentials because they should never be used - * outside the v2-v3 migration which is handled by joost - */ - - // Import newsletter subscriptions - app.post('/import/subscribers', (req, res) => Import.subscribers(req, res, tools)) - - // Import users - app.post('/import/user', (req, res) => Import.user(req, res, tools)) - - // Migrate user - app.post('/migrate', (req, res) => Import.migrate(req, res, tools)) -} diff --git a/sites/backend/src/routes/index.mjs b/sites/backend/src/routes/index.mjs index 9b1541c8e7a..6463cfe032d 100644 --- a/sites/backend/src/routes/index.mjs +++ b/sites/backend/src/routes/index.mjs @@ -9,7 +9,6 @@ import { optionPacksRoutes } from './option-packs.mjs' import { subscribersRoutes } from './subscribers.mjs' import { flowsRoutes } from './flows.mjs' import { adminRoutes } from './admin.mjs' -import { importsRoutes } from './imports.mjs' export const routes = { apikeysRoutes, @@ -23,5 +22,4 @@ export const routes = { subscribersRoutes, flowsRoutes, adminRoutes, - importsRoutes, } diff --git a/sites/backend/tests/account.mjs b/sites/backend/tests/account.mjs index b41af67e4e6..c9d775d67e5 100644 --- a/sites/backend/tests/account.mjs +++ b/sites/backend/tests/account.mjs @@ -217,7 +217,6 @@ export const accountTests = async (chai, config, expect, store) => { expect(err === null).to.equal(true) expect(res.status).to.equal(200) expect(res.body.result).to.equal(`success`) - expect(typeof res.body.account.img).to.equal('string') done() }) }).timeout(5000) @@ -247,7 +246,6 @@ export const accountTests = async (chai, config, expect, store) => { expect(err === null).to.equal(true) expect(res.status).to.equal(200) expect(res.body.result).to.equal(`success`) - expect(typeof res.body.account.img).to.equal('string') confirmation = res.body.confirmation done() }) @@ -275,7 +273,6 @@ export const accountTests = async (chai, config, expect, store) => { expect(err === null).to.equal(true) expect(res.status).to.equal(200) expect(res.body.result).to.equal(`success`) - expect(typeof res.body.account.img).to.equal('string') confirmation = res.body.confirmation done() }) @@ -302,7 +299,6 @@ export const accountTests = async (chai, config, expect, store) => { expect(err === null).to.equal(true) expect(res.status).to.equal(200) expect(res.body.result).to.equal(`success`) - expect(typeof res.body.account.img).to.equal('string') confirmation = res.body.confirmation done() }) @@ -331,7 +327,6 @@ export const accountTests = async (chai, config, expect, store) => { expect(err === null).to.equal(true) expect(res.status).to.equal(200) expect(res.body.result).to.equal(`success`) - expect(typeof res.body.account.img).to.equal('string') confirmation = res.body.confirmation done() }) diff --git a/sites/backend/tests/curated-set.mjs b/sites/backend/tests/curated-set.mjs index 9657b75f6c4..cd8d02800a5 100644 --- a/sites/backend/tests/curated-set.mjs +++ b/sites/backend/tests/curated-set.mjs @@ -42,7 +42,6 @@ export const curatedSetTests = async (chai, config, expect, store) => { chest: 930, neck: 360, }, - img: cat, }, } store.curatedSet = { @@ -77,7 +76,7 @@ export const curatedSetTests = async (chai, config, expect, store) => { expect(res.status).to.equal(201) expect(res.body.result).to.equal(`created`) for (const [key, val] of Object.entries(data[auth])) { - if (!['measies', 'img', 'test'].includes(key)) { + if (!['measies', 'test'].includes(key)) { expect(JSON.stringify(res.body.curatedSet[key])).to.equal(JSON.stringify(val)) } } @@ -226,8 +225,8 @@ export const curatedSetTests = async (chai, config, expect, store) => { set: 1, notes: 'These are the notes', name: 'me', - img: 'https://images.pexels.com/photos/1404819/pexels-photo-1404819.jpeg?cs=srgb&dl=pexels-cong-h-1404819.jpg&fm=jpg&w=640&h=427&_gl=1*nyz31t*_ga*MTM0OTk5OTY4NS4xNjYxMjUyMjc0*_ga_8JE65Q40S6*MTY5Mzg0MzAwNi4yNC4xLjE2OTM4NDMwMjIuMC4wLjA.', height: '166cm', + img: cat, }) .end((err, res) => { expect(err === null).to.equal(true) diff --git a/sites/backend/tests/option-pack.mjs b/sites/backend/tests/option-pack.mjs index 38a6edc2e1b..bc8fcc729b5 100644 --- a/sites/backend/tests/option-pack.mjs +++ b/sites/backend/tests/option-pack.mjs @@ -46,7 +46,6 @@ export const optionPackTests = async (chai, config, expect, store) => { necklineBend: 0.7, necklineDrop: 0.4, }, - img: cat, }, } store.apack = { @@ -81,7 +80,7 @@ export const optionPackTests = async (chai, config, expect, store) => { expect(res.status).to.equal(201) expect(res.body.result).to.equal(`created`) for (const [key, val] of Object.entries(data[auth])) { - if (!['options', 'img', 'test'].includes(key)) { + if (!['options', 'test'].includes(key)) { expect(JSON.stringify(res.body.optionPack[key])).to.equal(JSON.stringify(val)) } } diff --git a/sites/backend/tests/pattern.mjs b/sites/backend/tests/pattern.mjs index b96a0022924..0009f01efc1 100644 --- a/sites/backend/tests/pattern.mjs +++ b/sites/backend/tests/pattern.mjs @@ -27,7 +27,6 @@ export const patternTests = async (chai, config, expect, store) => { name: 'Just a test', notes: 'These are my notes', public: true, - set: store.account.sets.her.id, data: { some: 'value', }, @@ -39,7 +38,6 @@ export const patternTests = async (chai, config, expect, store) => { expect(res.body.result).to.equal(`created`) expect(typeof res.body.pattern?.id).to.equal('number') expect(res.body.pattern.userId).to.equal(store.account.id) - expect(res.body.pattern.setId).to.equal(store.account.sets.her.id) expect(res.body.pattern.design).to.equal('aaron') expect(res.body.pattern.public).to.equal(true) store.account.patterns[auth] = res.body.pattern @@ -121,29 +119,6 @@ export const patternTests = async (chai, config, expect, store) => { }) }) - it(`${store.icon('pattern', auth)} Should not update the set field (${auth})`, (done) => { - chai - .request(config.api) - .patch(`/patterns/${store.account.patterns[auth].id}/${auth}`) - .set( - 'Authorization', - auth === 'jwt' - ? 'Bearer ' + store.account.token - : 'Basic ' + - new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString( - 'base64' - ) - ) - .send({ set: 1 }) - .end((err, res) => { - expect(err === null).to.equal(true) - expect(res.status).to.equal(200) - expect(res.body.result).to.equal(`success`) - expect(res.body.pattern.setId).to.equal(store.account.sets.her.id) - done() - }) - }) - for (const field of ['data', 'settings']) { it(`${store.icon('pattern', auth)} Should update the ${field} field (${auth})`, (done) => { const data = {} From 90a18404ebc36fd2b28214bb82c3bc37f7131af7 Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Tue, 17 Oct 2023 18:08:57 +0200 Subject: [PATCH 6/8] chore(backend): Remove lint --- sites/backend/src/models/curated-set.mjs | 2 +- sites/backend/src/models/set.mjs | 2 +- sites/backend/src/models/subscriber.mjs | 1 - sites/backend/src/models/user.mjs | 4 ++-- sites/backend/src/utils/cloudflare-images.mjs | 24 ------------------- sites/backend/tests/option-pack.mjs | 1 - 6 files changed, 4 insertions(+), 30 deletions(-) diff --git a/sites/backend/src/models/curated-set.mjs b/sites/backend/src/models/curated-set.mjs index 13a744791dc..409b384f6e5 100644 --- a/sites/backend/src/models/curated-set.mjs +++ b/sites/backend/src/models/curated-set.mjs @@ -253,7 +253,7 @@ CuratedSetModel.prototype.guardedUpdate = async function ({ params, body, user } * Handle the image, if there is one */ if (typeof body.img === 'string') { - const img = await storeImage( + await storeImage( { id: `cset-${this.record.id}`, metadata: { user: this.user.uid }, diff --git a/sites/backend/src/models/set.mjs b/sites/backend/src/models/set.mjs index 26fcee2325d..e44d11112db 100644 --- a/sites/backend/src/models/set.mjs +++ b/sites/backend/src/models/set.mjs @@ -1,5 +1,5 @@ import { log } from '../utils/log.mjs' -import { replaceImage, storeImage, importImage } from '../utils/cloudflare-images.mjs' +import { replaceImage, storeImage } from '../utils/cloudflare-images.mjs' import { decorateModel } from '../utils/model-decorator.mjs' /* diff --git a/sites/backend/src/models/subscriber.mjs b/sites/backend/src/models/subscriber.mjs index b29479fec33..12466e68149 100644 --- a/sites/backend/src/models/subscriber.mjs +++ b/sites/backend/src/models/subscriber.mjs @@ -1,5 +1,4 @@ import { hash } from '../utils/crypto.mjs' -import { log } from '../utils/log.mjs' import { clean, i18nUrl } from '../utils/index.mjs' import { decorateModel } from '../utils/model-decorator.mjs' diff --git a/sites/backend/src/models/user.mjs b/sites/backend/src/models/user.mjs index 2284ff90830..a2fb03893a8 100644 --- a/sites/backend/src/models/user.mjs +++ b/sites/backend/src/models/user.mjs @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken' import { log } from '../utils/log.mjs' import { hash, hashPassword, randomString, verifyPassword } from '../utils/crypto.mjs' -import { replaceImage, importImage, removeImage } from '../utils/cloudflare-images.mjs' +import { replaceImage, removeImage } from '../utils/cloudflare-images.mjs' import { clean, asJson, i18nUrl, writeExportedData } from '../utils/index.mjs' import { decorateModel } from '../utils/model-decorator.mjs' import { userCard } from '../templates/svg/user-card.mjs' @@ -171,7 +171,7 @@ UserModel.prototype.oauthSignIn = async function ({ body }) { */ if (oauthData.img) { try { - const img = await replaceImage({ + await replaceImage({ id: `user-${ihash}`, metadata: { ihash }, url: oauthData.img, diff --git a/sites/backend/src/utils/cloudflare-images.mjs b/sites/backend/src/utils/cloudflare-images.mjs index ded8d73d322..16ba4eeba09 100644 --- a/sites/backend/src/utils/cloudflare-images.mjs +++ b/sites/backend/src/utils/cloudflare-images.mjs @@ -92,30 +92,6 @@ export async function removeImage(id) { return true } -/* - * Method that imports and image from URL and does not bother waiting for the answer - */ -export async function importImage(props, isTest = false) { - if (isTest) return props.id || false - // Bypass slow ass upload when testing import - if (!config.import) return `default-avatar` - - // Only upload user images for now - if (props.id.slice(0, 5) !== 'user-') return `default-avatar` - - const form = getFormData(props) - /* - * The image may already exist, so swallow the error - */ - try { - await axios.post(config.api, form, { headers }) - } catch { - // Do nothing - } - - return props.id -} - /* * Helper method to construct the form data for cloudflare */ diff --git a/sites/backend/tests/option-pack.mjs b/sites/backend/tests/option-pack.mjs index bc8fcc729b5..5da29d422fd 100644 --- a/sites/backend/tests/option-pack.mjs +++ b/sites/backend/tests/option-pack.mjs @@ -1,4 +1,3 @@ -import { cat } from './cat.mjs' import { capitalize } from '../src/utils/index.mjs' export const optionPackTests = async (chai, config, expect, store) => { From 74f6e12d768b83e8f987d7c3598e5a5a6e1f8e15 Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Tue, 17 Oct 2023 18:14:17 +0200 Subject: [PATCH 7/8] chore(backend): Shut up eslint --- sites/backend/tests/account.mjs | 112 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/sites/backend/tests/account.mjs b/sites/backend/tests/account.mjs index c9d775d67e5..a4dbaf0d5f2 100644 --- a/sites/backend/tests/account.mjs +++ b/sites/backend/tests/account.mjs @@ -224,6 +224,7 @@ export const accountTests = async (chai, config, expect, store) => { let confirmation step( + // eslint-disable-line no-undef `${store.icon('user', auth)} Should update the account email address (${auth})`, (done) => { chai @@ -252,59 +253,68 @@ export const accountTests = async (chai, config, expect, store) => { } ) - step(`${store.icon('user', auth)} Should confirm the email change (${auth})`, (done) => { - chai - .request(config.api) - .patch(`/account/${auth}`) - .set( - 'Authorization', - auth === 'jwt' - ? 'Bearer ' + store.account.token - : 'Basic ' + - new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString( - 'base64' - ) - ) - .send({ - confirm: 'emailchange', - confirmation, - }) - .end((err, res) => { - expect(err === null).to.equal(true) - expect(res.status).to.equal(200) - expect(res.body.result).to.equal(`success`) - confirmation = res.body.confirmation - done() - }) - }) - - step(`${store.icon('user', auth)} Restore email address (${auth})`, (done) => { - chai - .request(config.api) - .patch(`/account/${auth}`) - .set( - 'Authorization', - auth === 'jwt' - ? 'Bearer ' + store.account.token - : 'Basic ' + - new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString( - 'base64' - ) - ) - .send({ - email: store.account.email, - test: true, - }) - .end((err, res) => { - expect(err === null).to.equal(true) - expect(res.status).to.equal(200) - expect(res.body.result).to.equal(`success`) - confirmation = res.body.confirmation - done() - }) - }) + step( + // eslint-disable-line no-undef + `${store.icon('user', auth)} Should confirm the email change (${auth})`, + (done) => { + chai + .request(config.api) + .patch(`/account/${auth}`) + .set( + 'Authorization', + auth === 'jwt' + ? 'Bearer ' + store.account.token + : 'Basic ' + + new Buffer( + `${store.account.apikey.key}:${store.account.apikey.secret}` + ).toString('base64') + ) + .send({ + confirm: 'emailchange', + confirmation, + }) + .end((err, res) => { + expect(err === null).to.equal(true) + expect(res.status).to.equal(200) + expect(res.body.result).to.equal(`success`) + confirmation = res.body.confirmation + done() + }) + } + ) step( + // eslint-disable-line no-undef + `${store.icon('user', auth)} Restore email address (${auth})`, + (done) => { + chai + .request(config.api) + .patch(`/account/${auth}`) + .set( + 'Authorization', + auth === 'jwt' + ? 'Bearer ' + store.account.token + : 'Basic ' + + new Buffer( + `${store.account.apikey.key}:${store.account.apikey.secret}` + ).toString('base64') + ) + .send({ + email: store.account.email, + test: true, + }) + .end((err, res) => { + expect(err === null).to.equal(true) + expect(res.status).to.equal(200) + expect(res.body.result).to.equal(`success`) + confirmation = res.body.confirmation + done() + }) + } + ) + + step( + // eslint-disable-line no-undef `${store.icon('user', auth)} Should confirm the (restore) email change (${auth})`, (done) => { chai From 7939c1bc4508038da7a0aa7f96732a4c235974e8 Mon Sep 17 00:00:00 2001 From: Joost De Cock Date: Tue, 17 Oct 2023 18:18:03 +0200 Subject: [PATCH 8/8] chore(backend): Thanks prettier, real nice --- sites/backend/tests/account.mjs | 114 +++++++++++++++----------------- 1 file changed, 54 insertions(+), 60 deletions(-) diff --git a/sites/backend/tests/account.mjs b/sites/backend/tests/account.mjs index a4dbaf0d5f2..74de5702e34 100644 --- a/sites/backend/tests/account.mjs +++ b/sites/backend/tests/account.mjs @@ -223,8 +223,8 @@ export const accountTests = async (chai, config, expect, store) => { } let confirmation + // eslint-disable-next-line no-undef step( - // eslint-disable-line no-undef `${store.icon('user', auth)} Should update the account email address (${auth})`, (done) => { chai @@ -253,68 +253,62 @@ export const accountTests = async (chai, config, expect, store) => { } ) - step( - // eslint-disable-line no-undef - `${store.icon('user', auth)} Should confirm the email change (${auth})`, - (done) => { - chai - .request(config.api) - .patch(`/account/${auth}`) - .set( - 'Authorization', - auth === 'jwt' - ? 'Bearer ' + store.account.token - : 'Basic ' + - new Buffer( - `${store.account.apikey.key}:${store.account.apikey.secret}` - ).toString('base64') - ) - .send({ - confirm: 'emailchange', - confirmation, - }) - .end((err, res) => { - expect(err === null).to.equal(true) - expect(res.status).to.equal(200) - expect(res.body.result).to.equal(`success`) - confirmation = res.body.confirmation - done() - }) - } - ) + // eslint-disable-next-line no-undef + step(`${store.icon('user', auth)} Should confirm the email change (${auth})`, (done) => { + chai + .request(config.api) + .patch(`/account/${auth}`) + .set( + 'Authorization', + auth === 'jwt' + ? 'Bearer ' + store.account.token + : 'Basic ' + + new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString( + 'base64' + ) + ) + .send({ + confirm: 'emailchange', + confirmation, + }) + .end((err, res) => { + expect(err === null).to.equal(true) + expect(res.status).to.equal(200) + expect(res.body.result).to.equal(`success`) + confirmation = res.body.confirmation + done() + }) + }) - step( - // eslint-disable-line no-undef - `${store.icon('user', auth)} Restore email address (${auth})`, - (done) => { - chai - .request(config.api) - .patch(`/account/${auth}`) - .set( - 'Authorization', - auth === 'jwt' - ? 'Bearer ' + store.account.token - : 'Basic ' + - new Buffer( - `${store.account.apikey.key}:${store.account.apikey.secret}` - ).toString('base64') - ) - .send({ - email: store.account.email, - test: true, - }) - .end((err, res) => { - expect(err === null).to.equal(true) - expect(res.status).to.equal(200) - expect(res.body.result).to.equal(`success`) - confirmation = res.body.confirmation - done() - }) - } - ) + // eslint-disable-next-line no-undef + step(`${store.icon('user', auth)} Restore email address (${auth})`, (done) => { + chai + .request(config.api) + .patch(`/account/${auth}`) + .set( + 'Authorization', + auth === 'jwt' + ? 'Bearer ' + store.account.token + : 'Basic ' + + new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString( + 'base64' + ) + ) + .send({ + email: store.account.email, + test: true, + }) + .end((err, res) => { + expect(err === null).to.equal(true) + expect(res.status).to.equal(200) + expect(res.body.result).to.equal(`success`) + confirmation = res.body.confirmation + done() + }) + }) + // eslint-disable-next-line no-undef step( - // eslint-disable-line no-undef `${store.icon('user', auth)} Should confirm the (restore) email change (${auth})`, (done) => { chai