Initial commit: added frontend and backend

This commit is contained in:
2026-09-22 12:02:38 +05:30
commit cd2770e590
154 changed files with 25892 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
node_modules
.env
+13
View File
@@ -0,0 +1,13 @@
const mongoose = require('mongoose');
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
};
module.exports = connectDB;
+56
View File
@@ -0,0 +1,56 @@
const axios = require('axios');
const FormData = require('form-data');
exports.analyzeImage = async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No image provided' });
}
// In a real scenario, we would forward this to the Perfect Corp API
// For now, we will return a mock response matching the expected structure
// or you could proxy it like this:
/*
const formData = new FormData();
formData.append('image', req.file.buffer, req.file.originalname);
const response = await axios.post(process.env.PERFECT_CORP_API_URL, formData, {
headers: {
...formData.getHeaders(),
'Authorization': `Bearer ${process.env.PERFECT_CORP_API_KEY}`
}
});
return res.json({ result: response.data });
*/
// MOCK RESPONSE
console.log('Mocking perfect corp analysis for image:', req.file.originalname);
const mockResult = {
results: [
{
data: [
{
url: 'https://example.com/mock-mask.zip'
}
]
}
],
// Add other mock data that the frontend expects to parse...
face_attributes: {
age: 30,
gender: 'female'
},
skin_issues: {
wrinkles: 10,
spots: 5,
acne: 2
}
};
res.json({ result: mockResult });
} catch (error) {
console.error('Error analyzing image:', error);
res.status(500).json({ error: 'Failed to analyze image' });
}
};
@@ -0,0 +1,27 @@
const Report = require('../models/Report');
const User = require('../models/User');
exports.getDashboardUsers = async (req, res) => {
try {
// Fetch all users
const users = await User.find().sort({ createdAt: -1 });
// We also need the latest report link for each user
// In a real scenario, this could be optimized with an aggregation pipeline
const dashboardData = await Promise.all(users.map(async (user) => {
const latestReport = await Report.findOne({ phone: user.phone }).sort({ createdAt: -1 });
return {
id: user._id,
name: user.name,
phone: user.phone,
lastLink: latestReport ? latestReport.link : null,
};
}));
res.json(dashboardData);
} catch (error) {
console.error('Error fetching dashboard users:', error);
res.status(500).json({ success: false, message: 'Server error' });
}
};
+43
View File
@@ -0,0 +1,43 @@
const Report = require('../models/Report');
const User = require('../models/User');
exports.createReport = async (req, res) => {
try {
const { reportId, phone, userName, data, link } = req.body;
if (!reportId || !phone || !data) {
return res.status(400).json({ success: false, message: 'Missing required fields' });
}
const report = await Report.create({
reportId,
phone,
userName,
data,
link
});
res.status(201).json({ success: true, report });
} catch (error) {
console.error('Error creating report:', error);
res.status(500).json({ success: false, message: 'Server error' });
}
};
exports.getReport = async (req, res) => {
try {
const { reportId } = req.params;
const report = await Report.findOne({ reportId });
if (!report) {
return res.status(404).json({ success: false, message: 'Report not found' });
}
// Return the report data directly to match frontend expectation
res.json(report.data);
} catch (error) {
console.error('Error fetching report:', error);
res.status(500).json({ success: false, message: 'Server error' });
}
};
+78
View File
@@ -0,0 +1,78 @@
const User = require('../models/User');
exports.createUser = async (req, res) => {
try {
const { name, phone } = req.body;
if (!name || !phone) {
return res.status(400).json({ success: false, message: 'Name and phone are required' });
}
// Generate a random 4 digit OTP
const generatedOtp = Math.floor(1000 + Math.random() * 9000).toString();
const otpExpiry = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes from now
let user = await User.findOne({ phone });
let isExisting = false;
if (user) {
isExisting = true;
user.otp = generatedOtp;
user.otpExpiry = otpExpiry;
user.name = name; // Update name just in case
await user.save();
} else {
user = await User.create({
name,
phone,
otp: generatedOtp,
otpExpiry
});
}
res.json({
success: true,
user: {
otp: user.otp,
isExisting
}
});
} catch (error) {
console.error('Error creating user:', error);
res.status(500).json({ success: false, message: 'Server error' });
}
};
exports.verifyOtp = async (req, res) => {
try {
const { phone, otp } = req.body;
if (!phone || !otp) {
return res.status(400).json({ success: false, message: 'Phone and OTP required' });
}
const user = await User.findOne({ phone });
if (!user) {
return res.status(404).json({ success: false, message: 'User not found' });
}
if (user.otp !== otp) {
return res.status(400).json({ success: false, message: 'Invalid OTP' });
}
if (user.otpExpiry < new Date()) {
return res.status(400).json({ success: false, message: 'OTP expired' });
}
// Clear OTP after successful verification
user.otp = null;
user.otpExpiry = null;
await user.save();
res.json({ success: true, message: 'OTP verified successfully' });
} catch (error) {
console.error('Error verifying OTP:', error);
res.status(500).json({ success: false, message: 'Server error' });
}
};
+47
View File
@@ -0,0 +1,47 @@
exports.sendOtp = async (req, res) => {
try {
const { phone, name, otpToUse, verificationLink, isExisting } = req.body;
if (!phone || !otpToUse) {
return res.status(400).json({ success: false, message: 'Phone and OTP required' });
}
// Mock WhatsApp API call
console.log(`[WhatsApp Mock] Sending OTP ${otpToUse} to ${phone}`);
console.log(`[WhatsApp Mock] Verification Link: ${verificationLink}`);
// In production, use axios to call the real WhatsApp provider API here.
/*
await axios.post(process.env.WHATSAPP_API_URL, {
to: phone,
type: "template",
template: { ... }
}, {
headers: { 'Authorization': `Bearer ${process.env.WHATSAPP_API_KEY}` }
});
*/
res.json({ success: true, message: 'OTP sent via WhatsApp successfully' });
} catch (error) {
console.error('Error sending WhatsApp OTP:', error);
res.status(500).json({ success: false, message: 'Failed to send OTP' });
}
};
exports.sendReport = async (req, res) => {
try {
const { phone, name, overallScore, origin } = req.body;
if (!phone || overallScore === undefined) {
return res.status(400).json({ success: false, message: 'Phone and overallScore required' });
}
// Mock WhatsApp API call
console.log(`[WhatsApp Mock] Sending Report (Score: ${overallScore}) to ${phone}`);
res.json({ success: true, message: 'Report sent via WhatsApp successfully' });
} catch (error) {
console.error('Error sending WhatsApp Report:', error);
res.status(500).json({ success: false, message: 'Failed to send report' });
}
};
+33
View File
@@ -0,0 +1,33 @@
const mongoose = require('mongoose');
const reportSchema = new mongoose.Schema(
{
reportId: {
type: String,
required: true,
unique: true,
},
phone: {
type: String,
required: true,
ref: 'User',
},
userName: {
type: String,
required: true,
},
data: {
type: Object, // Store the raw JSON from Perfect Corp
required: true,
},
link: {
type: String,
},
},
{
timestamps: true,
}
);
const Report = mongoose.model('Report', reportSchema);
module.exports = Report;
+27
View File
@@ -0,0 +1,27 @@
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
phone: {
type: String,
required: true,
unique: true,
},
otp: {
type: String,
},
otpExpiry: {
type: Date,
},
},
{
timestamps: true,
}
);
const User = mongoose.model('User', userSchema);
module.exports = User;
+1746
View File
File diff suppressed because it is too large Load Diff
+24
View File
@@ -0,0 +1,24 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.20.0",
"cors": "^2.8.6",
"dotenv": "^18.0.2",
"express": "^5.2.1",
"form-data": "^4.0.6",
"mongoose": "^9.10.1",
"multer": "^2.4.0"
},
"devDependencies": {
"nodemon": "^3.1.14"
}
}
+33
View File
@@ -0,0 +1,33 @@
const express = require('express');
const router = express.Router();
const multer = require('multer');
// Configure multer for memory storage (we'll forward the buffer to the external API)
const upload = multer({ storage: multer.memoryStorage() });
// Controllers
const { analyzeImage } = require('../controllers/analysisController');
const { createUser, verifyOtp } = require('../controllers/userController');
const { createReport, getReport } = require('../controllers/reportController');
const { sendOtp, sendReport } = require('../controllers/whatsappController');
const { getDashboardUsers } = require('../controllers/dashboardController');
// 1. Analysis Proxy
router.post('/perfectcorp/analyze', upload.single('image'), analyzeImage);
// 2. User & OTP Management
router.post('/users', createUser);
router.post('/verify-otp', verifyOtp);
// 3. Reports
router.post('/reports', createReport);
router.get('/reports/:reportId', getReport);
// 4. WhatsApp Integration
router.post('/whatsapp/send-otp', sendOtp);
router.post('/whatsapp/send-report', sendReport);
// 5. Admin Dashboard
router.get('/dashboard/users', getDashboardUsers);
module.exports = router;
+24
View File
@@ -0,0 +1,24 @@
const express = require('express');
const cors = require('cors');
const dotenv = require('dotenv');
const connectDB = require('./config/db');
// Load env vars
dotenv.config();
// Connect to database
connectDB();
const app = express();
// Middleware
app.use(cors());
app.use(express.json());
// Routes
const apiRoutes = require('./routes/api');
app.use('/api', apiRoutes);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));