diff --git a/.github/workflows/daily-check.yml b/.github/workflows/daily-check.yml new file mode 100644 index 0000000..bb205be --- /dev/null +++ b/.github/workflows/daily-check.yml @@ -0,0 +1,53 @@ +name: Daily Check and Test + +on: + schedule: + - cron: '0 0 * * *' # Runs every day at midnight UTC + push: + branches: + - development + +jobs: + check_and_test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Check for changes + id: check_changes + run: | + git fetch origin test + git diff --exit-code origin/development origin/test + + - name: Push to test branch + if: steps.check_changes.outcome == 'failure' + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git checkout development + git push origin HEAD:test + + - name: Run tests + if: steps.check_changes.outcome == 'failure' + run: | + npm install + npm test + + - name: Notify via email + if: always() + uses: dawidd6/action-send-mail@v3 + with: + server_address: smtp.gmail.com + server_port: 587 + username: ${{ secrets.SMTP_USERNAME }} + password: ${{ secrets.SMTP_PASSWORD }} + subject: Daily Test Results + to: you@example.com + from: github-actions@example.com + content_type: text/html + body: | + Tests have passed successfully. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e4ba297 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,191 @@ +#### 1.0.0 (2025-01-06) + +##### Build System / Dependencies + +* package update (e8d32ef1) +* intergrating jest (a91a2ed1) +* setting up testing mechanicems (1c5c819a) +* preping app for test case running (b88e435c) +* gitignore update (f01507d7) +* adding devDependency (f2e9b21a) +* added express dev dependency (a7ae2da5) +* add dev dependency jwt (ea19d5af) +* fixed an error in npm package file (ebe9b94e) +* added base packages (1d704226) + +##### New Features + +* adding autherization check (024f4ea2) +* fixing the error in admin log creation (61368091) +* improvements for subscription model (4aa80b33) +* add some more details (be3488d5) +* adding proper actions to admin controller (583983c9) +* add middleware (cf2f84e6) +* add middleware to verify token (16607fcf) +* add a jwt token creation (00d85396) +* add something to check the branch (daef7827) +* adding the tests back to branch (39849e6b) +* adding location model test (48ecd9bd) +* adding resources test cases (8236c14f) +* adding location test cases (46f6a3f5) +* adding subscription test cases (98e06a9b) +* adding notification testing code (b8c964e0) +* adding incident report test cases (41e94131) +* adding feedback controller tets (47a2b838) +* adding testing for alert controller (d8a1928e) +* adding alert model testing (6b624ffa) +* add test for user reports model (b53c6954) +* add user report controller tests (b6494088) +* added admin logs controller tests (6e9f5121) +* adding user controller testing (affff2ab) +* added user controller testing (76cf2fcd) +* conecting all the routes (12a9db18) +* adding new routes and removing old (4ab126fb) +* add save location function (806e481b) +* remove the transformation function (53e79f0a) +* changed the eo spatial index option (0bde8b15) +* main schema update (6268abdd) +* forecast schema (d31051cc) +* current weather schema (51ed54b6) +* adding schema for weather anomaly (8913bd1a) +* function to save location (74ed7dd0) +* get weather for saved locations (5fdbd976) +* looks for recent data (14d707e0) +* updated the get current location weather function (adf23543) +* adding the finished routes to index (5607b23c) +* removed unneccessary routes (2521b680) +* removed update and elete functions for adminlogs (1fda1145) +* changed getadminlogsbyid function (26205b71) +* changed getadminlogs function (752f9e6f) +* changed the adminlog creation function (6643a581) +* changed the admin logs model (01ace18b) +* connecting the shedulars to the app (9df95ff2) +* added weather service to fetch data from api (9acdc1b0) +* adding schedulars to run weather service (a2d7123b) +* added get nearby resources function (63010c6b) +* adding better pagination for querying (2a4f398f) +* improving change password function (13f7631a) +* adding a function to authenticate users (7893ca3d) +* improved delete user function (6b5fbf41) +* improving get user by Id (73400cd2) +* improving get all users function (449fc5d8) +* improved the current create user function (6f8eb2e8) +* adding function to check dbconnection (74e309ad) +* improving admin user check (38113970) +* improving verfied user check (ee9fa953) +* improving user type check (32ba78e3) +* adding better error handling and comments (35857821) +* added a modified version for just in case (beaf1499) +* improving the user model (1c95b5ba) +* improving user model (679c3ad1) +* weatherRoutes.js (5ab12847) +* weatherController.js (5b984577) +* userReportRoutes.js (003ec489) +* userReportController.js (0e13ed23) +* notificationRoutes.js (740961be) +* userRoutes.js (5ac1fd18) +* notificationController.js (bf789875) +* locationRoutes.js (53f508d8) +* userController.js (668333cf) +* locationController.js (24626185) +* incidentReportsRoutes.js (1272300c) +* incidentReportsController.js (5682c7de) +* subscriptionRoutes.js (94d42b8e) +* feedbackRoutes.js (800c37be) +* feedbackController.js (f45a91a0) +* subscriptionController.js (43247cec) +* alertsRoutes.js (c838b87d) +* alertsController.js (73dc4ea5) +* adminLogsRoutes.js (7b99a0a9) +* resourceRoutes.js (f88e1bc3) +* adminLogsController.js (c5163068) +* resourceController.js (198b02b0) +* adding db connection checker (785be652) +* adding user Routes (dd0dc7c1) +* added user controll functions (60bfc9ac) +* connect the routed to app (09c1cbb6) +* configured the routes (6358f3fb) +* adding auth middleware (9d8366e9) +* improved user model (2293dc6d) +* adminLogsController.js (815fb822) +* made improvements to the userReports and user models (7bb9189f) +* made improvements to location model (0cb5ffb2) +* feedback and incident report models (1394bfa4) +* alert and notification models (2ef50b88) +* weather data model (6306392a) +* add location model (b6e65148) +* add userReport model (06ca4cc7) +* added user model (7d49c282) +* starting point (c527094a) +* mongodb connection (1c4e6e11) + +##### Bug Fixes + +* fixed linting issues (747d42a1) +* adding proper action tags (1e02166d) +* fixed major issues in user related functions (2d110327) +* adding proper action (4fb247e7) +* fixxing an issue in case insensitive locations (84843d20) +* correcting function name changes (129e353d) +* changing the line (7d9a452b) +* commenting for conflit (658a3074) +* updated the resource controller function to support more types (c739a71d) +* adding new controller functions (74de4c89) +* updating the incidentreport controller function (1ad1a2bb) +* now checks target_types are mapped or not before creating logs (f61645db) +* made location model use case-insensitive names (21294e2c) +* changing mapping and formating of adminlogs model (ca7e0e58) +* adding more target types to the adminlogs model (0d993644) +* trying to fix admin controller type error (783fe5af) +* fixed an issue in routing (e49ab004) +* fixed an error in userRoutes.js (a3b44c3f) +* better structure for radability (cf9c5437) +* fixed a typo (7fb86abe) +* fixed some incorrect imports (254381e4) +* made updating user function work (d159dae3) +* changed the imports (0f9199e6) +* removing unused imports (d4d05a4d) +* fiexd the mongodb not connecting (da2c42b8) +* updated the get all users function (5cae4ea9) +* updated the create user function (d9bfdf30) + +##### Other Changes + +* userReportRoutes.js (375eec19) +* //github.com/DisasterWatchHQ/disasterCatcher into development (ec97ad2b) +* subscriptionRoutes.js (3037424d) +* index.js (be0fe87c) +* //github.com/DisasterWatchHQ/disasterCatcher into development (7375bd56) +* feedbackRoutes.js (3a855ca7) +* //github.com/DisasterWatchHQ/disasterCatcher into development (fcdb6002) +* userReportController.js (7c3ab254) +* //github.com/DisasterWatchHQ/disasterCatcher into development (88658b8e) +* alertsRoutes.js (5e3fa5b2) +* subscriptionController.js (54e3c591) +* feedbackController.js (3e74f421) +* added fixes for the latest issues" (316608d7) +* //github.com/DisasterWatchHQ/disasterCatcher into development (06e1daf4) +* //github.com/DisasterWatchHQ/disasterCatcher into development (e20b5be7) +* //github.com/DisasterWatchHQ/disasterCatcher into development (8a2092c0) +* //github.com/DisasterWatchHQ/disasterCatcher into development (551fbcb5) +* //github.com/DisasterWatchHQ/disasterCatcher into development (a034044e) +* //github.com/DisasterWatchHQ/disasterCatcher into development (77dce587) +* //github.com/DisasterWatchHQ/disasterCatcher into development (4d551116) +* fixed a typo in package import (7d952725) +* fixed a typo (32b59574) +* adding error middleware (c80a1cc9) +* added 3 models (70dc2123) + +##### Refactors + +* removed admin verifications (ce873f96) +* change controller functions to match the changes to model (22070f03) +* removing user types (dbc2a3e9) +* feedbackRoutes.js (e5b7ae62) +* feedbackController.js (436a00d6) +* incidentReportsRoutes.js (2933251e) +* feedback.js (9a3f7b11) +* incidentReportsController.js (34e73eec) +* incidentReport.js (bce88d56) +* userController.js (d081a3e7) + diff --git a/controllers/userController.js b/controllers/userController.js index 5372270..8e70cfb 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -6,20 +6,28 @@ const isValidObjectId = (id) => mongoose.Types.ObjectId.isValid(id); export const createUser = async (req, res) => { try { - const { name, email, password, type } = req.body; + const { name, email, password, workId, associated_department } = req.body; - if (!name || !email || !password) { + if (!name || !email || !password || !workId || !associated_department) { return res.status(400).json({ success: false, - message: "Name, email, and password are required.", + message: "Name, email, password, work ID, and department are required.", }); } - const existingUser = await User.findOne({ email: email.toLowerCase() }); + const existingUser = await User.findOne({ + $or: [ + { email: email.toLowerCase() }, + { workId: workId } + ] + }); + if (existingUser) { return res.status(409).json({ success: false, - message: "Email already registered.", + message: existingUser.email === email.toLowerCase() + ? "Email already registered." + : "Work ID already registered.", }); } @@ -27,12 +35,14 @@ export const createUser = async (req, res) => { name, email: email.toLowerCase(), password, - type: type || "anonymous", + workId, + associated_department, + isVerified: false, // Default to unverified }); res.status(201).json({ success: true, - message: "User created successfully.", + message: "User created successfully. Awaiting verification.", user, }); } catch (error) { @@ -44,16 +54,16 @@ export const createUser = async (req, res) => { } }; -// Get All Users with Pagination export const getAllUsers = async (req, res) => { try { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; - const { type, email } = req.query; + const { department, email, isVerified } = req.query; const query = {}; - if (type) query.type = type; + if (department) query.associated_department = department; if (email) query.email = new RegExp(email, "i"); + if (isVerified !== undefined) query.isVerified = isVerified === 'true'; const users = await User.find(query) .skip((page - 1) * limit) @@ -190,6 +200,13 @@ export const authenticateUser = async (req, res) => { }); } + if (!user.isVerified) { + return res.status(401).json({ + success: false, + message: "Account not verified. Please wait for verification.", + }); + } + const isMatch = await user.comparePassword(password); if (!isMatch) { return res.status(401).json({ @@ -203,7 +220,7 @@ export const authenticateUser = async (req, res) => { await user.save(); const token = jwt.sign( - { userId: user._id, type: user.type }, + { userId: user._id }, process.env.JWT_SECRET, { expiresIn: "24h" }, ); @@ -223,7 +240,8 @@ export const authenticateUser = async (req, res) => { id: user._id, name: user.name, email: user.email, - type: user.type, + department: user.associated_department, + isVerified: user.isVerified }, }); } catch (error) { diff --git a/models/users.js b/models/users.js index 04e96b3..5250a1a 100644 --- a/models/users.js +++ b/models/users.js @@ -29,14 +29,10 @@ const userSchema = new Schema( required: [true, "Password is required"], minlength: [6, "Password must be at least 6 characters"], }, - type: { + workId: { type: String, - required: true, - enum: { - values: ["registered", "verified", "anonymous", "admin"], - message: "{VALUE} is not supported", - }, - default: "anonymous", + required: [true, "Work ID is required"], + unique: true, }, location: locationSchema, associated_department: { @@ -46,7 +42,7 @@ const userSchema = new Schema( message: "{VALUE} is not a valid department", }, }, - verification_status: { + isVerified: { type: Boolean, default: false, }, @@ -61,7 +57,6 @@ const userSchema = new Schema( }, ); -/// Password hashing middleware userSchema.pre("save", async function (next) { if (!this.isModified("password")) return next(); @@ -74,7 +69,6 @@ userSchema.pre("save", async function (next) { } }); -// Compare password method userSchema.methods.comparePassword = async function (candidatePassword) { try { return await bcrypt.compare(candidatePassword, this.password); @@ -83,7 +77,6 @@ userSchema.methods.comparePassword = async function (candidatePassword) { } }; -// JSON transform userSchema.methods.toJSON = function () { const userObject = this.toObject(); delete userObject.password; @@ -91,10 +84,11 @@ userSchema.methods.toJSON = function () { return userObject; }; -/// Indexes -userSchema.index({ email: 1 }); -userSchema.index({ type: 1 }); -userSchema.index({ "location.latitude": 1, "location.longitude": 1 }); +userSchema.index( + { "location.latitude": 1, "location.longitude": 1 }, + { sparse: true }, +); +userSchema.index({ workId: 1 }, { unique: true }); const User = mongoose.model("User", userSchema); export default User; diff --git a/routes/userRoutes.js b/routes/userRoutes.js index 83277c1..b33ee9e 100644 --- a/routes/userRoutes.js +++ b/routes/userRoutes.js @@ -8,23 +8,20 @@ import { authenticateUser, changePassword, } from "../controllers/userController.js"; -import { - protectRoute, - verifyUserType, - verifyToken, -} from "../middlewares/authMiddleware.js"; +import { protectRoute, verifyToken } from "../middlewares/authMiddleware.js"; const router = express.Router(); router.post("/login", authenticateUser); - router.post("/register", createUser); + +// All routes below this middleware require authentication router.use(protectRoute, verifyToken); -router.get("/", verifyUserType("admin"), getAllUsers); +router.get("/", getAllUsers); router.get("/:id", getUserById); router.put("/:id", updateUser); router.delete("/:id", deleteUser); -router.put("/change-password/:id", changePassword); +router.post("/:id/change-password", changePassword); -export default router; +export default router; \ No newline at end of file