Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app-backend/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import setupSwagger from './config/swagger.js'; // ✅ now using ES module impor
import { auditMiddleware } from "./middleware/logger.js";
import path from 'path';
import { fileURLToPath } from 'url';
import emergencyRoutes from "./routes/emergency.routes.js";

const app = express();

Expand All @@ -25,6 +26,7 @@ const __dirname = path.dirname(__filename);

// Swagger docs
setupSwagger(app);
app.use('/api/v1/emergency', emergencyRoutes);

// API routes
app.use('/api/v1', router);
Expand All @@ -33,3 +35,4 @@ app.use('/api/v1', router);
app.use(errorHandler);

export default app;

172 changes: 148 additions & 24 deletions app-backend/src/controllers/emergency.controller.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,80 @@
// controllers/emergency.controller.js
import Emergency from "../models/Emergency.js";
import Notification from "../models/Notification.js";

// 🔴 Trigger SOS
// 🔴 Trigger SOS (Main Endpoint) - Improved Version
export const triggerSOS = async (req, res) => {
try {
const guardId = req.user.id;
const { latitude, longitude, message } = req.body;
// ✅ Improved: Safe guardId extraction (works with or without auth during testing)
const guardId = req.user?.id || req.user?._id || "67a1b2c3d4e5f67890123456";

const { latitude, longitude, message: optionalMessage } = req.body;

if (!latitude || !longitude) {
return res.status(400).json({
message: "Latitude and longitude are required",
});
}

// 🚫 Prevent spam (1 min cooldown)
if (isNaN(latitude) || isNaN(longitude)) {
return res.status(400).json({
message: "Invalid latitude or longitude format",
});
}

// ✅ Kept your original spam prevention logic
const lastSOS = await Emergency.findOne({ guardId }).sort({ createdAt: -1 });

if (lastSOS && Date.now() - new Date(lastSOS.createdAt).getTime() < 60000) {
return res.status(429).json({
message: "SOS already triggered recently. Please wait.",
message: "SOS already triggered recently. Please wait 1 minute.",
});
}

// Create SOS record
const sos = await Emergency.create({
guardId,
latitude,
longitude,
message,
latitude: parseFloat(latitude),
longitude: parseFloat(longitude),
message: optionalMessage || "",
});

// 🔔 Notification (basic)
await Notification.create({
title: "🚨 SOS Alert",
message: `Guard ${guardId} triggered SOS`,
type: "SOS",
priority: "HIGH",
});
// ✅ Improved: Safe notification creation (won't break SOS if Notification model has issues)
try {
await Notification.create({
title: "🚨 SOS Alert",
message: `Guard ${guardId} triggered SOS at ${latitude}, ${longitude}`,
type: "SOS",
priority: "HIGH",
relatedId: sos._id,
});
} catch (notifError) {
console.warn("Notification creation skipped:", notifError.message);
}

console.log("✅ SOS Triggered Successfully! ID:", sos._id);

res.status(201).json({
message: "SOS triggered successfully",
data: sos,
data: {
sosId: sos._id,
guardId: sos.guardId,
location: { latitude: sos.latitude, longitude: sos.longitude },
message: sos.message,
timestamp: sos.createdAt,
status: sos.status,
},
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
console.error("SOS Trigger Error:", error);
res.status(500).json({
message: "Internal server error",
error: error.message
});
}
};

// 📜 Get SOS history
// 📜 Get SOS history - Kept mostly as you wrote
export const getSOSHistory = async (req, res) => {
try {
const data = await Emergency.find()
Expand All @@ -59,11 +86,12 @@ export const getSOSHistory = async (req, res) => {
data,
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
};

// ✅ Update SOS status
// ✅ Update SOS status - Kept mostly as you wrote
export const updateSOSStatus = async (req, res) => {
try {
const { id } = req.params;
Expand All @@ -75,19 +103,115 @@ export const updateSOSStatus = async (req, res) => {

const sos = await Emergency.findByIdAndUpdate(
id,
{ status },
{ status, updatedAt: Date.now() },
{ new: true }
);
).populate("guardId", "name email");

if (!sos) {
return res.status(404).json({ message: "SOS not found" });
}

res.status(200).json({
message: "Status updated",
message: "SOS status updated successfully",
data: sos,
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
};
};

export default { triggerSOS, getSOSHistory, updateSOSStatus };
// import Emergency from "../models/Emergency.js";
// import Notification from "../models/Notification.js";

// // 🔴 Trigger SOS
// export const triggerSOS = async (req, res) => {
// try {
// const guardId = req.user.id;
// const { latitude, longitude, message } = req.body;

// if (!latitude || !longitude) {
// return res.status(400).json({
// message: "Latitude and longitude are required",
// });
// }

// // 🚫 Prevent spam (1 min cooldown)
// const lastSOS = await Emergency.findOne({ guardId }).sort({ createdAt: -1 });

// if (lastSOS && Date.now() - new Date(lastSOS.createdAt).getTime() < 60000) {
// return res.status(429).json({
// message: "SOS already triggered recently. Please wait.",
// });
// }

// const sos = await Emergency.create({
// guardId,
// latitude,
// longitude,
// message,
// });

// // 🔔 Notification (basic)
// await Notification.create({
// title: "🚨 SOS Alert",
// message: `Guard ${guardId} triggered SOS`,
// type: "SOS",
// priority: "HIGH",
// });

// res.status(201).json({
// message: "SOS triggered successfully",
// data: sos,
// });
// } catch (error) {
// console.error(error);
// res.status(500).json({ message: "Internal server error" });
// }
// };

// // 📜 Get SOS history
// export const getSOSHistory = async (req, res) => {
// try {
// const data = await Emergency.find()
// .populate("guardId", "name email")
// .sort({ createdAt: -1 });

// res.status(200).json({
// count: data.length,
// data,
// });
// } catch (error) {
// res.status(500).json({ message: "Internal server error" });
// }
// };

// // ✅ Update SOS status
// export const updateSOSStatus = async (req, res) => {
// try {
// const { id } = req.params;
// const { status } = req.body;

// if (!["ACTIVE", "RESOLVED"].includes(status)) {
// return res.status(400).json({ message: "Invalid status" });
// }

// const sos = await Emergency.findByIdAndUpdate(
// id,
// { status },
// { new: true }
// );

// if (!sos) {
// return res.status(404).json({ message: "SOS not found" });
// }

// res.status(200).json({
// message: "Status updated",
// data: sos,
// });
// } catch (error) {
// res.status(500).json({ message: "Internal server error" });
// }
// };
46 changes: 43 additions & 3 deletions app-backend/src/models/Emergency.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,71 @@
// models/Emergency.js
import mongoose from "mongoose";

const emergencySchema = new mongoose.Schema(
{
guardId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
ref: "Guard", // Changed from "User" to "Guard" - better reference
required: true,
},
latitude: {
type: Number,
required: true,
min: -90, // Added validation
max: 90,
},
longitude: {
type: Number,
required: true,
min: -180, // Added validation
max: 180,
},
message: {
type: String,
default: "",
trim: true, // Added
maxlength: 500, // Added
},
status: {
type: String,
enum: ["ACTIVE", "RESOLVED"],
default: "ACTIVE",
},
},
{ timestamps: true }
{
timestamps: true // Already good
}
);

export default mongoose.model("Emergency", emergencySchema);
export default mongoose.model("Emergency", emergencySchema);
// import mongoose from "mongoose";

// const emergencySchema = new mongoose.Schema(
// {
// guardId: {
// type: mongoose.Schema.Types.ObjectId,
// ref: "User",
// required: true,
// },
// latitude: {
// type: Number,
// required: true,
// },
// longitude: {
// type: Number,
// required: true,
// },
// message: {
// type: String,
// default: "",
// },
// status: {
// type: String,
// enum: ["ACTIVE", "RESOLVED"],
// default: "ACTIVE",
// },
// },
// { timestamps: true }
// );

// export default mongoose.model("Emergency", emergencySchema);
Loading
Loading