345 lines
8.9 KiB
JavaScript
345 lines
8.9 KiB
JavaScript
import express from "express";
|
|
import pool from "../db/pool.js";
|
|
|
|
const router = express.Router();
|
|
|
|
// Get all listings
|
|
router.get("/", async (req, res) => {
|
|
const speciesId = req.query.species_id;
|
|
const breedId = req.query.breed_id;
|
|
const state = req.query.state;
|
|
const district = req.query.district;
|
|
const minPrice = req.query.min_price;
|
|
const listingType = req.query.listing_type;
|
|
|
|
let baseQuery = `
|
|
SELECT l.*, a.species_id, a.breed_id, loc.state, loc.district
|
|
FROM listings l
|
|
LEFT JOIN animals a ON a.id = l.animal_id
|
|
LEFT JOIN locations loc ON loc.id = a.location_id
|
|
WHERE 1=1
|
|
`;
|
|
const queryParams = [];
|
|
let paramIndex = 1;
|
|
|
|
if (speciesId) {
|
|
baseQuery += ` AND a.species_id = $${paramIndex}`;
|
|
queryParams.push(speciesId);
|
|
paramIndex++;
|
|
}
|
|
if (breedId) {
|
|
baseQuery += ` AND a.breed_id = $${paramIndex}`;
|
|
queryParams.push(breedId);
|
|
paramIndex++;
|
|
}
|
|
if (state) {
|
|
baseQuery += ` AND loc.state = $${paramIndex}`;
|
|
queryParams.push(state);
|
|
paramIndex++;
|
|
}
|
|
if (district) {
|
|
baseQuery += ` AND loc.district = $${paramIndex}`;
|
|
queryParams.push(district);
|
|
paramIndex++;
|
|
}
|
|
if (minPrice) {
|
|
baseQuery += ` AND l.price >= $${paramIndex}`;
|
|
queryParams.push(minPrice);
|
|
paramIndex++;
|
|
}
|
|
if (listingType) {
|
|
baseQuery += ` AND l.listing_type = $${paramIndex}`;
|
|
queryParams.push(listingType);
|
|
paramIndex++;
|
|
}
|
|
|
|
try {
|
|
const listingsResult = await pool.query(baseQuery, queryParams);
|
|
res.status(200).json(listingsResult.rows);
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: "Internal Server Error in fetching listings",
|
|
});
|
|
}
|
|
});
|
|
|
|
// Get listing by ID
|
|
router.get("/:id", async (req, res) => {
|
|
const listingId = req.params.id;
|
|
try {
|
|
const listingResult = await pool.query(
|
|
"SELECT * FROM listings WHERE id = $1",
|
|
[listingId]
|
|
);
|
|
if (listingResult.rows.length === 0) {
|
|
return res.status(404).json({ error: "Listing not found" });
|
|
}
|
|
res.status(200).json(listingResult.rows[0]);
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: `Internal Server Error in fetching the specified ${listingId} listing`,
|
|
});
|
|
}
|
|
});
|
|
|
|
// Update listing by ID
|
|
router.put("/:id", async (req, res) => {
|
|
const listingId = req.params.id;
|
|
const { title, description, price } = req.body;
|
|
try {
|
|
const updateResult = await pool.query(
|
|
"UPDATE listings SET title = $1, description = $2, price = $3, updated_at = NOW() WHERE id = $4 RETURNING *",
|
|
[title, description, price, listingId]
|
|
);
|
|
if (updateResult.rows.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ error: "Listing not found for update" });
|
|
}
|
|
res.status(200).json(updateResult.rows[0]);
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: `Internal Server Error in updating the specified ${listingId} listing`,
|
|
});
|
|
}
|
|
});
|
|
|
|
// Submit a new listing
|
|
router.post("/", async (req, res) => {
|
|
const client = await pool.connect();
|
|
try {
|
|
await client.query("BEGIN");
|
|
|
|
const {
|
|
seller_id,
|
|
title,
|
|
price,
|
|
currency,
|
|
is_negotiable,
|
|
listing_type,
|
|
animal,
|
|
} = req.body;
|
|
|
|
// Add a new location if provided
|
|
if (!animal.location_id && animal.new_location) {
|
|
const newLocation = {
|
|
...animal.new_location,
|
|
};
|
|
if (
|
|
newLocation.is_saved_address &&
|
|
!newLocation.user_id &&
|
|
seller_id
|
|
) {
|
|
newLocation.user_id = seller_id;
|
|
}
|
|
animal.location_id = await addNewLocation(client, newLocation);
|
|
}
|
|
|
|
const animalId = await addAnimalToListing(client, animal);
|
|
|
|
const listingInsertQuery =
|
|
"INSERT INTO listings (seller_id, animal_id, title, price, currency, is_negotiable, listing_type, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) RETURNING *";
|
|
const listingValues = [
|
|
seller_id,
|
|
animalId,
|
|
title,
|
|
price,
|
|
currency,
|
|
is_negotiable,
|
|
listing_type,
|
|
];
|
|
const listingResult = await client.query(
|
|
listingInsertQuery,
|
|
listingValues
|
|
);
|
|
|
|
if (
|
|
req.body.media &&
|
|
Array.isArray(req.body.media) &&
|
|
req.body.media.length > 0
|
|
) {
|
|
const listingId = listingResult.rows[0].id;
|
|
const mediaInsertQuery = `
|
|
INSERT INTO listing_media (listing_id, media_url, media_type, is_primary, sort_order, created_at, updated_at)
|
|
VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
|
|
RETURNING *;
|
|
`;
|
|
for (let i = 0; i < req.body.media.length; i++) {
|
|
const media = req.body.media[i];
|
|
await client.query(mediaInsertQuery, [
|
|
listingId,
|
|
media.media_url,
|
|
media.media_type,
|
|
typeof media.is_primary !== "undefined"
|
|
? media.is_primary
|
|
: false,
|
|
typeof media.sort_order !== "undefined"
|
|
? media.sort_order
|
|
: i + 1,
|
|
]);
|
|
}
|
|
}
|
|
|
|
await client.query("COMMIT");
|
|
res.status(201).json(listingResult.rows[0]);
|
|
} catch (error) {
|
|
await client.query("ROLLBACK");
|
|
res.status(500).json({
|
|
error:
|
|
"Internal Server Error in creating new listing: " +
|
|
error.message,
|
|
});
|
|
} finally {
|
|
client.release();
|
|
}
|
|
});
|
|
|
|
const addAnimalToListing = async (client, animal) => {
|
|
try {
|
|
const animalInsertQuery =
|
|
"INSERT INTO animals (species_id, breed_id, sex, age_months, weight_kg, color_markings, quantity, purpose, health_status, vaccinated, dewormed, previous_pregnancies_count, pregnancy_status, milk_yield_litre_per_day, ear_tag_no, description, suggested_care, location_id, created_from, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, NOW(), NOW()) RETURNING id";
|
|
const animalValues = [
|
|
animal.species_id,
|
|
animal.breed_id,
|
|
animal.sex,
|
|
animal.age_months,
|
|
animal.weight_kg,
|
|
animal.color_markings,
|
|
animal.quantity,
|
|
animal.purpose,
|
|
animal.health_status,
|
|
animal.vaccinated,
|
|
animal.dewormed,
|
|
animal.previous_pregnancies_count,
|
|
animal.pregnancy_status,
|
|
animal.milk_yield_litre_per_day,
|
|
animal.ear_tag_no,
|
|
animal.description,
|
|
animal.suggested_care,
|
|
animal.location_id,
|
|
animal.created_from || "listing",
|
|
];
|
|
const animalResult = await client.query(
|
|
animalInsertQuery,
|
|
animalValues
|
|
);
|
|
const animalId = animalResult.rows[0].id;
|
|
return animalId;
|
|
} catch (error) {
|
|
throw new Error("Error adding animal to listing: " + error.message);
|
|
}
|
|
};
|
|
|
|
const addNewLocation = async (client, location) => {
|
|
try {
|
|
const {
|
|
user_id = null,
|
|
is_saved_address = false,
|
|
location_type = null,
|
|
country = null,
|
|
state = null,
|
|
district = null,
|
|
city_village = null,
|
|
pincode = null,
|
|
lat = null,
|
|
lng = null,
|
|
source_type = "unknown",
|
|
source_confidence = "medium",
|
|
} = location;
|
|
|
|
const locationInsertQuery =
|
|
"INSERT INTO locations (user_id, is_saved_address, location_type, country, state, district, city_village, pincode, lat, lng, source_type, source_confidence, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NOW(), NOW()) RETURNING id";
|
|
const locationValues = [
|
|
user_id,
|
|
is_saved_address,
|
|
location_type,
|
|
country,
|
|
state,
|
|
district,
|
|
city_village,
|
|
pincode,
|
|
lat,
|
|
lng,
|
|
source_type,
|
|
source_confidence,
|
|
];
|
|
const locationResult = await client.query(
|
|
locationInsertQuery,
|
|
locationValues
|
|
);
|
|
return locationResult.rows[0].id;
|
|
} catch (error) {
|
|
throw new Error("Error adding new location: " + error.message);
|
|
}
|
|
};
|
|
|
|
// Delete listing by ID
|
|
router.delete("/:id", async (req, res) => {
|
|
const listingId = req.params.id;
|
|
try {
|
|
const deleteResult = await pool.query(
|
|
"DELETE FROM listings WHERE id = $1 RETURNING *",
|
|
[listingId]
|
|
);
|
|
if (deleteResult.rows.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ error: "Listing not found or already deleted" });
|
|
}
|
|
res.status(200).json({
|
|
message: "Listing deleted successfully",
|
|
listing: deleteResult.rows[0],
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: `Internal Server Error in deleting the specified ${listingId} listing`,
|
|
});
|
|
}
|
|
});
|
|
|
|
// Get all listings for a user
|
|
router.get("/user/:user_id", async (req, res) => {
|
|
const userId = req.params.user_id;
|
|
try {
|
|
const listingsResult = await pool.query(
|
|
"SELECT * FROM listings WHERE seller_id = $1 ORDER BY created_at DESC",
|
|
[userId]
|
|
);
|
|
res.status(200).json(listingsResult.rows);
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: "Internal Server Error in fetching user listings",
|
|
});
|
|
}
|
|
});
|
|
|
|
// Mark listing as sold or update listing status
|
|
router.patch("/:id/status", async (req, res) => {
|
|
const listingId = req.params.id;
|
|
const { status } = req.body;
|
|
if (!status) {
|
|
return res.status(400).json({ error: "Status must be provided" });
|
|
}
|
|
try {
|
|
const updateResult = await pool.query(
|
|
"UPDATE listings SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *",
|
|
[status, listingId]
|
|
);
|
|
if (updateResult.rows.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ error: "Listing not found for status update" });
|
|
}
|
|
res.status(200).json({
|
|
message: "Listing status updated",
|
|
listing: updateResult.rows[0],
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
error: `Internal Server Error updating listing status for ${listingId}`,
|
|
});
|
|
}
|
|
});
|
|
|
|
export default router;
|