Skip to content

Commit

Permalink
Merge branch 'release/0.1.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
DominusKelvin committed Feb 22, 2024
2 parents 5a44d35 + 57d7337 commit 0cf48d8
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 73 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ To launch the respective templates on StackBlitz, click on the 'Open in StackBli

## Docs

[Read the docs](https://docs.sailscasts.com).
[Read the docs](https://docs.sailscasts.com/boring-stack/).

## Support

Expand Down
5 changes: 5 additions & 0 deletions create-sails/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
"bugs": {
"url": "https://github.com/sailscastshq/boring-stack/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/sailscastshq/boring-stack.git",
"directory": "packages/create-sails"
},
"homepage": "https://github.com/sailscastshq/boring-stack/tree/main/create-sails#readme",
"engines": {
"node": "^14.13.1 || >=16.0.0"
Expand Down
8 changes: 5 additions & 3 deletions inertia-sails/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "inertia-sails",
"version": "0.1.7",
"version": "0.1.8",
"description": "The Sails adapter for Inertia.",
"main": "index.js",
"sails": {
Expand All @@ -13,10 +13,12 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/sailscastshq/inertia-sails.git"
"url": "git+https://github.com/sailscastshq/boring-stack.git",
"directory": "packages/inertia-sails"
},
"peerDependencies": {
"sails": ">=1"
"sails": ">=1",
"sails-flash": ">=0.0.1"
},
"keywords": [
"Inertia",
Expand Down
41 changes: 29 additions & 12 deletions inertia-sails/private/inertia-middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,27 @@ const getPartialData = require('./get-partial-data')
const resolveValidationErrors = require('./resolve-validation-errors')
function inertia(sails, { hook, sharedProps, sharedViewData, rootView }) {
return function inertiaMiddleware(req, res, next) {
hook.share('errors', resolveValidationErrors(req))
/**
* Flash messages stored in the session.
* @typedef {Object} FlashMessages
* @property {Array} message - Flash message(s).
* @property {Array} error - Error message(s).
* @property {Array} success - Success message(s).
*/
const flash = {
message: req.flash('message'),
error: req.flash('error'),
success: req.flash('success')
}
hook.share('flash', flash) // Share the flash object as props
/**
* Validation errors stored in the session, resolved and formatted for Inertia.js.
* @type {Object}
*/
const validationErrors = resolveValidationErrors(req)
req.flash('errors', validationErrors) // Flash the validation error so we can share it later

hook.share('errors', req.flash('errors')[0] || {}) // Share validation errors as props

hook.render = function (component, props = {}, viewData = {}) {
const allProps = {
Expand Down Expand Up @@ -49,14 +69,16 @@ function inertia(sails, { hook, sharedProps, sharedViewData, rootView }) {
}

if (isInertiaRequest(req)) {
res.set(INERTIA, true)
res.set('Vary', 'Accept')
return res.json(page)
} else {
// Implements full page reload
return sails.hooks.views.render(rootView, {
page,
viewData: allViewData
})
}

// Implements full page reload
return sails.hooks.views.render(rootView, {
page,
viewData: allViewData
})
}
/**
* Handle 303 and external redirects
Expand All @@ -73,11 +95,6 @@ function inertia(sails, { hook, sharedProps, sharedViewData, rootView }) {
)
}

if (isInertiaRequest(req)) {
res.set(INERTIA, true)
res.set('Vary', 'Accept')
}

return next()
}
}
Expand Down
2 changes: 1 addition & 1 deletion inertia-sails/private/resolve-validation-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ module.exports = function resolveValidationErrors(req) {
const defaultErrors = { default: collectedErrors.default }
return defaultErrors
}

delete req.session.errors
return collectedErrors
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "boring-stack",
"version": "0.1.2",
"version": "0.1.3",
"private": "true",
"description": "The Boring JavaScript Stack 🥱 - an opinionated project starter for fullstack JavaScript",
"scripts": {
Expand Down
23 changes: 19 additions & 4 deletions templates/mellow-vue/api/controllers/auth/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ password attempt.`,
email: {
description: 'The email to try in this attempt, e.g. "[email protected]".',
type: 'string',
isEmail: true,
required: true
},

Expand Down Expand Up @@ -39,6 +40,9 @@ that, thanks to the included "custom" hook, when a relevant request is received
from a logged-in user, that user's entire record from the database will be fetched
and exposed as a shared data via loggedInUser prop.)`,
responseType: 'redirect'
},
badCombo: {
responseType: 'badRequest'
}
},

Expand All @@ -48,12 +52,23 @@ and exposed as a shared data via loggedInUser prop.)`,
})

if (!user) {
throw 'badCombo'
throw {
badCombo: {
problems: [{ login: 'Wrong email/password.' }]
}
}
}

await sails.helpers.passwords
.checkPassword(password, user.password)
.intercept('incorrect', 'badCombo')
try {
await sails.helpers.passwords.checkPassword(password, user.password)
} catch (e) {
sails.log.error(e.message)
throw {
badCombo: {
problems: [{ login: 'Wrong email/password.' }]
}
}
}

if (rememberMe) {
this.req.session.cookie.maxAge =
Expand Down
49 changes: 28 additions & 21 deletions templates/mellow-vue/api/controllers/auth/signup.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ module.exports = {
'If this request was sent from a graphical user interface, the request ' +
'parameters should have been validated/coerced _before_ they were sent.'
},
emailAlreadyInUse: {
statusCode: 409,
viewTemplatePath: '500',
description: 'The email address is no longer available.',
extendedDescription:
'This is an edge case that is not always anticipated by websites and APIs. Since it is pretty rare, the 500 server error page is used as a simple catch-all. If this becomes important in the future, this could easily be expanded into a custom error page or resolution flow. But for context: this behavior of showing the 500 server error page mimics how popular apps like Slack behave under the same circumstances.'
},
success: {
responseType: 'redirect'
}
Expand All @@ -45,26 +38,40 @@ module.exports = {
fn: async function ({ fullName, email: userEmail, password }) {
const email = userEmail.toLowerCase()

const unverifiedUser = await User.create({
email,
password,
fullName,
tosAcceptedByIp: this.req.ip,
emailProofToken: sails.helpers.strings.random('url-friendly'),
emailProofTokenExpiresAt:
Date.now() + sails.config.custom.emailProofTokenTTL
})
.intercept('E_UNIQUE', 'emailAlreadyInUse')
.intercept({ name: 'UsageError' }, () => {
try {
unverifiedUser = await User.create({
email,
password,
fullName,
tosAcceptedByIp: this.req.ip,
emailProofToken: sails.helpers.strings.random('url-friendly'),
emailProofTokenExpiresAt:
Date.now() + sails.config.custom.emailProofTokenTTL
}).fetch()
} catch (error) {
if (error.code === 'E_UNIQUE') {
throw {
badSignupRequest: {
problems: [
`"signup" Apologies, but something went wrong with signing you up. Please try again.`
{
email: 'An account with this email address already exists.'
}
]
}
}
})
.fetch()
} else if (error.name === 'UsageError') {
throw {
badSignupRequest: {
problems: [
{
signup:
'Apologies, but something went wrong with signing you up. Please try again.'
}
]
}
}
}
}

this.req.session.userEmail = unverifiedUser.email

Expand Down
49 changes: 27 additions & 22 deletions templates/mellow-vue/api/responses/badRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,39 @@ module.exports = function badRequest(optionalData) {

// Check if it's an Inertia request
if (req.header('X-Inertia')) {
console.log(optionalData)
if (
optionalData &&
optionalData.code &&
(optionalData.code === 'E_MISSING_OR_INVALID_PARAMS' ||
optionalData.name === 'UsageError')
) {
if (optionalData && optionalData.problems) {
const errors = {}
optionalData.problems.forEach((problem) => {
const regex = /"(.*?)"/
const matches = problem.match(regex)
if (typeof problem === 'object') {
Object.keys(problem).forEach((propertyName) => {
const sanitizedProblem = problem[propertyName].replace(/\.$/, '') // Trim trailing dot
if (!errors[propertyName]) {
errors[propertyName] = [sanitizedProblem]
} else {
errors[propertyName].push(sanitizedProblem)
}
})
} else {
const regex = /"(.*?)"/
const matches = problem.match(regex)

if (matches && matches.length > 1) {
const propertyName = matches[1]
const sanitizedProblem = problem.replace(/"([^"]+)"/, '$1')
if (!errors[propertyName]) {
errors[propertyName] = [sanitizedProblem]
} else {
errors[propertyName].push(sanitizedProblem)
if (matches && matches.length > 1) {
const propertyName = matches[1]
const sanitizedProblem = problem
.replace(/"([^"]+)"/, '$1')
.replace('\n', '')
.replace('·', '')
.trim()
if (!errors[propertyName]) {
errors[propertyName] = [sanitizedProblem]
} else {
errors[propertyName].push(sanitizedProblem)
}
}
}
})

if (req.session) {
req.session.errors = errors
}

return res.status(statusCodeToSet).redirect('back')
req.session.errors = errors
return res.redirect(303, 'back')
}
}

Expand Down
9 changes: 8 additions & 1 deletion templates/mellow-vue/assets/js/pages/login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ const disableLoginButton = computed(() => {
<h1 class="text-2xl">Log into your account</h1>
<p class="text-lg text-gray">Welcome back, please enter your details</p>
</section>
<p
class="b my-4 rounded-sm border-red-400 bg-red-100 p-4 text-red-500"
v-if="form.errors.email || form.errors.login"
>
{{ form.errors?.login || form.errors?.email }}
</p>

<form
@submit.prevent="form.post('/login')"
class="mb-4 flex flex-col space-y-6"
Expand All @@ -74,7 +81,7 @@ const disableLoginButton = computed(() => {
</svg>
</span>
<input
type="email"
type="text"
id="email"
placeholder="Your email"
class="block w-full rounded-lg border border-gray/50 bg-white py-3 pl-10 pr-3 shadow-sm placeholder:text-lg placeholder:text-gray focus:outline-none focus:ring-1 focus:ring-gray-100"
Expand Down
15 changes: 15 additions & 0 deletions templates/mellow-vue/assets/js/pages/signup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ const disableSignupButton = computed(() => {
Welcome! Please enter your details to sign up
</p>
</section>
<p
class="b my-4 rounded-sm border-red-400 bg-red-100 p-4 text-red-500"
v-if="form.errors.signup"
>
{{ form.errors?.signup }}
</p>
<form
@submit.prevent="form.post('/signup')"
class="mb-4 flex flex-col space-y-6"
Expand Down Expand Up @@ -101,6 +107,9 @@ const disableSignupButton = computed(() => {
class="block w-full rounded-lg border border-gray/50 bg-white py-3 pl-10 pr-3 shadow-sm placeholder:text-lg placeholder:text-gray focus:outline-none focus:ring-1 focus:ring-gray-100"
v-model="form.fullName"
/>
<p class="absolute text-red-500" v-if="form.errors.fullName">
{{ form.errors.fullName }}
</p>
</label>
<label for="email" class="relative block"
><span class="block text-lg">Email</span>
Expand All @@ -124,6 +133,9 @@ const disableSignupButton = computed(() => {
class="block w-full rounded-lg border border-gray/50 bg-white py-3 pl-10 pr-3 shadow-sm placeholder:text-lg placeholder:text-gray focus:outline-none focus:ring-1 focus:ring-gray-100"
v-model="form.email"
/>
<p class="absolute text-red-500" v-if="form.errors.email">
{{ form.errors.email }}
</p>
</label>
<label for="password" class="relative block"
><span class="block text-lg">Password</span>
Expand Down Expand Up @@ -214,6 +226,9 @@ const disableSignupButton = computed(() => {
</svg>
</button>
</span>
<p class="absolute text-red-500" v-if="form.errors.password">
{{ form.errors.password }}
</p>
</label>
<ul class="flex justify-between text-sm">
<li
Expand Down
2 changes: 1 addition & 1 deletion templates/mellow-vue/jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// silences wrong TS error, we don't compile, we only typecheck
"outDir": "./irrelevant/unused",
"allowJs": true,
"checkJs": true,
"checkJs": false,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
Expand Down
Loading

0 comments on commit 0cf48d8

Please sign in to comment.