diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index 500623c..d2009c2 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -72,14 +72,15 @@ jobs: script: | source $HOME/.bash_profile echo "해당 리포지토리로 이동" - cd $HOME/git/42cabi-admin/backend + cd $HOME/git/42cabi-admin echo "리포지토리 pull" git pull origin main echo "앱 빌드" + cd $HOME/git/42cabi-admin/backend npm install npm run build:fe npm run build echo "env 파일 복사" - cp 42cabi-admin.env $HOME/git/42cabi-admin/backend/.env + cp $HOME/42cabi-admin.env $HOME/git/42cabi-admin/backend/.env echo "앱 배포 (reload)" - pm2 reload 42cabi-admin + pm2 reload 42cabi-admin-prod diff --git a/backend/src/entities/cabinet.entity.ts b/backend/src/entities/cabinet.entity.ts index 8570c10..ecd22e5 100644 --- a/backend/src/entities/cabinet.entity.ts +++ b/backend/src/entities/cabinet.entity.ts @@ -79,6 +79,14 @@ export default class Cabinet { }) title: string; + @Column({ + name: 'status_note', + nullable: true, + type: 'varchar', + length: 64, + }) + status_note: string; + @OneToMany(() => Lent, (lent) => lent.cabinet) lent: Lent[]; } diff --git a/backend/src/entities/user.entity.ts b/backend/src/entities/user.entity.ts index 8e11b62..80a254e 100644 --- a/backend/src/entities/user.entity.ts +++ b/backend/src/entities/user.entity.ts @@ -1,4 +1,3 @@ -import UserStateType from 'src/enums/user.state.type.enum'; import { Column, CreateDateColumn, @@ -27,14 +26,6 @@ export default class User { }) intra_id: string; - @Column({ - name: 'state', - type: 'enum', - enum: UserStateType, - default: UserStateType.NORMAL, - }) - state: UserStateType; - @Column({ name: 'email', unique: true, diff --git a/backend/src/enums/user.state.type.enum.ts b/backend/src/enums/user.state.type.enum.ts deleted file mode 100644 index 98f43b5..0000000 --- a/backend/src/enums/user.state.type.enum.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * 유저의 상태를 나타냄 - */ -enum UserStateType { - NORMAL = 'NORMAL', - BANNED = 'BANNED', - BLACKHOLED = 'BLACKHOLED', -} -export default UserStateType; diff --git a/backend/src/return/repository/return.repository.ts b/backend/src/return/repository/return.repository.ts index 948dc2b..275fe22 100644 --- a/backend/src/return/repository/return.repository.ts +++ b/backend/src/return/repository/return.repository.ts @@ -5,6 +5,7 @@ import { Repository } from 'typeorm'; import Cabinet from 'src/entities/cabinet.entity'; import Lent from 'src/entities/lent.entity'; import LentLog from 'src/entities/lent.log.entity'; +import BanLog from 'src/entities/ban.log.entity'; export class ReturnRepository implements IReturnRepository { constructor( @@ -25,6 +26,15 @@ export class ReturnRepository implements IReturnRepository { if (result === null || result.lent.length === 0) { return null; } + const blocked = await this.cabinetRepository.manager.findOne(BanLog, { + where: { + ban_user_id: result.lent[0].user.user_id, + }, + order: { + unbanned_date: 'DESC', + }, + }); + const banned = blocked && blocked.unbanned_date > new Date(); const rtn = { cabinet_id: result.cabinet_id, cabinet_num: result.cabinet_num, @@ -40,7 +50,7 @@ export class ReturnRepository implements IReturnRepository { extension: 0, // NOTE: 무슨 필드? user_id: result.lent[0].user.user_id, intra_id: result.lent[0].user.intra_id, - auth: result.lent[0].user.state === 'NORMAL' ? 1 : 0, + auth: banned ? 0 : 1, email: result.lent[0].user.email, phone: '010-123-4567', // NOTE: 삭제 필요 firstLogin: result.lent[0].user.first_login, diff --git a/backend/src/search/repository/rawquery-search.repository.ts b/backend/src/search/repository/rawquery-search.repository.ts index 6ec6778..e3a9085 100644 --- a/backend/src/search/repository/rawquery-search.repository.ts +++ b/backend/src/search/repository/rawquery-search.repository.ts @@ -25,7 +25,7 @@ export class RawquerySearchRepository implements ISearchRepository { const lentInfo = []; const content = ` - SELECT u.intra_id, u.state, c.cabinet_id, c.cabinet_num, c.location, c.section, c.floor, c.cabinet_status, l.lent_id, l.lent_time, l.expire_time + SELECT u.intra_id, c.cabinet_id, c.cabinet_num, c.location, c.section, c.floor, c.cabinet_status, l.lent_id, l.lent_time, l.expire_time FROM user u LEFT JOIN lent l ON u.user_id=l.lent_user_id @@ -38,14 +38,13 @@ export class RawquerySearchRepository implements ISearchRepository { for (let i = 0; i < getLentInfoByIntraId.length; i += 1) { lentInfo.push({ intra_id: getLentInfoByIntraId[i].intra_id, - auth: getLentInfoByIntraId[i].state === 'NORMAL' ? 1 : 0, + //auth: getLentInfoByIntraId[i].state === 'BANNED' ? 0 : 1, cabinet_id: getLentInfoByIntraId[i].cabinet_id, cabinet_num: getLentInfoByIntraId[i].cabinet_num, location: getLentInfoByIntraId[i].location, section: getLentInfoByIntraId[i].section, floor: getLentInfoByIntraId[i].floor, - activation: - getLentInfoByIntraId[i].cabinet_status === 'AVAILABLE' ? 1 : 0, + activation: getLentInfoByIntraId[i].cabinet_status === 'BROKEN' ? 0 : 1, lent_id: getLentInfoByIntraId[i].lent_id, lent_time: getLentInfoByIntraId[i].lent_time, expire_time: getLentInfoByIntraId[i].expire_time, @@ -81,8 +80,7 @@ export class RawquerySearchRepository implements ISearchRepository { location: getLentLogByIntraId[i].location, section: getLentLogByIntraId[i].section, floor: getLentLogByIntraId[i].floor, - activation: - getLentLogByIntraId[i].cabinet_status === 'AVAILABLE' ? 1 : 0, + activation: getLentLogByIntraId[i].cabinet_status === 'BROKEN' ? 0 : 1, log_id: getLentLogByIntraId[i].log_id, lent_time: getLentLogByIntraId[i].lent_time, return_time: getLentLogByIntraId[i].return_time, @@ -120,8 +118,7 @@ export class RawquerySearchRepository implements ISearchRepository { location: getLentByCabinetNum[i].location, section: getLentByCabinetNum[i].section, floor: getLentByCabinetNum[i].floor, - activation: - getLentByCabinetNum[i].cabinet_status === 'AVAILABLE' ? 1 : 0, + activation: getLentByCabinetNum[i].cabinet_status === 'BROKEN' ? 0 : 1, lent_id: getLentByCabinetNum[i].lent_id, log_id: getLentByCabinetNum[i].log_id, lent_time: getLentByCabinetNum[i].lent_time, @@ -162,7 +159,7 @@ export class RawquerySearchRepository implements ISearchRepository { section: getLentLogByCabinetNum[i].section, floor: getLentLogByCabinetNum[i].floor, activation: - getLentLogByCabinetNum[i].cabinet_status === 'AVAILABLE' ? 1 : 0, + getLentLogByCabinetNum[i].cabinet_status === 'BROKEN' ? 0 : 1, lent_id: getLentLogByCabinetNum[i].lent_id, log_id: getLentLogByCabinetNum[i].log_id, lent_time: getLentLogByCabinetNum[i].lent_time, diff --git a/backend/src/search/repository/search.repository.ts b/backend/src/search/repository/search.repository.ts index a71ba3a..d3af3e1 100644 --- a/backend/src/search/repository/search.repository.ts +++ b/backend/src/search/repository/search.repository.ts @@ -1,4 +1,5 @@ import { InjectRepository } from '@nestjs/typeorm'; +import BanLog from 'src/entities/ban.log.entity'; import Cabinet from 'src/entities/cabinet.entity'; import LentLog from 'src/entities/lent.log.entity'; import User from 'src/entities/user.entity'; @@ -17,9 +18,8 @@ export class SearchRepository implements ISearchRepository { async getLentByIntraId(intraId: string): Promise { const result = await this.userRepository .createQueryBuilder('u') - .select(['u.intra_id', 'u.state']) + .select(['u.intra_id', 'u.user_id']) .addSelect([ - 'c.cabinet_id', 'c.cabinet_id', 'c.cabinet_num', 'c.location', @@ -32,18 +32,28 @@ export class SearchRepository implements ISearchRepository { .leftJoin('cabinet', 'c', 'c.cabinet_id = l.lent_cabinet_id') .where('u.intra_id = :intraId', { intraId }) .execute(); + if (result.length === 0) { return []; } + const blocked = await this.userRepository.manager.findOne(BanLog, { + where: { + ban_user_id: result[0].u_user_id, + }, + order: { + unbanned_date: 'DESC', + }, + }); + const banned = blocked && blocked.unbanned_date > new Date(); return result.map((val) => ({ intra_id: val.u_intra_id, - auth: val.u_state === 'NORMAL' ? 1 : 0, + auth: banned ? 0 : 1, cabinet_id: val.c_cabinet_id, cabinet_num: val.c_cabinet_num, location: val.c_location, section: val.c_section, floor: val.c_floor, - activation: val.cabinet_status === 'AVAILABLE' ? 1 : 0, + activation: val.cabinet_status === 'BROKEN' ? 0 : 1, lent_id: val.l_lent_id, lent_time: val.l_lent_time, expire_time: val.l_expire_time, @@ -64,7 +74,7 @@ export class SearchRepository implements ISearchRepository { location: val.c_location, section: val.c_section, floor: val.c_floor, - activation: val.c_cabinet_status === 'AVAILABLE' ? 1 : 0, + activation: val.c_cabinet_status === 'BROKEN' ? 0 : 1, log_id: val.ll_log_id, lent_time: val.ll_lent_time, return_time: val.ll_return_time, @@ -97,11 +107,11 @@ export class SearchRepository implements ISearchRepository { location: val.location, section: val.section, floor: val.floor, - activation: val.status === 'AVAILABLE' ? 1 : 0, + activation: val.status === 'BROKEN' ? 0 : 1, lent_id: null, lent_time: null, expire_time: null, - auth: 0, + auth: 1, // 현재 빌리고 있는데 블럭 당할수가 없음. })); } return result.map((val) => ({ @@ -111,11 +121,11 @@ export class SearchRepository implements ISearchRepository { location: val.location, section: val.section, floor: val.floor, - activation: val.status === 'AVAILABLE' ? 1 : 0, + activation: val.status === 'BROKEN' ? 0 : 1, lent_id: val.lent[0].lent_id, lent_time: val.lent[0].lent_time, expire_time: val.lent[0].expire_time, - auth: 0, + auth: 1, // 현재 빌리고 있는데 블럭 당할수가 없음. })); } @@ -137,7 +147,7 @@ export class SearchRepository implements ISearchRepository { location: val.c_location, section: val.c_section, floor: val.c_floor, - activation: val.c_cabinet_status === 'AVAILABLE' ? 1 : 0, + activation: val.c_cabinet_status === 'BROKEN' ? 0 : 1, log_id: val.ll_log_id, lent_time: val.ll_lent_time, return_time: val.ll_return_time, diff --git a/frontend/src/Components/CabinetDetail.tsx b/frontend/src/Components/CabinetDetail.tsx index 2a28529..a7e0e84 100644 --- a/frontend/src/Components/CabinetDetail.tsx +++ b/frontend/src/Components/CabinetDetail.tsx @@ -1,14 +1,14 @@ -import { useSelector, shallowEqual, useDispatch } from "react-redux"; -import { useEffect, useMemo, useCallback } from "react"; +import { useSelector, shallowEqual } from "react-redux"; +import { useEffect, useMemo } from "react"; import { RootState } from "../ReduxModules/rootReducer"; import moment from "moment"; import { useNavigate } from "react-router-dom"; import ExpiredInfo from "./ExpiredInfo"; import { DetailBox, BigFontSize } from "./DetailStyleComponent"; -// import LentDisabledInfo from "./LentDisabled"; -import { GetDisabledResponse } from "../ReduxModules/StatusDisabled"; +import LentDisabledInfo from "./LentDisabled"; +// import { GetDisabledResponse } from "../ReduxModules/StatusDisabled"; import styled from "styled-components"; -import * as API from "../Networks/APIType"; +// import * as API from "../Networks/APIType"; const CabinetDetail = () => { const SearchResponseRedux = useSelector( @@ -25,7 +25,7 @@ const CabinetDetail = () => { ); const navigate = useNavigate(); - const dispatch = useDispatch(); + // const dispatch = useDispatch(); const currentPage = window.location.pathname.split("/")[2]; useEffect(() => { @@ -59,33 +59,33 @@ const CabinetDetail = () => { : "없음"; const CabinetActivationInfo = - data !== undefined && data[0] !== undefined && data[0].activation === 1 - ? "사용 가능" - : "사용 불가"; - - const getDisableData = useCallback(async () => { - try { - const token = localStorage.getItem("accessToken"); - const res = await API.axiosFormat( - { - method: "GET", - url: API.url("/api/activation"), - }, - token - ); - dispatch(GetDisabledResponse(res.data)); - } catch (e) { - console.log(e); - const axiosError = e as API.axiosError; - API.HandleError(navigate, axiosError); - } - }, [dispatch, navigate]); + data !== undefined && data[0] !== undefined && data[0].activation === 0 + ? "사용 불가" + : ""; - useEffect(() => { - // if (CabinetActivationInfo === "사용 불가") { - getDisableData(); - // } - }, [CabinetActivationInfo, getDisableData]); + // const getDisableData = useCallback(async () => { + // try { + // const token = localStorage.getItem("accessToken"); + // const res = await API.axiosFormat( + // { + // method: "GET", + // url: API.url("/api/activation"), + // }, + // token + // ); + // dispatch(GetDisabledResponse(res.data)); + // } catch (e) { + // console.log(e); + // const axiosError = e as API.axiosError; + // API.HandleError(navigate, axiosError); + // } + // }, [dispatch, navigate]); + + // useEffect(() => { + // if (CabinetActivationInfo === "사용 불가") { + // getDisableData(); + // } + // }, [CabinetActivationInfo, getDisableData]); // const cabinetFloor = // data !== undefined && data[0] !== undefined ? data[0].floor : 0; @@ -100,9 +100,8 @@ const CabinetDetail = () => { // const CabinetDisabledReason = // data !== undefined && // data[0] !== undefined && - // data[0].activation === 0 && - // targetCabinetData !== undefined - // ? targetCabinetData.note + // data[0].activation === 0 ? + // data[0].note; // : ""; if (data === undefined || data.length === 0) { @@ -124,16 +123,12 @@ const CabinetDetail = () => { } else { return ( - {/* */} + {CabinetInfo}

현재 대여자 : {CabinetUserInfo}

대여 기간 : {CabinetLentInfo}

- {/* - {CabinetActivationInfo === "사용 불가" ? CabinetActivationInfo : ""} - - {CabinetActivationInfo === "사용 불가" && ( + {CabinetActivationInfo} + {/* {CabinetActivationInfo === "사용 불가" && (

비활성화 사유 : {CabinetDisabledReason}

)} */} @@ -156,13 +151,10 @@ const NoneCabinet = styled.div` padding-bottom: 10rem; `; -// const CabinetStatusMessage = styled.p<{ -// activation: boolean; -// }>` -// display: ${(props) => (props.activation ? "none" : "")}; -// font-size: ${(props) => (props.activation ? "1.6rem" : "2rem")}; -// font-weight: ${(props) => (props.activation ? "normal" : "bold")}; -// color: ${(props) => (props.activation ? "black" : "#bc0000")}; -// `; +const CabinetStatusMessage = styled.p` + font-size: 2rem; + font-weight: bold; + color: #bc0000; +`; export default CabinetDetail; diff --git a/frontend/src/Components/UserDetail.tsx b/frontend/src/Components/UserDetail.tsx index 0468007..00f6409 100644 --- a/frontend/src/Components/UserDetail.tsx +++ b/frontend/src/Components/UserDetail.tsx @@ -5,7 +5,7 @@ import moment from "moment"; import { useNavigate } from "react-router-dom"; import ExpiredInfo from "./ExpiredInfo"; import { DetailBox, BigFontSize } from "./DetailStyleComponent"; -// import LentDisabledInfo from "./LentDisabled"; +import LentDisabledInfo from "./LentDisabled"; import styled from "styled-components"; const UserDetail = () => { @@ -60,9 +60,9 @@ const UserDetail = () => { } return ( - {/* */} + {UserInfo} - {data[0].auth === 1 && ( + {data[0].auth === 0 && ( 페널티가 남아있는 사용자입니다. )}

현재 사물함 : {UserCabinetInfo}