npmrun 2 years ago
parent
commit
bbe1f8628a
  1. 5
      package.json
  2. 6
      packages/hapi-router/dist/hapi-router.cjs.js
  3. 2
      packages/hapi-router/dist/hapi-router.cjs.js.map
  4. 4
      packages/hapi-router/dist/index.d.ts
  5. 7
      packages/hapi-router/src/index.ts
  6. 3
      packages/hapi-router/src/util/decorators.ts
  7. 14
      patches/hapi-sequelizejs@4.5.0.patch
  8. 10
      readme.md
  9. 13
      route.txt
  10. 3
      source/auth/index.ts
  11. BIN
      source/db/data.db
  12. 52
      source/models/User.ts
  13. 8
      source/plugins/index.ts
  14. 8
      source/route/views/index.ts
  15. 9
      source/route/views/user.ts
  16. 6
      source/run.ts
  17. 5
      template/views/index.pug
  18. 2
      template/views/user.pug
  19. 7
      types/global.d.ts

5
package.json

@ -64,5 +64,10 @@
"tsc-alias": "^1.7.0",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.3.2"
},
"pnpm": {
"patchedDependencies": {
"hapi-sequelizejs@4.5.0": "patches/hapi-sequelizejs@4.5.0.patch"
}
}
}

6
packages/hapi-router/dist/hapi-router.cjs.js

@ -327,6 +327,8 @@ var routePlugin = (function () {
}
}
if (validateObj && !!Object.keys(validateObj).length) {
var failReason_1 = validateObj.failReason;
delete validateObj.failReason;
if (validateObj.failAction === "log") {
if (!options.log)
options.log = {};
@ -345,7 +347,7 @@ var routePlugin = (function () {
request = argus[0];
h = argus[1];
if (request.logs && !!request.logs.length && errto_1) {
request.yar.flash('error', request.logs.map(function (v) { return v.error.message; }));
request.yar.flash('error', failReason_1);
return [2, h.redirect(errto_1)];
}
return [4, ff_1.call.apply(ff_1, __spread([this], argus))];
@ -381,7 +383,7 @@ var routePlugin = (function () {
h = argus[1];
if (request.$joi_error) {
loggerSite.debug('传输参数错误: ', request.$joi_error);
request.yar.flash('error', request.$joi_error);
request.yar.flash('error', failReason_1);
delete request.$joi_error;
return [2, h.redirect(errto_2)];
}

2
packages/hapi-router/dist/hapi-router.cjs.js.map

File diff suppressed because one or more lines are too long

4
packages/hapi-router/dist/index.d.ts

@ -13,11 +13,13 @@ declare module '@noderun/hapi-router' {
}
declare module '@noderun/hapi-router/util/decorators' {
export function method(opts?: string | Array<string>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
type TMethod = "GET" | "POST" | "PUT" | "DELETE";
export function method(opts?: TMethod | Array<TMethod>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function route(route?: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function config(options: Object): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function auth(isAuth?: boolean | "try" | "required" | "optional"): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function validate(validate: Object): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function swagger(desc: any, notes: any, tags: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export {};
}

7
packages/hapi-router/src/index.ts

@ -106,6 +106,8 @@ class routePlugin {
}
}
if (validateObj&&!!Object.keys(validateObj).length) {
const failReason = validateObj.failReason
delete validateObj.failReason
if(validateObj.failAction === "log"){
if(!options.log) options.log = {}
options.log.collect = true
@ -114,7 +116,8 @@ class routePlugin {
const request = argus[0]
const h = argus[1]
if(request.logs&&!!request.logs.length && errto){
request.yar.flash('error', request.logs.map((v: any)=>v.error.message));
// request.yar.flash('error', request.logs.map((v: any)=>v.error.message));
request.yar.flash('error', failReason);
return h.redirect(errto);
}
return await ff.call(this, ...argus)
@ -133,7 +136,7 @@ class routePlugin {
const h = argus[1]
if(request.$joi_error){
loggerSite.debug('传输参数错误: ', request.$joi_error)
request.yar.flash('error', request.$joi_error);
request.yar.flash('error', failReason);
delete request.$joi_error
return h.redirect(errto);
}

3
packages/hapi-router/src/util/decorators.ts

@ -3,7 +3,8 @@
*
* @param opts
*/
export function method(opts?:string|Array<string>) {
type TMethod = "GET" | "POST" | "PUT" | "DELETE"
export function method(opts?:TMethod|Array<TMethod>) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$method = opts
}

14
patches/hapi-sequelizejs@4.5.0.patch

@ -0,0 +1,14 @@
diff --git a/lib/models.js b/lib/models.js
index f545bf6e0fb2cab3cf9e39408f0552b35ee7a955..11591b2096df7d9c06e06a89fd2d80b846933933 100644
--- a/lib/models.js
+++ b/lib/models.js
@@ -40,7 +40,8 @@ async function load(files, sequelize) {
return files.reduce((acc, file) => {
const models = {};
const filepath = Path.isAbsolute(file) ? file : Path.join(process.cwd(), file);
- const Model = require(filepath)(sequelize, sequelize.Sequelize.DataTypes);
+ const m = require(filepath)
+ const Model = (m.default || m)(sequelize, sequelize.Sequelize.DataTypes);
models[Model.name] = Model;
return Object.assign({}, acc, models);
}, {});

10
readme.md

@ -15,4 +15,12 @@
## 对于验证库的处理方式参考
https://docs4dev.com/questions/345443
https://github.com/nelsonic/hapi-validation-question
https://github.com/nelsonic/hapi-validation-question
## 缓存
https://github.com/hapijs/catbox-redis/blob/master/test/cluster.js
https://hapi.dev/module/catbox/api/?v=12.1.0
https://juejin.cn/post/7067093432737398792

13
route.txt

@ -1,15 +1,6 @@
D:\@code\project\hapi-demo\source\route\api对应路径:
不需权限 : GET /api/{path*}
需要权限 : GET /api/v1/upload
需要权限 : POST /api/v1/upload/upload
不需权限 : POST /api/v1/user/register
需要权限 : POST /api/v1/user/logout
不需权限 : POST /api/v1/user/login
需要权限 : DELETE /api/v1/user/del
需要权限 : GET /api/v1/user/userinfo
D:\@code\project\hapi-demo\source\route\htmx对应路径:
D:\1XYX\demo\hapi-demo\source\route\htmx对应路径:
不需权限 : GET /htmx/clicked
D:\@code\project\hapi-demo\source\route\views对应路径:
D:\1XYX\demo\hapi-demo\source\route\views对应路径:
不需权限(提供无需验证): GET /404
不需权限 : GET /css
不需权限(提供无需验证): GET /

3
source/auth/index.ts

@ -14,9 +14,6 @@ export async function validateJwt(decoded, request: Req, h) {
}
export async function validateSession(request: Req, session) {
console.log(request.path);
console.log(session);
console.log(`session id: ${session.id}`);
const User = request.getModel("User")
if (session.id) {
const result = await User.findOne({ where: { id: session.id } });

BIN
source/db/data.db

Binary file not shown.

52
source/models/User.ts

@ -1,5 +1,41 @@
module.exports = function (sequelize, DataTypes) {
const User = sequelize.define('User', {
import { Sequelize, DataTypes, Optional, Model } from "sequelize"
interface UserAttributes {
id: number;
username: string;
password: string;
nickname: string;
email: string;
createdAt?: Date;
updatedAt?: Date;
deletedAt?: Date;
}
export interface UserInput extends Optional<UserAttributes, 'id'> { }
export interface UserOuput extends Required<UserAttributes> { }
export type TUserModel = ReturnType<typeof UserModel>
type DT = typeof DataTypes
export default function UserModel(sequelize: Sequelize, DataTypes: DT) {
class User extends Model<UserAttributes, UserInput> implements UserAttributes {
public id: number;
public username: string;
public password: string;
public nickname: string;
public email: string;
// timestamps!
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
public readonly deletedAt!: Date;
}
User.init({
id: {
type: DataTypes.INTEGER.UNSIGNED,
autoIncrement: true,
primaryKey: true,
},
username: {
type: DataTypes.STRING,
allowNull: false
@ -15,8 +51,14 @@ module.exports = function (sequelize, DataTypes) {
email: {
type: DataTypes.STRING,
}
}, {
});
}, {
sequelize,
timestamps: true,
paranoid: true // 对模型施加了一个软删除
})
// 覆盖User的toJSON方法
interface User{
toJSON: ()=> UserOuput
}
return User
};

8
source/plugins/index.ts

@ -61,10 +61,10 @@ export default [
options: {
auth: ['/api'],
sourceDir: [
{
dir: path.resolve(sourceDir, "route/api"),
prefix: "api"
},
// {
// dir: path.resolve(sourceDir, "route/api"),
// prefix: "api"
// },
{
dir: path.resolve(sourceDir, "route/htmx"),
prefix: "htmx"

8
source/route/views/index.ts

@ -24,16 +24,13 @@ export default class {
payload: LoginUserSchema,
$errto: '/login',
// failAction: 'log'
failAction: 'function'
failAction: 'function',
failReason: '用户名或密码错误,请重试',
})
@method("POST")
@route("/login")
async login_POST(request: Req, h: Res): ReturnValue {
const { username, password, referrer } = request.payload as any;
if(!username || !password ){
request.yar.flash('error', 'username or password can not be empty.');
return h.redirect("/login");
}
const User = request.getModel("User");
const account = <any>await User.findOne({ where: { username: username } });
@ -42,7 +39,6 @@ export default class {
return h.redirect("/login");
}
request.cookieAuth.set({ id: account.id, nickname: account.nickname });
console.log(account.nickname);
request.yar.flash('success', '用户已登录');
return h.redirect(referrer ? referrer : "/");
}

9
source/route/views/user.ts

@ -12,13 +12,12 @@ export default class {
async index(request: Req, h: Res): ReturnValue {
const { id } = request.auth.credentials
const User = request.getModel("User")
let result = <any>await User.findOne({ where: { id: id } })
let result = await User.findOne({ where: { id: id } })
if (result == null) {
return gFail(null, "不存在该用户")
}
result = result.toJSON()
delete result.password
console.log(result);
return h.view("views/user.pug", { userinfo: result })
const userinfo = result.toJSON()
delete userinfo.password
return h.view("views/user.pug", { userinfo })
}
}

6
source/run.ts

@ -31,8 +31,8 @@ const run = async (): Promise<Server> => {
logging: false,
// logging: loggerSQL.debug.bind(loggerSQL) // Alternative way to use custom logger, displays all messages
}), // sequelize instance
// sync: true, // sync models - default false
// forceSync: false, // force sync (drops tables) - default false
sync: true, // sync models - default false
forceSync: false, // force sync (drops tables) - default false
},
],
},
@ -139,7 +139,7 @@ const run = async (): Promise<Server> => {
};
process.on("unhandledRejection", (err) => {
console.log("hh:", err);
console.log("unhandledRejection:", err);
process.exit(1);
});

5
template/views/index.pug

@ -17,3 +17,8 @@ block content
| !
if isLogin
button(hx-get="/htmx/clicked" hx-push-url="/about" hx-trigger="click" hx-target="this" hx-swap="outerHTML") Click Me!
<form action="/api/v1/upload/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file" multiple />
+security
<button type="submit" id="upload">上传</button>
</form>

2
template/views/user.pug

@ -9,5 +9,7 @@ block head
block content
section.section
.container
div nickname: #{user.nickname}
div email: #{user.email}
div username: #{user.username}
div id: #{user.id}

7
types/global.d.ts

@ -2,6 +2,7 @@ import { Logger } from "log4js";
import { Server } from "@hapi/hapi";
import { Request, ResponseToolkit, Lifecycle } from "@hapi/hapi";
import { Model, ModelCtor } from "Sequelize";
import { TUserModel } from "@/models/User";
declare global {
var server: Server;
@ -10,9 +11,13 @@ declare global {
var loggerSQL: Logger;
}
interface Models {
"User": TUserModel
}
declare module '@hapi/hapi' {
interface Request {
getModel<T extends {} = any, M extends {} = any>(name: string): ModelCtor<Model<T, M>>
getModel<T extends keyof Models, M extends Models[T]>(name: T): M
}
interface ResponseToolkit {

Loading…
Cancel
Save