Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 - 2024 Donald Pakkies
Copyright (c) 2021 - 2025 Donald Pakkies

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@formidablejs/framework",
"version": "0.27.6",
"version": "0.27.7",
"description": "Formidable Framework Core",
"author": "Donald Pakkies",
"license": "MIT",
Expand Down
11 changes: 7 additions & 4 deletions src/Auth/Auth.imba
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,24 @@ class Auth
let property = 'username'

if dbIdentifier === 'email'
user = await Database.table(dbTable).where('email', body.email).first!
user = await Database.table(dbTable).whereRaw('LOWER(email) = LOWER(?)', [body.email]).first!

property = 'email'

elif dbIdentifier === 'username'
user = await Database.table(dbTable).where('username', body.username).first!
user = await Database.table(dbTable).whereRaw('LOWER(username) = LOWER(?)', [body.username]).first!
elif dbIdentifier === 'username-email'
user = await Database.table(dbTable).where('username', body.username).orWhere('email', body.username).first!
user = await Database.table(dbTable)
.whereRaw('LOWER(username) = LOWER(?)', [body.username])
.orWhereRaw('LOWER(email) = LOWER(?)', [body.username])
.first!

if user && await Hash.check(body.password, user.password)
return user

throw ValidationException.withMessages({
[property]: [
'Invalid credentials'
"Invalid {dbIdentifier === 'email' ? 'Email' : 'Username'} or password."
]
})

Expand Down
16 changes: 8 additions & 8 deletions src/Auth/Drivers/Driver.imba
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export default class Driver

isValid.forEach do(field)
errors[field] = [
"The {field} is already taken."
"The {field} is invalid or has already taken."
]

throw ValidationException.withMessages(errors)
Expand All @@ -300,22 +300,22 @@ export default class Driver

if dbIdentifier == 'email'
const results = await Database.table(dbTable)
.where('email', body.email)
.whereRaw('LOWER(email) = LOWER(?)', [body.email])
.count!

return ['email'] if results[0]['count(*)'] > 0
return ['email'] if results[0]['count(*)'] > 0 || results[0]['count'] > 0

else
const [ emailResults, usernameResults ] = await Promise.all([
Database.table(dbTable).where('email', body.email).count!,
Database.table(dbTable).where('username', body.username).count!
Database.table(dbTable).whereRaw('LOWER(email) = LOWER(?)', [body.email]).count!,
Database.table(dbTable).whereRaw('LOWER(username) = LOWER(?)', [body.username]).count!
])

let fields = []

if emailResults[0]['count(*)'] > 0
if emailResults[0]['count(*)'] > 0 || emailResults[0]['count'] > 0
fields.push('email')
elif usernameResults[0]['count(*)'] > 0
elif usernameResults[0]['count(*)'] > 0 || usernameResults[0]['count'] > 0
fields.push('username')

return fields if fields.length > 0
Expand Down Expand Up @@ -352,7 +352,7 @@ export default class Driver

def findUser body\object
return await Database.table(self.getProvider.table)
.where('email', body.email)
.whereRaw('LOWER(email) = LOWER(?)', [body.email])
.first!

def verificationUrl user\object
Expand Down
135 changes: 0 additions & 135 deletions src/Support/Decorators/tsUse.imba

This file was deleted.

31 changes: 20 additions & 11 deletions src/Support/Decorators/use.imba
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import isEmpty from '../Helpers/isEmpty'
import isString from '../Helpers/isString'
import die from '../Helpers/die'
import Request from '../../Http/Request/Request'
import ResponseFactory from '../../Http/Response/Response'
import ValidationException from '../../Validator/Exceptions/ValidationException'

def use target, key, descriptor
def DI target, key, descriptor, paramaters = null
if isClass target then return

const value = descriptor.value
const definition = this
const definition = paramaters ?? this

const config = {
reply: null
Expand All @@ -34,11 +35,11 @@ def use target, key, descriptor

config.request = request

await definition.forEach do(object, key)
for own key, object of definition
let response = null

if isString(object) && object.substring(0, 'table:'.length) === 'table:'
response = bind(object.split(':')[1]).handle(request, key)
response = await bind(object.split(':')[1]).handle(request, key)

elif isString(object) && object.substring(0, 'query:'.length) === 'query:'
const query = object.split(':')[1]
Expand Down Expand Up @@ -68,13 +69,13 @@ def use target, key, descriptor
response = param

elif object instanceof Bind
response = object.handle(request, key)
response = await object.handle(request, key)

elif Repository.isPrototypeOf(object)
const param = Object.values(request.params!)[key] || undefined
const repo = new object

const results = repo.table.where(repo.routeKeyName || 'id', param).first!
const results = await repo.table.where(repo.routeKeyName || 'id', param).first!

response = results

Expand Down Expand Up @@ -114,12 +115,13 @@ def use target, key, descriptor

const validator = response.validate!

if (validator.fails!)
throw ValidationException.withMessages(validator.errors.errors)
await new Promise do(resolve, reject)
validator.checkAsync
do resolve!
do reject(ValidationException.withMessages(validator.errors.errors))

if response.hasHeader('X-FORMIDABLE-VALIDATE')
die do
reply.send().code(204)
die do new ResponseFactory('', 204)

else
response = !!object.prototype && !!object.prototype.constructor.name ? new object : object
Expand All @@ -133,4 +135,11 @@ def use target, key, descriptor

return descriptor

exports.@use = use

def typescriptDI ...paramaters
return do(target, key, descriptor)
DI(target, key, descriptor, paramaters)

exports.DI = DI
exports.use = typescriptDI
exports.@use = DI
43 changes: 42 additions & 1 deletion src/Validator/ValidationServiceResolver.imba
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import DB from '../Database/Database'
import ServiceResolver from '../Support/ServiceResolver'
import Validator from './Validator'

Expand All @@ -10,15 +11,55 @@ export default class ValidationServiceResolver < ServiceResolver

def register
Validator.get!.register 'nullable', self.nullable, ''
Validator.get!.registerAsync 'unique', self.unique
Validator.get!.registerAsync 'exists', self.exists

def nullable
true

def unique value\string, definition\string, field\string, passes\CallableFunction
let [
table,
column = field,
ignore = null
] = definition.split(',')

let results

if ignore
const [
identifierValue,
identifierColumn = 'id'
] = ignore.split(':')

results = await DB.table(table)
.whereRaw("LOWER({column}) = LOWER(?) AND {identifierColumn} != ?", [ value, identifierValue ])
.first!
else
results = await DB.table(table)
.whereRaw("LOWER({column}) = LOWER(?)", [ value ])
.first!

passes(!results, "The {field} has already been taken.")

def exists value\string, definition\string, field\string, passes\CallableFunction
let [
table,
column = field,
ignore = null
] = definition.split(',')

const results = await DB.table(table)
.whereRaw("LOWER({field}) = LOWER(?)", [value])
.first()

passes(results ? true : false, "The selected {field} is invalid.")

def registeredRules
{ }

def registerRules rules\object
Object.keys(rules).forEach do(name)
Validator.get!.registerAsync(name, rules[name].handler)
Validator.get!.registerAsync(name, rules[name])

this
3 changes: 1 addition & 2 deletions src/index.imba
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { @context, context } from './Support/Decorators/context'
import { @use } from './Support/Decorators/use'
import { @use, use } from './Support/Decorators/use'
import { Command } from './Foundation/Console/Command'
import { Context } from './Foundation/Context'
import { FastifyReply, FastifyRequest, RequestGenericInterface, FastifyInstance } from 'fastify'
import { handleException, handleMaintenanceMode } from './Foundation/Exceptions/Handler/handleException'
import { Mail, MailServiceResolver } from '@formidablejs/mailer'
import { Mailable } from './Mail/Mailable'
import { Prop } from '@formidablejs/console'
import { use } from './Support/Decorators/tsUse'
import * as helpers from './Support/Helpers/index'
import AcceptLanguage from './Support/Language/Middleware/AcceptLanguage'
import Application from './Foundation/Application'
Expand Down
4 changes: 2 additions & 2 deletions types/Http/Request/ValidationRules.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ type Rules =
'accepted' | `after:${string}` | `after_or_equal:${string}` | 'alpha' | `alpha_dash` | 'alpha_num' |
'array' | `before:${string}` | `before_or_equal:${string}` | `between:${number|string},${number|string}`|
'boolean' | 'confirmed' | 'date' | `digits:${number}` | `digits_between:${number},${number}` |
`different:${string}` | 'email' | 'file' | `file_size:${number}` | 'hex' | 'image' | `in:${any}` |
`different:${string}` | 'email' | `exists:${string}` | 'file' | `file_size:${number}` | 'hex' | 'image' | `in:${any}` |
'integer' | `max:${number}` | `min:${number}` | `mimetype:${string}` | `mimes:${string}` | `not_in:${string}` |
'number' | 'present' | 'required' | `required_if:${string}` | `required_unless:${string}` |
`required_with:${string}` | `required_with_all:${string}` | `required_without:${string}` |
`required_without_all:${string}` | `same:${string}` | `size:${string}` | 'string' | 'url' | `regex:${string}` |
`required_without_all:${string}` | `same:${string}` | `size:${string}` | 'string' | `unique:${string}` | 'url' | `regex:${string}` |
'video'

type ValidationRules<T = void> = {
Expand Down
1 change: 0 additions & 1 deletion types/Support/Decorators/tsUse.d.ts

This file was deleted.

Loading