Skip to content

Commit

Permalink
Refactor: backend (#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
marihachi authored Nov 30, 2024
1 parent 980aea8 commit 0a50071
Show file tree
Hide file tree
Showing 22 changed files with 445 additions and 440 deletions.
8 changes: 0 additions & 8 deletions backend/src/modules/entities.ts

This file was deleted.

6 changes: 3 additions & 3 deletions backend/src/modules/httpRoute/ApiRouteBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import express from "express";
import { Container } from "inversify";
import { UserEntity } from "../entities";
import { UserObject } from "../valueObject";
import { authenticate } from "./authentication";
import { ApiRouteContext } from "./ApiRouteContext";

Expand Down Expand Up @@ -70,10 +70,10 @@ function createMiddlewareStack<R>(
}

// ハンドラ用の認証情報
let user: UserEntity | undefined;
let user: UserObject | undefined;
let scopes: string[] | undefined;
if (req.authInfo != null) {
user = req.user as UserEntity;
user = req.user as UserObject;
scopes = (req.authInfo as { scope: string[] }).scope;
}

Expand Down
8 changes: 4 additions & 4 deletions backend/src/modules/httpRoute/ApiRouteContext.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import express from "express";
import z from 'zod';
import { UserEntity } from "../entities";
import { UserObject } from "../valueObject";
import { appError, BadRequest } from "../appErrors";
import { Container } from "inversify";

export class ApiRouteContext {
private _user: UserEntity | undefined;
private _user: UserObject | undefined;
private _scopes: string[] | undefined;
constructor(
public params: unknown,
public container: Container,
public req: express.Request,
public res: express.Response,
user: UserEntity | undefined,
user: UserObject | undefined,
scopes: string[] | undefined,
) {
this._user = user;
this._scopes = scopes;
}

public getUser(): UserEntity {
public getUser(): UserObject {
if (this._user == null) throw new Error('not authenticated');
return this._user;
}
Expand Down
7 changes: 7 additions & 0 deletions backend/src/modules/valueObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { components } from '../../openapi/generated/schema';

export type TokenObject = components['schemas']['Api.v1.Token'];
export type UserObject = components['schemas']['Api.v1.User'];
export type AuthResultObject = components['schemas']['Api.v1.AuthInfo'];
export type LeafObject = components['schemas']['Api.v1.Leaf'];
export type ChatRoomObject = components['schemas']['Api.v1.ChatRoom'];
55 changes: 20 additions & 35 deletions backend/src/repositories/LeafRepository.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { leaf } from "@prisma/client";
import * as sql from "@prisma/client/sql";
import { Container } from "inversify";
import { TYPES } from "../container/types";
import { AccessContext } from "../modules/AccessContext";
import { DB } from "../modules/db";
import { LeafEntity } from "../modules/entities";

export type LeafEntity = {
leafId: string,
leafKind: string,
userId: string,
chatRoomId?: string,
createdAt: string,
content: string,
};

/**
* 投稿を作成する
Expand All @@ -23,7 +30,7 @@ export async function createTimelineLeaf(
},
});

return mapEntity(row);
return toEntity(row);
}

/**
Expand All @@ -44,13 +51,13 @@ export async function createChatLeaf(
},
});

return mapEntity(row);
return toEntity(row);
}

/**
* 投稿を取得する
*/
export async function get(
export async function getLeaf(
params: { leafId: string },
ctx: AccessContext,
container: Container,
Expand All @@ -66,54 +73,32 @@ export async function get(
return undefined;
}

return mapEntity(row);
}

/**
* タイムラインを取得する\
* prevCursorとnextCursorはleafIdを指定します。
*/
export async function fetchHomeTimeline(
params: { kind: string, prevCursor?: string, nextCursor?: string, limit?: number },
ctx: AccessContext,
container: Container,
): Promise<LeafEntity[]> {
const db = container.get<DB>(TYPES.db);
const limit = params.limit ?? 50;
if (params.nextCursor != null) {
const rows = await db.$queryRawTyped(sql.fetchHomeTimelineNextCursor(ctx.userId, params.nextCursor, limit));
rows.reverse();
return rows.map(x => mapEntity(x));
} else if (params.prevCursor != null) {
const rows = await db.$queryRawTyped(sql.fetchHomeTimelinePrevCursor(ctx.userId, params.prevCursor, limit));
return rows.map(x => mapEntity(x));
} else {
const rows = await db.$queryRawTyped(sql.fetchHomeTimelineLatest(ctx.userId, limit));
return rows.map(x => mapEntity(x));
}
return toEntity(row);
}

/**
* 投稿を削除する
* @returns 削除に成功したかどうか
*/
export async function remove(
export async function deleteLeaf(
params: { leafId: string },
ctx: AccessContext,
container: Container,
): Promise<boolean> {
): Promise<void> {
const db = container.get<DB>(TYPES.db);
const result = await db.leaf.deleteMany({
where: {
leaf_id: params.leafId,
},
});
return (result.count > 0);
if (result.count == 0) {
throw new Error('failed to remove a resource.');
}
}

function mapEntity(row: leaf): LeafEntity {
export function toEntity(row: leaf): LeafEntity {
const leaf: LeafEntity = {
leafId: row.leaf_id,
leafKind: row.leaf_kind,
userId: row.user_id,
createdAt: row.created_at.toJSON(),
content: row.content,
Expand Down
24 changes: 12 additions & 12 deletions backend/src/repositories/PasswordVerificationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import { TYPES } from "../container/types";
import { AccessContext } from "../modules/AccessContext";
import { DB } from "../modules/db";

export type PasswordVerificationEntity = {
userId: string,
algorithm: string,
salt: string,
iteration: number,
hash: string,
};

/*
* パスワード検証情報を追加する
*/
export async function create(
export async function createVerification(
params: { userId: string, algorithm: string, salt: string, iteration: number, hash: string },
ctx: AccessContext,
container: Container,
Expand All @@ -29,7 +37,7 @@ export async function create(
/*
* パスワード検証情報を取得する
*/
export async function get(
export async function getVerification(
params: { userId: string },
ctx: AccessContext,
container: Container,
Expand All @@ -48,19 +56,11 @@ export async function get(
return mapEntity(row);
}

export type PasswordVerificationEntity = {
userId: string,
algorithm: string,
salt: string,
iteration: number,
hash: string,
};

/**
* パスワード検証情報を削除する
* @returns 削除に成功したかどうか
*/
export async function remove(
export async function deleteVerification(
params: { userId: string },
ctx: AccessContext,
container: Container,
Expand All @@ -75,7 +75,7 @@ export async function remove(
return (result.count > 0);
}

function mapEntity(row: password_verification): PasswordVerificationEntity {
export function mapEntity(row: password_verification): PasswordVerificationEntity {
return {
userId: row.user_id,
algorithm: row.algorithm,
Expand Down
12 changes: 8 additions & 4 deletions backend/src/repositories/TokenRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import { Container } from "inversify";
import { TYPES } from "../container/types";
import { AccessContext } from "../modules/AccessContext";
import { DB } from "../modules/db";
import { TokenEntity } from "../modules/entities";

export type TokenKind = "access_token" | "refresh_token";

export type TokenEntity = {
token: string;
scopes: string[];
};

/**
* トークン情報を追加する
*/
export async function create(
export async function createToken(
params: { userId: string, tokenKind: TokenKind, scopes: string[], token: string, },
ctx: AccessContext,
container: Container,
Expand Down Expand Up @@ -50,7 +54,7 @@ export async function create(
/**
* トークン情報を取得する
*/
export async function get(
export async function getToken(
params: { token: string },
ctx: AccessContext,
container: Container,
Expand Down Expand Up @@ -81,7 +85,7 @@ export async function get(
* トークン情報を削除する
* @returns 削除に成功したかどうか
*/
export async function remove(
export async function deleteToken(
params: { token: string },
ctx: AccessContext,
container: Container,
Expand Down
16 changes: 11 additions & 5 deletions backend/src/repositories/UserRepository.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { user } from "@prisma/client";
import { AccessContext } from "../modules/AccessContext";
import { DB } from "../modules/db";
import { UserEntity } from "../modules/entities";
import { Container } from "inversify";
import { TYPES } from "../container/types";

export type UserEntity = {
userId: string;
userName: string;
displayName: string;
passwordAuthEnabled: boolean;
};

/**
* ユーザーを追加する
*/
export async function create(
export async function createUser(
params: { userName: string, displayName: string, passwordAuthEnabled: boolean },
ctx: AccessContext,
container: Container,
Expand All @@ -29,7 +35,7 @@ export async function create(
/**
* ユーザーを取得する
*/
export async function get(
export async function getUser(
params: { userId?: string, userName?: string },
ctx: AccessContext,
container: Container,
Expand Down Expand Up @@ -58,7 +64,7 @@ export async function get(
* ユーザーを削除する
* @returns 削除に成功したかどうか
*/
export async function remove(
export async function deleteUser(
params: { userId: string },
ctx: AccessContext,
container: Container,
Expand Down Expand Up @@ -178,7 +184,7 @@ export async function getFollowedBy(
return rows.map(row => mapEntity(row.user_followed_by));
}

function mapEntity(row: user): UserEntity {
export function mapEntity(row: user): UserEntity {
return {
userId: row.user_id,
userName: row.name,
Expand Down
17 changes: 9 additions & 8 deletions backend/src/routes/apiVer1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { corsApi } from '../modules/httpRoute/cors';
import type { Endpoints } from '../modules/httpRoute/endpoints';
import * as LeafService from '../services/LeafService';
import * as UserService from '../services/UserService';
import * as AuthService from '../services/AuthService';
import * as UserFollowingService from '../services/UserFollowingService';
import * as QueryService from '../services/QueryService';

const zUuid = z.string().length(36);
const zNumericString = z.string().regex(/^[+-]?\d*\.?\d+$/, { message: 'invalid numeric string' });
Expand All @@ -34,7 +35,7 @@ export class ApiVer1Router {
password: z.string().min(1).optional(),
})
);
const result = await AuthService.signin(params, { userId: ctx.getUser().userId }, ctx.container);
const result = await UserService.signin(params, { userId: ctx.getUser().userId }, ctx.container);
return result;
},
});
Expand All @@ -51,7 +52,7 @@ export class ApiVer1Router {
displayName: z.string().min(1),
})
);
const result = await AuthService.signup(params, { userId: ctx.getUser().userId }, ctx.container);
const result = await UserService.signup(params, { userId: ctx.getUser().userId }, ctx.container);
return result;
},
});
Expand Down Expand Up @@ -154,7 +155,7 @@ export class ApiVer1Router {
userId: zUuid,
})
);
await UserService.followUser(params, { userId: ctx.getUser().userId }, ctx.container);
await UserFollowingService.followUser(params, { userId: ctx.getUser().userId }, ctx.container);
},
});

Expand All @@ -175,7 +176,7 @@ export class ApiVer1Router {
offset: (params.offset != null ? Number(params.offset) : undefined),
limit: (params.limit != null ? Number(params.limit) : undefined),
};
const result = await UserService.getFollowings(params2, { userId: ctx.getUser().userId }, ctx.container);
const result = await UserFollowingService.getFollowings(params2, { userId: ctx.getUser().userId }, ctx.container);
return result;
},
});
Expand All @@ -197,7 +198,7 @@ export class ApiVer1Router {
offset: (params.offset != null ? Number(params.offset) : undefined),
limit: (params.limit != null ? Number(params.limit) : undefined),
};
const result = await UserService.getFollowedBy(params2, { userId: ctx.getUser().userId }, ctx.container);
const result = await UserFollowingService.getFollowedBy(params2, { userId: ctx.getUser().userId }, ctx.container);
return result;
},
});
Expand All @@ -219,7 +220,7 @@ export class ApiVer1Router {
...params,
limit: Number(params.limit),
};
const result = await UserService.fetchHomeTimeline(params2, { userId: ctx.getUser().userId }, ctx.container);
const result = await QueryService.fetchHomeTimeline(params2, { userId: ctx.getUser().userId }, ctx.container);
return result;
},
});
Expand Down Expand Up @@ -259,7 +260,7 @@ export class ApiVer1Router {
userId: zUuid,
})
);
await UserService.unfollowUser(params, { userId: ctx.getUser().userId }, ctx.container);
await UserFollowingService.unfollowUser(params, { userId: ctx.getUser().userId }, ctx.container);
},
});

Expand Down
Loading

0 comments on commit 0a50071

Please sign in to comment.