first commit

This commit is contained in:
2026-01-26 10:54:31 +03:30
commit 1db3038221
20 changed files with 4026 additions and 0 deletions

8
.dockerignore Normal file
View File

@@ -0,0 +1,8 @@
node_modules
npm-debug.log
Dockerfile
docker-compose.yml
.git
.gitignore
.env

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
.env
uploads/

9
Dockerfile Normal file
View File

@@ -0,0 +1,9 @@
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
ENV PORT=3000
EXPOSE 3000
CMD ["npm", "start"]

21
docker-compose.yml Normal file
View File

@@ -0,0 +1,21 @@
services:
api:
build: .
ports:
- "3000:3000"
environment:
- PORT=3000
- MONGODB_URI=mongodb://appuser:apppass@mongo:27017/inspect?authSource=admin
depends_on:
- mongo
mongo:
image: mongo:7
restart: unless-stopped
environment:
- MONGO_INITDB_ROOT_USERNAME=appuser
- MONGO_INITDB_ROOT_PASSWORD=apppass
- MONGO_INITDB_DATABASE=inspect
volumes:
- mongo-data:/data/db
volumes:
mongo-data:

27
lib/jwtUtils.js Normal file
View File

@@ -0,0 +1,27 @@
const jwt = require("jsonwebtoken");
const generateToken = (userId) => {
const token = jwt.sign({ userId }, "[)51k:7W71Ki+^p:;XxE4LQ£-I@B49", {
expiresIn: "7d",
});
return token;
};
const verifyToken = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ message: "Unauthorized: Token missing" });
}
jwt.verify(token, "[)51k:7W71Ki+^p:;XxE4LQ£-I@B49", (err, decoded) => {
if (err) {
return res.status(401).json({ message: "Unauthorized: Invalid token" });
}
req.userId = decoded.userId;
next();
});
};
module.exports = { generateToken, verifyToken };

89
models/Inspect.js Normal file
View File

@@ -0,0 +1,89 @@
const mongoose = require("mongoose");
const inspectSchema = new mongoose.Schema(
{
place_key: {
type: String,
required: true,
},
user_id: {
type: String,
required: true,
},
province: {
type: String,
required: true,
},
license_type: {
type: String,
required: false,
},
document_number: {
type: String,
required: false,
},
issuer: {
type: String,
required: false,
},
economic_code: {
type: String,
required: false,
},
registration_number: {
type: String,
required: false,
},
ownership_type: {
type: String,
required: false,
},
unit_type: {
type: String,
required: false,
},
description: {
type: String,
required: false,
},
violation_amount: {
type: String,
required: false,
},
plaintiff_damage: {
type: String,
required: false,
},
infractions: {
type: [
{
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
},
],
required: false,
},
inspectors: {
type: [
{
fullname: {
type: String,
required: true,
},
},
],
required: false,
},
},
{ timestamps: true }
);
const Place = mongoose.model("Inspect", inspectSchema);
module.exports = Place;

13
models/UpdateData.js Normal file
View File

@@ -0,0 +1,13 @@
const mongoose = require("mongoose");
const UpdateDataSchema = new mongoose.Schema({
records: {
type: Map,
of: [mongoose.Schema.Types.Mixed],
default: {},
},
});
const UpdateData = mongoose.model("UpdateData", UpdateDataSchema);
module.exports = UpdateData;

48
models/herd.js Normal file
View File

@@ -0,0 +1,48 @@
const mongoose = require("mongoose");
const inspectSchema = new mongoose.Schema({
agent: {
type: String,
required: false,
},
birth_day: {
type: String,
required: false,
},
contractor_code: {
type: String,
required: false,
},
gender: {
type: String,
required: false,
},
herd_code: {
type: String,
required: false,
},
national_id_livestock_code: {
type: String,
required: false,
},
registering_date: {
type: String,
required: false,
},
registering_user: {
type: String,
required: false,
},
type: {
type: String,
required: false,
},
unique_identifier: {
type: String,
required: false,
},
});
const Herd = mongoose.model("Herds", inspectSchema);
module.exports = Herd;

36
models/peopleInfo.js Normal file
View File

@@ -0,0 +1,36 @@
const mongoose = require("mongoose");
const peopleInfoSchema = new mongoose.Schema(
{
mobile: { type: String, required: false, index: true },
name: { type: String, required: false, index: true },
family: { type: String, required: false, index: true },
birthdate: { type: String, required: false },
nationalcode: { type: String, required: false, index: true },
mellicard: { type: String, required: false },
info1: { type: String, required: false },
info2: { type: String, required: false },
info3: { type: String, required: false },
info4: { type: String, required: false },
},
{ timestamps: false }
);
peopleInfoSchema.index({ nationalcode: 1 });
peopleInfoSchema.index({ mobile: 1 });
peopleInfoSchema.index({ name: 1, family: 1 });
peopleInfoSchema.index(
{ name: "text", family: "text" },
{
default_language: "none",
weights: { name: 10, family: 10 },
}
);
peopleInfoSchema.index({ name: 1 });
peopleInfoSchema.index({ family: 1 });
const PeopleInfo = mongoose.model("PeopleInfo", peopleInfoSchema);
module.exports = PeopleInfo;

27
models/place.js Normal file
View File

@@ -0,0 +1,27 @@
const mongoose = require("mongoose");
const placeSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
location: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
},
{ timestamps: true }
);
const Place = mongoose.model("Place", placeSchema);
module.exports = Place;

15
models/user.js Normal file
View File

@@ -0,0 +1,15 @@
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
mobile: { type: String, required: true, unique: true },
password: { type: String, required: true },
fullname: { type: String, required: true, unique: false },
pic: { type: String, required: false },
province: { type: String, required: true },
city: { type: String, required: false },
permissions: { type: Array, default: ["all"], required: false },
});
const User = mongoose.model("User", userSchema);
module.exports = User;

2134
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"dependencies": {
"axios": "^1.7.7",
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^17.2.3",
"express": "^4.18.2",
"jsonstream": "^1.0.3",
"JSONStream": "^1.3.5",
"jsonwebtoken": "^9.0.2",
"mongodb": "^6.3.0",
"mongoose": "^8.0.3",
"oboe": "^2.1.7",
"querystring": "^0.2.1",
"stream-json": "^1.9.1"
},
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"devStart": "nodemon server.js"
},
"devDependencies": {
"nodemon": "^3.0.2"
}
}

54
routes/herdRoutes.js Normal file
View File

@@ -0,0 +1,54 @@
const express = require("express");
const router = express.Router();
const Herd = require("../models/herd");
const { verifyToken } = require("../lib/jwtUtils");
router.post("/herds", async (req, res) => {
try {
const {
agent,
birth_day,
contractor_code,
gender,
herd_code,
national_id_livestock_code,
registering_date,
registering_user,
type,
unique_identifier,
} = req.body;
const newHerd = new Herd({
agent,
birth_day,
contractor_code,
gender,
herd_code,
national_id_livestock_code,
registering_date,
registering_user,
type,
unique_identifier,
});
const savedHerd = await newHerd.save();
res.status(201).json(savedHerd);
} catch (error) {
console.error("Error creating herd:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/herds", async (req, res) => {
try {
const herds = await Herd.find();
res.status(200).json(herds);
} catch (error) {
console.error("Error retrieving herds:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
module.exports = router;

225
routes/inspectRoutes.js Normal file
View File

@@ -0,0 +1,225 @@
const express = require("express");
const router = express.Router();
const Inspect = require("../models/Inspect");
const { verifyToken } = require("../lib/jwtUtils");
router.use(verifyToken);
router.post("/inspections", async (req, res) => {
try {
const {
place_key,
province,
license_type,
document_number,
issuer,
economic_code,
registration_number,
ownership_type,
unit_type,
description,
infractions,
violation_amount,
plaintiff_damage,
inspectors,
user_id,
} = req.body;
const newInspection = new Inspect({
place_key,
province,
license_type,
document_number,
issuer,
economic_code,
registration_number,
ownership_type,
unit_type,
description,
infractions,
violation_amount,
plaintiff_damage,
inspectors,
user_id,
});
await newInspection.save();
res.status(201).json({
message: "inspection created successfully",
place: newInspection,
});
} catch (error) {
console.error("Error creating inspection:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/inspections/:place_key", async (req, res) => {
try {
const placeId = req.params.place_key;
const inspections = await Inspect.find({ place_key: placeId }).sort({
createdAt: -1,
});
if (!inspections || inspections.length === 0) {
return res
.status(404)
.json({ message: "Inspections not found for this place" });
}
res.status(200).json(inspections);
} catch (error) {
console.error("Error retrieving inspections:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/userinspections/:userInspects", async (req, res) => {
try {
const userInspects = req.params.userInspects;
const inspections = await Inspect.find({ user_id: userInspects }).sort({
createdAt: -1,
});
if (!inspections || inspections.length === 0) {
return res
.status(404)
.json({ message: "Inspections not found for this user" });
}
res.status(200).json(inspections);
} catch (error) {
console.error("Error retrieving inspections:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/inspects", async (req, res) => {
try {
const places = await Inspect.find().sort({ createdAt: -1 });
res.status(200).json(places);
} catch (error) {
console.error("Error retrieving inspects:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/inspectkeys", async (req, res) => {
try {
const places = await Inspect.find()
.select("place_key infractions")
.sort({ createdAt: -1 });
const placesWithInfractions = places.map((place) => ({
place_key: place.place_key,
hasInfractions: place.infractions.length > 0,
}));
res.status(200).json(placesWithInfractions);
} catch (error) {
console.error("Error retrieving inspects:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.delete("/inspections/:inspectId", async (req, res) => {
try {
const inspectId = req.params.inspectId;
const deletedPlace = await Inspect.findByIdAndDelete(inspectId);
if (!deletedPlace) {
return res.status(404).json({ message: "Inspection not found" });
}
res.status(200).json({
message: "Inspection deleted successfully",
place: deletedPlace,
});
} catch (error) {
console.error("Error deleting inspection:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.delete(
"/inspections/:id/infractions/:infractionId",
async (req, res) => {
const inspectId = req.params.id;
const infractionId = req.params.infractionId;
try {
const inspect = await Inspect.findById(inspectId);
if (!inspect) {
return res.status(404).json({ message: "Place not found" });
}
inspect.infractions.pull({ _id: infractionId });
await inspect.save();
res.status(200).json({ message: "Infraction deleted successfully" });
} catch (error) {
console.error("Error deleting infraction:", error);
res.status(500).json({ message: "Internal Server Error" });
}
}
);
//routes
router.put("/inspections/:inspectionId", async (req, res) => {
try {
const inspectionId = req.params.inspectionId;
const {
place_key,
province,
license_type,
document_number,
issuer,
economic_code,
registration_number,
ownership_type,
unit_type,
description,
infractions,
violation_amount,
plaintiff_damage,
inspectors,
} = req.body;
const updatedPlace = await Inspect.findByIdAndUpdate(
inspectionId,
{
place_key,
province,
license_type,
document_number,
issuer,
economic_code,
registration_number,
ownership_type,
unit_type,
description,
infractions,
violation_amount,
plaintiff_damage,
inspectors,
},
{ new: true }
);
if (!updatedPlace) {
return res.status(404).json({ message: "Inspection not found" });
}
res.status(200).json({
message: "Inspection updated successfully",
place: updatedPlace,
});
} catch (error) {
console.error("Error updating Inspection:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
module.exports = router;

View File

@@ -0,0 +1,543 @@
const express = require("express");
const router = express.Router();
const https = require("https");
const querystring = require("querystring");
const zlib = require("zlib");
const { verifyToken } = require("../lib/jwtUtils");
function getRandomElement(array) {
const randomIndex = Math.floor(Math.random() * array.length);
return array[randomIndex];
}
function parseBaJsonResponse(response, rawBuffer) {
const encoding = String(response.headers["content-encoding"] || "")
.trim()
.toLowerCase();
let buf = rawBuffer;
if (encoding === "gzip") {
buf = zlib.gunzipSync(buf);
} else if (encoding === "deflate") {
buf = zlib.inflateSync(buf);
} else if (encoding === "br") {
buf = zlib.brotliDecompressSync(buf);
}
return JSON.parse(buf.toString("utf8"));
}
async function performLogin() {
const getOptions = {
hostname: "ba124.ir",
path: "/Account/Login",
method: "GET",
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7",
Connection: "keep-alive",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
},
};
const loginPageCookies = await new Promise((resolve, reject) => {
const request = https.request(getOptions, (response) => {
let data = "";
response.on("data", (chunk) => {
data += chunk;
});
response.on("end", () => {
const csrfMatch = data.match(
/<input name="__RequestVerificationToken" type="hidden" value="([^"]+)"/
);
const csrfToken = csrfMatch ? csrfMatch[1] : null;
if (!csrfToken) {
reject(new Error("Could not extract CSRF token"));
return;
}
const cookies = response.headers["set-cookie"] || [];
const cookieString = cookies
.map((cookie) => cookie.split(";")[0])
.join("; ");
resolve({ csrfToken, cookieString });
});
});
request.on("error", (error) => {
reject(error);
});
request.end();
});
const randomUser = getRandomElement([
4072893341, 4072452238, 4070413170, 4189617652, 4071417919, 4172069355,
]);
const postData = querystring.stringify({
NationalId: randomUser,
Password: randomUser,
__RequestVerificationToken: loginPageCookies.csrfToken,
});
const postOptions = {
hostname: "ba124.ir",
path: "/Account/Login",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Content-Length": Buffer.byteLength(postData),
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7",
Connection: "keep-alive",
Cookie: loginPageCookies.cookieString,
Host: "ba124.ir",
Origin: "https://ba124.ir",
Referer: "https://ba124.ir/Account/Login",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
},
};
const finalCookie = await new Promise((resolve, reject) => {
const request = https.request(postOptions, (response) => {
response.on("data", () => {});
response.on("end", () => {
const cookies = response.headers["set-cookie"] || [];
const cookieString = cookies
.map((cookie) => cookie.split(";")[0])
.join("; ");
const combinedCookie = loginPageCookies.cookieString
? `${loginPageCookies.cookieString}; ${cookieString}`
: cookieString;
resolve(combinedCookie);
});
});
request.on("error", (error) => {
reject(error);
});
request.write(postData);
request.end();
});
return finalCookie;
}
async function makeInquiryRequest(info, type, cookie) {
const payloadData =
type === "person"
? querystring.stringify({
nationalCode: info,
birthDateString: "1404/08/12",
})
: type === "unit"
? querystring.stringify({
NationalCode: info,
})
: JSON.stringify({
NationaId: info,
});
const requestOptions = {
hostname: "ba124.ir",
path:
type === "person"
? "/Inquiries/PersonInfo"
: type === "unit"
? "/Inquiries/CallGetLegalPersonInfoByNationalCode"
: "/Inquiries/AsnafGWLicenseInquiry",
method: "POST",
headers: {
"Content-Type":
type === "person" || type === "unit"
? "application/x-www-form-urlencoded; charset=UTF-8"
: "application/json; charset=UTF-8",
"Content-Length": Buffer.byteLength(payloadData),
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
Accept: "application/json, text/javascript, */*; q=0.01",
Accept_Encoding: "gzip, deflate, br, zstd",
Accept_Language: "en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7",
Connection: "keep-alive",
Cookie: cookie,
Host: "ba124.ir",
Origin: "https://ba124.ir",
Referer:
type === "person"
? "https://ba124.ir/Inquiries/PersonInfo"
: type === "unit"
? "https://ba124.ir/Inquiries/GetLegalPersonInfoByNationalCode"
: "https://ba124.ir/Inquiries/AsnafGWLicenseInquiry",
"Sec-Ch-Ua":
'"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"X-Requested-With": "XMLHttpRequest",
},
};
const finalInfo = await new Promise((resolve, reject) => {
const request = https.request(requestOptions, (response) => {
const chunks = [];
response.on("data", (chunk) => {
chunks.push(chunk);
});
response.on("end", () => {
try {
const raw = Buffer.concat(chunks);
const jsonData = parseBaJsonResponse(response, raw);
resolve(jsonData);
} catch (error) {
reject(new Error(`Invalid JSON response: ${error.message}`));
}
});
});
request.on("error", (error) => {
reject(error);
});
request.write(payloadData);
request.end();
});
return finalInfo;
}
async function makeLadingRequest(start, end, postal, cookie) {
const payloadData = JSON.stringify({
FromIssuDate: start,
ToIssuDate: end,
CodePosti: postal,
MabdaYaMaghsad: 3,
});
const requestOptions = {
hostname: "ba124.ir",
path: "/Inquiries/CallGetBarnamehInfoByCodePosti",
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
"Content-Length": Buffer.byteLength(payloadData),
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
Accept: "application/json, text/javascript, */*; q=0.01",
Accept_Encoding: "gzip, deflate, br, zstd",
Accept_Language:
"en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7,ar-AE;q=0.6,ar;q=0.5,en-GB;q=0.4",
Connection: "keep-alive",
Cookie: cookie,
Host: "ba124.ir",
Origin: "https://ba124.ir",
Referer: "https://ba124.ir/Inquiries/GetBarnamehInfoByCodePosti",
"Sec-Ch-Ua":
'"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Linux"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"X-Requested-With": "XMLHttpRequest",
},
};
const finalInfo = await new Promise((resolve, reject) => {
const request = https.request(requestOptions, (response) => {
const chunks = [];
response.on("data", (chunk) => {
chunks.push(chunk);
});
response.on("end", () => {
try {
const raw = Buffer.concat(chunks);
const jsonData = parseBaJsonResponse(response, raw);
resolve(jsonData);
} catch (error) {
reject(new Error(`Invalid JSON response: ${error.message}`));
}
});
});
request.on("error", (error) => {
reject(error);
});
request.write(payloadData);
request.end();
});
return finalInfo;
}
async function makeVeterinaryTransferRequest(trIDCode, cookie) {
const payloadData = querystring.stringify({
trIDCode,
});
const requestOptions = {
hostname: "ba124.ir",
path: "/Inquiries/CallVeterinaryTransfer",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Content-Length": Buffer.byteLength(payloadData),
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
Accept: "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language":
"en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7,ar-AE;q=0.6,ar;q=0.5,en-GB;q=0.4",
Connection: "keep-alive",
Cookie: cookie,
Host: "ba124.ir",
Origin: "https://ba124.ir",
Referer: "https://ba124.ir/Inquiries/VeterinaryTransfer",
"Sec-Ch-Ua":
'"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Linux"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"X-Requested-With": "XMLHttpRequest",
},
};
const finalInfo = await new Promise((resolve, reject) => {
const request = https.request(requestOptions, (response) => {
const chunks = [];
response.on("data", (chunk) => {
chunks.push(chunk);
});
response.on("end", () => {
try {
const raw = Buffer.concat(chunks);
const jsonData = parseBaJsonResponse(response, raw);
resolve(jsonData);
} catch (error) {
reject(new Error(`Invalid JSON response: ${error.message}`));
}
});
});
request.on("error", (error) => {
reject(error);
});
request.write(payloadData);
request.end();
});
return finalInfo;
}
async function makeAgriWindowsUnitsRequest(PartIdCode, cookie) {
const payloadData = querystring.stringify({
PartIdCode,
});
const requestOptions = {
hostname: "ba124.ir",
path: "/Inquiries/CallAgriWindowsUnits",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Content-Length": Buffer.byteLength(payloadData),
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
Accept: "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language":
"en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7,ar-AE;q=0.6,ar;q=0.5,en-GB;q=0.4",
Connection: "keep-alive",
Cookie: cookie,
Host: "ba124.ir",
Origin: "https://ba124.ir",
Referer: "https://ba124.ir/Inquiries/VeterinaryTransfer",
"Sec-Ch-Ua":
'"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Linux"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"X-Requested-With": "XMLHttpRequest",
},
};
const finalInfo = await new Promise((resolve, reject) => {
const request = https.request(requestOptions, (response) => {
const chunks = [];
response.on("data", (chunk) => {
chunks.push(chunk);
});
response.on("end", () => {
try {
const raw = Buffer.concat(chunks);
const jsonData = parseBaJsonResponse(response, raw);
resolve(jsonData);
} catch (error) {
reject(new Error(`Invalid JSON response: ${error.message}`));
}
});
});
request.on("error", (error) => {
reject(error);
});
request.write(payloadData);
request.end();
});
return finalInfo;
}
router.use(verifyToken);
router.get("/national-documents", async (req, res) => {
const { info, type } = req.query;
if (!info) {
return res.status(400).json({
error: "Missing required field: info",
});
}
try {
let finalCookie = await performLogin();
let finalInfo = await makeInquiryRequest(info, type, finalCookie);
while (finalInfo && finalInfo.error) {
console.log("Session expired, retrying login and request...");
finalCookie = await performLogin();
finalInfo = await makeInquiryRequest(info, type, finalCookie);
}
res.json(finalInfo);
} catch (error) {
res.status(500).json({
error: "Failed to fetch person info",
message: error.message,
});
}
});
router.get("/ladinginfo", async (req, res) => {
const { start, end, postal } = req.query;
if (!start || !end || !postal) {
return res.status(400).json({
error: "Missing required fields: start, end, and postal are required",
});
}
try {
let finalCookie = await performLogin();
let finalInfo = await makeLadingRequest(start, end, postal, finalCookie);
while (finalInfo && finalInfo.error) {
console.log("Session expired, retrying login and request...");
finalCookie = await performLogin();
finalInfo = await makeLadingRequest(start, end, postal, finalCookie);
}
res.json(finalInfo);
} catch (error) {
res.status(500).json({
error: "Failed to fetch lading info",
message: error.message,
});
}
});
router.get("/veterinary-transfer", async (req, res) => {
const { trIDCode } = req.query;
if (!trIDCode) {
return res.status(400).json({
error: "Missing required field: trIDCode",
});
}
try {
let finalCookie = await performLogin();
let finalInfo = await makeVeterinaryTransferRequest(trIDCode, finalCookie);
while (finalInfo && finalInfo.error) {
console.log("Session expired, retrying login and request...");
finalCookie = await performLogin();
finalInfo = await makeVeterinaryTransferRequest(trIDCode, finalCookie);
}
res.json(finalInfo);
} catch (error) {
res.status(500).json({
error: "Failed to fetch veterinary transfer info",
message: error.message,
});
}
});
router.get("/inquiry-farm", async (req, res) => {
const { PartIdCode } = req.query;
if (!PartIdCode) {
return res.status(400).json({
error: "Missing required field: PartIdCode",
});
}
try {
let finalCookie = await performLogin();
let finalInfo = await makeAgriWindowsUnitsRequest(PartIdCode, finalCookie);
while (finalInfo && finalInfo.error) {
console.log("Session expired, retrying login and request...");
finalCookie = await performLogin();
finalInfo = await makeAgriWindowsUnitsRequest(PartIdCode, finalCookie);
}
res.json(finalInfo);
} catch (error) {
res.status(500).json({
error: "Failed to fetch inquiry farm info",
message: error.message,
});
}
});
module.exports = router;

359
routes/peopleInfoRoutes.js Normal file
View File

@@ -0,0 +1,359 @@
const express = require("express");
const router = express.Router();
const PeopleInfo = require("../models/peopleInfo");
router.get("/people_info", async (req, res) => {
try {
const { searchfield, value } = req.query;
if (!searchfield || !value) {
return res.status(400).json({
message: "searchfield and value parameters are required",
});
}
let matchQuery = {};
if (searchfield === "mobile") {
let normalizedSearch = value.replace(/\D/g, "");
const withLeadingZero = normalizedSearch.startsWith("0")
? normalizedSearch
: `0${normalizedSearch}`;
const withoutLeadingZero = normalizedSearch.startsWith("0")
? normalizedSearch.substring(1)
: normalizedSearch;
const numericValue = parseInt(withoutLeadingZero, 10);
matchQuery = {
$or: [
{ mobile: withLeadingZero },
{ mobile: withoutLeadingZero },
{ mobile: numericValue },
],
};
} else if (searchfield === "name") {
matchQuery = {
$or: [
{ name: { $regex: value, $options: "i" } },
{ family: { $regex: value, $options: "i" } },
{
$expr: {
$regexMatch: {
input: { $concat: ["$name", " ", "$family"] },
regex: value,
options: "i",
},
},
},
],
};
} else if (searchfield === "nationalcode") {
matchQuery = { nationalcode: value };
} else {
return res.status(400).json({
message:
"Invalid searchfield. Must be 'mobile', 'name', or 'nationalcode'",
});
}
const pipeline = [
{ $match: matchQuery },
{ $limit: 10000 },
{
$group: {
_id: "$nationalcode",
items: {
$push: {
name: "$name",
family: "$family",
mobile: "$mobile",
mellicard: "$mellicard",
mellatcard: "$mellatcard",
father: "$father",
birthdate: "$birthdate",
info1: "$info1",
info2: "$info2",
info3: "$info3",
info4: "$info4",
hasMellatcard: {
$cond: [{ $ne: ["$mellatcard", null] }, true, false],
},
hasMellicard: {
$cond: [{ $ne: ["$mellicard", null] }, true, false],
},
},
},
},
},
{
$project: {
nationalcode: "$_id",
items: 1,
firstWithMellatcard: {
$arrayElemAt: [
{
$filter: {
input: "$items",
as: "item",
cond: { $eq: ["$$item.hasMellatcard", true] },
},
},
0,
],
},
firstWithMellicard: {
$arrayElemAt: [
{
$filter: {
input: "$items",
as: "item",
cond: { $eq: ["$$item.hasMellicard", true] },
},
},
0,
],
},
hasAnyMellatcard: {
$gt: [
{
$size: {
$filter: {
input: "$items",
as: "item",
cond: { $eq: ["$$item.hasMellatcard", true] },
},
},
},
0,
],
},
hasAnyMellicard: {
$gt: [
{
$size: {
$filter: {
input: "$items",
as: "item",
cond: { $eq: ["$$item.hasMellicard", true] },
},
},
},
0,
],
},
},
},
{
$project: {
nationalcode: 1,
name: {
$cond: [
{ $ne: ["$firstWithMellatcard", null] },
"$firstWithMellatcard.name",
{
$cond: [
{ $ne: ["$firstWithMellicard", null] },
"$firstWithMellicard.name",
{ $arrayElemAt: ["$items.name", 0] },
],
},
],
},
family: {
$cond: [
{ $ne: ["$firstWithMellatcard", null] },
"$firstWithMellatcard.family",
{
$cond: [
{ $ne: ["$firstWithMellicard", null] },
"$firstWithMellicard.family",
{ $arrayElemAt: ["$items.family", 0] },
],
},
],
},
father: {
$cond: [
{ $ne: ["$firstWithMellatcard", null] },
"$firstWithMellatcard.father",
{
$cond: [
{ $ne: ["$firstWithMellicard", null] },
"$firstWithMellicard.father",
null,
],
},
],
},
birthdate: {
$cond: [
{ $ne: ["$firstWithMellatcard", null] },
"$firstWithMellatcard.birthdate",
{
$cond: [
{ $ne: ["$firstWithMellicard", null] },
"$firstWithMellicard.birthdate",
null,
],
},
],
},
mobile: {
$filter: {
input: "$items.mobile",
as: "mob",
cond: { $ne: ["$$mob", null] },
},
},
allCards: {
$reduce: {
input: "$items",
initialValue: [],
in: {
$concatArrays: [
"$$value",
{
$filter: {
input: ["$$this.mellatcard", "$$this.mellicard"],
as: "card",
cond: { $ne: ["$$card", null] },
},
},
],
},
},
},
info: {
$reduce: {
input: "$items",
initialValue: [],
in: {
$concatArrays: [
"$$value",
{
$filter: {
input: [
"$$this.info1",
"$$this.info2",
"$$this.info3",
"$$this.info4",
],
as: "inf",
cond: { $ne: ["$$inf", null] },
},
},
],
},
},
},
},
},
{
$project: {
nationalcode: 1,
name: 1,
family: 1,
father: 1,
birthdate: 1,
mobile: 1,
card: "$allCards",
info: 1,
},
},
];
const results = await PeopleInfo.aggregate(pipeline).allowDiskUse(true);
const processedResults = results.map((result) => {
const mobileSet = new Set();
result.mobile.forEach((mob) => {
if (mob == null) return;
const mobStr = String(mob);
const normalized = mobStr.startsWith("0")
? mobStr.substring(1)
: mobStr;
mobileSet.add(`0${normalized}`);
});
result.mobile = Array.from(mobileSet);
if (result.card) {
const cardSet = new Set();
result.card.forEach((card) => {
if (card && typeof card === "string") {
cardSet.add(card.trim());
}
});
result.card = Array.from(cardSet);
}
if (result.birthdate && result.birthdate instanceof Date) {
result.birthdate = result.birthdate.toISOString().split("T")[0];
}
result.info = result.info.map((inf) => {
return typeof inf === "string" ? inf.replace(/\t/g, "") : inf;
});
return result;
});
res.status(200).json({
data: processedResults,
count: processedResults.length,
});
} catch (error) {
console.error("Error fetching people info:", error);
res
.status(500)
.json({ message: "Internal Server Error", error: error.message });
}
});
router.post("/people_info", async (req, res) => {
try {
const {
first_name,
last_name,
mobile,
postal,
province,
city,
nationalcode,
} = req.body;
const newPeopleInfo = new PeopleInfo({
first_name,
last_name,
mobile,
postal,
province,
city,
nationalcode,
});
await newPeopleInfo.save();
res.status(201).json({
message: "People info created successfully",
data: newPeopleInfo,
});
} catch (error) {
console.error("Error creating people info:", error);
res
.status(500)
.json({ message: "Internal Server Error", error: error.message });
}
});
module.exports = router;

159
routes/placeRoutes.js Normal file
View File

@@ -0,0 +1,159 @@
const express = require("express");
const router = express.Router();
const Place = require("../models/place");
const UpdateData = require("../models/UpdateData");
const { verifyToken } = require("../lib/jwtUtils");
router.use(verifyToken);
router.post("/place", async (req, res) => {
try {
const { name, description, location, category } = req.body;
const newPlace = new Place({ name, description, location, category });
await newPlace.save();
res
.status(201)
.json({ message: "Place created successfully", place: newPlace });
} catch (error) {
console.error("Error creating place:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/place_data/:placeId", async (req, res) => {
try {
const placeId = req.params.placeId;
const place = await Place.findById(placeId);
if (!place) {
return res.status(404).json({ message: "Place not found" });
}
res.status(200).json({ place });
} catch (error) {
console.error("Error retrieving place:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/places", async (req, res) => {
try {
const places = await Place.find();
res.status(200).json(places);
} catch (error) {
console.error("Error retrieving places:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.delete("/places/:placeId", async (req, res) => {
try {
const placeId = req.params.placeId;
const deletedPlace = await Place.findByIdAndDelete(placeId);
if (!deletedPlace) {
return res.status(404).json({ message: "Place not found" });
}
res
.status(200)
.json({ message: "Place deleted successfully", place: deletedPlace });
} catch (error) {
console.error("Error deleting place:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.put("/places/:placeId", async (req, res) => {
try {
const placeId = req.params.placeId;
const { name, description, location, category } = req.body;
const updatedPlace = await Place.findByIdAndUpdate(
placeId,
{ name, description, location, category },
{ new: true } // Set { new: true } to return the updated document
);
if (!updatedPlace) {
return res.status(404).json({ message: "Place not found" });
}
res
.status(200)
.json({ message: "Place updated successfully", place: updatedPlace });
} catch (error) {
console.error("Error updating place:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.post("/update-data", async (req, res) => {
const { province } = req.body;
if (!province) {
return res.status(400).send("Province is required");
}
let api = `https://pos.rasadyaar.ir/api/report/pos/${province}`;
console.log("Fetching data from:", api);
try {
const response = await fetch(api);
const newProvinceData = await response.json();
await UpdateData.updateOne(
{},
{ $set: { [`records.${province}`]: newProvinceData } },
{ upsert: true }
);
res.status(200).send(`Data for ${province} successfully updated!`);
} catch (error) {
console.error("Error fetching or updating province data:", error);
res.status(500).send("Failed to update data.");
}
});
router.get("/stewards/:key", async (req, res) => {
const { key } = req.params;
try {
const data = await UpdateData.findOne();
if (data && data.records) {
const recordData = data.records.get(key);
if (recordData) {
res.status(200).json(recordData);
} else {
res.status(404).json({ message: `No data found for key: ${key}` });
}
} else {
res.status(404).json({ message: "No data found" });
}
} catch (error) {
console.error(error);
res.status(500).json({ message: "Server error" });
}
});
module.exports = router;
// router
// .route("/:id")
// .get((req, res) => {
// res.send(`User Get ${req.params.id}`);
// })
// .post((req, res) => {
// res.send(`User Get ${req.params.id}`);
// })
// .put((req, res) => {
// res.send(`User Get ${req.params.id}`);
// })
// .delete((req, res) => {
// res.send(`User Get ${req.params.id}`);
// });
// module.exports = router;

161
routes/userRoutes.js Normal file
View File

@@ -0,0 +1,161 @@
const express = require("express");
const router = express.Router();
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const { verifyToken, generateToken } = require("../lib/jwtUtils");
router.post("/user", async (req, res) => {
try {
const { mobile, password, fullname, pic, province, permissions, city } =
req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({
mobile,
password: hashedPassword,
pic,
fullname,
province,
city,
permissions,
});
await newUser.save();
const token = generateToken(newUser._id);
res.status(201).json({
message: "User created successfully",
user: newUser,
token,
});
} catch (error) {
console.error("Error creating user:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.post("/login", async (req, res) => {
try {
const { mobile, password } = req.body;
const user = await User.findOne({ mobile });
if (!user) {
return res.status(403).json({ message: "Invalid credentials" });
}
const passwordMatch = await bcrypt.compare(password, user.password);
if (!passwordMatch) {
return res.status(403).json({ message: "Invalid credentials" });
}
const token = generateToken(user._id);
const userWithoutPassword = { ...user.toObject() };
delete userWithoutPassword.password;
res
.status(200)
.json({ message: "Login successful", token, user: userWithoutPassword });
} catch (error) {
console.error("Error during login:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.use(verifyToken);
router.get("/user_profile/:userId", async (req, res) => {
try {
const userId = req.params.userId;
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
res.status(200).json({ user });
} catch (error) {
console.error("Error retrieving user:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.get("/users/:province", async (req, res) => {
try {
const province = req.params.province;
const users = (await User.find({ province: province })).filter(
(item) => !item.permissions.includes("admin")
);
res.status(200).json(users);
} catch (error) {
console.error("Error retrieving users:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.delete("/users/:userId", async (req, res) => {
try {
const userId = req.params.userId;
const deletedUser = await User.findByIdAndDelete(userId);
if (!deletedUser) {
return res.status(404).json({ message: "User not found" });
}
res
.status(200)
.json({ message: "User deleted successfully", user: deletedUser });
} catch (error) {
console.error("Error deleting user:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
router.put("/user/:userId", async (req, res) => {
try {
const userId = req.params.userId;
const { mobile, password, fullname, pic, province, permissions } = req.body;
const updatedUser = await User.findByIdAndUpdate(
userId,
{ mobile, password, fullname, pic, province, permissions },
{ new: true } // Set { new: true } to return the updated document
);
if (!updatedUser) {
return res.status(404).json({ message: "User not found" });
}
res
.status(200)
.json({ message: "User updated successfully", user: updatedUser });
} catch (error) {
console.error("Error updating user:", error);
res.status(500).json({ message: "Internal Server Error" });
}
});
module.exports = router;
// router
// .route("/:id")
// .get((req, res) => {
// res.send(`User Get ${req.params.id}`);
// })
// .post((req, res) => {
// res.send(`User Get ${req.params.id}`);
// })
// .put((req, res) => {
// res.send(`User Get ${req.params.id}`);
// })
// .delete((req, res) => {
// res.send(`User Get ${req.params.id}`);
// });
// module.exports = router;

70
server.js Normal file
View File

@@ -0,0 +1,70 @@
require("dotenv").config();
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const app = express();
app.use(express.json());
const allowedOrigins = [
"http://localhost:3000",
"http://localhost:3001",
"http://localhost:3002",
"https://bazres.rasadyar.com/",
"https://bazres.rasadyar.net/",
"https://bazres.rasadyar.com",
"https://bazres.rasadyar.net",
"https://ban.rasadyar.com",
"https://ban.rasadyar.net",
"https://www.ban.rasadyar.com",
"https://www.ban.rasadyar.net",
];
app.use(
cors({
origin: function (origin, callback) {
if (!origin) return callback(null, true);
if (allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true,
allowedHeaders: ["Content-Type", "Authorization"],
})
);
const PlaceRoutes = require("./routes/placeRoutes");
const UserRoutes = require("./routes/userRoutes");
const InspectionRoutes = require("./routes/inspectRoutes");
const HerdRoutes = require("./routes/herdRoutes");
const PeopleInfoRoutes = require("./routes/peopleInfoRoutes");
const NationalDocumentsRoutes = require("./routes/nationalDocumentsRoutes");
app.use("/", PeopleInfoRoutes);
app.use("/", UserRoutes);
app.use("/", HerdRoutes);
app.use("/", PlaceRoutes);
app.use("/", InspectionRoutes);
app.use("/", NationalDocumentsRoutes);
const uri =
process.env.MONGODB_URI ||
"mongodb://root:uV6NAvWigykzUK1CR1VJdf4mNbFD0kHjYgZU1lJKgMR0IFTwt1DyCFpKgxwkPeJt@31.7.78.133:14364/default?authSource=admin";
const mongooseOptions = {};
mongoose
.connect(uri, mongooseOptions)
.then(() => {
console.log("Connected to MongoDB");
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
})
.catch((error) => console.error("Error connecting to MongoDB:", error));