diff --git a/.env.example b/.env.example index 2e09f7e..edaf759 100644 --- a/.env.example +++ b/.env.example @@ -1,15 +1,15 @@ - - DB_HOST=localhost -DB_USER=root +DB_USER=testuser DB_PASSWORD=Admin@123 -DB_NAME=spurrindev +DB_NAME=spurrinai -EMAIL_USER=spurrinai@gmail.com -EMAIL_PASS=wblspqqpzpxfcjaq +EMAIL_USER=info@spurrin.com +EMAIL_PASS=app_password EMAIL_HOST=smtp.gmail.com EMAIL_PORT=587 + + 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_ACCESS_TOKEN_EXPIRY=5h @@ -19,12 +19,8 @@ JWT_REFRESH_TOKEN_EXPIRY=7d BACK_URL = http://localhost:3000/ # email - -mail = srikanth.mallikarjuna@tech4biz.io -apppassword = 0peCQnLEZVfZ - -# mail = info@spurrin.com -# apppassword=nbF314CF84Ja +mail = info@spurrin.com +apppassword= app_password # PORT PORT = 3000 @@ -38,6 +34,4 @@ SENDER_SECURITY = false # SENDER_PORT = 465 # SENDER_SECURITY = true - -SSL_CERT = "/home/ubuntu/spurrinai-backend-node/fullchain.pem" -SSL_KEY = "/home/ubuntu/spurrinai-backend-node/privkey.pem" \ No newline at end of file +OPENAI_API_KEY= your_api_key diff --git a/checklist.txt b/checklist.txt new file mode 100644 index 0000000..0e4a2e8 --- /dev/null +++ b/checklist.txt @@ -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 +); diff --git a/readme.md b/readme.md index 190d7ba..d5cb324 100644 --- a/readme.md +++ b/readme.md @@ -6,10 +6,10 @@ A Node.js backend application for SpurrinAI platform. ``` project-root/ -├── src/ # Source code +├── src/ │ ├── app.js # App entry point │ ├── config/ # Configuration files -│ ├── controllers/ # Route controllers +│ ├── controllers/ # Route controllers with business logic │ ├── middleware/ # Custom middleware │ ├── migrations/ # Database migrations │ ├── routes/ # Route definitions @@ -32,8 +32,8 @@ project-root/ 1. Clone the repository: ```bash -git clone -b dev https://git.tech4biz.wiki/Tech4Biz-Services/spurrin-cleaned-node.git -cd spurrinai-backend +git clone git_repository_url +cd spurrinai-backend (or respected folder ) ``` 2. Install dependencies: @@ -58,31 +58,10 @@ npm run setup ```bash npm run dev ``` - -2. Run tests: +# Run migrations up ```bash -# Run all tests -npm test - -# Run unit tests only -npm run test:unit - -# Run integration tests only -npm run test:integration +npm run migrate:up ``` - -3. Code Quality: -```bash -# Lint code -npm run lint - -# Fix linting issues -npm run lint:fix - -# Format code -npm run format -``` - ## Production Mode 1. Build the application: @@ -154,40 +133,6 @@ npm run migrate:up 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 diff --git a/src/app.js b/src/app.js index de0ebf3..59f3a52 100644 --- a/src/app.js +++ b/src/app.js @@ -126,7 +126,7 @@ async function startServer() { // Root endpoint app.get('/', (req, res) => { - res.send("SpurrinAI Backend is running!"); + res.send("SpurrinAI Backend is running!!!"); }); app.get('/logs', (req, res) => { diff --git a/src/controllers/analysisController.js b/src/controllers/analysisController.js index 57c1a31..6c36d0f 100644 --- a/src/controllers/analysisController.js +++ b/src/controllers/analysisController.js @@ -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 hospitals = await db.query(query, params); diff --git a/src/controllers/appUserController.js b/src/controllers/appUserController.js index 97d03a8..b27f37c 100644 --- a/src/controllers/appUserController.js +++ b/src/controllers/appUserController.js @@ -1,13 +1,9 @@ const bcrypt = require("bcrypt"); const db = require("../config/database"); // Database connection 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 nlp = require("compromise"); 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_security = process.env.SENDER_SECURITY; const path = require('path') @@ -24,11 +20,7 @@ const transporter = nodemailer.createTransport({ auth: { user: "kavya.j@tech4biz.io", // Your Zoho email address pass: "8pQfkBw8gbrz", // Your Zoho App Password (not your account password) - }, - // tls: { - // rejectUnauthorized: false, // Allow self-signed certificates - // minVersion: "TLSv1.2" - // } + } }); 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 { 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) if (pin && (typeof pin !== 'string' || pin.length !== 4)) { 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 { 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) { return res.status(400).json({ 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 remember_me_ = (remember_me === undefined || remember_me === '') ? 0 : remember_me; - - // Check if the hospital_code exists in the `hospitals` table const hospitalQuery = "SELECT hospital_code FROM hospitals WHERE hospital_code = ?"; @@ -681,8 +657,6 @@ exports.deleteAppUser = async (req, res) => { const { id } = req.params; const { hospital_code } = req.user; - console.log('req.user------------------------------------------------------------------',req.user) - // Check if the user exists const appUserquery = "SELECT * FROM app_users WHERE id = ?"; const users = await db.query(appUserquery, [id]); diff --git a/src/controllers/documentsController.js b/src/controllers/documentsController.js index c3b02a3..84eff85 100644 --- a/src/controllers/documentsController.js +++ b/src/controllers/documentsController.js @@ -497,4 +497,63 @@ exports.updateDocumentViews = async (req, res) => { console.error('Error updating document views:', error.message); res.status(500).json({ error: 'Internal server error' }); } -}; \ No newline at end of file +}; + + +// 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' }); + } +}; diff --git a/src/routes/documents.js b/src/routes/documents.js index e56733d..1d0234f 100644 --- a/src/routes/documents.js +++ b/src/routes/documents.js @@ -76,5 +76,8 @@ router.delete( documentController.deleteDocument ); +router.post('/:id/view', authMiddleware.authenticateToken, documentController.logDocumentView); +router.get('/:id/views',authMiddleware.authenticateToken, documentController.getDocumentViewCount); -module.exports = router; + +module.exports = router; \ No newline at end of file