library-ts/node/users/RequestHandler.ts

195 lines
4.5 KiB
TypeScript

import { RJLog } from "../log/RJLog";
import { RequestRequirement } from "./requirements/RequestRequirement";
import { UserManagementServer } from "./UserManagementServer";
import { FastifyRequest, FastifyReply } from 'fastify';
import { Message } from "../../browser/messages/Message";
import { UserData } from "./UserData";
import { UAParser } from 'ua-parser-js';
import { LocationData } from "./location/LocationData";
import { className } from "../../browser/tools/TypeUtilities";
export enum RequestType
{
GET,
POST
}
export abstract class RequestHandler
{
_ums:UserManagementServer;
get ums(){ return this._ums; };
_type:RequestType;
_url:string;
requirements:RequestRequirement[] = [];
get app(){ return this._ums.app };
get userDB(){ return this._ums.userDB; }
constructor( rt:RequestType, url:string, requirements:RequestRequirement[] = [] )
{
this._url = url;
this._type = rt;
this.requirements = requirements;
}
async initialize( ums:UserManagementServer ):Promise<void>
{
this._ums = ums;
await this._initialize();
await this._register();
for ( let r of this.requirements )
{
await r.initialize( this );
}
return Promise.resolve();
}
protected _register():Promise<void>
{
RJLog.log( RequestType[ this._type ], this._url );
if ( RequestType.GET == this._type )
{
this.app.get( this._url, ( request, reply ) => { this.handle( request, reply ); } );
}
else if ( RequestType.POST == this._type )
{
this.app.post( this._url, ( request, reply ) => { this.handle( request, reply ); } );
}
return Promise.resolve();
}
protected _currentRequest:FastifyRequest;
protected _currentReply:FastifyReply;
async handle( request:FastifyRequest, reply:FastifyReply ):Promise<void>
{
if ( ! request || ! reply )
{
RJLog.warn( "Aborting request:", "Request:", ! request, "Reply:", ! reply );
return Promise.resolve();
}
this._currentRequest = request;
this._currentReply = reply;
RJLog.log( "Processing request:", "Request:", request.url, request.ip );
for ( let r of this._ums.globalRequirements )
{
let messages = await r.handle( request, reply );
if ( Message.hasError( messages ) )
{
RJLog.log( "Global Requirement not fullfilled: ", className( r ), messages.map( m => JSON.stringify( m ) ).join( ", " ) );
return this.sendError( "Error during global requirements check" );
}
}
for ( let r of this.requirements )
{
let messages = await r.handle( request, reply );
if ( Message.hasError( messages ) )
{
RJLog.log( messages[ 0 ].content );
RJLog.log( "Requirement not fullfilled: ", className( r ), messages.map( m => JSON.stringify( m ) ).join( ", " ) );
return this.sendError( "Error during requirements check" );
}
}
await this._handle( request, reply );
this._currentRequest = null;
this._currentReply = null;
return Promise.resolve();
}
protected _initialize():Promise<void>
{
return Promise.resolve();
};
protected abstract _handle( request:FastifyRequest, reply:FastifyReply ):Promise<void>;
get ip()
{
return this._currentRequest.ip;
}
get userAgent()
{
return this._currentRequest.headers[ "user-agent" ];
}
getLocation():Promise<LocationData>
{
return this._ums.location.getLocation( this.ip );
}
protected sendJSON( obj:any ):Promise<void>
{
this._currentReply.send( obj );
return Promise.resolve();
}
getUser():Promise<UserData>
{
let request = this._currentRequest;
let requestBody = request.body;
let tokenData = requestBody as { token:string };
let tokenID = tokenData.token;
let session = this._ums._sessions.get( tokenID );
return this._ums.userDB.byID( session.userID );
}
protected sendInfo( info:string ):Promise<void>
{
RJLog.log( info );
return this.sendJSON( Message.Info( info ) );
}
protected sendError( error:string, with400ErrorCode:boolean = true ):Promise<void>
{
RJLog.log( error );
if ( with400ErrorCode )
{
this._currentReply.code( 400 );
}
return this.sendJSON( Message.Error( error ) );
}
protected sendEmail( to:string, title:string, message:string )
{
this._ums.sendEmail( to, title, message );
}
protected sendDataInfo( info:string, data:any )
{
let json = Message.Info( info ) as any;
json.data = data;
return this.sendJSON( json );
}
}