chore: More linting
This commit is contained in:
parent
8e187a947a
commit
a416b8b860
134 changed files with 1041 additions and 1055 deletions
|
@ -1,3 +1,5 @@
|
|||
.git
|
||||
coverage
|
||||
node_modules
|
||||
yarn.lock
|
||||
package.json
|
||||
|
|
18
.eslintrc.yml
Normal file
18
.eslintrc.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
env:
|
||||
browser: true
|
||||
es2021: true
|
||||
extends: eslint:recommended
|
||||
overrides:
|
||||
- files: ["*.yaml", "*.yml"]
|
||||
plugins: ["yaml"]
|
||||
extends: ["plugin:yaml/recommended"]
|
||||
parserOptions:
|
||||
ecmaVersion: latest
|
||||
sourceType: module
|
||||
rules: {}
|
||||
globals:
|
||||
it: readonly
|
||||
describe: readonly
|
||||
process: readonly
|
||||
__dirname: readonly
|
||||
|
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
yarn lint-staged
|
|
@ -3,4 +3,8 @@
|
|||
# So let's not
|
||||
*.yml
|
||||
*.md
|
||||
|
||||
yarn.lock
|
||||
.husky/pre-commit
|
||||
.prettierignore
|
||||
.gitignore
|
||||
.eslintignore
|
||||
|
|
|
@ -3,16 +3,16 @@ _:
|
|||
clean: 'rimraf dist'
|
||||
mbuild: 'NO_MINIFY=1 node build.mjs'
|
||||
symlink: 'mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -'
|
||||
test: ¬ests 'echo "{{name}}: No tests configured. Perhaps you''d like to do this?" && exit 0'
|
||||
test: 'echo "{{name}}: No tests configured. Perhaps you could write some?" && exit 0'
|
||||
vbuild: 'VERBOSE=1 node build.mjs'
|
||||
lab: "cd ../../sites/lab && yarn start"
|
||||
tips: "node ../../scripts/help.mjs"
|
||||
lab: 'cd ../../sites/lab && yarn start'
|
||||
tips: 'node ../../scripts/help.mjs'
|
||||
lint: "npx eslint 'src/**' 'tests/*.mjs'"
|
||||
_types:
|
||||
design:
|
||||
prettier: "npx prettier --write 'src/*.mjs' 'tests/*.mjs'"
|
||||
test: &test 'npx mocha tests/*.test.mjs'
|
||||
testci: &testci "npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js"
|
||||
testci: &testci 'npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js'
|
||||
plugin:
|
||||
prettier: "npx prettier --write 'src/*.mjs' 'tests/*.mjs'"
|
||||
test: *test
|
||||
|
@ -20,17 +20,15 @@ _types:
|
|||
core:
|
||||
report: 'c8 report'
|
||||
test: 'c8 mocha tests/*.test.mjs'
|
||||
testci: "mocha tests/*.test.mjs"
|
||||
testci: 'mocha tests/*.test.mjs'
|
||||
prettier: "npx prettier --write 'src/*.mjs' 'tests/*.mjs'"
|
||||
lint: "npx eslint 'src/*.mjs' 'tests/*.mjs'"
|
||||
i18n:
|
||||
prebuild: 'node scripts/prebuilder.mjs'
|
||||
test: *test
|
||||
testci: *testci
|
||||
models:
|
||||
test: "npx mocha tests/*.test.mjs"
|
||||
test: 'npx mocha tests/*.test.mjs'
|
||||
new-design:
|
||||
build: "SITE=new-design/shared node ../../sites/shared/prebuild/i18n-only.mjs && cp ../../scripts/banner.mjs ./lib && node build.mjs"
|
||||
build: 'SITE=new-design/shared node ../../sites/shared/prebuild/i18n-only.mjs && cp ../../scripts/banner.mjs ./lib && node build.mjs'
|
||||
lint: "npx eslint 'lib/*.mjs'"
|
||||
mbuild: '!'
|
||||
test: '!'
|
||||
|
@ -41,5 +39,4 @@ rehype-jargon:
|
|||
snapseries:
|
||||
lint: "npx eslint 'src/*.mjs'"
|
||||
backend:
|
||||
lint: "!"
|
||||
|
||||
lint: '!'
|
||||
|
|
|
@ -184,5 +184,5 @@ export const back = {
|
|||
}
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export const base = {
|
|||
'shoulderSlope',
|
||||
'waistToHips',
|
||||
],
|
||||
optionalMeasurements: [ 'highBust' ],
|
||||
optionalMeasurements: ['highBust'],
|
||||
options: {
|
||||
// Static
|
||||
brianFitSleeve: true,
|
||||
|
@ -37,7 +37,7 @@ export const base = {
|
|||
frontArmholeDeeper: { pct: 0.2, min: 0, max: 0.5, menu: 'advanced' },
|
||||
shoulderSlopeReduction: { pct: 0, min: 0, max: 80, menu: 'advanced' },
|
||||
},
|
||||
plugins: [ pluginBundle, bustPlugin ],
|
||||
plugins: [pluginBundle, bustPlugin],
|
||||
draft: ({
|
||||
measurements,
|
||||
options,
|
||||
|
@ -53,7 +53,6 @@ export const base = {
|
|||
macro,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
store.set('shoulderEase', (measurements.shoulderToShoulder * options.shoulderEase) / 2)
|
||||
|
||||
// Center back (cb) vertical axis
|
||||
|
@ -63,7 +62,10 @@ export const base = {
|
|||
points.cbHips = new Point(0, points.cbWaist.y + measurements.waistToHips)
|
||||
|
||||
// Shoulder line
|
||||
points.neck = new Point((measurements.neck * (1 + options.collarEase)) / options.collarFactor, 0)
|
||||
points.neck = new Point(
|
||||
(measurements.neck * (1 + options.collarEase)) / options.collarFactor,
|
||||
0
|
||||
)
|
||||
points.hps = points.neck.clone() // We started using HPS in many measurements
|
||||
// Shoulder point using shoulderSlope degree measurement
|
||||
points.shoulder = utils.beamsIntersect(
|
||||
|
@ -76,7 +78,8 @@ export const base = {
|
|||
points.cbShoulder = new Point(0, points.shoulder.y)
|
||||
points.cbArmhole = new Point(
|
||||
0,
|
||||
points.shoulder.y + measurements.biceps * (1 + options.bicepsEase) * options.armholeDepthFactor
|
||||
points.shoulder.y +
|
||||
measurements.biceps * (1 + options.bicepsEase) * options.armholeDepthFactor
|
||||
)
|
||||
|
||||
// Now take shoulder slope reduction into account
|
||||
|
@ -87,7 +90,10 @@ export const base = {
|
|||
points.cbHem = new Point(0, points.cbHips.y * (1 + options.lengthBonus))
|
||||
|
||||
// Side back (cb) vertical axis
|
||||
points.armhole = new Point((measurements.chest * (1 + options.chestEase)) / 4, points.cbArmhole.y)
|
||||
points.armhole = new Point(
|
||||
(measurements.chest * (1 + options.chestEase)) / 4,
|
||||
points.cbArmhole.y
|
||||
)
|
||||
points.waist = new Point(points.armhole.x, points.cbWaist.y)
|
||||
points.hips = new Point(points.armhole.x, points.cbHips.y)
|
||||
points.hem = new Point(points.armhole.x, points.cbHem.y)
|
||||
|
@ -170,10 +176,10 @@ export const base = {
|
|||
points.gridAnchor = points.cbHem
|
||||
|
||||
/*
|
||||
* People would like to have the option to shift the shoulder seam
|
||||
* See https://github.com/freesewing/freesewing/issues/642
|
||||
* So let's make the people happy
|
||||
*/
|
||||
* People would like to have the option to shift the shoulder seam
|
||||
* See https://github.com/freesewing/freesewing/issues/642
|
||||
* So let's make the people happy
|
||||
*/
|
||||
// Front armhole is a bit deeper, add those points
|
||||
let deeper = measurements.chest * options.frontArmholeDeeper
|
||||
for (const p of ['', 'Cp1', 'Cp2']) {
|
||||
|
@ -210,6 +216,5 @@ export const base = {
|
|||
}
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ export const front = {
|
|||
utils,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
// Re-use points for deeper armhole at the front
|
||||
points.armholePitchCp1 = points.frontArmholePitchCp1
|
||||
points.armholePitch = points.frontArmholePitch
|
||||
|
@ -62,7 +61,9 @@ export const front = {
|
|||
.curve_(points.mirroredNeckCp2, points.mirroredCbNeck)
|
||||
.split(points.s3CollarSplit)[0]
|
||||
.reverse()
|
||||
.join(new Path().move(points.hps).curve(points.neckCp2Front, points.cfNeckCp1, points.cfNeck))
|
||||
.join(
|
||||
new Path().move(points.hps).curve(points.neckCp2Front, points.cfNeckCp1, points.cfNeck)
|
||||
)
|
||||
.setRender(false)
|
||||
}
|
||||
if (options.s3Armhole < 0.1 && options.s3Armhole > -0.1) {
|
||||
|
@ -194,5 +195,5 @@ export const front = {
|
|||
}
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { sleevecap } from './sleevecap.mjs'
|
|||
// Setup our new design
|
||||
const Brian = new Design({
|
||||
data,
|
||||
parts: [ back, front, sleeve ]
|
||||
parts: [back, front, sleeve],
|
||||
})
|
||||
|
||||
// Named exports
|
||||
|
|
|
@ -4,12 +4,9 @@ export const sleeve = {
|
|||
from: sleevecap,
|
||||
name: 'brian.sleeve',
|
||||
options: {
|
||||
sleeveLengthBonus: { pct: 0, min: -40, max: 10, menu: 'style' }
|
||||
sleeveLengthBonus: { pct: 0, min: -40, max: 10, menu: 'style' },
|
||||
},
|
||||
measurements: [
|
||||
'shoulderToWrist',
|
||||
'wrist',
|
||||
],
|
||||
measurements: ['shoulderToWrist', 'wrist'],
|
||||
draft: ({
|
||||
store,
|
||||
sa,
|
||||
|
@ -26,7 +23,6 @@ export const sleeve = {
|
|||
macro,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
// Remove things inherited
|
||||
macro('cutonfold', false)
|
||||
macro('rmad')
|
||||
|
@ -40,7 +36,10 @@ export const sleeve = {
|
|||
|
||||
// Wrist
|
||||
points.centerWrist = points.sleeveTop.shift(-90, store.get('sleeveLength'))
|
||||
points.wristRight = points.centerWrist.shift(0, (measurements.wrist * (1 + options.cuffEase)) / 2)
|
||||
points.wristRight = points.centerWrist.shift(
|
||||
0,
|
||||
(measurements.wrist * (1 + options.cuffEase)) / 2
|
||||
)
|
||||
points.wristLeft = points.wristRight.rotate(180, points.centerWrist)
|
||||
|
||||
// Paths
|
||||
|
@ -70,7 +69,9 @@ export const sleeve = {
|
|||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
points.frontNotch = paths.sleevecap.shiftAlong(store.get('frontArmholeToArmholePitch'))
|
||||
points.backNotch = paths.sleevecap.reverse().shiftAlong(store.get('backArmholeToArmholePitch'))
|
||||
points.backNotch = paths.sleevecap
|
||||
.reverse()
|
||||
.shiftAlong(store.get('backArmholeToArmholePitch'))
|
||||
snippets.frontNotch = new Snippet('notch', points.frontNotch)
|
||||
snippets.backNotch = new Snippet('bnotch', points.backNotch)
|
||||
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||
|
@ -104,5 +105,5 @@ export const sleeve = {
|
|||
})
|
||||
}
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -166,7 +166,6 @@ export const sleevecap = {
|
|||
sleeveWidthGuarantee: { pct: 90, min: 25, max: 100, menu: 'advanced' },
|
||||
},
|
||||
draft: ({ store, units, options, Point, points, paths, log, snippets, macro, part }) => {
|
||||
|
||||
// Clean up from fron
|
||||
for (const path in paths) delete paths[path]
|
||||
delete snippets.logo
|
||||
|
@ -190,5 +189,5 @@ export const sleevecap = {
|
|||
points.gridAnchor = new Point(0, 0)
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -359,6 +359,5 @@ export {
|
|||
// Docs
|
||||
docs_coords,
|
||||
docs_overview,
|
||||
|
||||
Examples,
|
||||
}
|
||||
|
|
|
@ -69,7 +69,10 @@ export const stacks_leftEye = {
|
|||
stack,
|
||||
after: stacks_top,
|
||||
draft: ({ store, Point, points, part }) => {
|
||||
points.leftEye = new Point(store.get('x') + store.get('size') * 0.35, store.get('y') + store.get('size') * 0.4)
|
||||
points.leftEye = new Point(
|
||||
store.get('x') + store.get('size') * 0.35,
|
||||
store.get('y') + store.get('size') * 0.4
|
||||
)
|
||||
.attr('data-circle', store.get('size') * 0.1)
|
||||
.attr('data-circle-class', 'stroke-6xl')
|
||||
|
||||
|
@ -82,7 +85,10 @@ export const stacks_rightEye = {
|
|||
stack,
|
||||
after: stacks_top,
|
||||
draft: ({ store, Point, points, part }) => {
|
||||
points.rightEye = new Point(store.get('x') + store.get('size') * 0.65, store.get('y') + store.get('size') * 0.4)
|
||||
points.rightEye = new Point(
|
||||
store.get('x') + store.get('size') * 0.65,
|
||||
store.get('y') + store.get('size') * 0.4
|
||||
)
|
||||
.attr('data-circle', store.get('size') * 0.08)
|
||||
.attr('data-circle-class', 'stroke-7xl')
|
||||
|
||||
|
@ -95,10 +101,22 @@ export const stacks_mouth = {
|
|||
stack,
|
||||
after: stacks_top,
|
||||
draft: ({ store, Point, points, paths, Path, part }) => {
|
||||
points.left = new Point(store.get('x') + store.get('size') * 0.15, store.get('y') + store.get('size') * 0.5)
|
||||
points.right = new Point(store.get('x') + store.get('size') * 0.85, store.get('y') + store.get('size') * 0.5)
|
||||
points.leftCp = new Point(store.get('x') + store.get('size') * 0.35, store.get('y') + store.get('size') * 0.8)
|
||||
points.rightCp = new Point(store.get('x') + store.get('size') * 0.65, store.get('y') + store.get('size') * 0.8)
|
||||
points.left = new Point(
|
||||
store.get('x') + store.get('size') * 0.15,
|
||||
store.get('y') + store.get('size') * 0.5
|
||||
)
|
||||
points.right = new Point(
|
||||
store.get('x') + store.get('size') * 0.85,
|
||||
store.get('y') + store.get('size') * 0.5
|
||||
)
|
||||
points.leftCp = new Point(
|
||||
store.get('x') + store.get('size') * 0.35,
|
||||
store.get('y') + store.get('size') * 0.8
|
||||
)
|
||||
points.rightCp = new Point(
|
||||
store.get('x') + store.get('size') * 0.65,
|
||||
store.get('y') + store.get('size') * 0.8
|
||||
)
|
||||
|
||||
paths.mouth = new Path()
|
||||
.move(points.left)
|
||||
|
|
|
@ -30,7 +30,6 @@ function hugoFront({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Remove clutter
|
||||
for (const key in paths) {
|
||||
if (key !== 'seam') delete paths[key]
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
import { front } from './front.mjs'
|
||||
|
||||
function hugoPocket({ utils, store, sa, points, Path, paths, complete, paperless, macro, snippets, part }) {
|
||||
|
||||
function hugoPocket({
|
||||
utils,
|
||||
store,
|
||||
sa,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
complete,
|
||||
paperless,
|
||||
macro,
|
||||
snippets,
|
||||
part,
|
||||
}) {
|
||||
// Remove clutter
|
||||
for (const key in paths) {
|
||||
if (key !== 'pocket') delete paths[key]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { pocket } from './pocket.mjs'
|
||||
|
||||
function hugoPocketFacing({ sa, points, Path, paths, complete, paperless, macro, store, part }) {
|
||||
|
||||
// Remove clutter
|
||||
for (const key in paths) {
|
||||
if (key !== 'facing') delete paths[key]
|
||||
|
|
|
@ -19,7 +19,6 @@ function svenWaistband(params) {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
return part
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ export const bib = {
|
|||
paperless,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
// Construct the neck opening
|
||||
let tweak = 1
|
||||
let target = (measurements.head * options.neckRatio) / 4
|
||||
|
@ -230,5 +229,5 @@ export const bib = {
|
|||
}
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { pluginBundle } from '@freesewing/plugin-bundle'
|
|||
export const configpart = {
|
||||
name: 'tutorial.configpart',
|
||||
measurements: ['head'],
|
||||
plugins: [ pluginBundle ],
|
||||
plugins: [pluginBundle],
|
||||
options: {
|
||||
size: { pct: 50, min: 10, max: 100 },
|
||||
neckRatio: { pct: 80, min: 70, max: 90 },
|
||||
|
@ -13,6 +13,5 @@ export const configpart = {
|
|||
lengthRatio: { pct: 75, min: 55, max: 85 },
|
||||
},
|
||||
hide: true,
|
||||
draft: ({part}) => part
|
||||
draft: ({ part }) => part,
|
||||
}
|
||||
|
||||
|
|
|
@ -8,20 +8,7 @@ import { bib } from './bib.mjs'
|
|||
// Setup our new design
|
||||
const Tutorial = new Design({
|
||||
data,
|
||||
parts: [
|
||||
step1,
|
||||
step2,
|
||||
step3,
|
||||
step4,
|
||||
step5,
|
||||
step6,
|
||||
step7,
|
||||
step8,
|
||||
step9,
|
||||
step10,
|
||||
step11,
|
||||
bib,
|
||||
]
|
||||
parts: [step1, step2, step3, step4, step5, step6, step7, step8, step9, step10, step11, bib],
|
||||
})
|
||||
|
||||
// Named exports
|
||||
|
@ -38,6 +25,5 @@ export {
|
|||
step10,
|
||||
step11,
|
||||
bib,
|
||||
Tutorial
|
||||
Tutorial,
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ export const step1 = {
|
|||
macro,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
let w = 500 * options.size
|
||||
points.topLeft = new Point(0, 0)
|
||||
points.topRight = new Point(w, 0)
|
||||
|
@ -62,46 +61,31 @@ export const step1 = {
|
|||
}
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step2 = {
|
||||
name: 'tutorial.step2',
|
||||
after: configpart,
|
||||
draft: ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
measurements,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ Point, points, Path, paths, measurements, part }) => {
|
||||
points.right = new Point(measurements.head / 10, 0)
|
||||
points.bottom = new Point(0, measurements.head / 12)
|
||||
|
||||
points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right) / 2)
|
||||
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right) / 2)
|
||||
|
||||
paths.neck = new Path().move(points.right).curve(points.rightCp1, points.bottomCp2, points.bottom)
|
||||
paths.neck = new Path()
|
||||
.move(points.right)
|
||||
.curve(points.rightCp1, points.bottomCp2, points.bottom)
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step3 = {
|
||||
name: 'tutorial.step3',
|
||||
after: configpart,
|
||||
draft: ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
measurements,
|
||||
options,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ Point, points, Path, paths, measurements, options, part }) => {
|
||||
let tweak = 1
|
||||
let target = (measurements.head * options.neckRatio) / 4
|
||||
let delta
|
||||
|
@ -122,19 +106,13 @@ export const step3 = {
|
|||
} while (Math.abs(delta) > 1)
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step4 = {
|
||||
name: 'tutorial.step4',
|
||||
from: step3,
|
||||
draft: ({
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ points, Path, paths, part }) => {
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
|
||||
|
@ -155,6 +133,5 @@ export const step4 = {
|
|||
.close()
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -3,16 +3,7 @@ import { step4 } from './step1-4.mjs'
|
|||
export const step5 = {
|
||||
name: 'tutorial.step5',
|
||||
from: step4,
|
||||
draft: ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
measurements,
|
||||
options,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ Point, points, Path, paths, measurements, options, part }) => {
|
||||
const width = measurements.head * options.widthRatio
|
||||
const length = measurements.head * options.lengthRatio
|
||||
|
||||
|
@ -30,20 +21,13 @@ export const step5 = {
|
|||
.close()
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step6 = {
|
||||
name: 'tutorial.step6',
|
||||
from: step5,
|
||||
draft: ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ Point, points, Path, paths, part }) => {
|
||||
points.edgeLeft = new Point(points.topLeft.x, points.left.y)
|
||||
points.edgeRight = new Point(points.topRight.x, points.right.y)
|
||||
points.edgeTop = new Point(0, points.topLeft.y)
|
||||
|
@ -63,19 +47,13 @@ export const step6 = {
|
|||
.close()
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step7 = {
|
||||
name: 'tutorial.step7',
|
||||
from: step6,
|
||||
draft: ({
|
||||
Point,
|
||||
points,
|
||||
macro,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ Point, points, macro, part }) => {
|
||||
const strap = points.edgeTop.dy(points.top)
|
||||
|
||||
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
|
||||
|
@ -98,20 +76,13 @@ export const step7 = {
|
|||
})
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step8 = {
|
||||
name: 'tutorial.step8',
|
||||
from: step7,
|
||||
draft: ({
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
macro,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ points, Path, paths, macro, part }) => {
|
||||
const rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
|
@ -160,6 +131,5 @@ export const step8 = {
|
|||
.close()
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,7 @@ import { step8 } from './step5-8.mjs'
|
|||
export const step9 = {
|
||||
name: 'tutorial.step9',
|
||||
from: step8,
|
||||
draft: ({
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ points, Path, paths, part }) => {
|
||||
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
|
||||
points.topCp1 = points.topCp2.flipX()
|
||||
points.tipLeftTopStart = points.tipRightTopStart.flipX()
|
||||
|
@ -44,20 +38,13 @@ export const step9 = {
|
|||
delete paths.rect
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step10 = {
|
||||
name: 'tutorial.step10',
|
||||
from: step9,
|
||||
draft: ({
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
macro,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ points, Path, paths, macro, part }) => {
|
||||
macro('round', {
|
||||
from: points.topLeft,
|
||||
to: points.bottomRight,
|
||||
|
@ -95,23 +82,13 @@ export const step10 = {
|
|||
.close()
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const step11 = {
|
||||
name: 'tutorial.step11',
|
||||
from: step10,
|
||||
draft: ({
|
||||
Point,
|
||||
points,
|
||||
paths,
|
||||
macro,
|
||||
complete,
|
||||
snippets,
|
||||
Snippet,
|
||||
part,
|
||||
}) => {
|
||||
|
||||
draft: ({ Point, points, paths, macro, complete, snippets, Snippet, part }) => {
|
||||
// Complete?
|
||||
if (complete) {
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
|
@ -138,6 +115,5 @@ export const step11 = {
|
|||
}
|
||||
|
||||
return part
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ function ursulaBack({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Design pattern here
|
||||
|
||||
// Create points
|
||||
|
|
|
@ -12,7 +12,6 @@ function ursulaElastic({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Stretch utility method
|
||||
store.set('elasticScale', utils.stretchToScale(options.elasticStretch))
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ function ursulaFront({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Stretch utility method
|
||||
|
||||
store.set('xScale', utils.stretchToScale(options.fabricStretch))
|
||||
|
@ -217,6 +216,6 @@ export const front = {
|
|||
frontDip: { pct: 5.0, min: -5, max: 15, menu: 'style' },
|
||||
taperToGusset: { pct: 70, min: 5, max: 100, menu: 'style' },
|
||||
},
|
||||
plugins: [ pluginBundle ],
|
||||
plugins: [pluginBundle],
|
||||
draft: ursulaFront,
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ function ursulaGusset({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Create points
|
||||
points.frontGussetLeft = new Point(store.get('frontGussetLeft').x, 0)
|
||||
points.backGussetLeft = new Point(
|
||||
|
|
|
@ -16,7 +16,6 @@ function wahidBack({
|
|||
snippets,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Cleanup from Brian
|
||||
for (let i of Object.keys(paths)) delete paths[i]
|
||||
delete snippets.armholePitchNotch
|
||||
|
|
|
@ -35,7 +35,6 @@ function wahidFront({
|
|||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Cleanup from Brian
|
||||
for (let i of Object.keys(paths)) delete paths[i]
|
||||
delete snippets.armholePitchNotch
|
||||
|
|
|
@ -13,7 +13,6 @@ function wahidFrontFacing({
|
|||
sa,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Cleanup from front part
|
||||
for (let i of Object.keys(paths).filter((name) => name !== 'grainline')) delete paths[i]
|
||||
for (let i of Object.keys(snippets)) delete snippets[i]
|
||||
|
|
|
@ -13,7 +13,6 @@ function wahidFrontLining({
|
|||
sa,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Cleanup from Brian
|
||||
for (let i of Object.keys(paths)) delete paths[i]
|
||||
for (let i of Object.keys(snippets)) delete snippets[i]
|
||||
|
|
|
@ -13,7 +13,6 @@ function wahidPocketbag({
|
|||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
let pw = measurements.hips * options.pocketWidth // Pocket width
|
||||
let ph = store.get('pocketBagLength') // Pocket height
|
||||
points.topLeft = new Point(0, 0)
|
||||
|
|
|
@ -13,7 +13,6 @@ function wahidPocketFacing({
|
|||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const pw = measurements.hips * options.pocketWidth // Pocket width
|
||||
const pwh = pw * options.weltHeight // Pocket welt height
|
||||
const ph = store.get('pocketBagLength') + pwh // Pocket height
|
||||
|
|
|
@ -12,7 +12,6 @@ function wahidPocketInterfacing({
|
|||
paperless,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const pw = measurements.hips * options.pocketWidth // Pocket width
|
||||
const pwh = pw * options.weltHeight // Pocket welt height
|
||||
points.topLeft = new Point(0, 0)
|
||||
|
|
|
@ -12,7 +12,6 @@ function wahidPocketWelt({
|
|||
paperless,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const pw = measurements.hips * options.pocketWidth // Pocket width
|
||||
const pwh = pw * options.weltHeight // Pocket welt height
|
||||
points.topLeft = new Point(0, 0)
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
import { base } from './base.mjs'
|
||||
|
||||
function walburgaBack({
|
||||
points,
|
||||
macro,
|
||||
complete,
|
||||
snippets,
|
||||
Snippet,
|
||||
part,
|
||||
}) {
|
||||
|
||||
function walburgaBack({ points, macro, complete, snippets, Snippet, part }) {
|
||||
// Complete?
|
||||
if (complete) {
|
||||
// logo & title
|
||||
|
|
|
@ -17,7 +17,6 @@ function walburgaBase({
|
|||
utils,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// define some variables
|
||||
const hem_pos =
|
||||
options.length === 'toKnee'
|
||||
|
|
|
@ -16,7 +16,6 @@ function walburgaFront({
|
|||
utils,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const head = store.get('hhead') * 2
|
||||
const goldenRatio = store.get('goldenRatio')
|
||||
const ratio = goldenRatio * options.neckoRatio
|
||||
|
|
|
@ -15,7 +15,6 @@ function waraleeBackPocket({
|
|||
sa,
|
||||
part,
|
||||
}) {
|
||||
|
||||
if (false == options.backPocket) {
|
||||
return part
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ function waraleeCutout({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
let separateWaistband = options.separateWaistband
|
||||
if ('waistband' == options.frontPocketStyle) {
|
||||
separateWaistband = true
|
||||
|
|
|
@ -15,7 +15,6 @@ function waraleeFacings({
|
|||
sa,
|
||||
part,
|
||||
}) {
|
||||
|
||||
let frontPocketSize =
|
||||
options.frontPocketSize * measurements.crotchDepth /*- measurements.waistToHips*/
|
||||
let backPocketSize =
|
||||
|
|
|
@ -4,18 +4,7 @@ import { pantsProto } from './pantsproto.mjs'
|
|||
// To keep you from printing it completely, you could print this part in paperless mode
|
||||
// and only have a single sheet with all the dimensions on it.
|
||||
|
||||
function waraleeMini({
|
||||
options,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
complete,
|
||||
sa,
|
||||
macro,
|
||||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
function waraleeMini({ options, Path, points, paths, complete, sa, macro, store, part }) {
|
||||
let mini = options.minimizer
|
||||
let separateWaistband = options.separateWaistband
|
||||
if ('waistband' == options.frontPocketStyle) {
|
||||
|
|
|
@ -14,7 +14,6 @@ function waraleePants({
|
|||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
let separateWaistband = options.separateWaistband
|
||||
if ('waistband' == options.frontPocketStyle) {
|
||||
separateWaistband = true
|
||||
|
|
|
@ -1,17 +1,7 @@
|
|||
import { pluginBundle } from '@freesewing/plugin-bundle'
|
||||
import * as options from './options.mjs'
|
||||
|
||||
function waraleePantsProto({
|
||||
options,
|
||||
measurements,
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
function waraleePantsProto({ options, measurements, Point, Path, points, paths, store, part }) {
|
||||
let seatDepth =
|
||||
measurements.crotchDepth /* - measurements.waistToHips */ *
|
||||
(1 + options.waistRaise) *
|
||||
|
|
|
@ -15,7 +15,6 @@ function waraleePocket({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
if (false == options.frontPocket) {
|
||||
return part
|
||||
}
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
import { pantsProto } from './pantsproto.mjs'
|
||||
|
||||
function waraleeWaistband(type, {
|
||||
options,
|
||||
measurements,
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
complete,
|
||||
paperless,
|
||||
macro,
|
||||
sa,
|
||||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
function waraleeWaistband(
|
||||
type,
|
||||
{
|
||||
options,
|
||||
measurements,
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
complete,
|
||||
paperless,
|
||||
macro,
|
||||
sa,
|
||||
store,
|
||||
part,
|
||||
}
|
||||
) {
|
||||
const WidthReduction = 6
|
||||
let waistBand = store.get('waistBand')
|
||||
let waistBandLengthFront = points.fWaistSideHem.dist(points.fWaistFrontOverlapHem)
|
||||
|
|
|
@ -15,7 +15,6 @@ function yuriBack({
|
|||
measurements,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Clear paths from Brian
|
||||
for (const i in paths) {
|
||||
if (['backArmhole', 'backCollar'].indexOf(i) === -1) delete paths[i]
|
||||
|
|
|
@ -17,7 +17,6 @@ function yuriFront({
|
|||
Snippet,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Clear paths from Brian
|
||||
for (const i in paths) {
|
||||
if (['frontArmhole', 'frontCollar'].indexOf(i) === -1) delete paths[i]
|
||||
|
|
|
@ -14,7 +14,6 @@ function yuriGusset({
|
|||
store,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const w = store.get('gussetLength')
|
||||
points.top = new Point(0, 0)
|
||||
points.bottom = new Point(0, w)
|
||||
|
|
|
@ -13,7 +13,6 @@ function yuriHoodCenter({
|
|||
units,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const width = store.get('hoodCenterWidth')
|
||||
const length = complete ? width * 2.5 : store.get('hoodCenterLength')
|
||||
points.topLeft = new Point(0, 0)
|
||||
|
|
|
@ -16,7 +16,6 @@ function yuriHoodSide({
|
|||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
const neckOpening = store.get('frontNeckSeamLength') + store.get('backNeckSeamLength')
|
||||
const hoodOpening = measurements.head
|
||||
const neckCutoutDelta = store.get('neckCutoutFront') - store.get('neckCutoutBack')
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
import { sleeve as brianSleeve } from '@freesewing/brian'
|
||||
|
||||
function yuriSleeve({
|
||||
Point,
|
||||
Path,
|
||||
points,
|
||||
paths,
|
||||
complete,
|
||||
sa,
|
||||
paperless,
|
||||
macro,
|
||||
part,
|
||||
}) {
|
||||
|
||||
function yuriSleeve({ Point, Path, points, paths, complete, sa, paperless, macro, part }) {
|
||||
// Clear paths from Brian, but keep sleevecap
|
||||
for (let p of Object.keys(paths)) {
|
||||
if (p !== 'sleevecap') delete paths[p]
|
||||
|
|
23
package.json
23
package.json
|
@ -15,7 +15,7 @@
|
|||
"?": "node scripts/help.mjs",
|
||||
"tips": "node scripts/help.mjs",
|
||||
"lab": "cd sites/lab && yarn start",
|
||||
"kickstart": "npx lerna bootstrap && yarn buildall && yarn tips",
|
||||
"kickstart": "npx lerna bootstrap && yarn buildall && yarn prepare && yarn tips",
|
||||
"cleanall": "lerna run clean",
|
||||
"test": "lerna run test",
|
||||
"prettier": "npx prettier --write 'packages/**/src/*.mjs' 'packages/**/src/*.js' 'packages/i18n/src/locales/**/*.*' 'packages/**/tests/*.mjs'",
|
||||
|
@ -24,7 +24,10 @@
|
|||
"buildall": "lerna run cibuild_step0 && lerna run cibuild_step1 && lerna run cibuild_step2 && lerna run cibuild_step3 && lerna run cibuild_step4 && lerna run cibuild_step5 && lerna run cibuild_step6 && lerna run cibuild_step7",
|
||||
"build": "yarn buildall",
|
||||
"testall": "node scripts/testall.js",
|
||||
"lint": "lerna run lint",
|
||||
"lint": "lerna run lint -- ",
|
||||
"qa": "yarn qa:prettier && yarn qa:lint",
|
||||
"qa:prettier": "npx prettier",
|
||||
"qa:lint": "npx eslint",
|
||||
"release": "lerna exec --no-bail -- npm publish",
|
||||
"postrelease": "git add . && git commit -m ':bookmark: v$npm_package_version' && git tag -a v$npm_package_version -m ':bookmark: FreeSewing v$npm_package_version'",
|
||||
"ship": "lerna exec --no-bail -- npm publish",
|
||||
|
@ -35,7 +38,8 @@
|
|||
"famgen": "all-contributors generate",
|
||||
"checkdocs": "remark markdown --quiet --frail",
|
||||
"strapi:translate": "node scripts/strapi-en-to-other.mjs",
|
||||
"fixdocs": "remark markdown --quiet --frail --output"
|
||||
"fixdocs": "remark markdown --quiet --frail --output",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -45,10 +49,11 @@
|
|||
"url": "https://github.com/freesewing/freesewing/issues"
|
||||
},
|
||||
"prettier": "@freesewing/prettier-config",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
}
|
||||
"lint-staged": {
|
||||
"*": [
|
||||
"npx prettier --write",
|
||||
"npx eslint"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.2",
|
||||
|
@ -67,16 +72,18 @@
|
|||
"cross-env": "^7.0.2",
|
||||
"esbuild": "^0.15.3",
|
||||
"esbuild-plugin-yaml": "^0.0.1",
|
||||
"eslint": "^8.23.1",
|
||||
"eslint-plugin-yaml": "^0.5.0",
|
||||
"esm": "^3.2.25",
|
||||
"handlebars": "^4.7.7",
|
||||
"husky": "^8.0.1",
|
||||
"js-yaml": "^4.0.0",
|
||||
"lerna": "^5.1.4",
|
||||
"lint-staged": "^13.0.3",
|
||||
"mocha": "^10.0.0",
|
||||
"mustache": "^4.0.1",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.3.0",
|
||||
"prettier": "^2.7.1",
|
||||
"pretty-quick": "^3.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
|
|
|
@ -5,7 +5,6 @@ const expect = chai.expect
|
|||
|
||||
describe('Pattern', () => {
|
||||
describe('Pattern.draft()', () => {
|
||||
|
||||
it('Pattern.draft() should draft according to settings', () => {
|
||||
let count = 0
|
||||
const back = {
|
||||
|
|
|
@ -31,13 +31,12 @@
|
|||
"clean": "rimraf dist",
|
||||
"mbuild": "NO_MINIFY=1 node build.mjs",
|
||||
"symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -",
|
||||
"test": "npx mocha tests/*.test.mjs",
|
||||
"test": "echo \"i18n: No tests configured. Perhaps you'd like to do this?\" && exit 0",
|
||||
"vbuild": "VERBOSE=1 node build.mjs",
|
||||
"lab": "cd ../../sites/lab && yarn start",
|
||||
"tips": "node ../../scripts/help.mjs",
|
||||
"lint": "npx eslint 'src/**' 'tests/*.mjs'",
|
||||
"prebuild": "node scripts/prebuilder.mjs",
|
||||
"testci": "npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js",
|
||||
"precibuild_step7": "node scripts/prebuilder.mjs",
|
||||
"cibuild_step7": "node build.mjs"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import chai from 'chai'
|
||||
import { strings as i18n } from './dist/index.mjs'
|
||||
import * as i18n from '../prebuild/strings.js'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
@ -27,13 +27,12 @@ const languages = [
|
|||
]
|
||||
|
||||
function checkTranslations(from, to) {
|
||||
const originals = Object.keys(from.strings)
|
||||
const translated = to.strings
|
||||
for (let string of originals) {
|
||||
for (const string in from.strings) {
|
||||
if (typeof translated[string] === 'undefined') {
|
||||
console.log(`String ${string} in ${from.name} is not available in ${to.name}`)
|
||||
expect(typeof translated[string]).to.equal('string')
|
||||
}
|
||||
expect(typeof translated[string]).to.equal('string')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { bannerPlugin } from './dist/index.mjs'
|
||||
import { bannerPlugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { bannerPlugin } from '../../plugin-banner/src/index.mjs'
|
||||
import { bartackPlugin } from '../../plugin-bartack/src/index.mjs'
|
||||
import { buttonsPlugin } from '../../plugin-buttons/src/index.mjs'
|
||||
import { bannerPlugin } from '../../plugin-banner/src/index.mjs'
|
||||
import { bartackPlugin } from '../../plugin-bartack/src/index.mjs'
|
||||
import { buttonsPlugin } from '../../plugin-buttons/src/index.mjs'
|
||||
import { cutonfoldPlugin } from '../../plugin-cutonfold/src/index.mjs'
|
||||
import { dimensionPlugin } from '../../plugin-dimension/src/index.mjs'
|
||||
import { grainlinePlugin } from '../../plugin-grainline/src/index.mjs'
|
||||
import { logoPlugin } from '../../plugin-logo/src/index.mjs'
|
||||
import { mirrorPlugin } from '../../plugin-mirror/src/index.mjs'
|
||||
import { notchesPlugin } from '../../plugin-notches/src/index.mjs'
|
||||
import { titlePlugin } from '../../plugin-title/src/index.mjs'
|
||||
import { scaleboxPlugin } from '../../plugin-scalebox/src/index.mjs'
|
||||
import { roundPlugin } from '../../plugin-round/src/index.mjs'
|
||||
import { logoPlugin } from '../../plugin-logo/src/index.mjs'
|
||||
import { mirrorPlugin } from '../../plugin-mirror/src/index.mjs'
|
||||
import { notchesPlugin } from '../../plugin-notches/src/index.mjs'
|
||||
import { titlePlugin } from '../../plugin-title/src/index.mjs'
|
||||
import { scaleboxPlugin } from '../../plugin-scalebox/src/index.mjs'
|
||||
import { roundPlugin } from '../../plugin-round/src/index.mjs'
|
||||
import { sprinklePlugin } from '../../plugin-sprinkle/src/index.mjs'
|
||||
import { measurementsPlugin } from '../../plugin-measurements/src/index.mjs'
|
||||
import { name, version } from '../data.mjs'
|
||||
|
@ -66,4 +66,3 @@ export const plugin = {
|
|||
// More specifically named exports
|
||||
export const bundlePlugin = plugin
|
||||
export const pluginBundle = plugin
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import chai from 'chai'
|
|||
const expect = chai.expect
|
||||
|
||||
describe('Round Plugin Tests', () => {
|
||||
it("FIXME: No plugin tests configured", () => {
|
||||
it('FIXME: No plugin tests configured', () => {
|
||||
expect(1).to.equal(1)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from './dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from './dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design, round } from '@freesewing/core'
|
||||
import { plugin } from './dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design, round } from '@freesewing/core'
|
||||
import { plugin } from './dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from './dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from './dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -41,4 +41,3 @@ export const plugin = {
|
|||
// More specifically named exports
|
||||
export const roundPlugin = plugin
|
||||
export const pluginRound = plugin
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import chai from 'chai'
|
|||
const expect = chai.expect
|
||||
|
||||
describe('Round Plugin Tests', () => {
|
||||
it("FIXME: No plugin tests configured", () => {
|
||||
it('FIXME: No plugin tests configured', () => {
|
||||
expect(1).to.equal(1)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design, round } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
//import freesewing from '@freesewing/core'
|
||||
//import plugin from '../dist/index.mjs'
|
||||
//import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -15,4 +15,3 @@ export const svgAttrPlugin = plugin
|
|||
export const svgattrPlugin = plugin
|
||||
export const pluginSvgAttr = plugin
|
||||
export const pluginSvgattr = plugin
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import chai from 'chai'
|
||||
|
||||
const expect = chai.expect;
|
||||
const expect = chai.expect
|
||||
|
||||
describe('SVG Attributed Plugin Tests', () => {
|
||||
it("FIXME: No plugin tests defined", () => {
|
||||
it('FIXME: No plugin tests defined', () => {
|
||||
expect(1).to.equal(1)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -15,4 +15,3 @@ export const plugin = {
|
|||
// More specifically named exports
|
||||
export const versionfreeSvgPlugin = plugin
|
||||
export const pluginVersionfreeSvg = plugin
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import chai from 'chai'
|
||||
import { Design } from '@freesewing/core'
|
||||
import { plugin } from '../dist/index.mjs'
|
||||
import { plugin } from '../src/index.mjs'
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { withBreasts, withoutBreasts } from '@freesewing/models';
|
||||
import { withBreasts, withoutBreasts } from '@freesewing/models'
|
||||
|
||||
export default {
|
||||
users: [
|
||||
|
@ -10,15 +10,15 @@ export default {
|
|||
role: 'user',
|
||||
settings: {
|
||||
language: 'nl',
|
||||
units: 'imperial'
|
||||
units: 'imperial',
|
||||
},
|
||||
patron: 2,
|
||||
consent: {
|
||||
profile: true,
|
||||
measurements: true,
|
||||
openData: true
|
||||
openData: true,
|
||||
},
|
||||
status: 'active'
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
email: 'test@freesewing.org',
|
||||
|
@ -28,15 +28,15 @@ export default {
|
|||
role: 'user',
|
||||
settings: {
|
||||
language: 'nl',
|
||||
units: 'imperial'
|
||||
units: 'imperial',
|
||||
},
|
||||
patron: 4,
|
||||
consent: {
|
||||
profile: true,
|
||||
measurements: true,
|
||||
openData: true
|
||||
openData: true,
|
||||
},
|
||||
status: 'active'
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
email: 'admin@freesewing.org',
|
||||
|
@ -52,16 +52,16 @@ export default {
|
|||
patron: 8,
|
||||
settings: {
|
||||
language: 'en',
|
||||
units: 'metric'
|
||||
units: 'metric',
|
||||
},
|
||||
consent: {
|
||||
profile: true,
|
||||
measurements: true,
|
||||
openData: true
|
||||
openData: true,
|
||||
},
|
||||
newsletter: true,
|
||||
status: 'active'
|
||||
}
|
||||
status: 'active',
|
||||
},
|
||||
],
|
||||
people: [
|
||||
{
|
||||
|
@ -72,7 +72,7 @@ export default {
|
|||
breasts: false,
|
||||
units: 'metric',
|
||||
notes: 'This is an example person',
|
||||
measurements: withoutBreasts.size42
|
||||
measurements: withoutBreasts.size42,
|
||||
},
|
||||
{
|
||||
handle: 'persb',
|
||||
|
@ -84,37 +84,37 @@ export default {
|
|||
notes: 'This is an example person',
|
||||
measurements: {
|
||||
...withBreasts.size36,
|
||||
doesNotExist: 234
|
||||
}
|
||||
doesNotExist: 234,
|
||||
},
|
||||
},
|
||||
],
|
||||
patterns: [
|
||||
{
|
||||
handle: "recip",
|
||||
name: "Example pattern",
|
||||
notes: "These are the pattern notes",
|
||||
handle: 'recip',
|
||||
name: 'Example pattern',
|
||||
notes: 'These are the pattern notes',
|
||||
data: {
|
||||
settings: {
|
||||
sa: 10,
|
||||
complete: true,
|
||||
paperless: false,
|
||||
units: "imperial",
|
||||
units: 'imperial',
|
||||
measurements: {
|
||||
biceps: 335,
|
||||
hpsToWaist: 520,
|
||||
chest: 1080,
|
||||
waistToHips: 145,
|
||||
neck: 420,
|
||||
shoulderSlope: 13,
|
||||
shoulderSlope: 13,
|
||||
shoulderToShoulder: 465,
|
||||
hips: 990
|
||||
}
|
||||
hips: 990,
|
||||
},
|
||||
},
|
||||
design: "aaron",
|
||||
design: 'aaron',
|
||||
},
|
||||
created: "2019-08-14T09:47:27.163Z",
|
||||
created: '2019-08-14T09:47:27.163Z',
|
||||
user: 'tuser',
|
||||
person:"persa"
|
||||
}
|
||||
]
|
||||
person: 'persa',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ verifyConfig(config, chalk)
|
|||
mongoose.Promise = global.Promise
|
||||
mongoose
|
||||
.connect(config.db.uri, {
|
||||
useNewUrlParser: true
|
||||
useNewUrlParser: true,
|
||||
})
|
||||
.then(() => {
|
||||
console.log(chalk.green('Successfully connected to the database'))
|
||||
|
@ -37,7 +37,7 @@ mongoose
|
|||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
console.log(chalk.red('Could not connect to the database. Exiting now...'), err)
|
||||
process.exit()
|
||||
})
|
||||
|
|
|
@ -9,7 +9,11 @@ export const showHelp = () => {
|
|||
console.log()
|
||||
console.log(' ', chalk.bold.blue('npm run clear:users'), '👉 Truncate the users collection')
|
||||
console.log(' ', chalk.bold.blue('npm run clear:people'), '👉 Truncate the people collection')
|
||||
console.log(' ', chalk.bold.blue('npm run clear:patterns'), '👉 Truncate the patterns collection')
|
||||
console.log(
|
||||
' ',
|
||||
chalk.bold.blue('npm run clear:patterns'),
|
||||
'👉 Truncate the patterns collection'
|
||||
)
|
||||
console.log(
|
||||
' ',
|
||||
chalk.bold.blue('npm run clear:confirmations'),
|
||||
|
@ -26,33 +30,33 @@ export const showHelp = () => {
|
|||
}
|
||||
|
||||
export const clearUsers = async () => {
|
||||
await User.deleteMany().then(result => {
|
||||
if (result.ok) console.log('🔥 Users deleted')
|
||||
else console.log('🚨 Could not remove users', result)
|
||||
await User.deleteMany().then((result) => {
|
||||
if (result.ok) console.log('🔥 Users deleted')
|
||||
else console.log('🚨 Could not remove users', result)
|
||||
})
|
||||
}
|
||||
export const clearPeople = async () => {
|
||||
await Person.deleteMany().then(result => {
|
||||
if (result.ok) console.log('🔥 People removed')
|
||||
else console.log('🚨 Could not remove people', result)
|
||||
await Person.deleteMany().then((result) => {
|
||||
if (result.ok) console.log('🔥 People removed')
|
||||
else console.log('🚨 Could not remove people', result)
|
||||
})
|
||||
}
|
||||
export const clearPatterns = async () => {
|
||||
await Pattern.deleteMany().then(result => {
|
||||
if (result.ok) console.log('🔥 Patterns deleted')
|
||||
else console.log('🚨 Could not remove patterns', result)
|
||||
await Pattern.deleteMany().then((result) => {
|
||||
if (result.ok) console.log('🔥 Patterns deleted')
|
||||
else console.log('🚨 Could not remove patterns', result)
|
||||
})
|
||||
}
|
||||
export const clearConfirmations = async () => {
|
||||
await Confirmation.deleteMany().then(result => {
|
||||
if (result.ok) console.log('🔥 Confirmations deleted')
|
||||
else console.log('🚨 Could not remove confirmations', result)
|
||||
await Confirmation.deleteMany().then((result) => {
|
||||
if (result.ok) console.log('🔥 Confirmations deleted')
|
||||
else console.log('🚨 Could not remove confirmations', result)
|
||||
})
|
||||
}
|
||||
export const clearNewsletterSubscribers = async () => {
|
||||
await Newsletter.deleteMany().then(result => {
|
||||
if (result.ok) console.log('🔥 Newsletter subscriptions deleted')
|
||||
else console.log('🚨 Could not remove newsletter subscriptions', result)
|
||||
await Newsletter.deleteMany().then((result) => {
|
||||
if (result.ok) console.log('🔥 Newsletter subscriptions deleted')
|
||||
else console.log('🚨 Could not remove newsletter subscriptions', result)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -65,8 +69,8 @@ export const loadSampleData = async () => {
|
|||
ehash: ehash(sample.email),
|
||||
picture: sample.handle + '.svg',
|
||||
time: {
|
||||
created: new Date()
|
||||
}
|
||||
created: new Date(),
|
||||
},
|
||||
})
|
||||
user.createAvatar()
|
||||
promises.push(user.save())
|
||||
|
@ -83,7 +87,7 @@ export const loadSampleData = async () => {
|
|||
return Promise.all(promises)
|
||||
}
|
||||
|
||||
export const runTasks = options => {
|
||||
export const runTasks = (options) => {
|
||||
let promises = []
|
||||
if (options.clearAll || options.reboot || options.clearUsers) promises.push(clearUsers())
|
||||
if (options.clearAll || options.reboot || options.clearPeople) promises.push(clearPeople())
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
export default [
|
||||
{
|
||||
name: 'clearUsers',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'clearModels',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'clearPatterns',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'clearConfirmations',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'clearNewsletterSubscribers',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'clearAll',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'reboot',
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
},
|
||||
{
|
||||
name: 'help',
|
||||
type: Boolean
|
||||
}
|
||||
type: Boolean,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -5,8 +5,7 @@ import { ehash } from '../utils'
|
|||
|
||||
function AdminController() {}
|
||||
|
||||
|
||||
AdminController.prototype.search = function(req, res) {
|
||||
AdminController.prototype.search = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
|
@ -16,26 +15,26 @@ AdminController.prototype.search = function(req, res) {
|
|||
{ handle: { $regex: `.*${req.body.query}.*` } },
|
||||
{ username: { $regex: `.*${req.body.query}.*` } },
|
||||
{ ehash: ehash(req.body.query) },
|
||||
]
|
||||
],
|
||||
})
|
||||
.sort('username')
|
||||
.exec((err, users) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
Person.find({ handle: { $regex: `.*${req.body.query}.*` } })
|
||||
.sort('handle')
|
||||
.exec((err, people) => {
|
||||
.sort('username')
|
||||
.exec((err, users) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
if (users === null && people === null) return res.sendStatus(404)
|
||||
return res.send({
|
||||
users: users.map(user => user.adminProfile()),
|
||||
people: people.map(person => person.info()),
|
||||
})
|
||||
Person.find({ handle: { $regex: `.*${req.body.query}.*` } })
|
||||
.sort('handle')
|
||||
.exec((err, people) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
if (users === null && people === null) return res.sendStatus(404)
|
||||
return res.send({
|
||||
users: users.map((user) => user.adminProfile()),
|
||||
people: people.map((person) => person.info()),
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.setPatronStatus = function(req, res) {
|
||||
AdminController.prototype.setPatronStatus = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
|
@ -49,7 +48,7 @@ AdminController.prototype.setPatronStatus = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.setRole = function(req, res) {
|
||||
AdminController.prototype.setRole = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
|
@ -63,7 +62,7 @@ AdminController.prototype.setRole = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.unfreeze = function(req, res) {
|
||||
AdminController.prototype.unfreeze = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
|
@ -77,7 +76,7 @@ AdminController.prototype.unfreeze = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.impersonate = function(req, res) {
|
||||
AdminController.prototype.impersonate = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
|
@ -95,16 +94,14 @@ AdminController.prototype.impersonate = function(req, res) {
|
|||
Pattern.find({ user: user.handle }, (err, patternList) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
for (let pattern of patternList) patterns[pattern.handle] = pattern
|
||||
return user.updateLoginTime(() =>
|
||||
res.send({ account, people, patterns, token })
|
||||
)
|
||||
return user.updateLoginTime(() => res.send({ account, people, patterns, token }))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.patronList = function(req, res) {
|
||||
AdminController.prototype.patronList = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
|
@ -116,16 +113,16 @@ AdminController.prototype.patronList = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.subscriberList = function(req, res) {
|
||||
AdminController.prototype.subscriberList = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
if (admin.role !== 'admin') return res.sendStatus(403)
|
||||
User.find({newsletter: true}, (err, subscribedUsers) => {
|
||||
User.find({ newsletter: true }, (err, subscribedUsers) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
let subscribers = subscribedUsers.map(user => ({
|
||||
let subscribers = subscribedUsers.map((user) => ({
|
||||
ehash: user.ehash,
|
||||
email: user.email
|
||||
email: user.email,
|
||||
}))
|
||||
Newsletter.find({}, (err, subs) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
|
@ -135,12 +132,12 @@ AdminController.prototype.subscriberList = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
AdminController.prototype.stats = function(req, res) {
|
||||
AdminController.prototype.stats = function (req, res) {
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, admin) => {
|
||||
if (err || admin === null) return res.sendStatus(400)
|
||||
if (admin.role !== 'admin') return res.sendStatus(403)
|
||||
User.find({ "consent.profile": true }, (err, users) => {
|
||||
User.find({ 'consent.profile': true }, (err, users) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
Person.find({}, (err, people) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
|
@ -157,21 +154,21 @@ AdminController.prototype.stats = function(req, res) {
|
|||
}
|
||||
|
||||
function saveAndReturnAccount(res, user) {
|
||||
user.save(function(err, updatedUser) {
|
||||
user.save(function (err, updatedUser) {
|
||||
if (err) {
|
||||
return res.sendStatus(500)
|
||||
} else return res.send({ account: updatedUser.account() })
|
||||
})
|
||||
}
|
||||
|
||||
const getToken = account => {
|
||||
const getToken = (account) => {
|
||||
return jwt.sign(
|
||||
{
|
||||
_id: account._id,
|
||||
handle: account.handle,
|
||||
role: account.role,
|
||||
aud: config.jwt.audience,
|
||||
iss: config.jwt.issuer
|
||||
iss: config.jwt.issuer,
|
||||
},
|
||||
config.jwt.secretOrKey
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
getHandle,
|
||||
createHandle,
|
||||
imageType,
|
||||
saveAvatarFromBase64
|
||||
saveAvatarFromBase64,
|
||||
} from '../utils'
|
||||
import config from '../config'
|
||||
import queryString from 'query-string'
|
||||
|
@ -19,22 +19,22 @@ import axios from 'axios'
|
|||
|
||||
function AuthController() {}
|
||||
|
||||
AuthController.prototype.initOauth = function(req, res) {
|
||||
AuthController.prototype.initOauth = function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
let confirmation = new Confirmation({
|
||||
type: 'oauth',
|
||||
data: {
|
||||
language: req.body.language,
|
||||
provider: req.body.provider
|
||||
}
|
||||
provider: req.body.provider,
|
||||
},
|
||||
})
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
return res.send({ state: confirmation._id })
|
||||
})
|
||||
}
|
||||
|
||||
AuthController.prototype.loginOauth = function(req, res) {
|
||||
AuthController.prototype.loginOauth = function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
Confirmation.findById(req.body.confirmation, (err, confirmation) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
|
@ -57,7 +57,7 @@ AuthController.prototype.loginOauth = function(req, res) {
|
|||
Pattern.find({ user: user.handle }, (err, patternList) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
for (let pattern of patternList) patterns[pattern.handle] = pattern
|
||||
confirmation.remove(err => {
|
||||
confirmation.remove((err) => {
|
||||
if (err !== null) return res.sendStatus(500)
|
||||
user.updateLoginTime(() => res.send({ account, people, token, signup }))
|
||||
})
|
||||
|
@ -67,7 +67,7 @@ AuthController.prototype.loginOauth = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
AuthController.prototype.providerCallback = function(req, res) {
|
||||
AuthController.prototype.providerCallback = function (req, res) {
|
||||
let language, token, email, avatarUri, username
|
||||
let provider = req.params.provider
|
||||
let conf = config.oauth[provider]
|
||||
|
@ -89,19 +89,19 @@ AuthController.prototype.providerCallback = function(req, res) {
|
|||
code: req.query.code,
|
||||
accept: 'json',
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: config.api + '/oauth/callback/from/' + provider
|
||||
redirect_uri: config.api + '/oauth/callback/from/' + provider,
|
||||
})
|
||||
.then(result => {
|
||||
.then((result) => {
|
||||
if (result.status !== 200) return res.sendStatus(401)
|
||||
if (provider === 'github') token = queryString.parse(result.data).access_token
|
||||
else if (provider === 'google') token = result.data.access_token
|
||||
// Contact API for user info
|
||||
const headers = token => ({ headers: { Authorization: 'Bearer ' + token } })
|
||||
const headers = (token) => ({ headers: { Authorization: 'Bearer ' + token } })
|
||||
go.get(conf.dataUri, headers(token))
|
||||
.then(async result => {
|
||||
.then(async (result) => {
|
||||
if (provider === 'github') {
|
||||
email = await getGithubEmail(result.data.email, go, conf.emailUri, headers(token)),
|
||||
avatarUri = result.data.avatar_url
|
||||
;(email = await getGithubEmail(result.data.email, go, conf.emailUri, headers(token))),
|
||||
(avatarUri = result.data.avatar_url)
|
||||
username = result.data.login
|
||||
} else if (provider === 'google') {
|
||||
for (let address of result.data.emailAddresses) {
|
||||
|
@ -120,7 +120,7 @@ AuthController.prototype.providerCallback = function(req, res) {
|
|||
// New user: signup
|
||||
signup = true
|
||||
let handle = getHandle()
|
||||
go.get(avatarUri, { responseType: 'arraybuffer' }).then(avatar => {
|
||||
go.get(avatarUri, { responseType: 'arraybuffer' }).then((avatar) => {
|
||||
let type = imageType(avatar.headers['content-type'])
|
||||
saveAvatarFromBase64(
|
||||
new Buffer(avatar.data, 'binary').toString('base64'),
|
||||
|
@ -142,21 +142,21 @@ AuthController.prototype.providerCallback = function(req, res) {
|
|||
},
|
||||
time: {
|
||||
created: new Date(),
|
||||
login: new Date()
|
||||
}
|
||||
login: new Date(),
|
||||
},
|
||||
}
|
||||
if (provider === 'github') {
|
||||
userData.social.github = result.data.login
|
||||
userData.bio = result.data.bio
|
||||
}
|
||||
let user = new User(userData)
|
||||
user.save(function(err) {
|
||||
user.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
let validation = createHandle(20)
|
||||
confirmation.data.handle = user.handle
|
||||
confirmation.data.validation = validation
|
||||
confirmation.data.signup = true
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
return res.redirect(
|
||||
createUrl(
|
||||
|
@ -175,18 +175,20 @@ AuthController.prototype.providerCallback = function(req, res) {
|
|||
if (user.bio === '') user.bio = result.data.bio
|
||||
user.social.github = result.data.login
|
||||
}
|
||||
user.save(function(err) {
|
||||
user.save(function (err) {
|
||||
let validation = createHandle(20)
|
||||
confirmation.data.handle = user.handle
|
||||
confirmation.data.validation = validation
|
||||
confirmation.data.signup = false
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
return res.redirect(
|
||||
// Watch out for pending users
|
||||
createUrl(language, (user.status === 'pending')
|
||||
? '/confirm/signup/' + req.query.state + '/'
|
||||
: '/login/callback/' + confirmation._id + '/' + validation
|
||||
createUrl(
|
||||
language,
|
||||
user.status === 'pending'
|
||||
? '/confirm/signup/' + req.query.state + '/'
|
||||
: '/login/callback/' + confirmation._id + '/' + validation
|
||||
)
|
||||
)
|
||||
})
|
||||
|
@ -194,12 +196,12 @@ AuthController.prototype.providerCallback = function(req, res) {
|
|||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
console.log('api token error', err)
|
||||
res.sendStatus(401)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
console.log('post token error', err)
|
||||
res.sendStatus(401)
|
||||
})
|
||||
|
@ -207,20 +209,17 @@ AuthController.prototype.providerCallback = function(req, res) {
|
|||
}
|
||||
|
||||
/*
|
||||
* Github does not always return the email address
|
||||
* See https://github.com/freesewing/backend/issues/162
|
||||
*/
|
||||
* Github does not always return the email address
|
||||
* See https://github.com/freesewing/backend/issues/162
|
||||
*/
|
||||
const getGithubEmail = async (email, client, uri, headers) => {
|
||||
if (email === null) {
|
||||
return client.get(uri, headers)
|
||||
.then(result => {
|
||||
for (let e of result.data) {
|
||||
if (e.primary) return e.email
|
||||
}
|
||||
})
|
||||
}
|
||||
else return email
|
||||
return client.get(uri, headers).then((result) => {
|
||||
for (let e of result.data) {
|
||||
if (e.primary) return e.email
|
||||
}
|
||||
})
|
||||
} else return email
|
||||
}
|
||||
|
||||
|
||||
export default AuthController
|
||||
|
|
|
@ -4,95 +4,100 @@ import config from '../config'
|
|||
function GithubController() {}
|
||||
|
||||
// Create a gist
|
||||
GithubController.prototype.createGist = function(req, res) {
|
||||
GithubController.prototype.createGist = function (req, res) {
|
||||
if (!req.body.data) return res.sendStatus(400)
|
||||
let client = GithubClient()
|
||||
client.post('/gists', {
|
||||
public: true,
|
||||
description: `An open source sewing pattern from freesewing.org`,
|
||||
files: {
|
||||
'pattern.yaml': { content: req.body.data }
|
||||
}
|
||||
})
|
||||
.then(result => {
|
||||
let id = result.data.id
|
||||
client.post(`/gists/${id}/comments`, {
|
||||
body: `👉 https://freesewing.org/recreate/gist/${id} 👀`
|
||||
client
|
||||
.post('/gists', {
|
||||
public: true,
|
||||
description: `An open source sewing pattern from freesewing.org`,
|
||||
files: {
|
||||
'pattern.yaml': { content: req.body.data },
|
||||
},
|
||||
})
|
||||
.then(result => res.send({id}))
|
||||
.catch(err => res.sendStatus(500))
|
||||
})
|
||||
.catch(err => res.sendStatus(500))
|
||||
.then((result) => {
|
||||
let id = result.data.id
|
||||
client
|
||||
.post(`/gists/${id}/comments`, {
|
||||
body: `👉 https://freesewing.org/recreate/gist/${id} 👀`,
|
||||
})
|
||||
.then((result) => res.send({ id }))
|
||||
.catch((err) => res.sendStatus(500))
|
||||
})
|
||||
.catch((err) => res.sendStatus(500))
|
||||
}
|
||||
|
||||
GithubController.prototype.createIssue = function(req, res) {
|
||||
GithubController.prototype.createIssue = function (req, res) {
|
||||
if (!req.body.data) return res.sendStatus(400)
|
||||
if (!req.body.design) return res.sendStatus(400)
|
||||
let client = GithubClient()
|
||||
client.post('/gists', {
|
||||
public: true,
|
||||
description: `A FreeSewing crash report`,
|
||||
files: {
|
||||
'pattern.yaml': { content: req.body.data },
|
||||
'settings.yaml': { content: req.body.patternProps.settings },
|
||||
'events.yaml': { content: req.body.patternProps.events },
|
||||
'errors.md': { content: req.body.traces },
|
||||
'parts.json': { content: req.body.patternProps.parts },
|
||||
}
|
||||
})
|
||||
.then(gist => {
|
||||
client.post('/repos/freesewing/freesewing/issues', {
|
||||
title: `Error while drafting ${req.body.design}`,
|
||||
body: `An error occured while drafting ${req.body.design} and a [crash report](https://gist.github.com/${gist.data.id}) was generated.`,
|
||||
labels: [
|
||||
`:package: ${req.body.design}`,
|
||||
':robot: robot'
|
||||
]
|
||||
client
|
||||
.post('/gists', {
|
||||
public: true,
|
||||
description: `A FreeSewing crash report`,
|
||||
files: {
|
||||
'pattern.yaml': { content: req.body.data },
|
||||
'settings.yaml': { content: req.body.patternProps.settings },
|
||||
'events.yaml': { content: req.body.patternProps.events },
|
||||
'errors.md': { content: req.body.traces },
|
||||
'parts.json': { content: req.body.patternProps.parts },
|
||||
},
|
||||
})
|
||||
.then(issue => {
|
||||
let notify = (typeof config.github.notify.specific[req.body.design] === 'undefined')
|
||||
? config.github.notify.dflt
|
||||
: config.github.notify.specific[req.body.design]
|
||||
let id = issue.data.number
|
||||
let path = `/recreate/gist/${gist.data.id}`
|
||||
let body = 'Ping '
|
||||
for (const user of notify) body += `@${user} `
|
||||
if (req.body.userGithub) body += `@${req.body.userGithub} `
|
||||
body += " 👋 \nRecreate this:\n\n"
|
||||
body += `- **Lab**: 👉 https://lab.freesewing.dev/v/next/` +
|
||||
`${req.body.design}?from=github&preload=${gist.data.id}`
|
||||
body += "\n\n"
|
||||
body += `- **Production**: 👉 https://freesewing.org${path}`
|
||||
body += "\n\n"
|
||||
if (req.body.userHandle) body += `(user handle: ${req.body.userHandle})`
|
||||
client.post(`/repos/freesewing/freesewing/issues/${id}/comments`, { body })
|
||||
.then(result => res.send({id}))
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
res.sendStatus(500)
|
||||
})
|
||||
.then((gist) => {
|
||||
client
|
||||
.post('/repos/freesewing/freesewing/issues', {
|
||||
title: `Error while drafting ${req.body.design}`,
|
||||
body: `An error occured while drafting ${req.body.design} and a [crash report](https://gist.github.com/${gist.data.id}) was generated.`,
|
||||
labels: [`:package: ${req.body.design}`, ':robot: robot'],
|
||||
})
|
||||
.then((issue) => {
|
||||
let notify =
|
||||
typeof config.github.notify.specific[req.body.design] === 'undefined'
|
||||
? config.github.notify.dflt
|
||||
: config.github.notify.specific[req.body.design]
|
||||
let id = issue.data.number
|
||||
let path = `/recreate/gist/${gist.data.id}`
|
||||
let body = 'Ping '
|
||||
for (const user of notify) body += `@${user} `
|
||||
if (req.body.userGithub) body += `@${req.body.userGithub} `
|
||||
body += ' 👋 \nRecreate this:\n\n'
|
||||
body +=
|
||||
`- **Lab**: 👉 https://lab.freesewing.dev/v/next/` +
|
||||
`${req.body.design}?from=github&preload=${gist.data.id}`
|
||||
body += '\n\n'
|
||||
body += `- **Production**: 👉 https://freesewing.org${path}`
|
||||
body += '\n\n'
|
||||
if (req.body.userHandle) body += `(user handle: ${req.body.userHandle})`
|
||||
client
|
||||
.post(`/repos/freesewing/freesewing/issues/${id}/comments`, { body })
|
||||
.then((result) => res.send({ id }))
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
res.sendStatus(500)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
res.sendStatus(500)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
res.sendStatus(500)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
res.sendStatus(500)
|
||||
})
|
||||
}
|
||||
|
||||
const GithubClient = () => axios.create({
|
||||
baseURL: config.github.api,
|
||||
timeout: 5000,
|
||||
auth: {
|
||||
username: config.github.bot.user,
|
||||
password: config.github.token
|
||||
},
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json'
|
||||
}
|
||||
})
|
||||
const GithubClient = () =>
|
||||
axios.create({
|
||||
baseURL: config.github.api,
|
||||
timeout: 5000,
|
||||
auth: {
|
||||
username: config.github.bot.user,
|
||||
password: config.github.token,
|
||||
},
|
||||
headers: {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
},
|
||||
})
|
||||
|
||||
export default GithubController
|
||||
|
|
|
@ -1,40 +1,37 @@
|
|||
import { Newsletter, Confirmation, User } from '../models'
|
||||
import {
|
||||
log,
|
||||
email,
|
||||
ehash,
|
||||
} from '../utils'
|
||||
import { log, email, ehash } from '../utils'
|
||||
import path from 'path'
|
||||
|
||||
const bail = (res, page='index') => res.sendFile(path.resolve(__dirname, '..', 'landing', `${page}.html`))
|
||||
const bail = (res, page = 'index') =>
|
||||
res.sendFile(path.resolve(__dirname, '..', 'landing', `${page}.html`))
|
||||
|
||||
function NewsletterController() {}
|
||||
|
||||
NewsletterController.prototype.subscribe = function(req, res, subscribe=true) {
|
||||
NewsletterController.prototype.subscribe = function (req, res, subscribe = true) {
|
||||
if (!req.body || !req.body.email) return res.sendStatus(400)
|
||||
let confirmation = new Confirmation({
|
||||
type: 'newsletter',
|
||||
data: { email: req.body.email }
|
||||
data: { email: req.body.email },
|
||||
})
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
log.info('newsletterSubscription', {
|
||||
email: req.body.email,
|
||||
confirmation: confirmation._id
|
||||
confirmation: confirmation._id,
|
||||
})
|
||||
email.subscribe(req.body.email, confirmation._id)
|
||||
return res.send({status: 'subscribed'})
|
||||
return res.send({ status: 'subscribed' })
|
||||
})
|
||||
}
|
||||
|
||||
NewsletterController.prototype.confirm = function(req, res, subscribe=true) {
|
||||
NewsletterController.prototype.confirm = function (req, res, subscribe = true) {
|
||||
if (!req.params.token) return bail(res, 'invalid')
|
||||
Confirmation.findById(req.params.token, (err, confirmation) => {
|
||||
if (err) return bail(res)
|
||||
if (confirmation === null) return bail(res)
|
||||
Newsletter.findOne(
|
||||
{
|
||||
ehash: ehash(confirmation.data.email)
|
||||
ehash: ehash(confirmation.data.email),
|
||||
},
|
||||
(err, reader) => {
|
||||
if (err) return bail(res)
|
||||
|
@ -46,10 +43,10 @@ NewsletterController.prototype.confirm = function(req, res, subscribe=true) {
|
|||
email: confirmation.data.email,
|
||||
ehash: hash,
|
||||
time: {
|
||||
created: new Date()
|
||||
}
|
||||
created: new Date(),
|
||||
},
|
||||
})
|
||||
sub.save(function(err) {
|
||||
sub.save(function (err) {
|
||||
if (err) {
|
||||
log.error('newsletterSubscriptionFailed', sub)
|
||||
console.log(err)
|
||||
|
@ -61,34 +58,33 @@ NewsletterController.prototype.confirm = function(req, res, subscribe=true) {
|
|||
return bail(res, 'subscribe')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
NewsletterController.prototype.unsubscribe = function(req, res) {
|
||||
NewsletterController.prototype.unsubscribe = function (req, res) {
|
||||
if (!req.params.ehash) return bail(res, 'invalid')
|
||||
|
||||
Newsletter.findOne({ ehash: req.params.ehash }, (err, reader) => {
|
||||
if (reader) {
|
||||
Newsletter.deleteOne({id: reader.id}, (err, result) => {
|
||||
Newsletter.deleteOne({ id: reader.id }, (err, result) => {
|
||||
if (!err) {
|
||||
console.log(`Unsubscribed ${reader.email} from the newsletter`)
|
||||
return bail(res, 'unsubscribe')
|
||||
}
|
||||
else return bail(res, 'oops')
|
||||
} else return bail(res, 'oops')
|
||||
})
|
||||
} else {
|
||||
User.findOne({ ehash: req.params.ehash }, (err, user) => {
|
||||
if (user) {
|
||||
user.newsletter = false
|
||||
user.save(function(err, updatedUser) {
|
||||
user.save(function (err, updatedUser) {
|
||||
if (err) {
|
||||
log.error('accountUpdateFailed', err)
|
||||
return res.sendStatus(500)
|
||||
} else return bail(res, 'unsubscribe')
|
||||
})
|
||||
}
|
||||
else return bail(res, 'oops')
|
||||
} else return bail(res, 'oops')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import config from "../config";
|
||||
import { capitalize } from "../utils";
|
||||
import sharp from 'sharp';
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import config from '../config'
|
||||
import { capitalize } from '../utils'
|
||||
import sharp from 'sharp'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import axios from 'axios'
|
||||
import remark from 'remark'
|
||||
import remarkParse from 'remark-parse'
|
||||
|
@ -14,13 +14,10 @@ import yaml from 'yaml'
|
|||
// Sites for which we generate images
|
||||
const sites = ['dev', 'org']
|
||||
// Langauges for which we generate images
|
||||
const languages = ['en', 'fr', 'de', 'es', 'nl' ]
|
||||
const languages = ['en', 'fr', 'de', 'es', 'nl']
|
||||
|
||||
// Load template once at startup
|
||||
const template = fs.readFileSync(
|
||||
path.resolve(...config.og.template),
|
||||
'utf-8'
|
||||
)
|
||||
const template = fs.readFileSync(path.resolve(...config.og.template), 'utf-8')
|
||||
|
||||
/* Helper method to extract intro from strapi markdown */
|
||||
const introFromStrapiMarkdown = async (md, slug) => {
|
||||
|
@ -33,17 +30,15 @@ const introFromStrapiMarkdown = async (md, slug) => {
|
|||
|
||||
/* Helper method to extract title from markdown frontmatter */
|
||||
const titleAndIntroFromLocalMarkdown = async (md, slug) => {
|
||||
const tree = await remark()
|
||||
.use(remarkParse)
|
||||
.use(remarkFrontmatter, ['yaml'])
|
||||
.parse(md)
|
||||
const tree = await remark().use(remarkParse).use(remarkFrontmatter, ['yaml']).parse(md)
|
||||
|
||||
if (tree.children[0].type !== 'yaml')
|
||||
console.log('Markdown does not start with frontmatter', slug)
|
||||
else return {
|
||||
title: titleAsLines(yaml.parse(tree.children[0].value).title),
|
||||
intro: introAsLines(toString(tree.children.slice(1, 2)))
|
||||
}
|
||||
else
|
||||
return {
|
||||
title: titleAsLines(yaml.parse(tree.children[0].value).title),
|
||||
intro: introAsLines(toString(tree.children.slice(1, 2))),
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -53,41 +48,40 @@ const loadDevBlogPost = async (slug) => {
|
|||
const result = await axios.get(
|
||||
`${config.strapi}/blogposts?_locale=en&dev_eq=true&slug_eq=${slug}`
|
||||
)
|
||||
if (result.data) return {
|
||||
title: titleAsLines(result.data[0].title),
|
||||
intro: introAsLines(await introFromStrapiMarkdown(result.data[0].body, slug)),
|
||||
sub: [
|
||||
result.data[0].author.displayname,
|
||||
new Date(result.data[0].published_at).toString().split(' ').slice(0,4).join(' '),
|
||||
],
|
||||
lead: 'Developer Blog',
|
||||
}
|
||||
if (result.data)
|
||||
return {
|
||||
title: titleAsLines(result.data[0].title),
|
||||
intro: introAsLines(await introFromStrapiMarkdown(result.data[0].body, slug)),
|
||||
sub: [
|
||||
result.data[0].author.displayname,
|
||||
new Date(result.data[0].published_at).toString().split(' ').slice(0, 4).join(' '),
|
||||
],
|
||||
lead: 'Developer Blog',
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/* Helper method to load markdown file from disk */
|
||||
const loadMarkdownFile = async (page, site, lang) => fs.promises.readFile(
|
||||
path.resolve('..', '..', 'markdown', site, ...page.split('/'), `${lang}.md`),
|
||||
'utf-8'
|
||||
).then(async (md) => md
|
||||
? {
|
||||
...(await titleAndIntroFromLocalMarkdown(md, page)),
|
||||
sub: [
|
||||
'freesewing.dev/',
|
||||
page
|
||||
],
|
||||
lead: capitalize(page.split('/').shift())
|
||||
}
|
||||
: false
|
||||
)
|
||||
const loadMarkdownFile = async (page, site, lang) =>
|
||||
fs.promises
|
||||
.readFile(path.resolve('..', '..', 'markdown', site, ...page.split('/'), `${lang}.md`), 'utf-8')
|
||||
.then(async (md) =>
|
||||
md
|
||||
? {
|
||||
...(await titleAndIntroFromLocalMarkdown(md, page)),
|
||||
sub: ['freesewing.dev/', page],
|
||||
lead: capitalize(page.split('/').shift()),
|
||||
}
|
||||
: false
|
||||
)
|
||||
|
||||
/* Find longest possible place to split a string */
|
||||
const splitLine = (line, chars) => {
|
||||
const words = line.split(' ')
|
||||
if (words[0].length > chars) {
|
||||
// Force a word break
|
||||
return [ line.slice(0, chars-1)+'-', line.slice(chars-1) ]
|
||||
return [line.slice(0, chars - 1) + '-', line.slice(chars - 1)]
|
||||
}
|
||||
// Glue chunks together until it's too long
|
||||
let firstLine = ''
|
||||
|
@ -97,22 +91,22 @@ const splitLine = (line, chars) => {
|
|||
else max = true
|
||||
}
|
||||
|
||||
return [ firstLine, words.join(' ').slice(firstLine.length) ]
|
||||
return [firstLine, words.join(' ').slice(firstLine.length)]
|
||||
}
|
||||
|
||||
/* Divide title into lines to fit on image */
|
||||
const titleAsLines = title => {
|
||||
const titleAsLines = (title) => {
|
||||
// Does it fit on one line?
|
||||
if (title.length <= config.og.chars.title_1) return [title]
|
||||
// Does it fit on two lines?
|
||||
let lines = splitLine(title, config.og.chars.title_1)
|
||||
if (lines[1].length <= config.og.chars.title_2) return lines
|
||||
// Three lines it is
|
||||
return [ lines[0], ...splitLine(lines[1], config.og.chars.title_2) ]
|
||||
return [lines[0], ...splitLine(lines[1], config.og.chars.title_2)]
|
||||
}
|
||||
|
||||
/* Divive intro into lines to fit on image */
|
||||
const introAsLines = intro => {
|
||||
const introAsLines = (intro) => {
|
||||
// Does it fit on one line?
|
||||
if (intro.length <= config.og.chars.intro) return [intro]
|
||||
// Two lines it is
|
||||
|
@ -124,19 +118,25 @@ const getMetaData = {
|
|||
dev: async (page) => {
|
||||
const chunks = page.split('/')
|
||||
// Home page
|
||||
if (chunks.length === 1 && chunks[0] === '') return {
|
||||
title: ['FreeSewing.dev'],
|
||||
intro: introAsLines('FreeSewing API documentation and tutorials for developers and contributors'),
|
||||
sub: ['Also featuring', ' our developers blog'],
|
||||
lead: '.dev',
|
||||
}
|
||||
if (chunks.length === 1 && chunks[0] === '')
|
||||
return {
|
||||
title: ['FreeSewing.dev'],
|
||||
intro: introAsLines(
|
||||
'FreeSewing API documentation and tutorials for developers and contributors'
|
||||
),
|
||||
sub: ['Also featuring', ' our developers blog'],
|
||||
lead: '.dev',
|
||||
}
|
||||
// Blog index page
|
||||
if (chunks.length === 1 && chunks[0] === 'blog') return {
|
||||
title: titleAsLines('FreeSewing Developer Blog'),
|
||||
intro: introAsLines("Contains no sewing news whatsover. Only posts for (aspiring) developers :)"),
|
||||
sub: ['freesewing.dev', '/blog'],
|
||||
lead: 'Developer Blog',
|
||||
}
|
||||
if (chunks.length === 1 && chunks[0] === 'blog')
|
||||
return {
|
||||
title: titleAsLines('FreeSewing Developer Blog'),
|
||||
intro: introAsLines(
|
||||
'Contains no sewing news whatsover. Only posts for (aspiring) developers :)'
|
||||
),
|
||||
sub: ['freesewing.dev', '/blog'],
|
||||
lead: 'Developer Blog',
|
||||
}
|
||||
// Blog post
|
||||
if (chunks.length === 2 && chunks[0] === 'blog') {
|
||||
return await loadDevBlogPost(chunks[1])
|
||||
|
@ -148,45 +148,43 @@ const getMetaData = {
|
|||
return md
|
||||
? md
|
||||
: {
|
||||
title: titleAsLines('FreeSewing.dev'),
|
||||
intro: introAsLines('Documentation, guides, and howtos for contributors and developers alike'),
|
||||
sub: ['https://freesewing.dev/', '<== Check it out'],
|
||||
lead: 'freesewing.dev'
|
||||
}
|
||||
title: titleAsLines('FreeSewing.dev'),
|
||||
intro: introAsLines(
|
||||
'Documentation, guides, and howtos for contributors and developers alike'
|
||||
),
|
||||
sub: ['https://freesewing.dev/', '<== Check it out'],
|
||||
lead: 'freesewing.dev',
|
||||
}
|
||||
},
|
||||
org: async (page, site, lang) => ({})
|
||||
org: async (page, site, lang) => ({}),
|
||||
}
|
||||
|
||||
/* Hide unused placeholders */
|
||||
const hidePlaceholders = list => {
|
||||
const hidePlaceholders = (list) => {
|
||||
let svg = template
|
||||
for (const i of list) {
|
||||
svg = svg
|
||||
.replace(`${i}title_1`, '')
|
||||
.replace(`${i}title_2`, '')
|
||||
.replace(`${i}title_3`, '')
|
||||
svg = svg.replace(`${i}title_1`, '').replace(`${i}title_2`, '').replace(`${i}title_3`, '')
|
||||
}
|
||||
|
||||
return svg
|
||||
}
|
||||
|
||||
/* Place text in SVG template */
|
||||
const decorateSvg = data => {
|
||||
const decorateSvg = (data) => {
|
||||
let svg
|
||||
// Single title line
|
||||
if (data.title.length === 1) {
|
||||
svg = hidePlaceholders([2,3])
|
||||
.replace(`1title_1`, data.title[0])
|
||||
svg = hidePlaceholders([2, 3]).replace(`1title_1`, data.title[0])
|
||||
}
|
||||
// Double title line
|
||||
else if (data.title.length === 2) {
|
||||
svg = hidePlaceholders([1,3])
|
||||
svg = hidePlaceholders([1, 3])
|
||||
.replace(`2title_1`, data.title[0])
|
||||
.replace(`2title_2`, data.title[1])
|
||||
}
|
||||
// Triple title line
|
||||
else if (data.title.length === 3) {
|
||||
svg = hidePlaceholders([1,2])
|
||||
svg = hidePlaceholders([1, 2])
|
||||
.replace(`3title_1`, data.title[0])
|
||||
.replace(`3title_2`, data.title[1])
|
||||
.replace(`3title_3`, data.title[2])
|
||||
|
@ -202,14 +200,14 @@ const decorateSvg = data => {
|
|||
|
||||
/* This generates open graph images */
|
||||
|
||||
function OgController() { }
|
||||
function OgController() {}
|
||||
|
||||
OgController.prototype.image = async function (req, res) {
|
||||
// Extract path parameters
|
||||
const { lang='en', site='dev' } = req.params
|
||||
const page = req.params["0"]
|
||||
if (sites.indexOf(site) === -1) return res.send({error: 'sorry'})
|
||||
if (languages.indexOf(lang) === -1) return res.send({error: 'sorry'})
|
||||
const { lang = 'en', site = 'dev' } = req.params
|
||||
const page = req.params['0']
|
||||
if (sites.indexOf(site) === -1) return res.send({ error: 'sorry' })
|
||||
if (languages.indexOf(lang) === -1) return res.send({ error: 'sorry' })
|
||||
|
||||
// Load meta data
|
||||
const data = await getMetaData[site](page, site, lang)
|
||||
|
@ -224,6 +222,4 @@ OgController.prototype.image = async function (req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default OgController;
|
||||
export default OgController
|
||||
|
|
|
@ -17,9 +17,9 @@ PatternController.prototype.create = (req, res) => {
|
|||
name: req.body.name,
|
||||
notes: req.body.notes,
|
||||
data: req.body.data,
|
||||
created: new Date()
|
||||
created: new Date(),
|
||||
})
|
||||
pattern.save(function(err) {
|
||||
pattern.save(function (err) {
|
||||
if (err) {
|
||||
log.error('patternCreationFailed', user)
|
||||
console.log(err)
|
||||
|
@ -56,7 +56,7 @@ PatternController.prototype.delete = (req, res) => {
|
|||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, async (err, user) => {
|
||||
if (err || user === null) return res.sendStatus(400)
|
||||
Pattern.deleteOne({ handle: req.params.handle, user: user.handle }, err => {
|
||||
Pattern.deleteOne({ handle: req.params.handle, user: user.handle }, (err) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
else return res.sendStatus(204)
|
||||
})
|
||||
|
@ -64,7 +64,7 @@ PatternController.prototype.delete = (req, res) => {
|
|||
}
|
||||
|
||||
// Delete multiple
|
||||
PatternController.prototype.deleteMultiple = function(req, res) {
|
||||
PatternController.prototype.deleteMultiple = function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
if (!req.body.patterns) return res.sendStatus(400)
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
|
@ -77,9 +77,9 @@ PatternController.prototype.deleteMultiple = function(req, res) {
|
|||
Pattern.deleteMany(
|
||||
{
|
||||
user: user.handle,
|
||||
$or: handles
|
||||
$or: handles,
|
||||
},
|
||||
err => {
|
||||
(err) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
const patterns = {}
|
||||
Patterns.find({ user: user.handle }, (err, patternList) => {
|
||||
|
@ -93,7 +93,7 @@ PatternController.prototype.deleteMultiple = function(req, res) {
|
|||
}
|
||||
|
||||
function saveAndReturnPattern(res, pattern) {
|
||||
pattern.save(function(err, updatedPattern) {
|
||||
pattern.save(function (err, updatedPattern) {
|
||||
if (err) {
|
||||
log.error('patternUpdateFailed', updatedPattern)
|
||||
return res.sendStatus(500)
|
||||
|
|
|
@ -4,7 +4,7 @@ import { log } from '../utils'
|
|||
function PersonController() {}
|
||||
|
||||
// CRUD basics
|
||||
PersonController.prototype.create = function(req, res) {
|
||||
PersonController.prototype.create = function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, user) => {
|
||||
|
@ -17,10 +17,10 @@ PersonController.prototype.create = function(req, res) {
|
|||
units: req.body.units,
|
||||
breasts: req.body.breasts,
|
||||
picture: handle + '.svg',
|
||||
created: new Date()
|
||||
created: new Date(),
|
||||
})
|
||||
person.createAvatar()
|
||||
person.save(function(err) {
|
||||
person.save(function (err) {
|
||||
if (err) return res.sendStatus(400)
|
||||
log.info('personCreated', { handle: handle })
|
||||
return res.send({ person: person.info() })
|
||||
|
@ -28,7 +28,7 @@ PersonController.prototype.create = function(req, res) {
|
|||
})
|
||||
}
|
||||
|
||||
PersonController.prototype.read = function(req, res) {
|
||||
PersonController.prototype.read = function (req, res) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, user) => {
|
||||
|
@ -56,7 +56,7 @@ PersonController.prototype.update = (req, res) => {
|
|||
if (typeof data.measurements !== 'undefined')
|
||||
person.measurements = {
|
||||
...person.measurements,
|
||||
...data.measurements
|
||||
...data.measurements,
|
||||
}
|
||||
if (typeof data.picture !== 'undefined') person.saveAvatar(data.picture)
|
||||
|
||||
|
@ -69,7 +69,7 @@ PersonController.prototype.delete = (req, res) => {
|
|||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, async (err, user) => {
|
||||
if (err || user === null) return res.sendStatus(400)
|
||||
Person.deleteOne({ handle: req.params.handle, user: user.handle }, err => {
|
||||
Person.deleteOne({ handle: req.params.handle, user: user.handle }, (err) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
else return res.sendStatus(204)
|
||||
})
|
||||
|
@ -77,10 +77,10 @@ PersonController.prototype.delete = (req, res) => {
|
|||
}
|
||||
|
||||
// Clone
|
||||
PersonController.prototype.clone = function(req, res) {}
|
||||
PersonController.prototype.clone = function (req, res) {}
|
||||
|
||||
function saveAndReturnPerson(res, person) {
|
||||
person.save(function(err, updatedPerson) {
|
||||
person.save(function (err, updatedPerson) {
|
||||
if (err) {
|
||||
log.error('personUpdateFailed', updatedPerson)
|
||||
return res.sendStatus(500)
|
||||
|
|
|
@ -11,11 +11,10 @@ const getToken = async () => {
|
|||
`${config.strapi.protocol}://${config.strapi.host}:${config.strapi.port}/auth/local`,
|
||||
{
|
||||
identifier: config.strapi.username,
|
||||
password: config.strapi.password
|
||||
password: config.strapi.password,
|
||||
}
|
||||
)
|
||||
}
|
||||
catch(err) {
|
||||
} catch (err) {
|
||||
console.log('ERROR: Failed to load strapi token')
|
||||
return false
|
||||
}
|
||||
|
@ -23,18 +22,18 @@ const getToken = async () => {
|
|||
return result.data.jwt
|
||||
}
|
||||
|
||||
const withToken = token => ({
|
||||
const withToken = (token) => ({
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const ext = type => {
|
||||
const ext = (type) => {
|
||||
switch (type.toLowerCase()) {
|
||||
case 'image/jpg':
|
||||
case 'image/jpeg':
|
||||
return 'jpg'
|
||||
break;
|
||||
break
|
||||
case 'image/png':
|
||||
return 'png'
|
||||
break
|
||||
|
@ -46,47 +45,45 @@ const ext = type => {
|
|||
}
|
||||
}
|
||||
|
||||
const api = path => `${config.strapi.protocol}://${config.strapi.host}:${config.strapi.port}${path}`
|
||||
|
||||
const api = (path) =>
|
||||
`${config.strapi.protocol}://${config.strapi.host}:${config.strapi.port}${path}`
|
||||
|
||||
// Uploads a picture to Strapi
|
||||
const uploadPicture = async (img, name, token) => {
|
||||
const form = new FormData()
|
||||
const buff = asBuffer(img)
|
||||
const extention = ext(buff.type)
|
||||
if (!extention) return [false, {error: `Filetype ${buff.type} is not supported`}]
|
||||
if (!extention) return [false, { error: `Filetype ${buff.type} is not supported` }]
|
||||
|
||||
// I hate you strapi, because this hack is the only way I can get your shitty upload to work
|
||||
const filename = `${config.strapi.tmp}/viaBackend.${extention}`
|
||||
const file = fs.createReadStream(filename)
|
||||
form.append('files', file)
|
||||
form.append('fileInfo', JSON.stringify({
|
||||
alternativeText: `The picture/avatar for maker ${name}`,
|
||||
caption: `Maker: ${name}`,
|
||||
}))
|
||||
form.append(
|
||||
'fileInfo',
|
||||
JSON.stringify({
|
||||
alternativeText: `The picture/avatar for maker ${name}`,
|
||||
caption: `Maker: ${name}`,
|
||||
})
|
||||
)
|
||||
|
||||
let result
|
||||
try {
|
||||
result = await axios.post(
|
||||
api('/upload'),
|
||||
form,
|
||||
{
|
||||
headers: {
|
||||
...form.getHeaders(),
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
catch (err) {
|
||||
console.log("ERROR: Failed to upload picture")
|
||||
return [false, {error: 'Upload failed'}]
|
||||
result = await axios.post(api('/upload'), form, {
|
||||
headers: {
|
||||
...form.getHeaders(),
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
console.log('ERROR: Failed to upload picture')
|
||||
return [false, { error: 'Upload failed' }]
|
||||
}
|
||||
|
||||
return [true, result.data]
|
||||
}
|
||||
|
||||
const validRequest = body => (
|
||||
const validRequest = (body) =>
|
||||
body &&
|
||||
body.displayname &&
|
||||
body.about &&
|
||||
|
@ -94,40 +91,36 @@ const validRequest = body => (
|
|||
typeof body.displayname === 'string' &&
|
||||
typeof body.about === 'string' &&
|
||||
typeof body.picture === 'string'
|
||||
)
|
||||
|
||||
|
||||
// Creates a maker or author in Strapi
|
||||
const createPerson = async (type, data, token) => {
|
||||
let result
|
||||
try {
|
||||
result = await axios.post(
|
||||
api(`/${type}s`),
|
||||
data,
|
||||
withToken(token)
|
||||
)
|
||||
}
|
||||
catch (err) {
|
||||
console.log("ERROR: Failed to create", type)
|
||||
return [false, {error: 'Creation failed'}]
|
||||
result = await axios.post(api(`/${type}s`), data, withToken(token))
|
||||
} catch (err) {
|
||||
console.log('ERROR: Failed to create', type)
|
||||
return [false, { error: 'Creation failed' }]
|
||||
}
|
||||
|
||||
return [true, result.data]
|
||||
|
||||
}
|
||||
function StrapiController() {}
|
||||
|
||||
StrapiController.prototype.addPerson = async function(req, res, type) {
|
||||
StrapiController.prototype.addPerson = async function (req, res, type) {
|
||||
if (!validRequest(req.body)) return res.sendStatus(400)
|
||||
const token = await getToken()
|
||||
const [upload, picture] = await uploadPicture(req.body.picture, req.body.displayname, token)
|
||||
if (!upload) return res.status(400).send(picture)
|
||||
|
||||
const [create, person] = await createPerson(type, {
|
||||
picture: picture[0].id,
|
||||
displayname: req.body.displayname,
|
||||
about: req.body.about,
|
||||
}, token)
|
||||
const [create, person] = await createPerson(
|
||||
type,
|
||||
{
|
||||
picture: picture[0].id,
|
||||
displayname: req.body.displayname,
|
||||
about: req.body.about,
|
||||
},
|
||||
token
|
||||
)
|
||||
if (!create) return res.status(400).send(person)
|
||||
|
||||
return res.send(person)
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
import { User, Confirmation, Person, Pattern } from '../models'
|
||||
import {
|
||||
log,
|
||||
email,
|
||||
ehash,
|
||||
newHandle,
|
||||
uniqueHandle,
|
||||
} from '../utils'
|
||||
import { log, email, ehash, newHandle, uniqueHandle } from '../utils'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import config from '../config'
|
||||
import path from 'path'
|
||||
|
@ -15,15 +9,15 @@ import rimraf from 'rimraf'
|
|||
|
||||
function UserController() {}
|
||||
|
||||
UserController.prototype.login = function(req, res) {
|
||||
UserController.prototype.login = function (req, res) {
|
||||
if (!req.body || !req.body.username) return res.sendStatus(400)
|
||||
User.findOne(
|
||||
{
|
||||
$or: [
|
||||
{ username: req.body.username.toLowerCase().trim() },
|
||||
{ username: req.body.username.trim() },
|
||||
{ ehash: ehash(req.body.username) }
|
||||
]
|
||||
{ ehash: ehash(req.body.username) },
|
||||
],
|
||||
},
|
||||
(err, user) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
|
@ -44,9 +38,7 @@ UserController.prototype.login = function(req, res) {
|
|||
Pattern.find({ user: user.handle }, (err, patternList) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
for (let pattern of patternList) patterns[pattern.handle] = pattern
|
||||
return user.updateLoginTime(() =>
|
||||
res.send({ account, people, patterns, token })
|
||||
)
|
||||
return user.updateLoginTime(() => res.send({ account, people, patterns, token }))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -60,7 +52,7 @@ UserController.prototype.login = function(req, res) {
|
|||
}
|
||||
|
||||
// For people who have forgotten their password, or password-less logins
|
||||
UserController.prototype.confirmationLogin = function(req, res) {
|
||||
UserController.prototype.confirmationLogin = function (req, res) {
|
||||
if (!req.body || !req.body.id) return res.sendStatus(400)
|
||||
Confirmation.findById(req.body.id, (err, confirmation) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
|
@ -83,9 +75,7 @@ UserController.prototype.confirmationLogin = function(req, res) {
|
|||
Pattern.find({ user: user.handle }, (err, patternList) => {
|
||||
if (err) return res.sendStatus(400)
|
||||
for (let pattern of patternList) patterns[pattern.handle] = pattern
|
||||
return user.updateLoginTime(() =>
|
||||
res.send({ account, people, patterns, token })
|
||||
)
|
||||
return user.updateLoginTime(() => res.send({ account, people, patterns, token }))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -112,7 +102,7 @@ UserController.prototype.create = (req, res) => {
|
|||
log.info('accountActivated', { handle: user.handle })
|
||||
let account = user.account()
|
||||
let token = getToken(account)
|
||||
user.save(function(err) {
|
||||
user.save(function (err) {
|
||||
if (err) return res.sendStatus(400)
|
||||
Confirmation.findByIdAndDelete(req.body.id, (err, confirmation) => {
|
||||
return res.send({ account, people: {}, patterns: {}, token })
|
||||
|
@ -164,7 +154,7 @@ UserController.prototype.update = (req, res) => {
|
|||
if (typeof data.settings !== 'undefined') {
|
||||
user.settings = {
|
||||
...user.settings,
|
||||
...data.settings
|
||||
...data.settings,
|
||||
}
|
||||
return saveAndReturnAccount(res, user)
|
||||
} else if (data.newsletter === true || data.newsletter === false) {
|
||||
|
@ -183,7 +173,7 @@ UserController.prototype.update = (req, res) => {
|
|||
} else if (typeof data.consent === 'object') {
|
||||
user.consent = {
|
||||
...user.consent,
|
||||
...data.consent
|
||||
...data.consent,
|
||||
}
|
||||
return saveAndReturnAccount(res, user)
|
||||
} else if (typeof data.avatar !== 'undefined') {
|
||||
|
@ -223,15 +213,15 @@ UserController.prototype.update = (req, res) => {
|
|||
language: user.settings.language,
|
||||
email: {
|
||||
new: req.body.email,
|
||||
current: user.email
|
||||
}
|
||||
}
|
||||
current: user.email,
|
||||
},
|
||||
},
|
||||
})
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
log.info('emailchangeRequest', {
|
||||
newEmail: req.body.email,
|
||||
confirmation: confirmation._id
|
||||
confirmation: confirmation._id,
|
||||
})
|
||||
email.emailchange(req.body.email, user.email, user.settings.language, confirmation._id)
|
||||
return saveAndReturnAccount(res, user)
|
||||
|
@ -242,7 +232,7 @@ UserController.prototype.update = (req, res) => {
|
|||
}
|
||||
|
||||
function saveAndReturnAccount(res, user) {
|
||||
user.save(function(err, updatedUser) {
|
||||
user.save(function (err, updatedUser) {
|
||||
if (err) {
|
||||
log.error('accountUpdateFailed', err)
|
||||
return res.sendStatus(500)
|
||||
|
@ -274,7 +264,7 @@ UserController.prototype.signup = (req, res) => {
|
|||
if (!req.body.language) return res.status(400).send('languageMissing')
|
||||
User.findOne(
|
||||
{
|
||||
ehash: ehash(req.body.email)
|
||||
ehash: ehash(req.body.email),
|
||||
},
|
||||
(err, user) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
|
@ -293,10 +283,10 @@ UserController.prototype.signup = (req, res) => {
|
|||
status: 'pending',
|
||||
picture: handle + '.svg',
|
||||
time: {
|
||||
created: new Date()
|
||||
}
|
||||
created: new Date(),
|
||||
},
|
||||
})
|
||||
user.save(function(err) {
|
||||
user.save(function (err) {
|
||||
if (err) {
|
||||
log.error('accountCreationFailed', user)
|
||||
console.log(err)
|
||||
|
@ -310,10 +300,10 @@ UserController.prototype.signup = (req, res) => {
|
|||
language: req.body.language,
|
||||
email: req.body.email,
|
||||
password: req.body.password,
|
||||
handle
|
||||
}
|
||||
handle,
|
||||
},
|
||||
})
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
log.info('signupRequest', { email: req.body.email, confirmation: confirmation._id })
|
||||
email.signup(req.body.email, req.body.language, confirmation._id)
|
||||
|
@ -332,7 +322,7 @@ UserController.prototype.resend = (req, res) => {
|
|||
if (!req.body.language) return res.status(400).send('languageMissing')
|
||||
User.findOne(
|
||||
{
|
||||
ehash: ehash(req.body.email)
|
||||
ehash: ehash(req.body.email),
|
||||
},
|
||||
(err, user) => {
|
||||
if (err) return res.sendStatus(500)
|
||||
|
@ -343,12 +333,15 @@ UserController.prototype.resend = (req, res) => {
|
|||
data: {
|
||||
language: req.body.language,
|
||||
email: user.email,
|
||||
handle: user.handle
|
||||
}
|
||||
handle: user.handle,
|
||||
},
|
||||
})
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
log.info('resendActivationRequest', { email: req.body.email, confirmation: confirmation._id })
|
||||
log.info('resendActivationRequest', {
|
||||
email: req.body.email,
|
||||
confirmation: confirmation._id,
|
||||
})
|
||||
email.signup(req.body.email, req.body.language, confirmation._id)
|
||||
return res.sendStatus(200)
|
||||
})
|
||||
|
@ -363,8 +356,8 @@ UserController.prototype.resetPassword = (req, res) => {
|
|||
{
|
||||
$or: [
|
||||
{ username: req.body.username.toLowerCase().trim() },
|
||||
{ ehash: ehash(req.body.username) }
|
||||
]
|
||||
{ ehash: ehash(req.body.username) },
|
||||
],
|
||||
},
|
||||
(err, user) => {
|
||||
if (err) {
|
||||
|
@ -375,10 +368,10 @@ UserController.prototype.resetPassword = (req, res) => {
|
|||
let confirmation = new Confirmation({
|
||||
type: 'passwordreset',
|
||||
data: {
|
||||
handle: user.handle
|
||||
}
|
||||
handle: user.handle,
|
||||
},
|
||||
})
|
||||
confirmation.save(function(err) {
|
||||
confirmation.save(function (err) {
|
||||
if (err) return res.sendStatus(500)
|
||||
log.info('passwordresetRequest', { user: user.handle, confirmation: confirmation._id })
|
||||
email.passwordreset(user.email, user.settings.language, confirmation._id)
|
||||
|
@ -398,7 +391,7 @@ UserController.prototype.setPassword = (req, res) => {
|
|||
if (user === null) return res.sendStatus(401)
|
||||
if (confirmation.type === 'passwordreset' && confirmation.data.handle === user.handle) {
|
||||
user.password = req.body.password
|
||||
user.save(function(err) {
|
||||
user.save(function (err) {
|
||||
log.info('passwordSet', { user, req })
|
||||
let account = user.account()
|
||||
let token = getToken(account)
|
||||
|
@ -433,7 +426,7 @@ UserController.prototype.patronList = (req, res) => {
|
|||
let patrons = {
|
||||
2: [],
|
||||
4: [],
|
||||
8: []
|
||||
8: [],
|
||||
}
|
||||
for (let key of Object.keys(users)) {
|
||||
let user = users[key].profile()
|
||||
|
@ -443,7 +436,7 @@ UserController.prototype.patronList = (req, res) => {
|
|||
bio: user.bio,
|
||||
picture: user.picture,
|
||||
social: user.social,
|
||||
pictureUris: user.pictureUris
|
||||
pictureUris: user.pictureUris,
|
||||
})
|
||||
}
|
||||
return res.send(patrons)
|
||||
|
@ -458,17 +451,17 @@ UserController.prototype.export = (req, res) => {
|
|||
if (!dir) return res.sendStatus(500)
|
||||
let zip = new Zip()
|
||||
zip.file('account.json', JSON.stringify(user.export(), null, 2))
|
||||
loadAvatar(user).then(avatar => {
|
||||
loadAvatar(user).then((avatar) => {
|
||||
if (avatar) zip.file(user.picture, data)
|
||||
zip
|
||||
.generateAsync({
|
||||
type: 'uint8array',
|
||||
comment: 'freesewing.org',
|
||||
streamFiles: true
|
||||
streamFiles: true,
|
||||
})
|
||||
.then(function(data) {
|
||||
.then(function (data) {
|
||||
let file = path.join(dir, 'export.zip')
|
||||
fs.writeFile(file, data, err => {
|
||||
fs.writeFile(file, data, (err) => {
|
||||
log.info('dataExport', { user, req })
|
||||
return res.send({ export: uri(file) })
|
||||
})
|
||||
|
@ -477,7 +470,7 @@ UserController.prototype.export = (req, res) => {
|
|||
})
|
||||
}
|
||||
|
||||
const loadAvatar = async user => {
|
||||
const loadAvatar = async (user) => {
|
||||
if (user.picture)
|
||||
await fs.readFile(path.join(user.storagePath(), user.picture), (err, data) => data)
|
||||
else return false
|
||||
|
@ -489,7 +482,7 @@ UserController.prototype.restrict = (req, res) => {
|
|||
User.findById(req.user._id, (err, user) => {
|
||||
if (user === null) return res.sendStatus(400)
|
||||
user.status = 'frozen'
|
||||
user.save(function(err) {
|
||||
user.save(function (err) {
|
||||
if (err) {
|
||||
log.error('accountFreezeFailed', user)
|
||||
return res.sendStatus(500)
|
||||
|
@ -504,7 +497,7 @@ UserController.prototype.remove = (req, res) => {
|
|||
if (!req.user._id) return res.sendStatus(400)
|
||||
User.findById(req.user._id, (err, user) => {
|
||||
if (user === null) return res.sendStatus(400)
|
||||
rimraf(user.storagePath(), err => {
|
||||
rimraf(user.storagePath(), (err) => {
|
||||
if (err) {
|
||||
console.log('rimraf', err)
|
||||
log.error('accountRemovalFailed', { err, user, req })
|
||||
|
@ -520,14 +513,14 @@ UserController.prototype.remove = (req, res) => {
|
|||
})
|
||||
}
|
||||
|
||||
const getToken = account => {
|
||||
const getToken = (account) => {
|
||||
return jwt.sign(
|
||||
{
|
||||
_id: account._id,
|
||||
handle: account.handle,
|
||||
role: account.role,
|
||||
aud: config.jwt.audience,
|
||||
iss: config.jwt.issuer
|
||||
iss: config.jwt.issuer,
|
||||
},
|
||||
config.jwt.secretOrKey
|
||||
)
|
||||
|
@ -535,7 +528,7 @@ const getToken = account => {
|
|||
|
||||
const createTempDir = () => {
|
||||
let path = temporaryStoragePath(newHandle(10))
|
||||
fs.mkdir(path, { recursive: true }, err => {
|
||||
fs.mkdir(path, { recursive: true }, (err) => {
|
||||
if (err) {
|
||||
log.error('mkdirFailed', err)
|
||||
path = false
|
||||
|
@ -545,6 +538,6 @@ const createTempDir = () => {
|
|||
return path
|
||||
}
|
||||
|
||||
const uri = path => config.static + path.substring(config.storage.length)
|
||||
const uri = (path) => config.static + path.substring(config.storage.length)
|
||||
|
||||
export default UserController
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='msg'>
|
||||
<div class="msg">
|
||||
<h1>Love the enthusiasm</h1>
|
||||
<p>But you were already subscribed</p>
|
||||
</div>
|
||||
|
|
|
@ -34,21 +34,24 @@
|
|||
max-width: 36ch;
|
||||
margin: 6rem auto;
|
||||
}
|
||||
a, a:visited, a:active {
|
||||
a,
|
||||
a:visited,
|
||||
a:active {
|
||||
color: #d0bfff !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='msg'>
|
||||
<div class="msg">
|
||||
<h1>Hi</h1>
|
||||
<p>
|
||||
This is the FreeSewing backend.
|
||||
<br>
|
||||
<br />
|
||||
Try <a href="https://freesewing.org/">freesewing.org</a> instead.
|
||||
</p>
|
||||
<p>For questions, join us at
|
||||
<p>
|
||||
For questions, join us at
|
||||
<a href="https://discord.freesewing.org/">discord.freesewing.org</a>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -34,18 +34,18 @@
|
|||
max-width: 36ch;
|
||||
margin: 6rem auto;
|
||||
}
|
||||
a, a:visited, a:active {
|
||||
a,
|
||||
a:visited,
|
||||
a:active {
|
||||
color: #d0bfff !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='msg'>
|
||||
<div class="msg">
|
||||
<h1>What are you doing?</h1>
|
||||
<p>
|
||||
Try <a href="https://freesewing.org/">freesewing.org</a> instead.
|
||||
</p>
|
||||
<p>Try <a href="https://freesewing.org/">freesewing.org</a> instead.</p>
|
||||
</div>
|
||||
<img src="https://freesewing.org/avatar.svg" />
|
||||
</body>
|
||||
|
|
|
@ -34,18 +34,18 @@
|
|||
max-width: 36ch;
|
||||
margin: 6rem auto;
|
||||
}
|
||||
a, a:visited, a:active {
|
||||
a,
|
||||
a:visited,
|
||||
a:active {
|
||||
color: #d0bfff !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='msg'>
|
||||
<div class="msg">
|
||||
<h1>Oops</h1>
|
||||
<p>
|
||||
That did not go as planned
|
||||
</p>
|
||||
<p>That did not go as planned</p>
|
||||
</div>
|
||||
<img src="https://freesewing.org/avatar.svg" />
|
||||
</body>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='msg'>
|
||||
<div class="msg">
|
||||
<h1>Done</h1>
|
||||
<p>You are now subscribed to the FreeSewing newsletter</p>
|
||||
</div>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='msg'>
|
||||
<div class="msg">
|
||||
<h1>Gone</h1>
|
||||
<p>You are no longer subscribed to the FreeSewing newsletter</p>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import bodyParser from 'body-parser'
|
||||
|
||||
export default app => {
|
||||
export default (app) => {
|
||||
app.use(bodyParser.json({ limit: '20mb' }))
|
||||
app.use(bodyParser.urlencoded({ extended: true }))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import cors from 'cors'
|
||||
|
||||
export default app => {
|
||||
export default (app) => {
|
||||
app.use(cors())
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue