Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Add mellow react #114

Merged
merged 81 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
8d09b97
chore(mellow-react): update dependencies
DominusKelvin Sep 18, 2024
66937f7
feat(mellow-react): add routes
DominusKelvin Sep 18, 2024
41dee08
feat(mellow-react): add actions
DominusKelvin Sep 18, 2024
9d250e5
feat(mellow-react): add helpers
DominusKelvin Sep 18, 2024
73bb85c
feat(mellow-react): add custom hook
DominusKelvin Sep 18, 2024
51555ab
feat(mellow-react): add sails mail
DominusKelvin Sep 18, 2024
83b5004
feat(mellow-react): add mail config
DominusKelvin Sep 18, 2024
cb83079
feat(mellow-vue): use integer id
DominusKelvin Sep 18, 2024
4662061
fix(mellow-react): add url back
DominusKelvin Sep 18, 2024
9ecf66e
feat(mellow-react): add User model
DominusKelvin Sep 18, 2024
4681f4c
feat(mellow-react): add policies
DominusKelvin Sep 18, 2024
8eee3b8
feat(mellow-react): register policy mappings
DominusKelvin Sep 18, 2024
dcd1199
feat(mellow-react): add test
DominusKelvin Sep 18, 2024
78e6523
feat(mellow-react): update jsconfig
DominusKelvin Sep 18, 2024
af373dd
feat(mellow-react): add progressbar color
DominusKelvin Sep 18, 2024
428de2f
feat(mellow-react): add GoogleButton
DominusKelvin Sep 18, 2024
e4236ff
feat(mellow-react): add homepage
DominusKelvin Sep 19, 2024
7fd0823
feat(mellow-react): setup tailwindcss
DominusKelvin Sep 19, 2024
b2b7b9c
chore(mellow-vue): revert to earliest version of prettier
DominusKelvin Sep 19, 2024
dc66763
feat(mellow-react): add GoogleButton.jsx
DominusKelvin Sep 19, 2024
8d78553
chore(mellow-react): update prettier-config.js
DominusKelvin Sep 19, 2024
c67c691
chore(mellow-react): remove typedoc
DominusKelvin Sep 19, 2024
2dee160
chore(mellow-vue): remove trailing space
DominusKelvin Sep 19, 2024
07de4eb
chore(mellow-vue): remove jsdoc
DominusKelvin Sep 19, 2024
948a5a1
chore(mellow-vue): prettier
DominusKelvin Sep 19, 2024
e93399e
chore(mellow-react): prettier
DominusKelvin Sep 19, 2024
31746e6
chore(mellow-react): prettier
DominusKelvin Sep 19, 2024
b9dc475
feat(mellow-react): work on InputBase component
DominusKelvin Sep 19, 2024
ab58142
feat(mellow-react): add InputText
DominusKelvin Sep 20, 2024
98eefd0
feat(mellow-react): add InputBase
DominusKelvin Sep 20, 2024
dc4d027
feat(mellow-react): add AppLayout
DominusKelvin Sep 20, 2024
06d1b73
feat(mellow-react): update homepage
DominusKelvin Sep 20, 2024
d1a7fc8
feat(mellow-react): rename to testing env
DominusKelvin Sep 20, 2024
1ce3cfe
fix(mellow-react): update environment
DominusKelvin Sep 20, 2024
2e2fe23
fix(mellow-vue): update type in InputEmail
DominusKelvin Sep 20, 2024
98e1392
feat(mellow-react): add InputEmail component
DominusKelvin Sep 20, 2024
2a19c59
feat(mellow-react): add InputPassword
DominusKelvin Sep 20, 2024
e098abf
feat(mellow-react): add InputButton
DominusKelvin Sep 20, 2024
7a16080
fix(mellow-react): remove unneeded markups
DominusKelvin Sep 20, 2024
fb001e0
fix(mellow-react): use ternary
DominusKelvin Sep 20, 2024
d5d0386
fix(mellow-react): passing in props
DominusKelvin Sep 20, 2024
5b46cdc
fix(mellow-vue): spread props
DominusKelvin Sep 20, 2024
03d3211
fix(mellow-react): remove manual value and onChange props
DominusKelvin Sep 20, 2024
efba971
fix(mellow-react): fix not passing the input value
DominusKelvin Sep 20, 2024
676a893
fix(mellow-react): resolve issue with check box
DominusKelvin Sep 20, 2024
0325037
feat(mellow-react): submit login form
DominusKelvin Sep 20, 2024
444843c
feat(mellow-react): add signup page
DominusKelvin Sep 20, 2024
0c4de36
feat(mellow-react): add check-email page
DominusKelvin Sep 20, 2024
3c360ac
feat(mellow-react): add success page
DominusKelvin Sep 20, 2024
bf4e16f
feat(mellow-react): add link-expired page
DominusKelvin Sep 20, 2024
f90149c
feat(mellow-vue): abstract style for inputs in input base
DominusKelvin Sep 20, 2024
c6a2de7
feat(mellow-vue): use components in forgot-password page
DominusKelvin Sep 20, 2024
9ede1cf
feat(mellow-react): add forgot-password page
DominusKelvin Sep 20, 2024
e357ca2
fix(mellow-vue): add email error
DominusKelvin Sep 20, 2024
ced9a4d
feat(mellow-react): add forgot-password page
DominusKelvin Sep 20, 2024
d296913
fix(mellow-react): fix wrong endpoint
DominusKelvin Sep 20, 2024
bd66dfa
feat(mellow-vue): proper usage of components
DominusKelvin Sep 20, 2024
c4a776a
feat(mellow-react): add and use label prop
DominusKelvin Sep 20, 2024
9224307
feat(mellow-react): add forms css
DominusKelvin Sep 20, 2024
36f9f6e
feat(mellow-react): add rest password page
DominusKelvin Sep 20, 2024
ee4400d
fix(mellow-react): remove wrong function call
DominusKelvin Sep 20, 2024
7cd8451
chore(mellow-react): remove component that no longer exist
DominusKelvin Sep 20, 2024
f78cd03
feat(mellow-react): add dashboard
DominusKelvin Sep 20, 2024
7d7a9be
feat(mellow-vue): move profile to dashboard
DominusKelvin Sep 20, 2024
ee25742
fix(mellow-vue): fix deprecation for back redirect usage
DominusKelvin Sep 20, 2024
bb7928b
chore(mellow-react): install sails-hook-organics
DominusKelvin Sep 20, 2024
cd07307
feat(mellow-react): fix depreaction warning for redirect usage
DominusKelvin Sep 20, 2024
0a1bb42
fix(mellow-react): rename dashboard to index
DominusKelvin Sep 20, 2024
101dfa2
feat(mellow-react): add custom configs
DominusKelvin Sep 20, 2024
1d515b5
feat(mellow-react): add email templates
DominusKelvin Sep 20, 2024
58dcd2d
feat(mellow-vue): go to dashboard/profile
DominusKelvin Sep 20, 2024
527c559
feat(mellow-vue): remove user/profile.vue
DominusKelvin Sep 20, 2024
35e4db7
feat(mellow-vue): remove unused config
DominusKelvin Sep 20, 2024
04327f9
feat(mellow-vue): use confirmPassword instead of passwordConfirmation
DominusKelvin Sep 20, 2024
a31491a
fix(mellow-react): use confirmPassword not passwordConfirmation
DominusKelvin Sep 20, 2024
871aa94
feat(mellow-react): use 'dashboard/profile'
DominusKelvin Sep 20, 2024
07248d8
fix(mellow-react): make it easy to merge classes
DominusKelvin Sep 20, 2024
7219d6c
feat(mellow-react): add profile page
DominusKelvin Sep 20, 2024
286bd38
feat(mellow-react): fix issues with updating fields
DominusKelvin Sep 20, 2024
b3fb75c
fix(mellow-react): changed to undefined for forms
DominusKelvin Sep 20, 2024
9737754
feat(mellow-vue): remove accessing user details with .value
DominusKelvin Sep 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions templates/mellow-react/api/controllers/auth/callback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
module.exports = {
friendlyName: 'Callback',

description: 'Callback auth.',

inputs: {
provider: {
isIn: ['google'],
required: true
},
code: {
type: 'string',
required: true
}
},

exits: {
success: {
responseType: 'redirect'
}
},
fn: async function ({ code, provider }, exits) {
const req = this.req
const googleUser = await sails.wish.provider(provider).user(code)

User.findOrCreate(
{ or: [{ googleId: googleUser.id }, { email: googleUser.email }] },
{
googleId: googleUser.id,
email: googleUser.email,
fullName: googleUser.name,
googleAvatarUrl: googleUser.picture,
googleAccessToken: googleUser.accessToken,
googleIdToken: googleUser.idToken,
emailStatus: googleUser.verified_email ? 'verified' : 'unverified'
}
).exec(async (error, user, wasCreated) => {
if (error) throw error

if (!wasCreated && googleUser.verified_email) {
await User.updateOne({ id: user.id }).set({
emailStatus: 'verified'
})
}
if (!wasCreated && user.googleId !== googleUser.id) {
// Checks if the user email has changed since last log in
// And then update the email change candidate which will be used be used to prompt the user to update their email
await User.updateOne({ id: user.id }).set({
emailChangeCandidate: googleUser.email
})
}
if (!wasCreated && user.email !== googleUser.email) {
// Checks if the user email has changed since last log in
// And then update the email change candidate which will be used be used to prompt the user to update their email
await User.updateOne({ id: user.id }).set({
emailChangeCandidate: googleUser.email
})
}

// Checks if the user name has changed since last log in
// And then update the name if changed
if (!wasCreated && user.fullName !== googleUser.name) {
await User.updateOne({ id: user.id }).set({
fullName: googleUser.name
})
}

if (!wasCreated && user.googleAvatarUrl !== googleUser.picture) {
await User.updateOne({ id: user.id }).set({
googleAvatarUrl: googleUser.picture
})
}

if (!wasCreated && user.googleAccessToken !== googleUser.accessToken) {
await User.updateOne({ id: user.id }).set({
googleAccessToken: googleUser.accessToken
})
}

if (!wasCreated && user.googleIdToken !== googleUser.idToken) {
await User.updateOne({ id: user.id }).set({
googleIdToken: googleUser.idToken
})
}

req.session.userId = user.id
const urlToRedirectTo = '/dashboard'
return exits.success(urlToRedirectTo)
})
}
}
53 changes: 53 additions & 0 deletions templates/mellow-react/api/controllers/auth/forgot-password.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module.exports = {
friendlyName: 'Forgot password',

description:
'Send a password recovery notification to the user with the specified email address.',

inputs: {
email: {
description:
'The email address of the alleged user who wants to recover their password.',
example: '[email protected]',
type: 'string',
required: true,
isEmail: true
}
},

exits: {
success: {
description:
'The email address might have matched a user in the database. (If so, a recovery email was sent.)',
responseType: 'redirect'
}
},

fn: async function ({ email }) {
const userExists = await User.count({ email: this.req.session.userEmail })
if (!userExists) {
return '/check-email'
}

const token = await sails.helpers.strings.random('url-friendly')

const user = await User.updateOne({ email }).set({
passwordResetToken: token,
passwordResetTokenExpiresAt:
Date.now() + sails.config.custom.passwordResetTokenTTL
})

await sails.helpers.mail.send.with({
to: user.email,
subject: 'Password reset instructions',
template: 'email-reset-password',
templateData: {
fullName: user.fullName,
token
}
})

this.req.session.userEmail = user.email
return '/check-email'
}
}
81 changes: 81 additions & 0 deletions templates/mellow-react/api/controllers/auth/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module.exports = {
friendlyName: 'Login',

description: 'Log in using the provided email and password combination.',

extendedDescription: `This action attempts to look up the user record in the database with the
specified email address. Then, if such a user exists, it uses
bcrypt to compare the hashed password from the database with the provided
password attempt.`,

inputs: {
email: {
description: 'The email to try in this attempt, e.g. "[email protected]".',
type: 'string',
isEmail: true,
required: true
},

password: {
description:
'The unencrypted password to try in this attempt, e.g. "passwordlol".',
type: 'string',
required: true
},

rememberMe: {
description: "Whether to extend the lifetime of the user's session.",
type: 'boolean'
}
},

exits: {
success: {
description: 'The requesting user agent has been successfully logged in.',
extendedDescription: `Under the covers, this stores the id of the logged-in user in the session
as the \`userId\` key. The next time this user agent sends a request, assuming
it includes a cookie (like a web browser), Sails will automatically make this
user id available as req.session.userId in the corresponding action. (Also note
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'
}
},

fn: async function ({ email, password, rememberMe }) {
const user = await User.findOne({
email: email.toLowerCase()
})

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

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 =
sails.config.custom.rememberMeCookieMaxAge
}

this.req.session.userId = user.id
return '/dashboard'
}
}
22 changes: 22 additions & 0 deletions templates/mellow-react/api/controllers/auth/redirect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module.exports = {
friendlyName: 'Redirect',

description: 'Redirect auth.',

inputs: {
provider: {
isIn: ['google'],
required: true
}
},

exits: {
success: {
responseType: 'redirect'
}
},

fn: async function ({ provider }) {
return sails.wish.provider(provider).redirect()
}
}
44 changes: 44 additions & 0 deletions templates/mellow-react/api/controllers/auth/resend-link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module.exports = {
friendlyName: 'Resend link',

description: '',

inputs: {},

exits: {
success: {
responseType: 'redirect'
},
userNotFound: {
responseType: 'notFound'
}
},

fn: async function () {
const userExists = await User.count({ email: this.req.session.userEmail })
if (!userExists) {
return '/check-email'
}
const unverifiedUser = await User.updateOne(this.req.session.userEmail).set(
{
emailStatus: 'unverified',
emailProofToken: sails.helpers.strings.random('url-friendly'),
emailProofTokenExpiresAt:
Date.now() + sails.config.custom.emailProofTokenTTL
}
)

this.req.session.userId = unverifiedUser.id

await sails.helpers.mail.send.with({
subject: 'Verify your email',
template: 'email-verify-account',
to: unverifiedUser.email,
templateData: {
token: unverifiedUser.emailProofToken,
fullName: unverifiedUser.fullName
}
})
return '/check-email'
}
}
58 changes: 58 additions & 0 deletions templates/mellow-react/api/controllers/auth/reset-password.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module.exports = {
friendlyName: 'Reset password',

description: '',

inputs: {
token: {
description: 'The verification token from the email.',
example: 'lyCap0N9i8wKYz7rhrEPog'
},
password: {
type: 'string',
required: true,
minLength: 8
}
},

exits: {
success: {
responseType: 'redirect'
},
invalidOrExpiredToken: {
responseType: 'expired',
description: 'The provided token is expired, invalid, or already used up.'
},
badSignupRequest: {
responseType: 'badRequest',
description:
'The provided fullName, password and/or email address are invalid.',
extendedDescription:
'If this request was sent from a graphical user interface, the request ' +
'parameters should have been validated/coerced _before_ they were sent.'
}
},

fn: async function ({ token, password }) {
if (!token) {
throw 'invalidOrExpiredToken'
}

const user = await User.findOne({ passwordResetToken: token })

if (!user || user.passwordResetTokenExpiresAt <= Date.now()) {
throw 'invalidOrExpiredToken'
}
await User.updateOne({ id: user.id }).set({
password,
passwordResetToken: '',
passwordResetTokenExpiresAt: 0
})

this.req.session.userId = user.id

delete this.req.session.userEmail

return '/reset-password/success'
}
}
Loading
Loading