WIL6주차
이번 주 작업
gatcha 시스템
원시적인 형태의 가챠 시스템을 구현했다.
캐릭터 리스트 가운데 가운데 하나를 랜덤하게 얻을 수 있는 구조로 작업했다.
필요하다면 나중에 gatcha의 확률 테이블을 별도로 만들어서 관리해도 되겠다.
router.post('/gatcha',authMiddleware, async (req, res, next) => {
try {
//const players = await prisma.users.findMany({});
//유저 정보를 전부 받아온 다음
//user의 id를 parse하자.
const user = req.user;
let [playerName, cash] = await prisma.$transaction(async (tx) => {
let playerList = await tx.players.findMany({
});
let random_count = Math.floor(Math.random() * playerList.length);
let userteam = await tx.userTeams.create({
data: {
players : {
connect : {
id : playerList[random_count].id
}
},
user : {
connect : {
id : user.id
}
},
},
})
const updatedUser = await tx.userAccount.update({
where : {
userId : user.id
},
data: {
cash: {
decrement: gatchaPay
}
}
})
if(updatedUser.cash < 0)
{
return res.status(404).json({ Message: ` No Money ` })
}
return [playerList[random_count], updatedUser.cash]
})
return res.status(200).json({ Message: ` ${playerName.playerName} 을(를) 뽑았습니다. 잔액 ${cash} ` })
}
catch (err) {
next(err);
}
})
squad 시스템
유저 한 명당 1개의 스쿼드를 가질 수 있다는 조건 하에 squad를 작성했다.
처음에는 body에서 각각의 인덱스를 하나씩 입력 하는 방식으로 작업했으나, 어차피 인덱스만 보내면 된다는 지적을 받고 리스트 형태로 보내게 되었다.
작업 도중에 table이 한 번 바뀌었는데, 기존엔 squad라는 테이블을 별도로 만들어 관리했으나 나중에 다른 테이블과의 연결을 위해서 squad 테이블을 지우고 대신 teams 테이블에 isspuad 변수를 넣었다.
router.post('/squads', authMiddleware, async (req,res,next) => {
try{
const {squadList} = req.body;
const user = req.user;
for(let i of squadList) {
if(typeof i != 'number') {
throw new Error("입력 값이 잘못되었습니다.");
}
}
//teams 내에 현재 로그인한 유저의 것이며 isSquad가 참인 것을 모두 조회한다.
//그것들을 모두 squad 해제시킨다.
//그 다음 지정 받은 index를 베이스로 값을 가져오도록 하자.
const squadTransaction = await prisma.$transaction(async (tx) => {
//먼저 teams 내의 squad 에서 user의 팀을 해제한다.
const updatedTeam = await tx.userTeams.updateMany({
where : {
AND : {
userId : user.id,
isSquad : true,
},
},
data : {
isSquad : false,
},
});
//다음 입력 받은 인덱스를 받아 팀을 만든다.
const updatingTeam = await tx.userTeams.updateMany({
where : {
AND : {
userId : user.id,
id : {
in : squadList,
},
},
},
data : {
isSquad : true,
},
});
const check = await tx.userTeams.findMany({
where : {
userId : user.id,
AND : {
isSquad : true,
},
},
});
if(!updatingTeam) {
throw new Error("업데이트가 되지 않았습니다.")
}
if(check.length !== 3) {
throw new Error("숫자가 다릅니다.")
}
});
return res.status(200).json({message : "스쿼드 편성 완료!"});
} catch(err){
if(err === "invaildIndex") {
res.status(404).json({message : "확실치 않은 인덱스!"});
}
else {
next(err);
}
}
});
이적 시장 테이블 관련
기본 과제가 해결이 된 뒤 추가적으로 이적 시장을 추가하여 작업했다.
이적 시장은 등록(jwt 인증 필요), 구매(인증 필요), 조회(전체/캐릭터), 등록 취소(인증 필요)가 있다.
처음엔 userteams에서 데이터를 삭제한 뒤 이 안에 넣자는 방안이 제시되었으나 삭제를 통한 데이터 훼손 위험이 있으므로 user의 id 값만 바꾸는 방식으로 바꾸었다.
등록
router.post('/transfermarket', authMiddleware, async (req, res, next) => {
try {
const { userTeamId, price } = req.body;
const user = req.user;
const marketPlace = await prisma.$transaction(async (tx) => {
//삭제할 데이터가 있는지 확인 먼저 하자.
const deletedTeams = await tx.userTeams.findUnique({
where: {
id: userTeamId
},
});
if (!deletedTeams) {
throw new Error("해당 캐릭터가 존재하지 않습니다.");
}
if (deletedTeams.isSquad) {
throw new Error("이미 팀 편성된 캐릭터입니다.")
}
if (deletedTeams.userId !== user.id) {
throw new Error("다른 유저의 캐릭터입니다.")
}
const market = await tx.transferMarket.create({
data: {
userTeamsId: deletedTeams.id,
price: price,
},
});
return market;
});
return res.status(201).json({ data: marketPlace });
} catch (err) {
switch (err.message) {
case "해당 캐릭터가 존재하지 않습니다.":
return res.status(404).json({ error: "해당 캐릭터가 존재하지 않습니다." })
break;
case "이미 팀 편성된 캐릭터입니다.":
return res.status(404).json({ error: "이미 팀 편성된 캐릭터입니다." })
break;
case "다른 유저의 캐릭터입니다.":
return res.status(404).json({ error: "다른 유저의 캐릭터입니다." })
break;
default:
next(err);
break;
}
}
});
구매
router.post('/transfermarket/:marketId', authMiddleware, async (req, res, next) => {
try {
const { marketId } = req.params;
const user = req.user;
const purchased = await prisma.$transaction(async (tx) => {
//돈이 있는지 검수한다.
const userAccount = await tx.userAccount.findFirst({
where: {
userId: user.id
}
})
//먼저 경매장에서 제거한다.
const deletedfromMarket = await tx.transferMarket.delete({
where: {
id: parseInt(marketId, 10),
},
});
if (userAccount.cash < deletedfromMarket.price) {
throw new Error("돈이 부족합니다.");
}
if (!deleted) {
throw new Error("범위 외 접근입니다.");
}
//판매자는 돈을 벌고
await tx.userAccount.update({
where: {
userId: deletedfromMarket.userId
},
data: {
cash: {
increment: deletedfromMarket.price,
},
},
});
//구매자와 판매자의 정보를 변경하면 된다.
await tx.userTeams.update({
where: {
id: deletedfromMarket.userTeamsId
},
data: {
userId: user.id
}
})
//구매한 사람의 돈은 줄어든다.
await tx.userAccount.update({
where: {
userId: user.id
},
data: {
cash: {
decrement: deletedfromMarket.price
},
},
});
return inputUserTeams;
});
return res.status(201).json({ data: purchased });
} catch (err) {
switch (err.message) {
case "돈이 부족합니다.":
return res.status(404).json({ error: "돈이 부족합니다." });
break;
case "범위 외 접근입니다.":
return res.status(404).json({ error: "범위 외 접근입니다." });
break
default:
next(err);
break;
}
}
});
조회
router.get('/transfermarket', async (req, res, next) => {
try {
//유저 팀즈에서 마켓에 등록된 것들을 모두 가져온다.
const marketList = await prisma.userTeams.findMany({
where: {
TransferMarket: {
some: {}
}
},
include: {
TransferMarket: {
select : {
price : true
}
}
}
});
return res.status(201).json({ data: marketList });
} catch (err) {
next(err);
}
});
등록 취소
router.delete('/transfermarket', authMiddleware, async (req, res, next) => {
try {
const { transferMarketId } = req.body;
const user = req.user;
const cancelMarketAndPushTeams = await prisma.$transaction(async (tx) => {
//먼저 마켓에서 꺼내오자.
const cancelMarket = await tx.transferMarket.delete({
where: {
id: transferMarketId,
},
});
if (!cancelMarket) {
throw new Error("잘못된 접근입니다.");
}
const currentUserTeam = await tx.userTeams.findUnique({
where: {
id: cancelMarket.userTeamsId
}
})
if (currentUserTeam.userId !== user.id) {
throw new Error("다른 유저의 것입니다.");
}
//teams를 지우지 않으면 되니까 아예 별도의 로직은 필요 없다.
return currentUserTeam;
});
//취소된 것은 그냥 바로 teams에 들어오면 되는 거 아닌가.
return res.status(201).json({ data: cancelMarketAndPushTeams });
} catch (err) {
switch (err.message) {
case "잘못된 접근입니다.":
return res.status(404).json({ error: "잘못된 접근입니다." });
break;
case "다른 유저의 것입니다.":
return res.status(404).json({ error: "다른 유저의 것입니다." });
break
default:
next(err);
}
}
});
화요일 과제
select book_id, count(*), avg(day(return_date) - day(due_date)) from book_rental
where due_date < return_date
group by book_id
order by book_id;