Initial commit - all project files via Git LFS
This commit is contained in:
2
.env
Normal file
2
.env
Normal file
@@ -0,0 +1,2 @@
|
||||
EMAIL_USER=laxmibamnale2002@gmail.com
|
||||
EMAIL_PASS=smqcwjwdsuiywrse
|
||||
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||
3
contacts.json
Normal file
3
contacts.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
|
||||
]
|
||||
3
gallery-media/1755343085623-cert1.jpg
Normal file
3
gallery-media/1755343085623-cert1.jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6151d682778ae9a8794065adc611381fda940841aacbc1aa9aeb6d5dea51ffea
|
||||
size 771090
|
||||
3
gallery-media/1755343137920-cert2.jpg
Normal file
3
gallery-media/1755343137920-cert2.jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c498106d312c3e6df6b7cee5575dc4c535bc6f2c965dc7338abf93fc16863125
|
||||
size 945980
|
||||
3
gallery-media/1755343165376-cert3.jpg
Normal file
3
gallery-media/1755343165376-cert3.jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aebbabebc80ebf16465b20f24b3ce88153c6c9d8fbb0b042cb492d2ad959a185
|
||||
size 387688
|
||||
3
gallery-media/1755343199753-cert4.jpg
Normal file
3
gallery-media/1755343199753-cert4.jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c6756c2a1f395f71f0bea7b12fec08f0e6c39a74e4ce41beac8e40bd32cdd71d
|
||||
size 653272
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:00f9b20bb8f70db9d7ccd87a223729c8bfca846f8def0e3084448b0a0a564734
|
||||
size 203639
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0cef97032f9e432b0d8f9043b05f34142f2b2e6af88a9bf2c12d09a1b4497bd4
|
||||
size 356409
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:669c0ab89af15f1b9b026ba3f74c8a4b74eeda131f1652fa319c914275d71656
|
||||
size 270386
|
||||
67
gallery.json
Normal file
67
gallery.json
Normal file
@@ -0,0 +1,67 @@
|
||||
[
|
||||
{
|
||||
"id": 1755343085723,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "MKVDC Pune Sanmanpatra dated",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1755343085623-cert1.jpg",
|
||||
"createdAt": "2025-08-16T11:18:05.723Z"
|
||||
},
|
||||
{
|
||||
"id": 1755343138070,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "Ambarnath - Kulgaon Badlapur Barrage certificate",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1755343137920-cert2.jpg",
|
||||
"createdAt": "2025-08-16T11:18:58.070Z"
|
||||
},
|
||||
{
|
||||
"id": 1755343165414,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "American Water Works Association Certificate",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1755343165376-cert3.jpg",
|
||||
"createdAt": "2025-08-16T11:19:25.414Z"
|
||||
},
|
||||
{
|
||||
"id": 1755343199851,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "Kerala Water Authority - Letter of Appreciation",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1755343199753-cert4.jpg",
|
||||
"createdAt": "2025-08-16T11:19:59.851Z"
|
||||
},
|
||||
{
|
||||
"id": 1755343250163,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "wilo ecolution award 2024",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1755343250133-WhatsApp Image 2025-08-09 at 12.17.33 PM.jpeg",
|
||||
"createdAt": "2025-08-16T11:20:50.163Z",
|
||||
"updatedAt": "2025-12-16T09:05:46.425Z"
|
||||
},
|
||||
{
|
||||
"id": 1755764880336,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "Smart City Award for Western Zone, Solapur Automation",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1755764880241-WhatsApp Image 2023-09-27 at 5.04.05 PM.jpeg",
|
||||
"createdAt": "2025-08-21T08:28:00.336Z",
|
||||
"updatedAt": "2025-12-16T09:05:56.792Z"
|
||||
},
|
||||
{
|
||||
"id": 1762603729920,
|
||||
"category": "Awards & Achievements",
|
||||
"caption": "CERTIFICATE OF APPRECIATION from HON. CHIEF MINISTER OF GOA for JJM Work successfully completed and commissioned",
|
||||
"date": "",
|
||||
"type": "image",
|
||||
"url": "/gallery-media/1762603729917-CERTIFICATE OF APPRECIATION from HON. CHIEF MINISTER OF GOA for JJM Work successfully completed and commissioned.png",
|
||||
"createdAt": "2025-11-08T12:08:49.920Z"
|
||||
}
|
||||
]
|
||||
50
jobs.json
Normal file
50
jobs.json
Normal file
@@ -0,0 +1,50 @@
|
||||
[
|
||||
{
|
||||
"id": 1766485365354,
|
||||
"positionName": "Software Developer",
|
||||
"qualification": "BTech",
|
||||
"experience": "1",
|
||||
"location": "Pune",
|
||||
"skills": [
|
||||
"Python",
|
||||
"java"
|
||||
],
|
||||
"numberOfOpenings": "2",
|
||||
"jobDescription": "test",
|
||||
"postingDate": "2025-12-23",
|
||||
"closingDate": null,
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 1766486098759,
|
||||
"positionName": "Test",
|
||||
"qualification": "BTech",
|
||||
"experience": "1",
|
||||
"location": "Pune",
|
||||
"skills": [
|
||||
"Python",
|
||||
"java"
|
||||
],
|
||||
"numberOfOpenings": "2",
|
||||
"jobDescription": "test",
|
||||
"postingDate": "2025-12-23",
|
||||
"closingDate": null,
|
||||
"isActive": true
|
||||
},
|
||||
{
|
||||
"id": 1766486114343,
|
||||
"positionName": "Software Developer",
|
||||
"qualification": "BTech",
|
||||
"experience": "1",
|
||||
"location": "Pune",
|
||||
"skills": [
|
||||
"Python",
|
||||
"java"
|
||||
],
|
||||
"numberOfOpenings": "1",
|
||||
"jobDescription": "test",
|
||||
"postingDate": "2025-12-23",
|
||||
"closingDate": null,
|
||||
"isActive": true
|
||||
}
|
||||
]
|
||||
1430
package-lock.json
generated
Normal file
1430
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
package.json
Normal file
20
package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "lcepl-backend",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.3",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.1",
|
||||
"express": "^4.21.2",
|
||||
"fs": "^0.0.1-security",
|
||||
"multer": "^2.0.2",
|
||||
"nodemailer": "^7.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.0"
|
||||
}
|
||||
}
|
||||
162
projects.json
Normal file
162
projects.json
Normal file
@@ -0,0 +1,162 @@
|
||||
[
|
||||
{
|
||||
"id": 1754996200535,
|
||||
"sector": "electromechanical",
|
||||
"image": "/uploads/1754996200514-e811b15b-9d53-4c92-b2b0-280c724bec3b.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1754996228903,
|
||||
"sector": "renewable energy",
|
||||
"image": "/uploads/1754996228890-2a9cc942-939e-4b2a-8ed8-6fdb99cbe919.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1754996248901,
|
||||
"sector": "roads",
|
||||
"image": "/uploads/1754996248875-0e10027f-7b22-46c3-82d0-fd25ed88cd37.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1754996269954,
|
||||
"sector": "storm water management",
|
||||
"image": "/uploads/1754996269898-WhatsApp Image 2025-08-12 at 12.53.21 PM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1754996282054,
|
||||
"sector": "storm water management",
|
||||
"image": "/uploads/1754996282022-WhatsApp Image 2025-08-12 at 12.53.21 PM (1).jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1754996302879,
|
||||
"sector": "tunnel",
|
||||
"image": "/uploads/1754996302853-WhatsApp Image 2025-08-12 at 12.53.15 PM (1).jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1755338571673,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755338571628-Sewage-WT1.c1c508759572132379bf (1).jpg"
|
||||
},
|
||||
{
|
||||
"id": 1755338632351,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755338632341-Non-conventional-water-treatment-plants-.e452887dc76a9c77aa01.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1755339600178,
|
||||
"sector": "water supply",
|
||||
"image": "/uploads/1755339600135-water_treatment_plan_QDiP2.e7a8e82ec7e3a4e3c148.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1755511932847,
|
||||
"sector": "tunnel",
|
||||
"image": "/uploads/1755511932814-WhatsApp Image 2025-08-18 at 2.24.17 PM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1755670485719,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755670485689-Picture1.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1755670494520,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755670494409-Picture2.png"
|
||||
},
|
||||
{
|
||||
"id": 1755670504975,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755670504954-Picture3.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1755673960257,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755673960238-Picture4.png"
|
||||
},
|
||||
{
|
||||
"id": 1755673968617,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755673968590-Picture5.png"
|
||||
},
|
||||
{
|
||||
"id": 1755673977458,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1755673977434-Picture6.png"
|
||||
},
|
||||
{
|
||||
"id": 1755674126735,
|
||||
"sector": "electromechanical",
|
||||
"image": "/uploads/1755674126708-image (2).jpg"
|
||||
},
|
||||
{
|
||||
"id": 1755764796849,
|
||||
"sector": "real estate / buildings",
|
||||
"image": "/uploads/1755764796583-04da8a50-98a3-4516-86de-e8f8f46594b8.jpg"
|
||||
},
|
||||
{
|
||||
"id": 1762768071860,
|
||||
"sector": "real estate / buildings",
|
||||
"image": "/uploads/1762768071841-Gemini_Generated_Image_l7v50ml7v50ml7v5.png"
|
||||
},
|
||||
{
|
||||
"id": 1762768163950,
|
||||
"sector": "wastewater / sewerage works",
|
||||
"image": "/uploads/1762768163944-WhatsApp Image 2025-11-10 at 3.18.33 PM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058099201,
|
||||
"sector": "water supply",
|
||||
"image": "/uploads/1766058099192-Photo 40.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058106964,
|
||||
"sector": "water supply",
|
||||
"image": "/uploads/1766058106951-Photo 39.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058118717,
|
||||
"sector": "water supply",
|
||||
"image": "/uploads/1766058118709-Photo 28.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058179446,
|
||||
"sector": "electromechanical-instrumentation",
|
||||
"image": "/uploads/1766058179433-WhatsApp Image 2025-12-17 at 11.14.20 AM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058376010,
|
||||
"sector": "wastewater / sewerage",
|
||||
"image": "/uploads/1766058376000-WhatsApp Image 2025-12-17 at 6.56.08 PM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058429912,
|
||||
"sector": "wastewater / sewerage",
|
||||
"image": "/uploads/1766058429903-WhatsApp Image 2025-12-17 at 10.23.09 AM (2).jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058519500,
|
||||
"sector": "wastewater / sewerage",
|
||||
"image": "/uploads/1766058519485-WhatsApp Image 2025-12-17 at 10.23.00 AM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766058540827,
|
||||
"sector": "roads",
|
||||
"image": "/uploads/1766058540797-WhatsApp Image 2025-12-17 at 5.44.30 PM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766137181427,
|
||||
"sector": "electromechanical & instrumentation",
|
||||
"image": "/uploads/1766137181418-WhatsApp Image 2025-12-17 at 11.14.21 AM.jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766137224619,
|
||||
"sector": "electromechanical & instrumentation",
|
||||
"image": "/uploads/1766137224615-electro.png"
|
||||
},
|
||||
{
|
||||
"id": 1766137282049,
|
||||
"sector": "storm water",
|
||||
"image": "/uploads/1766137282043-WhatsApp Image 2025-12-17 at 1.16.29 PM (1).jpeg"
|
||||
},
|
||||
{
|
||||
"id": 1766137297598,
|
||||
"sector": "storm water",
|
||||
"image": "/uploads/1766137297588-WhatsApp Image 2025-12-17 at 1.16.29 PM.jpeg"
|
||||
}
|
||||
]
|
||||
8
routes/contactRoutes.js
Normal file
8
routes/contactRoutes.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { saveContact } = require('../controllers/contactController');
|
||||
|
||||
// ✅ Use `router.post`, NOT `app.post`
|
||||
router.post('/', saveContact);
|
||||
|
||||
module.exports = router;
|
||||
744
server.js
Normal file
744
server.js
Normal file
@@ -0,0 +1,744 @@
|
||||
const express = require("express");
|
||||
const cors = require("cors");
|
||||
const nodemailer = require("nodemailer");
|
||||
const multer = require("multer");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const app = express();
|
||||
const PORT = 8000;
|
||||
|
||||
const DATA_FILE = path.join(__dirname, "projects.json");
|
||||
const JOBS_DATA_FILE = path.join(__dirname, "jobs.json");
|
||||
const GALLERY_DATA_FILE = path.join(__dirname, "gallery.json");
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use("/uploads", express.static(path.join(__dirname, "uploads")));
|
||||
app.use("/applications", express.static(path.join(__dirname, "applications")));
|
||||
app.use("/gallery-media", express.static(path.join(__dirname, "gallery-media")));
|
||||
|
||||
const loadData = (filePath) => {
|
||||
if (!fs.existsSync(filePath)) return [];
|
||||
const data = fs.readFileSync(filePath, "utf-8");
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const saveData = (filePath, data) => {
|
||||
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
||||
};
|
||||
|
||||
// ====================== GALLERY API ====================== //
|
||||
|
||||
const galleryStorage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const dir = "./gallery-media";
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
||||
cb(null, dir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueName = Date.now() + "-" + file.originalname;
|
||||
cb(null, uniqueName);
|
||||
},
|
||||
});
|
||||
|
||||
const uploadGallery = multer({
|
||||
storage: galleryStorage,
|
||||
fileFilter: (req, file, cb) => {
|
||||
const filetypes = /jpeg|jpg|png|gif|mp4|mov|avi/;
|
||||
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
|
||||
const mimetype = filetypes.test(file.mimetype);
|
||||
|
||||
if (extname && mimetype) {
|
||||
return cb(null, true);
|
||||
} else {
|
||||
cb(new Error("Only images (JPEG, JPG, PNG, GIF) and videos (MP4, MOV, AVI) are allowed"));
|
||||
}
|
||||
},
|
||||
limits: { fileSize: 500 * 1024 * 1024 } // 500MB limit
|
||||
});
|
||||
|
||||
// Get all gallery items with filtering by category
|
||||
app.get("/api/gallery", (req, res) => {
|
||||
const items = loadData(GALLERY_DATA_FILE);
|
||||
|
||||
if (req.query.category) {
|
||||
const filtered = items.filter(item => item.category === req.query.category);
|
||||
return res.json(filtered);
|
||||
}
|
||||
|
||||
res.json(items);
|
||||
});
|
||||
|
||||
// Add new gallery item
|
||||
app.post("/api/gallery", uploadGallery.single("media"), (req, res) => {
|
||||
const { category, caption, date } = req.body;
|
||||
const mediaFile = req.file;
|
||||
|
||||
if (!category || !mediaFile) {
|
||||
return res.status(400).json({ error: "Category and media file are required" });
|
||||
}
|
||||
|
||||
const mediaType = mediaFile.mimetype.startsWith("video") ? "video" : "image";
|
||||
|
||||
const newItem = {
|
||||
id: Date.now(),
|
||||
category,
|
||||
caption: caption || "",
|
||||
date: date || "",
|
||||
type: mediaType,
|
||||
url: `/gallery-media/${mediaFile.filename}`,
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
const items = loadData(GALLERY_DATA_FILE);
|
||||
items.push(newItem);
|
||||
saveData(GALLERY_DATA_FILE, items);
|
||||
|
||||
res.status(201).json({ message: "Gallery item added successfully", item: newItem });
|
||||
});
|
||||
|
||||
// Update gallery item
|
||||
app.put("/api/gallery/:id", uploadGallery.single("media"), (req, res) => {
|
||||
const itemId = parseInt(req.params.id);
|
||||
const { category, caption, date } = req.body;
|
||||
const mediaFile = req.file;
|
||||
|
||||
let items = loadData(GALLERY_DATA_FILE);
|
||||
const itemIndex = items.findIndex(item => item.id === itemId);
|
||||
|
||||
if (itemIndex === -1) {
|
||||
return res.status(404).json({ error: "Gallery item not found" });
|
||||
}
|
||||
|
||||
const existingItem = items[itemIndex];
|
||||
let mediaType = existingItem.type;
|
||||
let mediaUrl = existingItem.url;
|
||||
|
||||
if (mediaFile) {
|
||||
// Delete old media file
|
||||
const oldFilename = existingItem.url.split("/").pop();
|
||||
const oldPath = path.join(__dirname, "gallery-media", oldFilename);
|
||||
if (fs.existsSync(oldPath)) {
|
||||
fs.unlinkSync(oldPath);
|
||||
}
|
||||
|
||||
mediaType = mediaFile.mimetype.startsWith("video") ? "video" : "image";
|
||||
mediaUrl = `/gallery-media/${mediaFile.filename}`;
|
||||
}
|
||||
|
||||
items[itemIndex] = {
|
||||
...existingItem,
|
||||
category: category || existingItem.category,
|
||||
caption: caption || existingItem.caption,
|
||||
date: date || existingItem.date,
|
||||
type: mediaType,
|
||||
url: mediaUrl,
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
saveData(GALLERY_DATA_FILE, items);
|
||||
res.json({ message: "Gallery item updated successfully", item: items[itemIndex] });
|
||||
});
|
||||
|
||||
// Delete gallery item
|
||||
app.delete("/api/gallery/:id", (req, res) => {
|
||||
const itemId = parseInt(req.params.id);
|
||||
const items = loadData(GALLERY_DATA_FILE);
|
||||
const itemIndex = items.findIndex(item => item.id === itemId);
|
||||
|
||||
if (itemIndex === -1) {
|
||||
return res.status(404).json({ error: "Gallery item not found" });
|
||||
}
|
||||
|
||||
// Delete associated media file
|
||||
const filename = items[itemIndex].url.split("/").pop();
|
||||
const filePath = path.join(__dirname, "gallery-media", filename);
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
|
||||
items.splice(itemIndex, 1);
|
||||
saveData(GALLERY_DATA_FILE, items);
|
||||
|
||||
res.json({ message: "Gallery item deleted successfully" });
|
||||
});
|
||||
|
||||
// ========= CONTACT FORM ========= //
|
||||
app.post("/contact", async (req, res) => {
|
||||
const { name, email, contact, message } = req.body;
|
||||
|
||||
// Validation
|
||||
if (!name || !email || !contact || !message) {
|
||||
return res.status(400).json({ success: false, error: "All fields are required" });
|
||||
}
|
||||
|
||||
// Additional validation
|
||||
if (name.length < 2) {
|
||||
return res.status(400).json({ success: false, error: "Name must be at least 2 characters" });
|
||||
}
|
||||
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
return res.status(400).json({ success: false, error: "Invalid email format" });
|
||||
}
|
||||
|
||||
const digits = contact.replace(/\D/g, "");
|
||||
if (digits.length < 7) {
|
||||
return res.status(400).json({ success: false, error: "Contact number must have at least 7 digits" });
|
||||
}
|
||||
|
||||
if (message.length < 10) {
|
||||
return res.status(400).json({ success: false, error: "Message must be at least 10 characters" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Use environment variables for email credentials
|
||||
const emailUser = process.env.EMAIL_USER || "laxmibamnale2002@gmail.com";
|
||||
const emailPass = process.env.EMAIL_PASS || "smqcwjwdsuiywrse";
|
||||
|
||||
if (!emailPass) {
|
||||
console.error("Email password not configured");
|
||||
return res.status(500).json({ success: false, message: "Server configuration error" });
|
||||
}
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "gmail",
|
||||
auth: {
|
||||
user: emailUser,
|
||||
pass: emailPass,
|
||||
},
|
||||
});
|
||||
|
||||
// Verify connection configuration
|
||||
await transporter.verify();
|
||||
|
||||
const mailToOwner = {
|
||||
from: emailUser, // Use your email as from address to avoid authentication issues
|
||||
replyTo: email, // Set reply-to to customer's email
|
||||
to: emailUser,
|
||||
subject: `New Contact Form Submission from ${name}`,
|
||||
html: `
|
||||
<h3>New Contact Form Submission</h3>
|
||||
<p><strong>Name:</strong> ${name}</p>
|
||||
<p><strong>Email:</strong> ${email}</p>
|
||||
<p><strong>Contact:</strong> ${contact}</p>
|
||||
<p><strong>Message:</strong></p>
|
||||
<p>${message.replace(/\n/g, "<br>")}</p>
|
||||
<p><em>Received on: ${new Date().toLocaleString()}</em></p>
|
||||
`,
|
||||
};
|
||||
|
||||
await transporter.sendMail(mailToOwner);
|
||||
|
||||
const autoReply = {
|
||||
from: emailUser,
|
||||
to: email,
|
||||
subject: "Thank you for contacting Laxmi Civil Engineering Services!",
|
||||
html: `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2 style="color: #0056b3;">Thank You for Contacting Us!</h2>
|
||||
<p>Dear ${name},</p>
|
||||
<p>Thank you for reaching out to Laxmi Civil Engineering Services Pvt. Ltd. We have received your message and will get back to you within 24-48 hours.</p>
|
||||
<p>For urgent inquiries, please call us at <strong>0231-2521554</strong> or <strong>0231-2683900</strong>.</p>
|
||||
<p><strong>Summary of your message:</strong></p>
|
||||
<blockquote style="background: #f9f9f9; padding: 10px; border-left: 4px solid #ccc;">
|
||||
${message.replace(/\n/g, "<br>")}
|
||||
</blockquote>
|
||||
<p>Best regards,<br/>Team Laxmi Civil Engineering Services</p>
|
||||
<hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">
|
||||
<p style="font-size: 12px; color: #777;">
|
||||
Laxmi Civil Engineering Services Pvt. Ltd.<br>
|
||||
1148, E. Sykes Extension, Kolhapur 416 001, Maharashtra, India.<br>
|
||||
Phone: 0231-2521554, 2683900 | Email: laxmibamnale2002@gmail.com
|
||||
</p>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
|
||||
await transporter.sendMail(autoReply);
|
||||
|
||||
res.status(200).json({ success: true, message: "Message sent successfully" });
|
||||
} catch (err) {
|
||||
console.error("Error sending email:", err);
|
||||
|
||||
if (err.code === "EAUTH") {
|
||||
res.status(500).json({ success: false, message: "Email authentication failed" });
|
||||
} else if (err.code === "EENVELOPE") {
|
||||
res.status(400).json({ success: false, message: "Invalid email address" });
|
||||
} else {
|
||||
res.status(500).json({ success: false, message: "Server error while sending email" });
|
||||
}
|
||||
}
|
||||
});
|
||||
// ========= PROJECT UPLOAD ========= //
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const dir = "./uploads";
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
||||
cb(null, dir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueName = Date.now() + "-" + file.originalname;
|
||||
cb(null, uniqueName);
|
||||
},
|
||||
});
|
||||
const upload = multer({ storage });
|
||||
|
||||
const loadProjects = () => {
|
||||
if (!fs.existsSync(DATA_FILE)) return [];
|
||||
const data = fs.readFileSync(DATA_FILE, "utf-8");
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const saveProjects = (projects) => {
|
||||
fs.writeFileSync(DATA_FILE, JSON.stringify(projects, null, 2));
|
||||
};
|
||||
|
||||
app.post("/api/projects", upload.single("image"), (req, res) => {
|
||||
const { sector } = req.body;
|
||||
const image = req.file ? `/uploads/${req.file.filename}` : "";
|
||||
|
||||
if (!sector || !image) {
|
||||
return res.status(400).json({ error: "Sector and image are required" });
|
||||
}
|
||||
|
||||
const newProject = {
|
||||
id: Date.now(),
|
||||
sector,
|
||||
image,
|
||||
};
|
||||
|
||||
const projects = loadProjects();
|
||||
projects.push(newProject);
|
||||
saveProjects(projects);
|
||||
|
||||
res.status(201).json({ message: "Project added successfully", project: newProject });
|
||||
});
|
||||
|
||||
app.get("/api/projects", (req, res) => {
|
||||
const projects = loadProjects();
|
||||
res.json(projects);
|
||||
});
|
||||
|
||||
app.post("/api/projects/update/:id", upload.single("image"), (req, res) => {
|
||||
const projectId = parseInt(req.params.id);
|
||||
const { sector } = req.body;
|
||||
|
||||
let projects = loadProjects();
|
||||
const projectIndex = projects.findIndex((p) => p.id === projectId);
|
||||
|
||||
if (projectIndex === -1) {
|
||||
return res.status(404).json({ error: "Project not found" });
|
||||
}
|
||||
|
||||
const existingProject = projects[projectIndex];
|
||||
|
||||
projects[projectIndex] = {
|
||||
...existingProject,
|
||||
sector,
|
||||
image: req.file ? `/uploads/${req.file.filename}` : existingProject.image,
|
||||
};
|
||||
|
||||
saveProjects(projects);
|
||||
|
||||
res.json({ message: "Project updated successfully", project: projects[projectIndex] });
|
||||
});
|
||||
|
||||
app.delete("/api/projects/:id", (req, res) => {
|
||||
const projectId = parseInt(req.params.id);
|
||||
|
||||
let projects = loadProjects();
|
||||
const updatedProjects = projects.filter((project) => project.id !== projectId);
|
||||
|
||||
if (projects.length === updatedProjects.length) {
|
||||
return res.status(404).json({ error: "Project not found" });
|
||||
}
|
||||
|
||||
saveProjects(updatedProjects);
|
||||
res.json({ message: "Project deleted successfully" });
|
||||
});
|
||||
|
||||
// ========= JOB APPLICATION UPLOAD ========= //
|
||||
const applicationStorage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const dir = "./applications";
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
||||
cb(null, dir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueName = Date.now() + "-" + file.originalname;
|
||||
cb(null, uniqueName);
|
||||
},
|
||||
});
|
||||
|
||||
const uploadApplication = multer({ storage: applicationStorage });
|
||||
|
||||
app.post("/send-application", uploadApplication.single("resume"), async (req, res) => {
|
||||
const {
|
||||
fullName,
|
||||
email,
|
||||
phone,
|
||||
address,
|
||||
education,
|
||||
skill,
|
||||
interest,
|
||||
totalExperience,
|
||||
expectedSalary,
|
||||
currentCompany,
|
||||
currentDesignation,
|
||||
} = req.body;
|
||||
|
||||
if (!fullName || !email || !phone || !education || !skill || !totalExperience || !req.file) {
|
||||
return res.status(400).json({ success: false, message: "Missing required fields" });
|
||||
}
|
||||
|
||||
const resumePath = path.join(__dirname, "applications", req.file.filename);
|
||||
|
||||
try {
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "gmail",
|
||||
auth: {
|
||||
user: "laxmibamnale2002@gmail.com",
|
||||
pass: "smqcwjwdsuiywrse",
|
||||
},
|
||||
});
|
||||
|
||||
const mailOptions = {
|
||||
from: email,
|
||||
to: "laxmibamnale2002@gmail.com",
|
||||
subject: `New Job Application from ${fullName}`,
|
||||
text: `Full Name: ${fullName}
|
||||
Email: ${email}
|
||||
Phone: ${phone}
|
||||
Address: ${address}
|
||||
Education: ${education}
|
||||
Skill: ${skill}
|
||||
Interest: ${interest}
|
||||
Experience: ${totalExperience}
|
||||
Expected Salary: ${expectedSalary}
|
||||
Current Company: ${currentCompany}
|
||||
Current Designation: ${currentDesignation}`,
|
||||
attachments: [
|
||||
{
|
||||
filename: req.file.originalname,
|
||||
path: resumePath,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
const autoReply = {
|
||||
from: "laxmibamnale2002@gmail.com",
|
||||
to: email,
|
||||
subject: "Application Received - Laxmi Civil Engineering Services",
|
||||
text: `Dear ${fullName},
|
||||
|
||||
Thank you for applying to Laxmi Civil Engineering Services Pvt. Ltd.
|
||||
|
||||
We have received your application and resume. Our HR team will review your profile and get back to you shortly if shortlisted.
|
||||
|
||||
Best regards,
|
||||
Laxmi Civil Engineering Services Pvt. Ltd.`,
|
||||
};
|
||||
|
||||
await transporter.sendMail(autoReply);
|
||||
|
||||
res.status(200).json({ success: true, message: "Application submitted successfully" });
|
||||
} catch (err) {
|
||||
console.error("Error submitting application:", err);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// ========= ENHANCED JOB POSTINGS API ========= //
|
||||
|
||||
const loadJobs = () => {
|
||||
if (!fs.existsSync(JOBS_DATA_FILE)) return [];
|
||||
const data = fs.readFileSync(JOBS_DATA_FILE, "utf-8");
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const saveJobs = (jobs) => {
|
||||
fs.writeFileSync(JOBS_DATA_FILE, JSON.stringify(jobs, null, 2));
|
||||
};
|
||||
|
||||
// Get all jobs with automatic status updates
|
||||
app.get("/api/jobs", (req, res) => {
|
||||
let jobs = loadJobs();
|
||||
const currentDate = new Date();
|
||||
|
||||
// Update job statuses based on closing date
|
||||
jobs = jobs.map(job => {
|
||||
if (job.closingDate && new Date(job.closingDate) < currentDate) {
|
||||
return { ...job, isActive: false };
|
||||
}
|
||||
return job;
|
||||
});
|
||||
|
||||
// Save updated statuses if any changed
|
||||
saveJobs(jobs);
|
||||
|
||||
res.json(jobs);
|
||||
});
|
||||
|
||||
// Create new job posting with enhanced fields
|
||||
app.post("/api/jobs", (req, res) => {
|
||||
const {
|
||||
positionName,
|
||||
qualification,
|
||||
experience,
|
||||
location,
|
||||
skills,
|
||||
numberOfOpenings,
|
||||
jobDescription,
|
||||
postingDate,
|
||||
closingDate,
|
||||
isActive = true
|
||||
} = req.body;
|
||||
|
||||
if (
|
||||
!positionName ||
|
||||
!qualification ||
|
||||
!experience ||
|
||||
!location ||
|
||||
!Array.isArray(skills) ||
|
||||
skills.length === 0 ||
|
||||
!numberOfOpenings ||
|
||||
!jobDescription ||
|
||||
!postingDate
|
||||
) {
|
||||
return res.status(400).json({ error: "Missing required fields" });
|
||||
}
|
||||
|
||||
const jobs = loadJobs();
|
||||
|
||||
const newJob = {
|
||||
id: Date.now(),
|
||||
positionName,
|
||||
qualification,
|
||||
experience,
|
||||
location,
|
||||
skills,
|
||||
numberOfOpenings,
|
||||
jobDescription,
|
||||
postingDate,
|
||||
closingDate: closingDate || null,
|
||||
isActive: closingDate ? new Date(closingDate) >= new Date() : isActive
|
||||
};
|
||||
|
||||
jobs.push(newJob);
|
||||
saveJobs(jobs);
|
||||
|
||||
res.status(201).json({ message: "Job created", job: newJob });
|
||||
});
|
||||
|
||||
// Update existing job posting with enhanced fields
|
||||
app.put("/api/jobs/:id", (req, res) => {
|
||||
const jobId = parseInt(req.params.id);
|
||||
const {
|
||||
positionName,
|
||||
qualification,
|
||||
experience,
|
||||
location,
|
||||
skills,
|
||||
|
||||
numberOfOpenings,
|
||||
jobDescription,
|
||||
postingDate,
|
||||
closingDate,
|
||||
isActive
|
||||
} = req.body;
|
||||
|
||||
const jobs = loadJobs();
|
||||
const index = jobs.findIndex((job) => job.id === jobId);
|
||||
|
||||
if (index === -1) {
|
||||
return res.status(404).json({ error: "Job not found" });
|
||||
}
|
||||
|
||||
if (
|
||||
!positionName ||
|
||||
!qualification ||
|
||||
!experience ||
|
||||
!location ||
|
||||
!Array.isArray(skills) ||
|
||||
skills.length === 0 ||
|
||||
!numberOfOpenings ||
|
||||
!jobDescription ||
|
||||
!postingDate
|
||||
) {
|
||||
return res.status(400).json({ error: "Missing required fields" });
|
||||
}
|
||||
|
||||
const currentDate = new Date();
|
||||
const closingDateObj = closingDate ? new Date(closingDate) : null;
|
||||
const actualIsActive = closingDateObj ? closingDateObj >= currentDate : isActive;
|
||||
|
||||
jobs[index] = {
|
||||
id: jobId,
|
||||
positionName,
|
||||
qualification,
|
||||
experience,
|
||||
location,
|
||||
skills,
|
||||
numberOfOpenings,
|
||||
jobDescription,
|
||||
postingDate,
|
||||
closingDate: closingDate || null,
|
||||
isActive: actualIsActive
|
||||
};
|
||||
|
||||
saveJobs(jobs);
|
||||
|
||||
res.json({ message: "Job updated", job: jobs[index] });
|
||||
});
|
||||
|
||||
// Toggle job active status
|
||||
app.patch("/api/jobs/:id/toggle-active", (req, res) => {
|
||||
const jobId = parseInt(req.params.id);
|
||||
const jobs = loadJobs();
|
||||
const index = jobs.findIndex((job) => job.id === jobId);
|
||||
|
||||
if (index === -1) {
|
||||
return res.status(404).json({ error: "Job not found" });
|
||||
}
|
||||
|
||||
// Don't allow toggling if there's a closing date in the past
|
||||
const currentDate = new Date();
|
||||
if (jobs[index].closingDate && new Date(jobs[index].closingDate) < currentDate) {
|
||||
return res.status(400).json({ error: "Cannot activate job with expired closing date" });
|
||||
}
|
||||
|
||||
jobs[index].isActive = !jobs[index].isActive;
|
||||
saveJobs(jobs);
|
||||
|
||||
res.json({ message: "Job status updated", job: jobs[index] });
|
||||
});
|
||||
|
||||
// Delete job posting
|
||||
app.delete("/api/jobs/:id", (req, res) => {
|
||||
const jobId = parseInt(req.params.id);
|
||||
let jobs = loadJobs();
|
||||
const initialLength = jobs.length;
|
||||
jobs = jobs.filter((job) => job.id !== jobId);
|
||||
|
||||
if (jobs.length === initialLength) {
|
||||
return res.status(404).json({ error: "Job not found" });
|
||||
}
|
||||
|
||||
saveJobs(jobs);
|
||||
|
||||
res.json({ message: "Job deleted" });
|
||||
});
|
||||
|
||||
// ========= CAREER CONTACT FORM ========= //
|
||||
const careerStorage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
const dir = "./career-applications";
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
|
||||
cb(null, dir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const uniqueName = Date.now() + "-" + file.originalname;
|
||||
cb(null, uniqueName);
|
||||
},
|
||||
});
|
||||
|
||||
const uploadCareer = multer({
|
||||
storage: careerStorage,
|
||||
limits: { fileSize: 10 * 1024 * 1024 },
|
||||
fileFilter: (req, file, cb) => {
|
||||
const allowedExt = ['.pdf', '.doc', '.docx'];
|
||||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
if (allowedExt.includes(ext)) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(new Error('Only PDF/DOC/DOCX files are allowed'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/careers/contact', uploadCareer.single('resume'), async (req, res) => {
|
||||
try {
|
||||
const { fullName, email, phone } = req.body;
|
||||
const resumeFile = req.file;
|
||||
|
||||
if (!fullName || !email || !resumeFile) {
|
||||
return res.status(400).json({ success: false, error: 'Missing required fields or resume.' });
|
||||
}
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
service: "gmail",
|
||||
auth: {
|
||||
user: "laxmibamnale2002@gmail.com",
|
||||
pass: "smqcwjwdsuiywrse",
|
||||
},
|
||||
});
|
||||
|
||||
const mailOptions = {
|
||||
from: '"Career Contact Form" <laxmibamnale2002@gmail.com>',
|
||||
to: "laxmibamnale2002@gmail.com",
|
||||
subject: `New Career Contact from ${fullName}`,
|
||||
text: `
|
||||
You have received a new career contact form submission.
|
||||
|
||||
Full Name: ${fullName}
|
||||
Email: ${email}
|
||||
Phone: ${phone || 'Not provided'}
|
||||
|
||||
Resume is attached.
|
||||
`,
|
||||
attachments: [
|
||||
{
|
||||
filename: resumeFile.originalname,
|
||||
path: resumeFile.path,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
const autoReply = {
|
||||
from: "<laxmibamnale2002@gmail.com>",
|
||||
to: email,
|
||||
subject: "Thank you for contacting Laxmi Civil Engineering Services",
|
||||
text: `Dear ${fullName},
|
||||
|
||||
Thank you for reaching out to us via the Career Contact form. We have received your details and resume.
|
||||
|
||||
Our HR team will review and get back to you soon.
|
||||
|
||||
Best regards,
|
||||
Laxmi Civil Engineering Services Pvt. Ltd.`,
|
||||
};
|
||||
|
||||
await transporter.sendMail(autoReply);
|
||||
|
||||
fs.unlink(resumeFile.path, (err) => {
|
||||
if (err) console.error('Error deleting uploaded resume:', err);
|
||||
});
|
||||
|
||||
res.json({ success: true, message: 'Career contact form submitted successfully.' });
|
||||
} catch (error) {
|
||||
console.error('Error in /api/careers/contact:', error);
|
||||
res.status(500).json({ success: false, message: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========= START SERVER ========= //
|
||||
app.listen(PORT, "0.0.0.0", () => {
|
||||
console.log(`Server running on http://0.0.0.0:${PORT}`);
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b18868133b335ea2090a0f979a237ffbc55e126cd838e6674e55c079ff211f01
|
||||
size 136480
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d7f81aa3c405fe8a1530a32162e46e70cecb6879c45886b73ab5470805c87d0d
|
||||
size 95483
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:971601aca01935b4252c71bc6046a190e9ce363e1fdcb3e0c3191f98151e3d0c
|
||||
size 117116
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:89854e5ffb6247fdbc2daa425eaa07582259841044f32c8a3b82190f9a01dbc2
|
||||
size 106340
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:06ead77138dc9b9e39fbb4f9a4e1f89e88a974659017c89a0a1cdc2a8d401639
|
||||
size 40215
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aa1a201f199ad52ff266d1f7d86cd52b40a268b5c067e56d8e9bb312d8f78d78
|
||||
size 77916
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f9f44f85a7fe7847a32aeead56bcf5a183e2b96726cf7c18b1ca982c833bce07
|
||||
size 41260
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:353a56addc86cf52057f96d712a1e9c284603e48cb6659b270d1795d9d844a65
|
||||
size 217645
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fa95b026a5572e1981a34fa471c0db1ef5f7d5cd2a70ae3126eefe04877ba577
|
||||
size 270148
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0969ee184ba4d08fbfe22b0b2a9d49dffca13430bf3b0b4cccbc0f278801c4c8
|
||||
size 266050
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:545b067a2f79fe311739ee81b5e1996e7b39ee0a487c69195e73036fe7120e25
|
||||
size 388066
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:53a0edd4dc4098523d53726512853e22ef552d745f4aed4522e3eff07c82ab2b
|
||||
size 184279
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dc28513a19968b279285647f01ba195d63c469671f273639ad18fd416514d483
|
||||
size 136512
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4157cf889539b71cfdb6d071cb7a770aac8f048294010032b250c25e51fe0e92
|
||||
size 74954
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:be0e72ab911a5b5d3e38ef303fe3e12577aa2375c4a678b29638c7d87b8be425
|
||||
size 30905
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c0d1472f857f577deccbb5238db41ce83c70725e59a27852ced86e38aba96972
|
||||
size 490294
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f42ff8a40a2029248dbbf537bc61f808bccff06433495f401010489d54bb870c
|
||||
size 33340
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5ebf1121ad3b28d5f203e08af0053c081cae1d16a0f3d944d440ec0b9dae02c9
|
||||
size 79635
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:016a9b7de9e0c53a62eceae8dccda11b580e86b1e04737cebc05593503c39ad3
|
||||
size 68559
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bfd53cb52febcecef8fdbf6b271fd96ce6e9f52fd273e2535a93034b46df764
|
||||
size 574646
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:af819c90ab29c7bf2577e804bddd74f449be8359925eaf1548835016896750cb
|
||||
size 93085
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a2218e865746cf08c666663e772e748e54566f668d728dc0993a5a502a3f9a99
|
||||
size 158030
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:911178bbdf45d142ff44f5ee2908f868027aa812ac5eaf436b62d7efada1c412
|
||||
size 115016
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d5bb053a2b168271db97b5dd825c39b2df1a49dc340bccf23f0a76e302f7f0ea
|
||||
size 274756
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0dfc6b5fd10587629e067afdc9086503e3086b0cb88be4546e2824cfef3c4e66
|
||||
size 229604
|
||||
3
uploads/1755670485689-Picture1.jpg
Normal file
3
uploads/1755670485689-Picture1.jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:34927bb18c3b47e65ed4ff8fd0883aee7c54915709b6e4433b746c38ed851090
|
||||
size 145817
|
||||
3
uploads/1755670494409-Picture2.png
Normal file
3
uploads/1755670494409-Picture2.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:de82b69aabc58848077a790ed8c4874c5398a42118990b2d0c5bf6017ad10816
|
||||
size 772511
|
||||
3
uploads/1755670504954-Picture3.jpg
Normal file
3
uploads/1755670504954-Picture3.jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9bb99fc68316b0c51ea7ddaf06f4a60347bf3a3aa4b1029c633d0d29562d0cae
|
||||
size 118059
|
||||
3
uploads/1755673960238-Picture4.png
Normal file
3
uploads/1755673960238-Picture4.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7f0fc2085eaac95b19d87dbb716d6880101679e0d60820aa5357e4a21d674f5c
|
||||
size 248825
|
||||
3
uploads/1755673968590-Picture5.png
Normal file
3
uploads/1755673968590-Picture5.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c538761aa7c28c070da0a18cdfaecc38b88638064a78126883fcd637c496f44c
|
||||
size 291194
|
||||
3
uploads/1755673977434-Picture6.png
Normal file
3
uploads/1755673977434-Picture6.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3033c81e52b8bd1d8fef279fee695a7abc4aa01af5515c58691c2cb2c063e161
|
||||
size 238091
|
||||
3
uploads/1755674126708-image (2).jpg
Normal file
3
uploads/1755674126708-image (2).jpg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f0509d8451f0de35d5e2b8d2fcafde5d918989fe4a05c456cef036d432a162da
|
||||
size 265880
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fbfc91893f43f579745a167c8271e99c15bc859d0542cc0cc1c6e945429411e1
|
||||
size 81411
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6604eaa800b5b64e97a7e5a7e5c77ff13927455692cc69070ccdcd12dff2c5e1
|
||||
size 341134
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:920ceaebc2f90401cee2d5b0c26c4fc2f9beada7d9a17dd90843a472111c2eed
|
||||
size 150356
|
||||
3
uploads/1762603614967-New-chhindwara-image.png
Normal file
3
uploads/1762603614967-New-chhindwara-image.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e181286a94a43674cc5f91f53dc7993a0b35deabc1676b76f6a95d2a82f09dd6
|
||||
size 1296332
|
||||
3
uploads/1762603765339-new1-chhindwara-image.png
Normal file
3
uploads/1762603765339-new1-chhindwara-image.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e4647cc03eb202cd888fa41ba400e9ff4bfcc8b563280cfbf3035f2fb0fb3893
|
||||
size 1308696
|
||||
3
uploads/1762750708567-final-chhindwara-image.png
Normal file
3
uploads/1762750708567-final-chhindwara-image.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8652fc37c2ca1cd4d186e61d5dcaf0528dea22cbc0026704a195f8f091678d4d
|
||||
size 1399820
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ff2674a0961bce76365d05311048c2866bbfb8e8d0059ede2f5484302eae3be9
|
||||
size 1643635
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ff2674a0961bce76365d05311048c2866bbfb8e8d0059ede2f5484302eae3be9
|
||||
size 1643635
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:be3d05534aa1434da4744a377e3d2cfd5360d075e7d23a3405812dd62794959d
|
||||
size 258388
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:722ac9b0e5c4ac59a7e098ac380b99bd28b8983a994ce66ab836f3a4ddb5b3a4
|
||||
size 220027
|
||||
3
uploads/1765176502539-Screenshot (363).png
Normal file
3
uploads/1765176502539-Screenshot (363).png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9d2d6b89d56c55b32fb1fb11f3dc4300e8a53882be08579782ce5866bb2a80a8
|
||||
size 163622
|
||||
3
uploads/1765178845236-47894 -UTR.jpeg
Normal file
3
uploads/1765178845236-47894 -UTR.jpeg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:49dda7fbecd085642f0f78e9c5d28730cf0a9cdb44098e9a651cbefcc68c503e
|
||||
size 312187
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3d0704c9283aea311467fed713cf5bec5b1a62c501842a5054ecee148588d25b
|
||||
size 143013
|
||||
3
uploads/1766058099192-Photo 40.jpeg
Normal file
3
uploads/1766058099192-Photo 40.jpeg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a4a3fff41cc800142586b213149acbc460d9020c3a26c8c5a52ba27b310e07ad
|
||||
size 198794
|
||||
3
uploads/1766058106951-Photo 39.jpeg
Normal file
3
uploads/1766058106951-Photo 39.jpeg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6a8da8fa8dd2242160f7a82f0e84fa50f940bb9bb98757d0af005d9fae7e2527
|
||||
size 224299
|
||||
3
uploads/1766058118709-Photo 28.jpeg
Normal file
3
uploads/1766058118709-Photo 28.jpeg
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:30430e08b449c6ef0a3191f76d763316957f931e60630e3e70112d1a8a20cabf
|
||||
size 171577
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fa95b026a5572e1981a34fa471c0db1ef5f7d5cd2a70ae3126eefe04877ba577
|
||||
size 270148
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:71d73cc2e658f634c63e967e84f9040be5ba6fc1e8711d0aaad4689689b7d06d
|
||||
size 244264
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d9a998d16ba7715aebef07321902b0dbf7d79e5e218c1ad4e98e37f7a82a98bc
|
||||
size 195839
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:545b067a2f79fe311739ee81b5e1996e7b39ee0a487c69195e73036fe7120e25
|
||||
size 388066
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:175b8d6158b2d800e0de03337810367e7d6f84eee5bffc1fab29449a9f2be425
|
||||
size 196030
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2bc83397b5da254b5cde16bfb86012f150600d4cb1fc440519631fd80de47aaa
|
||||
size 194412
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:38c83d7a6909fc5404684fdb3aeb53858447bc4a30194d1176c7c5cb73e3f1e7
|
||||
size 155144
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e9196f24a766e07e8b3fb9e46a3a6e4b6ac583c2eb4521c50e9888bec2b5acd7
|
||||
size 695000
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:267eca9db020fabcb0479b64ab51cd76c26a0afeac137b8c0dae08b0cb77354f
|
||||
size 266099
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:670b1ab2113c16a332d369ace1c1bf5bd593d8410ebb3f420dee5687e4d459df
|
||||
size 247663
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5ae818d036da6886c461772a64b4d1a0667937d178df2b3f8c3e2c54038a622a
|
||||
size 376889
|
||||
3
uploads/1766137224615-electro.png
Normal file
3
uploads/1766137224615-electro.png
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:061fb64bacdab2875d69fb93d173ea9e37660ddd8bb5a61470cb80c7ba82056f
|
||||
size 38986
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:353a56addc86cf52057f96d712a1e9c284603e48cb6659b270d1795d9d844a65
|
||||
size 217645
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5b2c3909ccaf45150a8fdc370f6d345c1198151f6523d1016e2c8486e4ebdd6c
|
||||
size 239400
|
||||
15
utils/fileHandler.js
Normal file
15
utils/fileHandler.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
const dataPath = path.join(__dirname, '../data/applications.json');
|
||||
|
||||
const readApplications = async () => {
|
||||
const data = await fs.readFile(dataPath, 'utf-8');
|
||||
return JSON.parse(data);
|
||||
};
|
||||
|
||||
const writeApplications = async (data) => {
|
||||
await fs.writeFile(dataPath, JSON.stringify(data, null, 2), 'utf-8');
|
||||
};
|
||||
|
||||
module.exports = { readApplications, writeApplications };
|
||||
Reference in New Issue
Block a user