upd
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { connect } from "mongoose";
|
||||
|
||||
async function connectDB() {
|
||||
try {
|
||||
await connect(process.env.MONGO_URI!, { dbName: "irth" });
|
||||
console.log("MongoDB connected...");
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
export default connectDB;
|
||||
@@ -0,0 +1,25 @@
|
||||
const refreshToken =
|
||||
"1000.da3146d49fa8a399f0c635e74954ff9c.e010dbb1bb605d7e1aa5bf7fc0521f8b";
|
||||
const clientId = "1000.6ZV07WFOC7PQOY3X109UN55Q9BMBBY";
|
||||
const clientSecret = "595f5262886a6e81475b533350a81e46fecda57fb5";
|
||||
const grantType = "refresh_token";
|
||||
|
||||
const updateAccessTokenApi = `https://accounts.zoho.com/oauth/v2/token?refresh_token=${refreshToken}&client_id=${clientId}&client_secret=${clientSecret}&grant_type=${grantType}`;
|
||||
const aparmentsApi =
|
||||
"https://www.zohoapis.com/crm/v6/Apartments?fields=Floor,Property_Status,Project_Name,Balcony_Area_Sqft,Unit_Type,Suite_Area_Sqft,No_Of_Bedrooms,Total_Area_Sqft,No_of_Bathrooms,Property_Name,Unit_View,Balcony_Area_Sqft,Unit_No,Suite_Area_Sqft";
|
||||
|
||||
const searchApartmentApi =
|
||||
"https://www.zohoapis.com/crm/v6/Apartments/search?fields=Floor,Property_Status,Project_Name,Balcony_Area_Sqft,Unit_Type,Suite_Area_Sqft,No_Of_Bedrooms,Total_Area_Sqft,No_of_Bathrooms,Property_Name,Unit_View,Balcony_Area_Sqft,Unit_No,Suite_Area_Sqft";
|
||||
|
||||
const searchCurrentApartmentApi = "https://www.zohoapis.com/crm/v6/Apartments";
|
||||
|
||||
export {
|
||||
updateAccessTokenApi,
|
||||
aparmentsApi,
|
||||
refreshToken,
|
||||
clientId,
|
||||
clientSecret,
|
||||
grantType,
|
||||
searchApartmentApi,
|
||||
searchCurrentApartmentApi,
|
||||
};
|
||||
@@ -0,0 +1,302 @@
|
||||
[
|
||||
{
|
||||
"unitName": "RHMD-8E-06",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 8,
|
||||
"position": "Front",
|
||||
"suiteArea": 487,
|
||||
"balconyArea": 121,
|
||||
"unitArea": 608,
|
||||
"unitPrice": 1699888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-9E-01",
|
||||
"bedrooms": "2 BR Squared",
|
||||
"floor": 9,
|
||||
"position": "Front",
|
||||
"suiteArea": 737,
|
||||
"balconyArea": 177,
|
||||
"unitArea": 914,
|
||||
"unitPrice": 2430888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-9W-06",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 9,
|
||||
"position": "Front",
|
||||
"suiteArea": 496,
|
||||
"balconyArea": 121,
|
||||
"unitArea": 618,
|
||||
"unitPrice": 1732888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-9W-15",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 9,
|
||||
"position": "Back",
|
||||
"suiteArea": 520,
|
||||
"balconyArea": 122,
|
||||
"unitArea": 642,
|
||||
"unitPrice": 1594888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-9W-17",
|
||||
"bedrooms": "2 BR Squared",
|
||||
"floor": 9,
|
||||
"position": "Back",
|
||||
"suiteArea": 729,
|
||||
"balconyArea": 328,
|
||||
"unitArea": " 1 058 ",
|
||||
"unitPrice": 2364888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-11E-14",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 11,
|
||||
"position": "Back",
|
||||
"suiteArea": 339,
|
||||
"balconyArea": 78,
|
||||
"unitArea": 416,
|
||||
"unitPrice": 1175888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-11W-12",
|
||||
"bedrooms": "Studio Flex",
|
||||
"floor": 11,
|
||||
"position": "Back",
|
||||
"suiteArea": 284,
|
||||
"balconyArea": 72,
|
||||
"unitArea": 356,
|
||||
"unitPrice": 1054888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-12W-01",
|
||||
"bedrooms": "2 BR Squared",
|
||||
"floor": 12,
|
||||
"position": "Front",
|
||||
"suiteArea": 737,
|
||||
"balconyArea": 177,
|
||||
"unitArea": 914,
|
||||
"unitPrice": 2454888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-12W-07",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 12,
|
||||
"position": "Front",
|
||||
"suiteArea": 492,
|
||||
"balconyArea": 129,
|
||||
"unitArea": 622,
|
||||
"unitPrice": 1784888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-12W-13",
|
||||
"bedrooms": "Studio Flex",
|
||||
"floor": 12,
|
||||
"position": "Back",
|
||||
"suiteArea": 273,
|
||||
"balconyArea": 68,
|
||||
"unitArea": 341,
|
||||
"unitPrice": 1014888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-12W-17",
|
||||
"bedrooms": "2 BR Squared",
|
||||
"floor": 12,
|
||||
"position": "Back",
|
||||
"suiteArea": 729,
|
||||
"balconyArea": 328,
|
||||
"unitArea": " 1 058 ",
|
||||
"unitPrice": 2388888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-15W-04",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 15,
|
||||
"position": "Front",
|
||||
"suiteArea": 320,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 401,
|
||||
"unitPrice": 1294888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-15W-16",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 15,
|
||||
"position": "Back",
|
||||
"suiteArea": 487,
|
||||
"balconyArea": 122,
|
||||
"unitArea": 609,
|
||||
"unitPrice": 1544888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-20E-02",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 20,
|
||||
"position": "Front",
|
||||
"suiteArea": 325,
|
||||
"balconyArea": 78,
|
||||
"unitArea": 403,
|
||||
"unitPrice": 1339888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-21W-04",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 21,
|
||||
"position": "Front",
|
||||
"suiteArea": 320,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 401,
|
||||
"unitPrice": 1340888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-21W-10",
|
||||
"bedrooms": "Studio Flex",
|
||||
"floor": 21,
|
||||
"position": "Back",
|
||||
"suiteArea": 273,
|
||||
"balconyArea": 68,
|
||||
"unitArea": 341,
|
||||
"unitPrice": 1052888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-24E-04",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 24,
|
||||
"position": "Front",
|
||||
"suiteArea": 320,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 401,
|
||||
"unitPrice": 1366888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-24W-10",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 24,
|
||||
"position": "Back",
|
||||
"suiteArea": 320,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 401,
|
||||
"unitPrice": 1202888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-24W-12",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 24,
|
||||
"position": "Back",
|
||||
"suiteArea": 501,
|
||||
"balconyArea": 119,
|
||||
"unitArea": 619,
|
||||
"unitPrice": 1605888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-25E-15",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 25,
|
||||
"position": "Back",
|
||||
"suiteArea": 520,
|
||||
"balconyArea": 122,
|
||||
"unitArea": 642,
|
||||
"unitPrice": 1674888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-26E-12",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 26,
|
||||
"position": "Back",
|
||||
"suiteArea": 319,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 400,
|
||||
"unitPrice": 1216888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-26E-14",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 26,
|
||||
"position": "Back",
|
||||
"suiteArea": 339,
|
||||
"balconyArea": 78,
|
||||
"unitArea": 416,
|
||||
"unitPrice": 1264888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-26W-09",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 26,
|
||||
"position": "Back",
|
||||
"suiteArea": 500,
|
||||
"balconyArea": 118,
|
||||
"unitArea": 618,
|
||||
"unitPrice": 1624888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-26W-14",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 26,
|
||||
"position": "Back",
|
||||
"suiteArea": 487,
|
||||
"balconyArea": 122,
|
||||
"unitArea": 609,
|
||||
"unitPrice": 1635888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-27E-12",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 27,
|
||||
"position": "Back",
|
||||
"suiteArea": 319,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 400,
|
||||
"unitPrice": 1224888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-27E-13",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 27,
|
||||
"position": "Back",
|
||||
"suiteArea": 309,
|
||||
"balconyArea": 78,
|
||||
"unitArea": 386,
|
||||
"unitPrice": 1181888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-28E-05",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 28,
|
||||
"position": "Front",
|
||||
"suiteArea": 319,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 400,
|
||||
"unitPrice": 1397888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-29W-13",
|
||||
"bedrooms": "1 BR Squared",
|
||||
"floor": 29,
|
||||
"position": "Back",
|
||||
"suiteArea": 520,
|
||||
"balconyArea": 122,
|
||||
"unitArea": 642,
|
||||
"unitPrice": 1756888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-30W-11",
|
||||
"bedrooms": "Studio Squared",
|
||||
"floor": 30,
|
||||
"position": "Back",
|
||||
"suiteArea": 320,
|
||||
"balconyArea": 81,
|
||||
"unitArea": 401,
|
||||
"unitPrice": 1248888
|
||||
},
|
||||
{
|
||||
"unitName": "RHMD-30W-15",
|
||||
"bedrooms": "2 BR Squared",
|
||||
"floor": 30,
|
||||
"position": "Back",
|
||||
"suiteArea": 729,
|
||||
"balconyArea": 328,
|
||||
"unitArea": " 1 058 ",
|
||||
"unitPrice": 2730888
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,41 @@
|
||||
import "dotenv/config";
|
||||
import express, { json } from "express";
|
||||
import cors from "cors";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import connectDB from "./config/db.js";
|
||||
import morgan from "morgan";
|
||||
import apartmentRoute from "./routes/apartment.js";
|
||||
import apartmentsRoute from "./routes/apartments.js";
|
||||
import updateAccessToken from "./routes/zohoAccessToken.js";
|
||||
import unitsRoute from "./routes/unitsRoute.js";
|
||||
// import updateApartmentsRoute from "./routes/updateApartmentsRoute.js";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
!fs.existsSync("logs") && fs.mkdirSync("logs");
|
||||
const accessLogStream = fs.createWriteStream(
|
||||
path.join(__dirname, "../logs/access.log"),
|
||||
{ flags: "a" }
|
||||
);
|
||||
|
||||
await connectDB();
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
app.use(cors());
|
||||
app.use(json());
|
||||
app.use(morgan("combined", { stream: accessLogStream }));
|
||||
|
||||
app.use("/apartments", apartmentsRoute);
|
||||
app.use("/apartment", apartmentRoute);
|
||||
app.use("/updateAccessToken", updateAccessToken);
|
||||
app.use("/units", unitsRoute);
|
||||
// app.use("/update-apartments", updateApartmentsRoute);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import { model, Schema } from "mongoose";
|
||||
|
||||
const unitSchema = new Schema(
|
||||
{
|
||||
propertyName: {
|
||||
type: String,
|
||||
},
|
||||
projectName: {
|
||||
type: String,
|
||||
},
|
||||
floor: {
|
||||
type: Number,
|
||||
},
|
||||
unitNo: {
|
||||
type: String,
|
||||
},
|
||||
propertyStatus: {
|
||||
type: String,
|
||||
},
|
||||
unitType: {
|
||||
type: String,
|
||||
},
|
||||
unitView: {
|
||||
type: String,
|
||||
},
|
||||
furnished: {
|
||||
type: String,
|
||||
},
|
||||
totalArea: {
|
||||
type: Number,
|
||||
},
|
||||
suiteArea: {
|
||||
type: Number,
|
||||
},
|
||||
balconyArea: {
|
||||
type: Number,
|
||||
},
|
||||
bedrooms: {
|
||||
type: Number,
|
||||
},
|
||||
bathrooms: {
|
||||
type: Number,
|
||||
},
|
||||
parkingSpaces: {
|
||||
type: Number,
|
||||
},
|
||||
unitPrice: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true },
|
||||
}
|
||||
);
|
||||
|
||||
const Unit = model("Unit", unitSchema);
|
||||
|
||||
export default Unit;
|
||||
@@ -0,0 +1,88 @@
|
||||
import { Router } from "express";
|
||||
import { searchCurrentApartmentApi } from "../consts.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { IApartment } from "../types/apartment.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
function ConvertApartmentRes(apartment: IApartment) {
|
||||
const convertedApartment: IApartment = {
|
||||
Balcony_Area_Sqft: apartment.Balcony_Area_Sqft,
|
||||
Floor: apartment.Floor,
|
||||
Property_Status: apartment.Property_Status,
|
||||
Unit_Type: apartment.Unit_Type,
|
||||
Project_Name: apartment.Project_Name,
|
||||
Suite_Area_Sqft: apartment.Suite_Area_Sqft,
|
||||
No_Of_Bedrooms: apartment.No_Of_Bedrooms,
|
||||
Unit_No: apartment.Unit_No,
|
||||
id: apartment.id,
|
||||
Total_Area_Sqft: apartment.Total_Area_Sqft,
|
||||
No_of_Bathrooms: apartment.No_of_Bathrooms,
|
||||
Property_Name: apartment.Property_Name,
|
||||
Unit_View: apartment.Unit_View,
|
||||
};
|
||||
|
||||
return convertedApartment;
|
||||
}
|
||||
|
||||
router.get("/:id", async (req, res) => {
|
||||
const accessToken = req?.headers?.authorization;
|
||||
const { id } = req.params;
|
||||
|
||||
try {
|
||||
const url = `${searchCurrentApartmentApi}/${id}`;
|
||||
const requestHeaders: HeadersInit = new Headers();
|
||||
requestHeaders.set("Authorization", `${accessToken}`);
|
||||
const response = await fetch(url, {
|
||||
headers: requestHeaders,
|
||||
});
|
||||
|
||||
if (response.status === 404) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "Квартира не найдена", code: 404 });
|
||||
}
|
||||
if (response.status === 401) {
|
||||
return res
|
||||
.status(401)
|
||||
.json({ message: "Неправильный токен или токен устарел", code: 401 });
|
||||
}
|
||||
const result = await response.json();
|
||||
|
||||
const convertedApartment = ConvertApartmentRes(result.data[0]);
|
||||
|
||||
return res.status(200).json({
|
||||
message: "ok",
|
||||
apartment: convertedApartment,
|
||||
code: 200,
|
||||
});
|
||||
} catch (error) {
|
||||
if (
|
||||
(error as Error).message === "invalid oauth token" ||
|
||||
(error as Error).message === "INVALID_TOKEN"
|
||||
) {
|
||||
console.log("error", error);
|
||||
logger.error(error);
|
||||
|
||||
return res
|
||||
.status(401)
|
||||
.json({ message: "Неправильный токен или токен устарел", code: 401 });
|
||||
}
|
||||
if (
|
||||
(error as Error).message ===
|
||||
"Please check if the URL trying to access is a correct one"
|
||||
) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "Квартира не найдена", code: 404 });
|
||||
}
|
||||
console.log("error", error);
|
||||
logger.error(error);
|
||||
|
||||
return res.status(500).json({ message: "Server Error", code: 500 });
|
||||
}
|
||||
});
|
||||
|
||||
const apartmentRoute = router;
|
||||
|
||||
export default apartmentRoute;
|
||||
@@ -0,0 +1,267 @@
|
||||
import { Router } from "express";
|
||||
import { aparmentsApi, searchCurrentApartmentApi } from "../consts.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { IApartment } from "../types/apartment.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
async function getAllApartments(
|
||||
page: number,
|
||||
accessToken: string,
|
||||
apartments: IApartment[]
|
||||
) {
|
||||
const response = await fetch(`${aparmentsApi}&page=${page}&per_page=200`, {
|
||||
headers: {
|
||||
Authorization: accessToken,
|
||||
},
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result?.code && result?.code === "INVALID_TOKEN") {
|
||||
throw new Error("INVALID_TOKEN");
|
||||
}
|
||||
|
||||
const updatedApartment = apartments.concat([...result.data]);
|
||||
const isMoreRecords = result.info.more_records;
|
||||
|
||||
if (!isMoreRecords) {
|
||||
return updatedApartment;
|
||||
}
|
||||
|
||||
return await getAllApartments(page + 1, accessToken, updatedApartment);
|
||||
}
|
||||
|
||||
function filterApartments(
|
||||
apartments: IApartment[],
|
||||
roveHome?: string[],
|
||||
apartmentType?: string[],
|
||||
costBetween?: string[],
|
||||
totalAreaBetween?: string[],
|
||||
floorBetween?: string[],
|
||||
views?: string[]
|
||||
) {
|
||||
const filteredApartments = apartments
|
||||
.filter((apart) => {
|
||||
// Rove home filter
|
||||
if (!roveHome || roveHome.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (roveHome.some((rove) => rove === apart.Project_Name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.filter((apart) => {
|
||||
// Apartment type filter
|
||||
if (!apartmentType || apartmentType.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (apartmentType.some((rove) => rove === apart.Unit_Type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.filter((apart) => {
|
||||
// Cost between filter еще не доступен тк нет цен
|
||||
|
||||
if (!costBetween || costBetween.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const leftCost = Number(costBetween[0]);
|
||||
const rightCost = Number(costBetween[1]);
|
||||
|
||||
return true;
|
||||
|
||||
// if (costBetween.some((rove) => rove === apart.Unit_Type)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
})
|
||||
.filter((apart) => {
|
||||
// Total area filter
|
||||
if (!totalAreaBetween || totalAreaBetween.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const leftArea = Number(totalAreaBetween[0]);
|
||||
const rightArea = Number(totalAreaBetween[1]);
|
||||
|
||||
if (
|
||||
(leftArea <= apart.Total_Area_Sqft &&
|
||||
rightArea >= apart.Total_Area_Sqft) ||
|
||||
(leftArea >= apart.Total_Area_Sqft &&
|
||||
rightArea <= apart.Total_Area_Sqft)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.filter((apart) => {
|
||||
// Views filter
|
||||
if (!views || views.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//view "Canal" "Amenities"
|
||||
// Canal / Amenities
|
||||
|
||||
// разделение по / с пробелом и без
|
||||
const apartViews = apart.Unit_View.split(" / ").join("/").split("/");
|
||||
for (let i = 0; i < apartViews.length; i++) {
|
||||
// Удаление Corner-
|
||||
const withoutCorner =
|
||||
apartViews[i].split("-").length > 1
|
||||
? apartViews[i].split("-")[1]
|
||||
: apartViews[i];
|
||||
|
||||
//удаление View
|
||||
const withoutView = withoutCorner.replace(" View", "");
|
||||
|
||||
if (views.some((view) => view === withoutView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
.filter((apart) => {
|
||||
// Floor filter
|
||||
|
||||
if (!floorBetween || floorBetween.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const leftFloor = Number(floorBetween[0]);
|
||||
const rightFloor = Number(floorBetween[1]);
|
||||
|
||||
if (
|
||||
(leftFloor <= apart.Floor && rightFloor >= apart.Floor) ||
|
||||
(leftFloor >= apart.Floor && rightFloor <= apart.Floor)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return filteredApartments;
|
||||
}
|
||||
|
||||
router.get("/", async (req, res) => {
|
||||
const accessToken = req?.headers?.authorization;
|
||||
const {
|
||||
per_page = 1000,
|
||||
page = 1,
|
||||
rove_home = "",
|
||||
apartment_type = "",
|
||||
cost_between = "",
|
||||
total_area_between = "",
|
||||
floor_between = "",
|
||||
views = "",
|
||||
sort_by = "",
|
||||
} = req.query;
|
||||
|
||||
try {
|
||||
const roveHomeFilter = (rove_home as string)
|
||||
.split(",")
|
||||
.filter((rove) => rove !== "");
|
||||
const apartmentTypeFilter = (apartment_type as string)
|
||||
.split(",")
|
||||
.filter((rove) => rove !== "");
|
||||
const costBetweenFilter = (cost_between as string)
|
||||
.split(",")
|
||||
.filter((cost) => cost !== "");
|
||||
const totalAreaBetween = (total_area_between as string)
|
||||
.split(",")
|
||||
.filter((area) => area !== "");
|
||||
const viewsFilter = (views as string)
|
||||
.split(",")
|
||||
.filter((view) => view !== "");
|
||||
const floorBetweenFilter = (floor_between as string)
|
||||
.split(",")
|
||||
.filter((floor) => floor !== "");
|
||||
|
||||
if (!accessToken)
|
||||
return res
|
||||
.status(401)
|
||||
.json({ message: "Отсутсвует access token", code: 401 });
|
||||
|
||||
try {
|
||||
const allApartments = await getAllApartments(1, accessToken, []);
|
||||
const filteredApartments = filterApartments(
|
||||
allApartments,
|
||||
roveHomeFilter,
|
||||
apartmentTypeFilter,
|
||||
costBetweenFilter,
|
||||
totalAreaBetween,
|
||||
floorBetweenFilter,
|
||||
viewsFilter
|
||||
);
|
||||
|
||||
const sortedApartments = [...filteredApartments].sort((a, b) => {
|
||||
if (sort_by === "asc_price") {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sort_by === "decr_price") {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sort_by === "asc_sqr") {
|
||||
return a.Total_Area_Sqft - b.Total_Area_Sqft;
|
||||
}
|
||||
|
||||
if (sort_by === "asc_floor") {
|
||||
return a.Floor - b.Floor;
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
const slicedApartments = sortedApartments.slice(
|
||||
((page as number) - 1) * (per_page as number),
|
||||
(per_page as number) * (page as number)
|
||||
);
|
||||
|
||||
res.status(200).json({
|
||||
message: "ok",
|
||||
apartments: slicedApartments,
|
||||
code: 200,
|
||||
});
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
if (
|
||||
(error as Error).message === "invalid oauth token" ||
|
||||
(error as Error).message === "INVALID_TOKEN"
|
||||
) {
|
||||
console.log("error", error);
|
||||
logger.error(error);
|
||||
|
||||
return res
|
||||
.status(401)
|
||||
.json({ message: "Неправильный токен или токен устарел", code: 401 });
|
||||
}
|
||||
|
||||
console.log("error", error);
|
||||
logger.error(error);
|
||||
|
||||
return res.status(500).json({ message: "Server Error", code: 500 });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
console.log("error", error);
|
||||
}
|
||||
});
|
||||
|
||||
const apartmentsRoute = router;
|
||||
|
||||
export default apartmentsRoute;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Router } from "express";
|
||||
import Unit from "../models/Unit.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", async (req, res) => {
|
||||
try {
|
||||
const units = await Unit.find(req.query);
|
||||
|
||||
res.json(units);
|
||||
} catch (error) {
|
||||
res.json({ error: (error as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:id", async (req, res) => {
|
||||
try {
|
||||
const unit = await Unit.findById(req.params.id);
|
||||
|
||||
res.json(unit);
|
||||
} catch (error) {
|
||||
res.json({ error: (error as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
const unitsRoute = router;
|
||||
|
||||
export default unitsRoute;
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Router } from "express";
|
||||
import data from "../data/irth_unit_pirces.json" assert { type: "json" };
|
||||
import Unit from "../models/Unit.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", async (req, res) => {
|
||||
for (const item of data) {
|
||||
const result = await Unit.findOneAndUpdate(
|
||||
{ propertyName: item.unitName },
|
||||
{ unitPrice: item.unitPrice },
|
||||
{ new: true }
|
||||
);
|
||||
|
||||
console.log("result", result);
|
||||
}
|
||||
|
||||
// const file = fs.readFileSync(
|
||||
// path.resolve("./src/data/irth_unit_pirces.json"),
|
||||
// { encoding: "utf8" }
|
||||
// );
|
||||
|
||||
// const data = JSON.parse(file);
|
||||
|
||||
res.json({ ok: 1 });
|
||||
});
|
||||
|
||||
const updateApartmentsRoute = router;
|
||||
|
||||
export default updateApartmentsRoute;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { updateAccessTokenApi } from "../consts.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
|
||||
var updateAccessToken = async function (req: Request, res: Response) {
|
||||
try {
|
||||
const response = await fetch(updateAccessTokenApi, {
|
||||
method: "post",
|
||||
});
|
||||
|
||||
const { access_token } = await response.json();
|
||||
return res.json({ accessToken: access_token });
|
||||
} catch (error) {
|
||||
console.log("error", (error as Error).message);
|
||||
logger.error(error);
|
||||
|
||||
return res.json({ error: (error as Error).message });
|
||||
}
|
||||
};
|
||||
|
||||
export default updateAccessToken;
|
||||
@@ -0,0 +1,17 @@
|
||||
interface IApartment {
|
||||
Floor: number;
|
||||
Property_Status: string;
|
||||
Unit_Type: string;
|
||||
Project_Name: string;
|
||||
Suite_Area_Sqft: number;
|
||||
Balcony_Area_Sqft: number;
|
||||
No_Of_Bedrooms: number;
|
||||
Unit_No: string;
|
||||
id: string;
|
||||
Total_Area_Sqft: number;
|
||||
No_of_Bathrooms: number;
|
||||
Property_Name: string;
|
||||
Unit_View: string;
|
||||
}
|
||||
|
||||
export type { IApartment };
|
||||
@@ -0,0 +1,27 @@
|
||||
import * as winston from "winston";
|
||||
|
||||
const { combine, timestamp, json } = winston.format;
|
||||
|
||||
export const logger = winston.createLogger({
|
||||
level: "info",
|
||||
format: combine(
|
||||
timestamp({
|
||||
format: "YYYY-MM-DD hh:mm:ss.SSS A",
|
||||
}),
|
||||
json()
|
||||
),
|
||||
transports: [
|
||||
//
|
||||
// - Write to all logs with level `debug` and below to `all.log`
|
||||
// - Write all logs error (and below) to `error.log`.
|
||||
//
|
||||
new winston.transports.File({
|
||||
filename: "logs/error.log",
|
||||
level: "error",
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: "logs/all.log",
|
||||
level: "debug",
|
||||
}),
|
||||
],
|
||||
});
|
||||
Reference in New Issue
Block a user