Skip to content
Merged
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
1 change: 1 addition & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 75 additions & 26 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app-backend/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
MONGO_URI=mongodb+srv://s223580955_db_user:Sanjolika%4020003@cluster0.tlvzspv.mongodb.net/
MONGO_URI=mongodb+srv://95groot:1995Groot@secureshift-cluster.0zfeq5j.mongodb.net/
PORT=5000
JWT_SECRET=some_long_random_secret_here
43 changes: 43 additions & 0 deletions app-backend/src/controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,46 @@ export const updateEmployerProfile = async (req, res) => {
res.status(500).json({ message: err.message });
}
};

/**
* @desc Register or update a push token for the logged-in user
* @route POST /api/v1/users/push-token
* @access Private (all roles)
*/
export const registerPushToken = async (req, res) => {
try {
const { token, platform, deviceId } = req.body;

if (!token || typeof token !== 'string') {
return res.status(400).json({ message: 'Push token is required.' });
}

const user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}

const existing = user.pushTokens?.find((item) => item.token === token);
if (existing) {
existing.platform = platform ?? existing.platform;
existing.deviceId = deviceId ?? existing.deviceId;
existing.updatedAt = new Date();
} else {
user.pushTokens = [
...(user.pushTokens ?? []),
{
token,
platform,
deviceId,
updatedAt: new Date(),
},
];
}

await user.save();

return res.status(200).json({ message: 'Push token registered.' });
} catch (err) {
return res.status(500).json({ message: err.message });
}
};
9 changes: 9 additions & 0 deletions app-backend/src/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ const userSchema = new mongoose.Schema(
default: null,
},

pushTokens: [
{
token: { type: String, required: true },
platform: { type: String },
deviceId: { type: String },
updatedAt: { type: Date, default: Date.now },
},
],

// soft delete fields
isDeleted: { type: Boolean, default: false, index: true }, // marks user as deactivated
deletedAt: { type: Date, default: null }, // when it was deactivated
Expand Down
36 changes: 35 additions & 1 deletion app-backend/src/routes/user.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
adminUpdateUserProfile,
getAllGuards,
listUsers,
deleteUser
deleteUser,
registerPushToken
} from '../controllers/user.controller.js';

const router = express.Router();
Expand Down Expand Up @@ -80,6 +81,39 @@ router
.get(auth, loadUser, getMyProfile)
.put(auth, loadUser, updateMyProfile);

/**
* @swagger
* /api/v1/users/push-token:
* post:
* summary: Register a push notification token
* tags: [Users]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - token
* properties:
* token:
* type: string
* platform:
* type: string
* deviceId:
* type: string
* responses:
* 200:
* description: Token registered
* 400:
* description: Validation error
* 401:
* description: Unauthorized
*/
router.post('/push-token', auth, loadUser, registerPushToken);

/**
* @swagger
* /api/v1/users/profile:
Expand Down
18 changes: 17 additions & 1 deletion guard_app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
// App.tsx
import { NavigationContainer } from '@react-navigation/native';
import React from 'react';
import React, { useEffect } from 'react';

import AppNavigator from './src/navigation/AppNavigator';
import { registerPushTokenIfNeeded, subscribeToPushTokenChanges } from './src/lib/pushNotifications';

Check failure on line 6 in guard_app/App.tsx

View workflow job for this annotation

GitHub Actions / ESLint & Prettier

Replace `·registerPushTokenIfNeeded,·subscribeToPushTokenChanges·` with `⏎··registerPushTokenIfNeeded,⏎··subscribeToPushTokenChanges,⏎`

Check warning on line 6 in guard_app/App.tsx

View workflow job for this annotation

GitHub Actions / ESLint & Prettier

`./src/lib/pushNotifications` import should occur before import of `./src/navigation/AppNavigator`

Check failure on line 6 in guard_app/App.tsx

View workflow job for this annotation

GitHub Actions / ESLint & Prettier

Replace `·registerPushTokenIfNeeded,·subscribeToPushTokenChanges·` with `⏎··registerPushTokenIfNeeded,⏎··subscribeToPushTokenChanges,⏎`

Check warning on line 6 in guard_app/App.tsx

View workflow job for this annotation

GitHub Actions / ESLint & Prettier

`./src/lib/pushNotifications` import should occur before import of `./src/navigation/AppNavigator`

export default function App() {
useEffect(() => {
let subscription: { remove: () => void } | null = null;
const register = async () => {
await registerPushTokenIfNeeded();
subscription = subscribeToPushTokenChanges(async (newToken) => {
await registerPushTokenIfNeeded(newToken);
});
};

void register();
return () => {
subscription?.remove();
};
}, []);

return (
<NavigationContainer>
<AppNavigator />
Expand Down
13 changes: 10 additions & 3 deletions guard_app/app.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"expo": {
"name": "SecureShift-GuardApp",
"slug": "SecureShift-GuardApp",
"slug": "secureshift-guardapp",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
Expand All @@ -20,10 +20,17 @@
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true
"edgeToEdgeEnabled": true,
"package": "com.secureshiftguardapp.secureshiftguardapp"
},
"web": {
"favicon": "./assets/favicon.png"
}
},
"extra": {
"eas": {
"projectId": "59453bc8-475d-40dd-9f7f-f275fd6d1eea"
}
},
"owner": "secureshift-guardapp"
}
}
Loading
Loading