forked from rohit/spurrin-backend
doc views by user
This commit is contained in:
parent
ba185c0cf5
commit
7531702923
24
.env.example
24
.env.example
@ -1,15 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
DB_HOST=localhost
|
DB_HOST=localhost
|
||||||
DB_USER=root
|
DB_USER=testuser
|
||||||
DB_PASSWORD=Admin@123
|
DB_PASSWORD=Admin@123
|
||||||
DB_NAME=spurrindev
|
DB_NAME=spurrinai
|
||||||
|
|
||||||
EMAIL_USER=spurrinai@gmail.com
|
EMAIL_USER=info@spurrin.com
|
||||||
EMAIL_PASS=wblspqqpzpxfcjaq
|
EMAIL_PASS=app_password
|
||||||
EMAIL_HOST=smtp.gmail.com
|
EMAIL_HOST=smtp.gmail.com
|
||||||
EMAIL_PORT=587
|
EMAIL_PORT=587
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JWT_ACCESS_TOKEN_SECRET=jN4!pY9*d#T2@x$L7wq&Z8^gFc%X5@K#m
|
JWT_ACCESS_TOKEN_SECRET=jN4!pY9*d#T2@x$L7wq&Z8^gFc%X5@K#m
|
||||||
JWT_REFRESH_TOKEN_SECRET=Lx$Z7#T2^d&n9!Y4%K8@Fcg*m#qX5p@wL
|
JWT_REFRESH_TOKEN_SECRET=Lx$Z7#T2^d&n9!Y4%K8@Fcg*m#qX5p@wL
|
||||||
JWT_ACCESS_TOKEN_EXPIRY=5h
|
JWT_ACCESS_TOKEN_EXPIRY=5h
|
||||||
@ -19,12 +19,8 @@ JWT_REFRESH_TOKEN_EXPIRY=7d
|
|||||||
BACK_URL = http://localhost:3000/
|
BACK_URL = http://localhost:3000/
|
||||||
|
|
||||||
# email
|
# email
|
||||||
|
mail = info@spurrin.com
|
||||||
mail = srikanth.mallikarjuna@tech4biz.io
|
apppassword= app_password
|
||||||
apppassword = 0peCQnLEZVfZ
|
|
||||||
|
|
||||||
# mail = info@spurrin.com
|
|
||||||
# apppassword=nbF314CF84Ja
|
|
||||||
|
|
||||||
# PORT
|
# PORT
|
||||||
PORT = 3000
|
PORT = 3000
|
||||||
@ -38,6 +34,4 @@ SENDER_SECURITY = false
|
|||||||
|
|
||||||
# SENDER_PORT = 465
|
# SENDER_PORT = 465
|
||||||
# SENDER_SECURITY = true
|
# SENDER_SECURITY = true
|
||||||
|
OPENAI_API_KEY= your_api_key
|
||||||
SSL_CERT = "/home/ubuntu/spurrinai-backend-node/fullchain.pem"
|
|
||||||
SSL_KEY = "/home/ubuntu/spurrinai-backend-node/privkey.pem"
|
|
||||||
|
|||||||
7
checklist.txt
Normal file
7
checklist.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS document_views (
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
document_id INT NOT NULL,
|
||||||
|
user_id INT NOT NULL,
|
||||||
|
user_role ENUM('Superadmin', 'Admin', 'Viewer', 'Spurrinadmin', 'AppUser') NOT NULL,
|
||||||
|
viewed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
67
readme.md
67
readme.md
@ -6,10 +6,10 @@ A Node.js backend application for SpurrinAI platform.
|
|||||||
|
|
||||||
```
|
```
|
||||||
project-root/
|
project-root/
|
||||||
├── src/ # Source code
|
├── src/
|
||||||
│ ├── app.js # App entry point
|
│ ├── app.js # App entry point
|
||||||
│ ├── config/ # Configuration files
|
│ ├── config/ # Configuration files
|
||||||
│ ├── controllers/ # Route controllers
|
│ ├── controllers/ # Route controllers with business logic
|
||||||
│ ├── middleware/ # Custom middleware
|
│ ├── middleware/ # Custom middleware
|
||||||
│ ├── migrations/ # Database migrations
|
│ ├── migrations/ # Database migrations
|
||||||
│ ├── routes/ # Route definitions
|
│ ├── routes/ # Route definitions
|
||||||
@ -32,8 +32,8 @@ project-root/
|
|||||||
|
|
||||||
1. Clone the repository:
|
1. Clone the repository:
|
||||||
```bash
|
```bash
|
||||||
git clone -b dev https://git.tech4biz.wiki/Tech4Biz-Services/spurrin-cleaned-node.git
|
git clone git_repository_url
|
||||||
cd spurrinai-backend
|
cd spurrinai-backend (or respected folder )
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Install dependencies:
|
2. Install dependencies:
|
||||||
@ -58,31 +58,10 @@ npm run setup
|
|||||||
```bash
|
```bash
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
# Run migrations up
|
||||||
2. Run tests:
|
|
||||||
```bash
|
```bash
|
||||||
# Run all tests
|
npm run migrate:up
|
||||||
npm test
|
|
||||||
|
|
||||||
# Run unit tests only
|
|
||||||
npm run test:unit
|
|
||||||
|
|
||||||
# Run integration tests only
|
|
||||||
npm run test:integration
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Code Quality:
|
|
||||||
```bash
|
|
||||||
# Lint code
|
|
||||||
npm run lint
|
|
||||||
|
|
||||||
# Fix linting issues
|
|
||||||
npm run lint:fix
|
|
||||||
|
|
||||||
# Format code
|
|
||||||
npm run format
|
|
||||||
```
|
|
||||||
|
|
||||||
## Production Mode
|
## Production Mode
|
||||||
|
|
||||||
1. Build the application:
|
1. Build the application:
|
||||||
@ -154,40 +133,6 @@ npm run migrate:up
|
|||||||
npm run migrate:down
|
npm run migrate:down
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Documentation
|
|
||||||
|
|
||||||
Detailed API documentation can be found in the [docs/API.md](docs/API.md) file.
|
|
||||||
|
|
||||||
## Environment Variables
|
|
||||||
|
|
||||||
Required environment variables in `.env`:
|
|
||||||
|
|
||||||
```env
|
|
||||||
# Server Configuration
|
|
||||||
PORT=3000
|
|
||||||
NODE_ENV=development
|
|
||||||
|
|
||||||
# Database Configuration
|
|
||||||
DB_HOST=localhost
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_NAME=spurrinai
|
|
||||||
DB_USER=postgres
|
|
||||||
DB_PASSWORD=your_password
|
|
||||||
|
|
||||||
# JWT Configuration
|
|
||||||
JWT_SECRET=your_jwt_secret
|
|
||||||
JWT_EXPIRES_IN=24h
|
|
||||||
|
|
||||||
# Email Configuration
|
|
||||||
SMTP_HOST=smtp.gmail.com
|
|
||||||
SMTP_PORT=587
|
|
||||||
SMTP_USER=your_email@gmail.com
|
|
||||||
SMTP_PASS=your_app_password
|
|
||||||
|
|
||||||
# File Upload Configuration
|
|
||||||
UPLOAD_DIR=uploads
|
|
||||||
MAX_FILE_SIZE=5242880 # 5MB
|
|
||||||
```
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
|||||||
@ -126,7 +126,7 @@ async function startServer() {
|
|||||||
|
|
||||||
// Root endpoint
|
// Root endpoint
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.send("SpurrinAI Backend is running!");
|
res.send("SpurrinAI Backend is running!!!");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/logs', (req, res) => {
|
app.get('/logs', (req, res) => {
|
||||||
|
|||||||
@ -174,25 +174,6 @@ exports.getActiveHospitalsAnalysis = async (req, res) => {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
// const query = `
|
|
||||||
// SELECT
|
|
||||||
// h.id,
|
|
||||||
// h.name_hospital as hospital_name,
|
|
||||||
// h.hospital_code,
|
|
||||||
// h.status,
|
|
||||||
// h.onboarding_status,
|
|
||||||
// COUNT(DISTINCT au.id) as total_app_users,
|
|
||||||
// COUNT(DISTINCT il.id) as total_interactions,
|
|
||||||
// MAX(il.created_at) as last_interaction_date
|
|
||||||
// FROM hospitals h
|
|
||||||
// LEFT JOIN app_users au ON h.hospital_code = au.hospital_code
|
|
||||||
// LEFT JOIN interaction_logs il ON h.hospital_code = il.hospital_code
|
|
||||||
// ${start_date && end_date ? 'WHERE il.created_at BETWEEN ? AND ?' : ''}
|
|
||||||
// GROUP BY h.id
|
|
||||||
// HAVING total_interactions > 0
|
|
||||||
// ORDER BY total_interactions DESC
|
|
||||||
// `;
|
|
||||||
|
|
||||||
const params = start_date && end_date ? [start_date, end_date] : [];
|
const params = start_date && end_date ? [start_date, end_date] : [];
|
||||||
const hospitals = await db.query(query, params);
|
const hospitals = await db.query(query, params);
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,9 @@
|
|||||||
const bcrypt = require("bcrypt");
|
const bcrypt = require("bcrypt");
|
||||||
const db = require("../config/database"); // Database connection
|
const db = require("../config/database"); // Database connection
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const JWT_ACCESS_TOKEN_SECRET = process.env.JWT_ACCESS_TOKEN_SECRET;
|
|
||||||
const JWT_ACCESS_TOKEN_EXPIRY = "5h";
|
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
const nlp = require("compromise");
|
const nlp = require("compromise");
|
||||||
const nodemailer = require("nodemailer");
|
const nodemailer = require("nodemailer");
|
||||||
const sender_mail = process.env.mail;
|
|
||||||
const sender_app_password = process.env.apppassword;
|
|
||||||
const sender_port = process.env.SENDER_PORT;
|
const sender_port = process.env.SENDER_PORT;
|
||||||
const sender_security = process.env.SENDER_SECURITY;
|
const sender_security = process.env.SENDER_SECURITY;
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
@ -24,11 +20,7 @@ const transporter = nodemailer.createTransport({
|
|||||||
auth: {
|
auth: {
|
||||||
user: "kavya.j@tech4biz.io", // Your Zoho email address
|
user: "kavya.j@tech4biz.io", // Your Zoho email address
|
||||||
pass: "8pQfkBw8gbrz", // Your Zoho App Password (not your account password)
|
pass: "8pQfkBw8gbrz", // Your Zoho App Password (not your account password)
|
||||||
},
|
}
|
||||||
// tls: {
|
|
||||||
// rejectUnauthorized: false, // Allow self-signed certificates
|
|
||||||
// minVersion: "TLSv1.2"
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.initWebSocket = (io) => {
|
exports.initWebSocket = (io) => {
|
||||||
@ -110,12 +102,6 @@ exports.updateSettings = async (req, res) => {
|
|||||||
const userId = req.user.id; // Assuming user is authenticated and userId is available
|
const userId = req.user.id; // Assuming user is authenticated and userId is available
|
||||||
const { pin, pin_enabled, remember_me } = req.body;
|
const { pin, pin_enabled, remember_me } = req.body;
|
||||||
|
|
||||||
console.log("data---",pin,pin_enabled,remember_me)
|
|
||||||
|
|
||||||
// if (typeof pin_enabled !== 'boolean' || typeof remember_me !== 'boolean') {
|
|
||||||
// return res.status(400).json({ error: 'Invalid data format' });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Validate pin (if provided)
|
// Validate pin (if provided)
|
||||||
if (pin && (typeof pin !== 'string' || pin.length !== 4)) {
|
if (pin && (typeof pin !== 'string' || pin.length !== 4)) {
|
||||||
return res.status(400).json({ error: 'Invalid PIN format. Must be a 4-digit string.' });
|
return res.status(400).json({ error: 'Invalid PIN format. Must be a 4-digit string.' });
|
||||||
@ -211,14 +197,6 @@ exports.signup = async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
const { pin, pin_status,remember_me, email, password, hospital_code, username } = req.body;
|
const { pin, pin_status,remember_me, email, password, hospital_code, username } = req.body;
|
||||||
|
|
||||||
console.log("pin--",pin)
|
|
||||||
console.log("pin_status",pin_status)
|
|
||||||
console.log("email--",email)
|
|
||||||
console.log('password---',password)
|
|
||||||
console.log("hospital_code---",hospital_code)
|
|
||||||
console.log("username--",username)
|
|
||||||
console.log("remember_me--",remember_me)
|
|
||||||
|
|
||||||
if (!email || !password || !hospital_code || !username) {
|
if (!email || !password || !hospital_code || !username) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
error: "Email, password, username, and hospital code are required",
|
error: "Email, password, username, and hospital code are required",
|
||||||
@ -228,8 +206,6 @@ exports.signup = async (req, res) => {
|
|||||||
const pin_enabled = (pin_status === undefined || pin_status === '') ? 0 : pin_status;
|
const pin_enabled = (pin_status === undefined || pin_status === '') ? 0 : pin_status;
|
||||||
const remember_me_ = (remember_me === undefined || remember_me === '') ? 0 : remember_me;
|
const remember_me_ = (remember_me === undefined || remember_me === '') ? 0 : remember_me;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Check if the hospital_code exists in the `hospitals` table
|
// Check if the hospital_code exists in the `hospitals` table
|
||||||
const hospitalQuery =
|
const hospitalQuery =
|
||||||
"SELECT hospital_code FROM hospitals WHERE hospital_code = ?";
|
"SELECT hospital_code FROM hospitals WHERE hospital_code = ?";
|
||||||
@ -681,8 +657,6 @@ exports.deleteAppUser = async (req, res) => {
|
|||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const { hospital_code } = req.user;
|
const { hospital_code } = req.user;
|
||||||
|
|
||||||
console.log('req.user------------------------------------------------------------------',req.user)
|
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
const appUserquery = "SELECT * FROM app_users WHERE id = ?";
|
const appUserquery = "SELECT * FROM app_users WHERE id = ?";
|
||||||
const users = await db.query(appUserquery, [id]);
|
const users = await db.query(appUserquery, [id]);
|
||||||
|
|||||||
@ -497,4 +497,63 @@ exports.updateDocumentViews = async (req, res) => {
|
|||||||
console.error('Error updating document views:', error.message);
|
console.error('Error updating document views:', error.message);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// POST /documents/:id/view
|
||||||
|
exports.logDocumentView = async (req, res) => {
|
||||||
|
const documentId = parseInt(req.params.id);
|
||||||
|
const userId = req.user.id; // from decoded JWT or session
|
||||||
|
const userRole = req.user.role; // e.g., 'Admin', 'Viewer', etc.
|
||||||
|
|
||||||
|
if (!documentId || !userId || !userRole) {
|
||||||
|
return res.status(400).json({ error: 'Missing required information' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const insertQuery = `
|
||||||
|
INSERT INTO document_views (document_id, user_id, user_role)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await db.query(insertQuery, [documentId, userId, userRole]);
|
||||||
|
|
||||||
|
res.status(200).json({ message: 'View logged successfully', insertId: result.insertId });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error logging document view:', error.message);
|
||||||
|
res.status(500).json({ message: 'Error logging view' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// GET /documents/:id/views
|
||||||
|
exports.getDocumentViewCount = async (req, res) => {
|
||||||
|
const documentId = parseInt(req.params.id);
|
||||||
|
|
||||||
|
if (!documentId) {
|
||||||
|
return res.status(400).json({ error: 'Document ID is required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query = `
|
||||||
|
SELECT
|
||||||
|
document_id,
|
||||||
|
user_id AS viewed_by,
|
||||||
|
user_role,
|
||||||
|
viewed_at
|
||||||
|
FROM document_views
|
||||||
|
WHERE document_id = ?
|
||||||
|
ORDER BY viewed_at DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [views] = await db.query(query, [documentId]);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
documentId,
|
||||||
|
totalViews: views.length,
|
||||||
|
views,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching view details:', error.message);
|
||||||
|
res.status(500).json({ message: 'Error fetching view details' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -76,5 +76,8 @@ router.delete(
|
|||||||
documentController.deleteDocument
|
documentController.deleteDocument
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.post('/:id/view', authMiddleware.authenticateToken, documentController.logDocumentView);
|
||||||
|
router.get('/:id/views',authMiddleware.authenticateToken, documentController.getDocumentViewCount);
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
|
module.exports = router;
|
||||||
Loading…
Reference in New Issue
Block a user