Create InjectSession & PersistSession modules; update session model
This commit is contained in:
parent
25a37cf1a2
commit
a6995c6a85
@ -5,3 +5,4 @@ export { default as MiddlewareUnit } from '../../lib/src/unit/Middlewares.ts'
|
|||||||
export { default as RoutesUnit } from '../../lib/src/unit/Routes.ts'
|
export { default as RoutesUnit } from '../../lib/src/unit/Routes.ts'
|
||||||
export { default as HttpKernelUnit } from '../../lib/src/unit/HttpKernel.ts'
|
export { default as HttpKernelUnit } from '../../lib/src/unit/HttpKernel.ts'
|
||||||
export { default as ModelsUnit } from '../../orm/src/ModelsUnit.ts'
|
export { default as ModelsUnit } from '../../orm/src/ModelsUnit.ts'
|
||||||
|
export { default as HttpServerUnit } from '../../lib/src/unit/HttpServer.ts'
|
||||||
|
@ -4,13 +4,13 @@ import {SessionModel} from '../../../lib/src/module.ts'
|
|||||||
|
|
||||||
export default class Session extends SessionModel {
|
export default class Session extends SessionModel {
|
||||||
protected static table = 'sessions'
|
protected static table = 'sessions'
|
||||||
protected static key = 'session_id'
|
protected static key = 'session_key'
|
||||||
|
|
||||||
protected static readonly CREATED_AT = 'start_time'
|
protected static readonly CREATED_AT = 'start_time'
|
||||||
protected static readonly UPDATED_AT = null // No updated at
|
protected static readonly UPDATED_AT = null // No updated at
|
||||||
|
|
||||||
@Field(Type.int)
|
@Field(Type.varchar)
|
||||||
protected session_id!: number
|
protected session_key!: string
|
||||||
|
|
||||||
@Field(Type.int)
|
@Field(Type.int)
|
||||||
protected user_id?: number
|
protected user_id?: number
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
ConfigUnit, DatabaseUnit, ControllerUnit, MiddlewareUnit, RoutesUnit, HttpKernelUnit, ModelsUnit
|
ConfigUnit, DatabaseUnit, ControllerUnit, MiddlewareUnit, RoutesUnit, HttpKernelUnit, ModelsUnit, HttpServerUnit
|
||||||
} from './bundle/daton_units.ts'
|
} from './bundle/daton_units.ts'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
@ -10,4 +10,5 @@ export default [
|
|||||||
MiddlewareUnit,
|
MiddlewareUnit,
|
||||||
ControllerUnit,
|
ControllerUnit,
|
||||||
RoutesUnit,
|
RoutesUnit,
|
||||||
|
HttpServerUnit,
|
||||||
]
|
]
|
||||||
|
@ -4,6 +4,7 @@ import { Response } from './Response.ts'
|
|||||||
import { HTTPResponse } from './type/HTTPResponse.ts'
|
import { HTTPResponse } from './type/HTTPResponse.ts'
|
||||||
import Utility from '../service/utility/Utility.ts'
|
import Utility from '../service/utility/Utility.ts'
|
||||||
import { Injectable } from '../../../di/src/decorator/Injection.ts'
|
import { Injectable } from '../../../di/src/decorator/Injection.ts'
|
||||||
|
import SessionInterface from './session/SessionInterface.ts'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Request implements HTTPRequest {
|
export class Request implements HTTPRequest {
|
||||||
@ -11,6 +12,7 @@ export class Request implements HTTPRequest {
|
|||||||
private readonly _deno_req: ServerRequest
|
private readonly _deno_req: ServerRequest
|
||||||
private _body: any
|
private _body: any
|
||||||
private _query: { [key: string]: any } = {}
|
private _query: { [key: string]: any } = {}
|
||||||
|
private _session!: SessionInterface
|
||||||
|
|
||||||
public readonly url: string
|
public readonly url: string
|
||||||
public readonly method: string
|
public readonly method: string
|
||||||
@ -30,6 +32,14 @@ export class Request implements HTTPRequest {
|
|||||||
return this.response.cookies
|
return this.response.cookies
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get session(): SessionInterface {
|
||||||
|
return this._session
|
||||||
|
}
|
||||||
|
|
||||||
|
set session(session: SessionInterface) {
|
||||||
|
this._session = session
|
||||||
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected utility: Utility,
|
protected utility: Utility,
|
||||||
from: ServerRequest
|
from: ServerRequest
|
||||||
|
59
lib/src/http/kernel/module/InjectSession.ts
Normal file
59
lib/src/http/kernel/module/InjectSession.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import Module from '../Module.ts'
|
||||||
|
import Kernel from '../Kernel.ts'
|
||||||
|
import {Request} from '../../Request.ts'
|
||||||
|
import SetSessionCookie from './SetSessionCookie.ts'
|
||||||
|
import SessionManager from '../../session/SessionManager.ts'
|
||||||
|
import {Logging} from '../../../service/logging/Logging.ts'
|
||||||
|
import {Injectable} from '../../../../../di/src/decorator/Injection.ts'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class InjectSession extends Module {
|
||||||
|
public static register(kernel: Kernel) {
|
||||||
|
kernel.register(this).after(SetSessionCookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected readonly sessions: SessionManager,
|
||||||
|
protected readonly logger: Logging,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async apply(request: Request): Promise<Request> {
|
||||||
|
if ( request.session ) return request
|
||||||
|
|
||||||
|
let key: string | undefined
|
||||||
|
try {
|
||||||
|
const result = await request.cookies.get('daton.session')
|
||||||
|
key = result?.value
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error('Invalid Daton session cookie. The session will not be injected.')
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.logger.debug(`Cookie: ${await request.cookies.get_raw('daton.session')}`)
|
||||||
|
} catch (e2) {}
|
||||||
|
|
||||||
|
this.logger.debug(e)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !key ) {
|
||||||
|
this.logger.warn(`No session key was found. Is the SetSessionCookie module registered?`)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
const has_existing = await this.sessions.has_session(key)
|
||||||
|
if ( has_existing ) {
|
||||||
|
request.session = await this.sessions.get_session(key)
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
|
||||||
|
const new_session = await this.sessions.get_session()
|
||||||
|
this.logger.verbose(`Populating new session: ${key}`)
|
||||||
|
new_session.set_key(key)
|
||||||
|
await new_session.persist()
|
||||||
|
request.session = new_session
|
||||||
|
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
}
|
14
lib/src/http/kernel/module/PersistSession.ts
Normal file
14
lib/src/http/kernel/module/PersistSession.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import Module from '../Module.ts'
|
||||||
|
import Kernel from '../Kernel.ts'
|
||||||
|
import {Request} from '../../Request.ts'
|
||||||
|
|
||||||
|
export default class PersistSession extends Module {
|
||||||
|
public static register(kernel: Kernel) {
|
||||||
|
kernel.register(this).last()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async apply(request: Request): Promise<Request> {
|
||||||
|
await request.session.persist()
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ export default class SetSessionCookie extends Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected utility: Utility,
|
protected readonly utility: Utility,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,10 @@ export default class ModelSessionManager extends SessionManager {
|
|||||||
public async has_session(key: string): Promise<boolean> {
|
public async has_session(key: string): Promise<boolean> {
|
||||||
const ModelClass: typeof Model = this.ModelClass as typeof Model
|
const ModelClass: typeof Model = this.ModelClass as typeof Model
|
||||||
|
|
||||||
return ModelClass.select(ModelClass.qualified_key_name())
|
const query = ModelClass.select(ModelClass.qualified_key_name())
|
||||||
.where(ModelClass.qualified_key_name(), '=', key)
|
.where(ModelClass.qualified_key_name(), '=', key)
|
||||||
.exists()
|
|
||||||
|
return await query.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async purge(key?: string): Promise<void> {
|
public async purge(key?: string): Promise<void> {
|
||||||
|
@ -4,6 +4,7 @@ import {Field} from '../../../../orm/src/model/Field.ts'
|
|||||||
import {Type} from '../../../../orm/src/db/types.ts'
|
import {Type} from '../../../../orm/src/db/types.ts'
|
||||||
|
|
||||||
export default class SessionModel extends Model<SessionModel> implements SessionInterface {
|
export default class SessionModel extends Model<SessionModel> implements SessionInterface {
|
||||||
|
protected static populate_key_on_insert: boolean = true
|
||||||
|
|
||||||
@Field(Type.json)
|
@Field(Type.json)
|
||||||
protected data?: string
|
protected data?: string
|
||||||
@ -14,7 +15,7 @@ export default class SessionModel extends Model<SessionModel> implements Session
|
|||||||
|
|
||||||
public set_key(key: string) {
|
public set_key(key: string) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this[this.key_name()] = parseInt(key)
|
this[this.key_name()] = key
|
||||||
}
|
}
|
||||||
|
|
||||||
public async persist(): Promise<void> {
|
public async persist(): Promise<void> {
|
||||||
@ -42,6 +43,5 @@ export default class SessionModel extends Model<SessionModel> implements Session
|
|||||||
|
|
||||||
public async init_session(): Promise<void> {
|
public async init_session(): Promise<void> {
|
||||||
this.data = JSON.stringify({})
|
this.data = JSON.stringify({})
|
||||||
await this.save()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ServerRequest } from '../../external/http.ts'
|
import { ServerRequest } from '../../external/http.ts'
|
||||||
import {HTTPResponse} from "./HTTPResponse.ts";
|
import {HTTPResponse} from './HTTPResponse.ts'
|
||||||
|
import SessionInterface from '../session/SessionInterface.ts'
|
||||||
|
|
||||||
export interface HTTPProtocol {
|
export interface HTTPProtocol {
|
||||||
string: string,
|
string: string,
|
||||||
@ -27,4 +28,6 @@ export interface HTTPRequest {
|
|||||||
query: any
|
query: any
|
||||||
hostname: string | undefined
|
hostname: string | undefined
|
||||||
secure: boolean
|
secure: boolean
|
||||||
|
|
||||||
|
session: SessionInterface,
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ import {StaticClass} from '../../../di/src/type/StaticClass.ts'
|
|||||||
import ModelSessionFactory from '../http/session/ModelSessionFactory.ts'
|
import ModelSessionFactory from '../http/session/ModelSessionFactory.ts'
|
||||||
import ModelSessionManagerFactory from '../http/session/ModelSessionManagerFactory.ts'
|
import ModelSessionManagerFactory from '../http/session/ModelSessionManagerFactory.ts'
|
||||||
import SessionInterface from '../http/session/SessionInterface.ts'
|
import SessionInterface from '../http/session/SessionInterface.ts'
|
||||||
|
import InjectSession from '../http/kernel/module/InjectSession.ts'
|
||||||
|
import PersistSession from '../http/kernel/module/PersistSession.ts'
|
||||||
|
|
||||||
@Unit()
|
@Unit()
|
||||||
export default class HttpKernel extends LifecycleUnit {
|
export default class HttpKernel extends LifecycleUnit {
|
||||||
@ -29,21 +31,23 @@ export default class HttpKernel extends LifecycleUnit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async up() {
|
public async up() {
|
||||||
|
this.determine_session_provider()
|
||||||
|
|
||||||
PrepareRequest.register(this.kernel)
|
PrepareRequest.register(this.kernel)
|
||||||
SetSessionCookie.register(this.kernel)
|
SetSessionCookie.register(this.kernel)
|
||||||
|
InjectSession.register(this.kernel)
|
||||||
|
PersistSession.register(this.kernel)
|
||||||
|
|
||||||
if ( this.config.get('server.powered_by.enable') ) {
|
if ( this.config.get('server.powered_by.enable') ) {
|
||||||
SetDatonHeaders.register(this.kernel)
|
SetDatonHeaders.register(this.kernel)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.determine_session_provider()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected determine_session_provider() {
|
protected determine_session_provider() {
|
||||||
const driver = this.config.get('server.session.driver')
|
const driver = this.config.get('server.session.driver')
|
||||||
|
|
||||||
if ( driver === 'memory' ) {
|
if ( driver === 'memory' ) {
|
||||||
this.logger.verbose('Adding the memory session production factories to the container...')
|
this.logger.info('Adding the memory session production factories to the container...')
|
||||||
this.injector.register_factory(new MemorySessionFactory())
|
this.injector.register_factory(new MemorySessionFactory())
|
||||||
this.injector.register_factory(new MemorySessionManagerFactory())
|
this.injector.register_factory(new MemorySessionManagerFactory())
|
||||||
} else if ( driver === 'database' ) {
|
} else if ( driver === 'database' ) {
|
||||||
|
32
lib/src/unit/HttpServer.ts
Normal file
32
lib/src/unit/HttpServer.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import LifecycleUnit from '../lifecycle/Unit.ts'
|
||||||
|
import {Unit} from '../lifecycle/decorators.ts'
|
||||||
|
import Kernel from '../http/kernel/Kernel.ts'
|
||||||
|
import {Logging} from '../service/logging/Logging.ts'
|
||||||
|
import {serve} from '../external/http.ts'
|
||||||
|
import {Request} from '../http/Request.ts'
|
||||||
|
|
||||||
|
@Unit()
|
||||||
|
export default class HttpServer extends LifecycleUnit {
|
||||||
|
protected _server: any // TODO replace with more specific type
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected readonly kernel: Kernel,
|
||||||
|
protected readonly logger: Logging,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async up() {
|
||||||
|
this._server = serve({ port: 8000 })
|
||||||
|
|
||||||
|
this.logger.success(`HTTP/S server listening on port 8000!`)
|
||||||
|
|
||||||
|
for await ( const native_request of this._server ) {
|
||||||
|
let req: Request = this.make(Request, native_request)
|
||||||
|
req = await this.kernel.handle(req)
|
||||||
|
|
||||||
|
req.response.body = req.session.get_key()
|
||||||
|
req.response.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ export default class PostgresConnection extends Connection {
|
|||||||
|
|
||||||
public async query(query: string) {
|
public async query(query: string) {
|
||||||
if ( !this._client ) throw new ConnectionNotReadyError(this.name)
|
if ( !this._client ) throw new ConnectionNotReadyError(this.name)
|
||||||
|
logger.verbose(`Executing query: \n${query}`)
|
||||||
const result = await this._client.query(query)
|
const result = await this._client.query(query)
|
||||||
|
|
||||||
let base_i = 0
|
let base_i = 0
|
||||||
|
@ -38,6 +38,11 @@ export abstract class Model<T extends Model<T>> extends Builder<T> {
|
|||||||
*/
|
*/
|
||||||
protected static key: string
|
protected static key: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If false (default), the primary key will be excluded from INSERTs.
|
||||||
|
*/
|
||||||
|
protected static populate_key_on_insert: boolean = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optionally, the timestamp field set on creation.
|
* Optionally, the timestamp field set on creation.
|
||||||
* @type string
|
* @type string
|
||||||
@ -642,7 +647,11 @@ export abstract class Model<T extends Model<T>> extends Builder<T> {
|
|||||||
* @return FieldValueObject
|
* @return FieldValueObject
|
||||||
*/
|
*/
|
||||||
protected _build_insert_field_object(): FieldValueObject {
|
protected _build_insert_field_object(): FieldValueObject {
|
||||||
const fields = this.field_defs().whereNot('model_key', '=', this.key_name())
|
let fields = this.field_defs()
|
||||||
|
|
||||||
|
if ( !(this.constructor as typeof Model).populate_key_on_insert )
|
||||||
|
fields = fields.whereNot('model_key', '=', this.key_name())
|
||||||
|
|
||||||
const values = {}
|
const values = {}
|
||||||
fields.each(field_def => {
|
fields.each(field_def => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
Loading…
Reference in New Issue
Block a user