Implement building endpoint in API
This commit is contained in:
parent
6a7644f59f
commit
26125be066
|
@ -0,0 +1,163 @@
|
||||||
|
## /generateAccessToken
|
||||||
|
|
||||||
|
**URL: POST** /generateAccessToken
|
||||||
|
|
||||||
|
**DESCRIPTION:** Used for generating new access tokens. Type X access token required via Authorization header
|
||||||
|
|
||||||
|
**BODY:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK",
|
||||||
|
"accessToken": "A.MTcxODcxNDg2MTg5Mw.NjUzZTk2NzdlNWMzZDM2YjE1YmE3NGVi.QilYuiOT_svRX2iN7f7-jw"
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## /testAccessToken
|
||||||
|
|
||||||
|
**URL: GET** /testAccessToken
|
||||||
|
|
||||||
|
**DESCRIPTION:** Used for testing access token validity. Type A access token required via Authorization header
|
||||||
|
|
||||||
|
**BODY:** N/A
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK",
|
||||||
|
"data": "Access token valid for user gargamel"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## /planets/getPlanet
|
||||||
|
|
||||||
|
**URL: GET** /planets/getPlanet/*:planetId*
|
||||||
|
|
||||||
|
**DESCRIPTION:** Used to get data about specific planet with ID provided in URL. Type A access token required via Authorization header
|
||||||
|
|
||||||
|
**BODY:** N/A
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK",
|
||||||
|
"data": {
|
||||||
|
"id": "661d1163567111a5b4be8829",
|
||||||
|
"owner": "653e9677e5c3d36b15ba74eb",
|
||||||
|
"name": "Lyoko",
|
||||||
|
"fields": 20,
|
||||||
|
"resources": [],
|
||||||
|
"buildings": [],
|
||||||
|
"fleet": [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## /planets/getAllPlanets
|
||||||
|
|
||||||
|
**URL: GET** /planets/getAllPlanets/
|
||||||
|
|
||||||
|
**DESCRIPTION:** Limited view of all planets of all players
|
||||||
|
|
||||||
|
**BODY:** N/A
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"planetId": "661d1163567111a5b4be8829",
|
||||||
|
"ownerId": "653e9677e5c3d36b15ba74eb",
|
||||||
|
"name": "Lyoko"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"planetId": "666af607f0ae1e11d2d03544",
|
||||||
|
"ownerId": "653e9677e5c3d36b15ba74eb",
|
||||||
|
"name": "Cortex"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## /research/getResearch
|
||||||
|
|
||||||
|
**URL: GET** /research/getResearch
|
||||||
|
|
||||||
|
**DESCRIPTION:** Used to get data about user research (which technologies are unlocked and on which level). Type A access token required via Authorization header
|
||||||
|
|
||||||
|
**BODY:** N/A
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "basic-engine",
|
||||||
|
"level": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "advanced-engine",
|
||||||
|
"level": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## /research/performResearch
|
||||||
|
|
||||||
|
**URL: POST** /research/performResearch
|
||||||
|
|
||||||
|
**DESCRIPTION:** Used to send request to start researching. Required buildings and resources are checked on planet provided in body. Type A access token required via Authorization header
|
||||||
|
|
||||||
|
**BODY:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"research": "string",
|
||||||
|
"planetId": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## /build/createBuilding
|
||||||
|
|
||||||
|
**URL: POST** /build/createBuilding
|
||||||
|
|
||||||
|
**DESCRIPTION:** Used to send request to build or upgrade building on planet. Required buildings and resources are checked on planet provided in body. Type A access token required via Authorization header
|
||||||
|
|
||||||
|
**BODY:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"building": "string",
|
||||||
|
"planetId": "string"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**OUTPUT:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "OK"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -46,3 +46,24 @@ export const getPlanetById = async (id: ObjectId) => {
|
||||||
_id: id
|
_id: id
|
||||||
}) as Promise<Planet | null>;
|
}) as Promise<Planet | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const createOrUpgradeBuilding = async (planetId: ObjectId, building: Building) => {
|
||||||
|
const planet = await getPlanetById(planetId);
|
||||||
|
if(!planet) throw new Error("Planet not found");
|
||||||
|
|
||||||
|
const buildingIndex = planet.buildings.findIndex(b => b.id === building.id);
|
||||||
|
if(buildingIndex === -1) {
|
||||||
|
planet.buildings.push(building);
|
||||||
|
} else {
|
||||||
|
planet.buildings[buildingIndex].level++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const planets = await Planets();
|
||||||
|
await planets.updateOne({
|
||||||
|
_id: planetId
|
||||||
|
}, {
|
||||||
|
$set: {
|
||||||
|
buildings: planet.buildings
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
import { type APIRoute } from "astro";
|
import { build, type APIRoute } from "astro";
|
||||||
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
||||||
import { getAccessToken } from "../../../lib/db/accessTokens";
|
import { calculateCurrentAvailableResources, updatePlanetResources } from "../../../lib/utils/resourceManager";
|
||||||
// import { getUserResources } from "../../../lib/db/users";
|
|
||||||
import { getUserResources } from "../../../lib/utils/resourceManager";
|
|
||||||
import buildings from '../../../lib/data/buildings.json';
|
import buildings from '../../../lib/data/buildings.json';
|
||||||
import calculateAvailableResources from "../../../lib/utils/calculateAvailableResources";
|
import { getUserByAccessToken, getUserResearch } from "../../../lib/db/users";
|
||||||
import { getUserByAccessToken } from "../../../lib/db/users";
|
import Planet from "../../../types/Planet";
|
||||||
|
import { createOrUpgradeBuilding, getPlanetById } from "../../../lib/db/planets";
|
||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
import DBResource from "../../../types/DBResource";
|
||||||
|
|
||||||
export const POST: APIRoute = async({ request }) => {
|
export const POST: APIRoute = async({ request }) => {
|
||||||
const response = await validateAccessToken(request);
|
const response = await validateAccessToken(request);
|
||||||
|
@ -20,21 +21,135 @@ export const POST: APIRoute = async({ request }) => {
|
||||||
}), { status: 401 }
|
}), { status: 401 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
const resources = await getUserResources(user._id);
|
|
||||||
const buildingId = (await request.json()).building;
|
let body;
|
||||||
const building = buildings.map(cat => cat.buildings.filter(b => b.id === buildingId))[0][0];
|
try {
|
||||||
const balance = calculateAvailableResources(resources, building.requirements.resources);
|
body = await request.json()
|
||||||
|
} catch(e) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid JSON body"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildingId = body.building;
|
||||||
|
let buildingData: {id: string, name: string, requirements: { buildings: Array<{}>, research: Array<{}>, resources: Array<DBResource> }, multiplier: number} | null = null;
|
||||||
|
buildings.forEach((category: any) => {
|
||||||
|
// console.log(category.buildings.filter((element: any) => element.id === buildingId)[0]);
|
||||||
|
if(buildingData !== null) return;
|
||||||
|
buildingData = category.buildings.find((element: any) => element.id === buildingId);
|
||||||
|
});
|
||||||
|
if(!buildingData) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid building id"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
buildingData = buildingData as {id: string, name: string, requirements: { buildings: Array<{}>, research: Array<{}>, resources: Array<DBResource> }, multiplier: number}; // fuck you typescript
|
||||||
|
let userPlanet: Planet | null;
|
||||||
|
try {
|
||||||
|
userPlanet = await getPlanetById(new ObjectId(body.planetId));
|
||||||
|
} catch(e) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: "Invalid planet id"
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(!userPlanet) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 404,
|
||||||
|
message: "Not Found",
|
||||||
|
error: "Planet not found"
|
||||||
|
}), { status: 404 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check requirements
|
||||||
|
// buildings
|
||||||
|
const playerBuildings = userPlanet.buildings;
|
||||||
|
buildingData.requirements.buildings.forEach((buildingReq: any) => {
|
||||||
|
if(playerBuildings.filter((building) => building.id === buildingReq.id)[0].level < buildingReq.level) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: `${buildingReq.id} level ${buildingReq.level} required, found ${playerBuildings.filter((building) => building.id === buildingReq.id)[0].level}`
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// research
|
||||||
|
const playerResearch = await getUserResearch(user);
|
||||||
|
buildingData.requirements.research.forEach((researchReq: any) => {
|
||||||
|
if(playerResearch.filter((research) => research.id === researchReq.id)[0].level < researchReq.level) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
error: `${researchReq.id} level ${researchReq.level} required, found ${playerResearch.filter((research) => research.id === researchReq.id)[0].level}`
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// resources
|
||||||
|
const resources = await calculateCurrentAvailableResources(userPlanet._id);
|
||||||
|
if(!resources) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 500,
|
||||||
|
message: "Internal Server Error",
|
||||||
|
error: "Failed to get resources"
|
||||||
|
}), { status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const playerCurrentResearch = playerResearch.filter((element: any) => element.id === buildingId)[0];
|
||||||
|
const level = playerCurrentResearch ? playerCurrentResearch.level : 0;
|
||||||
|
const newResources = structuredClone(resources);
|
||||||
|
const missingResources: Array<{}> = [];
|
||||||
|
Object.entries(buildingData.requirements.resources).forEach(([key, value]) => {
|
||||||
|
const res = resources.filter((element: DBResource) => element.name === value.name)[0];
|
||||||
|
const cost = playerCurrentResearch ? value.amount * Math.pow((buildingData as {multiplier: number}).multiplier, level) : value.amount;
|
||||||
|
|
||||||
|
if(res.amount < cost) {
|
||||||
|
missingResources.push({
|
||||||
|
name: key,
|
||||||
|
required: cost,
|
||||||
|
available: res.amount
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else newResources.filter((element: DBResource) => element.name === value.name)[0].amount -= cost;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(missingResources.length > 0) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
code: 400,
|
||||||
|
message: "Bad Request",
|
||||||
|
data: missingResources
|
||||||
|
}), { status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
await updatePlanetResources(userPlanet._id, newResources);
|
||||||
|
await createOrUpgradeBuilding(userPlanet._id, { id: buildingId, level: level + 1 });
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
code: 200,
|
code: 200,
|
||||||
message: "OK",
|
message: "OK"
|
||||||
accessToken: response,
|
|
||||||
data: {
|
|
||||||
resources,
|
|
||||||
building,
|
|
||||||
balance
|
|
||||||
}
|
|
||||||
}), { status: 200 }
|
}), { status: 200 }
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
import type { APIRoute } from "astro";
|
|
||||||
import { getAccessToken } from "../../../lib/db/accessTokens";
|
|
||||||
import validateAccessToken from "../../../lib/utils/validateAccessToken";
|
|
||||||
|
|
||||||
export const GET: APIRoute = async({ request }) => {
|
|
||||||
const response = await validateAccessToken(request);
|
|
||||||
if(response instanceof Response) return response;
|
|
||||||
|
|
||||||
const buildings = [
|
|
||||||
{
|
|
||||||
"name": "Iron Mine",
|
|
||||||
"level": 1,
|
|
||||||
"production": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Coal Mine",
|
|
||||||
"level": 2,
|
|
||||||
"production": 150
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return new Response(
|
|
||||||
JSON.stringify({
|
|
||||||
code: 200,
|
|
||||||
message: "OK",
|
|
||||||
data: {
|
|
||||||
buildings
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in New Issue