diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b0bc8d0 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +# Database Configuration +MYSQL_HOST=localhost +MYSQL_PORT=3306 +MYSQL_USER=root +MYSQL_PASSWORD= +MYSQL_DATABASE=lms + +# Email Configuration +EMAIL_SERVICE=gmail +EMAIL_USER=your-email@gmail.com +EMAIL_PASS=your-app-password +EMAIL_FROM=your-email@gmail.com + +# Application URL (for email verification links) +APP_URL=http://localhost:3000 \ No newline at end of file diff --git a/AUTHENTICATION_SETUP.md b/AUTHENTICATION_SETUP.md new file mode 100644 index 0000000..50abf1a --- /dev/null +++ b/AUTHENTICATION_SETUP.md @@ -0,0 +1,241 @@ +# Authentication System Setup for Campus Bridge + +This document explains how to set up and use the authentication system for Campus Bridge. + +## Overview + +The authentication system includes: +- User registration and login +- Session management +- Protected routes +- Database storage for user credentials + +## Setup Instructions + +### 1. Initialize the Database + +Since Node.js is not available on this system, you'll need to manually create the database tables. + +Open MySQL Workbench or Terminal and run: + +```sql +CREATE DATABASE lms; + +USE lms; + +CREATE TABLE learning_resources ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + file_path VARCHAR(255) NOT NULL +); + +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Insert a test user +INSERT INTO users (name, email, password) VALUES ('Test User', 'test@example.com', 'password123'); +``` + +If Node.js becomes available later, you can use the initialization script: + +```bash +npm run init-db +``` + +### 2. Start the Server + +```bash +npm start +``` + +Or for development: + +```bash +npm run dev +``` + +## API Endpoints + +### User Registration +- **Endpoint**: `POST /api/register` +- **Body**: + ```json + { + "name": "User Name", + "email": "user@example.com", + "password": "userpassword" + } + ``` +- **Response**: + ```json + { + "success": true, + "message": "User registered successfully" + } + ``` + +### User Login +- **Endpoint**: `POST /api/login` +- **Body**: + ```json + { + "email": "user@example.com", + "password": "userpassword" + } + ``` +- **Response**: + ```json + { + "success": true, + "message": "Login successful", + "sessionId": "session_identifier", + "user": { + "id": 1, + "name": "User Name", + "email": "user@example.com" + } + } + ``` + +### User Logout +- **Endpoint**: `POST /api/logout` +- **Body**: + ```json + { + "sessionId": "session_identifier" + } + ``` +- **Response**: + ```json + { + "success": true, + "message": "Logged out successfully" + } + ``` + +### Check Authentication +- **Endpoint**: `GET /api/auth/check` +- **Headers**: + ``` + X-Session-Id: session_identifier + ``` +- **Response**: + ```json + { + "success": true, + "message": "User is authenticated", + "user": { + "id": 1, + "name": "User Name", + "email": "user@example.com" + } + } + ``` + +## How It Works + +### Frontend + +1. **Login Process**: + - User submits credentials via the login form + - Credentials are sent to the backend `/api/login` endpoint + - If successful, the session ID is stored in `localStorage` + - User is redirected to the courses page + +2. **Session Management**: + - Session ID is stored in `localStorage` as `sessionId` + - On page load, protected pages check authentication status + - Session ID is sent in the `X-Session-Id` header for authenticated requests + +3. **Protected Routes**: + - Pages like `courses.html` check for a valid session on load + - Unauthorized users are shown an access denied message + +### Backend + +1. **Session Storage**: + - Sessions are stored in memory using a `Map` data structure + - Each session contains user information and creation timestamp + - Sessions can be destroyed on logout + +2. **Authentication Middleware**: + - `requireAuth` middleware checks for valid sessions + - Used to protect API endpoints that require authentication + +## Security Considerations + +### Current Implementation +- Passwords are stored in plain text (NOT secure for production) +- Sessions are stored in memory (will be lost on server restart) +- No password strength validation + +### Recommended Improvements for Production +1. Hash passwords using bcrypt: + ```javascript + const bcrypt = require('bcrypt'); + // Hash password before storing + const hashedPassword = await bcrypt.hash(password, 10); + // Compare hashed password during login + const isValid = await bcrypt.compare(password, hashedPassword); + ``` + +2. Use a proper session store like Redis: + ```javascript + const session = require('express-session'); + const RedisStore = require('connect-redis')(session); + ``` + +3. Add CSRF protection +4. Implement rate limiting for login attempts +5. Add input validation and sanitization +6. Use HTTPS in production +7. Implement password strength requirements + +## Testing + +### Default Test User +The database initialization script creates a test user: +- **Email**: test@example.com +- **Password**: password123 + +### Testing Authentication +1. Navigate to `http://localhost:8080/studentlogin.html` +2. Enter the test credentials +3. You should be redirected to the courses page +4. Try accessing `http://localhost:8080/courses.html` directly (should work if logged in) +5. Try logging out and accessing protected pages (should show access denied) + +## Troubleshooting + +### Common Issues + +1. **Cannot log in with test credentials**: + - Ensure you've run `npm run init-db` + - Check the database connection in `db.js` + - Verify the users table was created + +2. **Access denied to protected pages**: + - Make sure you're logged in + - Check browser console for errors + - Verify session ID is being stored in localStorage + +3. **Database connection errors**: + - Check database credentials in `db.js` + - Ensure MySQL server is running + - Verify the database exists + +### Debugging Tips + +1. Check browser developer tools Network tab to see API requests +2. Check server console for error messages +3. Use database client to verify data in tables +4. Check localStorage for session ID after login + +## Support + +For questions about this implementation, contact the Campus Bridge development team. \ No newline at end of file diff --git a/EMAIL_CONFIRMATION_SETUP.md b/EMAIL_CONFIRMATION_SETUP.md new file mode 100644 index 0000000..97fae57 --- /dev/null +++ b/EMAIL_CONFIRMATION_SETUP.md @@ -0,0 +1,60 @@ +# Email Confirmation Setup + +This guide explains how to configure email confirmation functionality for Campus Bridge LMS. + +## How It Works + +After a user successfully logs in, an email confirmation is automatically sent to their registered email address. This helps users know that their login was successful and provides an additional security measure. + +## Configuration + +1. **Environment Variables**: The email configuration is stored in the `.env` file in the root directory. + +2. **Required Settings**: + - `EMAIL_SERVICE`: The email service provider (default: gmail) + - `EMAIL_USER`: Your email address + - `EMAIL_PASS`: Your email password or app password + - `EMAIL_FROM`: The email address that will appear as the sender + +## Gmail Configuration + +For Gmail users, you need to generate an App Password: + +1. Go to your Google Account settings +2. Navigate to Security +3. Enable 2-Factor Authentication if not already enabled +4. Generate an App Password: + - Go to "App passwords" + - Select "Mail" and your device + - Copy the generated password +5. Use this App Password in the `EMAIL_PASS` field + +## Testing Email Functionality + +To test the email confirmation: + +1. Start the server: `npm start` +2. Navigate to the login page +3. Log in with valid credentials +4. Check the user's email inbox for a confirmation message + +## Customization + +You can customize the email template by modifying the `sendEmailConfirmation` function in `server.js`. The current template includes: +- User's name +- Login timestamp +- Security warning for unauthorized access + +## Troubleshooting + +If emails are not being sent: +1. Check that all environment variables are correctly set +2. Verify that your email credentials are correct +3. Ensure that your email provider allows SMTP access +4. Check the server console for error messages + +## Security Notes + +- Never commit your `.env` file to version control +- Use App Passwords instead of your regular email password +- Regularly rotate your App Passwords for security \ No newline at end of file diff --git a/GOOGLE_ANALYTICS_SETUP.md b/GOOGLE_ANALYTICS_SETUP.md new file mode 100644 index 0000000..d66c3c8 --- /dev/null +++ b/GOOGLE_ANALYTICS_SETUP.md @@ -0,0 +1,131 @@ +# Google Analytics Implementation for Campus Bridge + +This document explains how Google Analytics has been implemented in the Campus Bridge Learning Management System. + +## Implementation Overview + +We've implemented Google Analytics 4 (GA4) tracking across the Campus Bridge application to track user interactions, page views, and other important events. The implementation uses a centralized approach with a shared JavaScript file. + +## Files Modified + +1. `public/analytics.js` - Centralized analytics tracking script +2. `public/index.html` - Main landing page +3. `public/studentlogin.html` - Student login page +4. `public/courses.html` - Courses dashboard +5. `public/freecourses.html` - Free courses page + +## Setup Instructions + +### 1. Create a Google Analytics 4 Property + +1. Go to [Google Analytics](https://analytics.google.com/) +2. Sign in with your Google account +3. Click "Admin" (gear icon) in the lower left +4. In the "Account" column, select an existing account or create a new one +5. In the "Property" column, click "Create Property" +6. Select "Web" as the platform +7. Enter "Campus Bridge" as the property name +8. Enter your website URL +9. Select the appropriate reporting time zone +10. Click "Next" and complete the setup + +### 2. Get Your Measurement ID + +1. After creating the property, you'll get a Measurement ID (starts with "G-") +2. If you need to find it later: + - Go to "Admin" + - Select your property + - Click "Data Streams" + - Click your web stream + - Your Measurement ID is displayed at the top + +### 3. Update the Measurement ID + +1. Open `public/analytics.js` +2. Find the line: `gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-YOUR-GA4-ID-HERE';` +3. Replace `G-YOUR-GA4-ID-HERE` with your actual Measurement ID +4. Also update the line: `gtag('config', 'G-YOUR-GA4-ID-HERE');` + +### 4. Verify Implementation + +1. Deploy your application +2. Visit your site +3. Go to your Google Analytics Realtime reports +4. You should see active users + +## Tracked Events + +The implementation tracks the following events: + +### Page Views +- Automatic tracking of all page views + +### Navigation Events +- Clicks on main navigation elements +- Course card selections +- Sidebar navigation + +### Authentication Events +- Login attempts +- Successful logins + +### Course Interaction Events +- Course card clicks +- Video views in free courses + +### Chatbot Events +- Opening the Shakti AI chatbot +- Interactions with the chatbot + +## Custom Functions + +The `analytics.js` file provides several helper functions: + +- `trackPageView(pageName)` - Track page views +- `trackNavigation(destination)` - Track navigation events +- `trackCourseInteraction(courseName, action)` - Track course interactions +- `trackAuthEvent(eventType, description)` - Track authentication events +- `trackChatbotEvent(eventType, message)` - Track chatbot interactions +- `trackVideoView(courseName, videoTitle)` - Track video views + +## Adding Tracking to New Pages + +To add Google Analytics tracking to new pages: + +1. Include the analytics script in the `
` section: + ```html + + ``` + +2. Use the appropriate tracking functions for events: + ```javascript + // For navigation + trackNavigation('Page Name'); + + // For course interactions + trackCourseInteraction('Course Name', 'Action'); + + // For authentication + trackAuthEvent('event_type', 'Description'); + ``` + +## Privacy Considerations + +This implementation respects user privacy by: +- Not collecting personally identifiable information (PII) +- Only tracking interactions and page views +- Using standard GA4 anonymization features + +## Troubleshooting + +If you're not seeing data in Google Analytics: + +1. Check that you've updated the Measurement ID correctly +2. Verify there are no JavaScript errors in the browser console +3. Ensure your site is accessible via HTTPS (required for GA4) +4. Check that your ad blocker isn't blocking GA scripts +5. Confirm you're looking at the correct date range in GA reports + +## Support + +For questions about this implementation, contact the Campus Bridge development team. \ No newline at end of file diff --git a/README.md b/README.md index 09a7616..da1c75f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # Campus Bridge β Learning Management System (LMS) π Campus Bridge is a modern and lightweight LMS (Learning Management System) tailored for educational institutions, students, and self-paced learners. Built with simplicity, scalability, and beauty in mind. @@ -15,6 +14,25 @@ Campus Bridge is a modern and lightweight LMS (Learning Management System) tailo --- +## βοΈ Deployment Options + +### Render (Recommended for Full Application) +For a complete deployment with both frontend and backend functionality, we recommend Render which supports Node.js applications with database connectivity. + +π See [RENDER_DEPLOYMENT.md](RENDER_DEPLOYMENT.md) for detailed instructions + +### Local Development (Recommended) +For the complete experience, run the application locally: + +```bash +git clone https://github.com/Codeunia/Campus-Bridge.git +cd Campus-Bridge +npm install +npm start +``` + +--- + ## π§° Tech Stack | Layer | Tech Used | @@ -35,6 +53,10 @@ Campus Bridge is a modern and lightweight LMS (Learning Management System) tailo - β‘ Smooth integration between frontend & backend - β¨ Modern UI with responsive design - π§Ύ Organized by subject/topic +- π User authentication and session management +- π€ User registration and login +- π« Protected routes for authenticated users only +- π€ Shakthi Bot - AI assistant for website navigation --- @@ -46,12 +68,19 @@ CampusBridge-LMS/ βββ public/ # Frontend files β βββ index.html # Main UI page β βββ script.js # Dynamic JS logic +β βββ shakti-bot.js # Shakthi Bot AI assistant +β βββ *.html # All HTML pages with integrated Shakthi Bot β βββ uploads/ # Uploaded PDF files β βββ server.js # Main Express server βββ db.js # MySQL connection -βββ README.md # Youβre here! +βββ middleware.js # Authentication middleware +βββ init-db.js # Database initialization script +βββ README.md # Project documentation +βββ AUTHENTICATION_SETUP.md # Authentication system documentation +βββ GOOGLE_ANALYTICS_SETUP.md # Google Analytics implementation guide +βββ SHAKTHI_BOT_GUIDE.md # Comprehensive Shakthi Bot implementation guide ``` --- @@ -71,7 +100,7 @@ cd Campus-Bridge npm install express mysql multer cors ``` -### 3. Setup MySQL +### 3. Setup MySQL Tables Open MySQL Workbench or Terminal and run: @@ -85,20 +114,60 @@ CREATE TABLE learning_resources ( title VARCHAR(255) NOT NULL, file_path VARCHAR(255) NOT NULL ); + +CREATE TABLE users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Insert a test user +INSERT INTO users (name, email, password) VALUES ('Test User', 'test@example.com', 'password123'); ``` -### 4. Start the MySQL server +### 5. Start the MySQL server Make sure your local MySQL is running and matches your `db.js` config. -### 5. Start the Express server +### 6. Start the Express server + +```bash +npm start +``` + +Or for development: ```bash -node server.js +npm run dev ``` --- +## π Authentication + +Campus Bridge now includes a full authentication system with: + +- User registration +- User login/logout +- Session management +- Protected routes + +For detailed information about the authentication system, see [AUTHENTICATION_SETUP.md](AUTHENTICATION_SETUP.md). + +### Default Test User + +After running `npm run init-db`, a test user will be created: +- **Email**: test@example.com +- **Password**: password123 + +### Email Confirmation + +Campus Bridge now sends email confirmations after successful user login. For setup instructions, see [EMAIL_CONFIRMATION_SETUP.md](EMAIL_CONFIRMATION_SETUP.md). + +--- + ## π¬ API Usage (Postman) ### Upload PDF @@ -112,12 +181,33 @@ node server.js `GET http://localhost:3000/resources` +### User Registration + +`POST http://localhost:3000/api/register` +```json +{ + "name": "User Name", + "email": "user@example.com", + "password": "userpassword" +} +``` + +### User Login + +`POST http://localhost:3000/api/login` +```json +{ + "email": "user@example.com", + "password": "userpassword" +} +``` + --- ## π Visit in Browser -``` -http://localhost:3000/lectures.html +```bash +http://localhost:8080/ ``` --- @@ -128,6 +218,10 @@ http://localhost:3000/lectures.html - β Tag lectures by subject/branch - β YouTube integration - β Admin dashboard +- β Protected routes +- β Session management +- β Shakthi Bot AI assistant +- β Email confirmation after login --- ## π§ Contributing diff --git a/RENDER_DEPLOYMENT.md b/RENDER_DEPLOYMENT.md new file mode 100644 index 0000000..2095369 --- /dev/null +++ b/RENDER_DEPLOYMENT.md @@ -0,0 +1,123 @@ +# Deploying Campus Bridge LMS to Render + +This guide will help you deploy the full Campus Bridge LMS application to Render, which supports both the frontend and backend components. + +## Prerequisites + +1. A [Render](https://render.com) account (free) +2. A GitHub account +3. This repository forked or cloned + +## Deployment Steps + +### 1. Prepare Your Application + +The application has already been configured to work with Render's environment variables. The key changes made: + +1. **Database configuration** in [db.js](file:///Users/madanthambisetty/Downloads/Campus-Bridge/db.js) now uses environment variables +2. **Server configuration** in [server.js](file:///Users/madanthambisetty/Downloads/Campus-Bridge/server.js) listens on Render's PORT +3. **Email verification links** use APP_URL environment variable + +### 2. Create a Render Account + +1. Go to [https://render.com](https://render.com) +2. Sign up for a free account +3. Connect your GitHub account + +### 3. Deploy the Web Service + +1. Click "New +" and select "Web Service" +2. Connect to your GitHub repository +3. Configure the settings: + - **Name**: campus-bridge-lms + - **Environment**: Node + - **Build Command**: `npm install` + - **Start Command**: `npm start` + - **Instance Type**: Free + +4. Add environment variables in the "Advanced" section: + - `MYSQL_HOST`: Your database host + - `MYSQL_USER`: Your database username + - `MYSQL_PASSWORD`: Your database password + - `MYSQL_DATABASE`: lms + - `EMAIL_SERVICE`: gmail (or your email service) + - `EMAIL_USER`: your-email@gmail.com + - `EMAIL_PASS`: your-app-password + - `EMAIL_FROM`: your-email@gmail.com + - `APP_URL`: https://your-app-name.onrender.com (your Render app URL) + +### 4. Set Up Database + +Render offers free PostgreSQL databases. To use it: + +1. Click "New +" and select "PostgreSQL" +2. Choose the free tier +3. Once created, you'll get connection details + +Since Campus Bridge uses MySQL, you have two options: +1. Modify the application to use PostgreSQL instead (see migration guide below) +2. Use an external MySQL provider like PlanetScale (has a free tier) + +### 5. Alternative: Using PlanetScale for Database + +PlanetScale offers a free MySQL-compatible database: + +1. Go to [https://planetscale.com](https://planetscale.com) +2. Sign up for a free account +3. Create a new database +4. Get the connection details and use them as environment variables + +### 6. Environment Variables + +In Render, set these environment variables: + +``` +PORT=3000 +MYSQL_HOST=your-db-host +MYSQL_PORT=3306 +MYSQL_USER=your-db-username +MYSQL_PASSWORD=your-db-password +MYSQL_DATABASE=lms +EMAIL_SERVICE=gmail +EMAIL_USER=your-email@gmail.com +EMAIL_PASS=your-app-password +EMAIL_FROM=your-email@gmail.com +APP_URL=https://your-app-name.onrender.com +``` + +## Render Free Tier Limitations + +1. **Sleep Mode**: Web services fall asleep after 15 minutes of inactivity +2. **500 Build Minutes**: Per month +3. **CPU Time**: 500 hours per month +4. **Bandwidth**: 100GB per month + +## Migration from MySQL to PostgreSQL (Optional) + +If you want to use Render's free PostgreSQL database, you'll need to modify the database queries slightly: + +1. Update [db.js](file:///Users/madanthambisetty/Downloads/Campus-Bridge/db.js): +```javascript +const { Client } = require('pg'); + +const client = new Client({ + connectionString: process.env.DATABASE_URL, + ssl: { + rejectUnauthorized: false + } +}); + +client.connect(); + +module.exports = client; +``` + +2. Update query syntax in server.js and other files to be PostgreSQL compatible. + +## Support + +For questions about deployment or to report issues, contact: +**connect@campusbridge.io** + +For the complete GitHub repository: +**https://github.com/Codeunia/Campus-Bridge** \ No newline at end of file diff --git a/SHAKTHI_BOT_GUIDE.md b/SHAKTHI_BOT_GUIDE.md new file mode 100644 index 0000000..fa5f247 --- /dev/null +++ b/SHAKTHI_BOT_GUIDE.md @@ -0,0 +1,132 @@ +# Shakthi Bot - Campus Bridge AI Assistant + +Shakthi Bot is an intelligent chatbot assistant that helps users navigate the Campus Bridge Learning Management System. Named after the Sanskrit word for "power" or "strength," Shakthi Bot empowers students to easily find what they need within the platform. + +## Features + +- **Context-Aware Responses**: Provides relevant help based on the current page +- **Website Navigation Guidance**: Assists users in finding courses, lectures, assignments, and other resources +- **Login and Registration Help**: Guides users through account creation and login processes +- **Course Information**: Provides details about available courses and how to access them +- **Support Information**: Offers contact details for technical support +- **Consistent Experience**: Available on all pages of the application + +## Implementation + +### Files + +1. **`public/shakti-bot.js`** - Centralized JavaScript implementation +2. **HTML Files** - All pages include the chatbot elements and script reference + +### How It Works + +1. **Page Context Detection**: The bot detects which page the user is on to provide contextually relevant responses +2. **Natural Language Processing**: Users can ask questions in plain English +3. **Predefined Responses**: The bot has a comprehensive set of responses for common questions +4. **Dynamic UI**: Chat widget appears as a floating button that can be opened/closed + +### Pages with Shakthi Bot + +Shakthi Bot is now available on all pages of the Campus Bridge application, including but not limited to: +- Homepage (`index.html`) +- Login Page (`studentlogin.html`) +- Registration Page (`register.html`) +- Forgot Password Page (`forgot-password.html`) +- Courses Dashboard (`courses.html`) +- Free Courses Page (`freecourses.html`) +- Main Dashboard (`dashboard.html`) +- Placement Panel (`placement.html`) +- Assignments (`assignments.html`) +- Lectures (`lectures.html`) +- Attendance (`attendance.html`) +- Exams (`exams.html`) +- Timetable (`timetable.html`) +- Reports (`reports.html`) +- Profile (`profile.html`) +- Logout (`logout.html`) +- Assignment Details (`assignment-details.html`, `assignment-details2.html`) +- AI Assistant (`aiassistant.html`) +- Coding Tracks (`codingtracks.html`) +- DSA (`dsa.html`) +- Web Development (`webdevelop.html`) +- Python (`python.html`) +- Java (`java.html`) +- Course List (`devcourse.html`) +- Main Board (`mainboard.html`) + +## Usage + +Users can interact with Shakthi Bot by: + +1. Clicking the circular icon in the bottom-right corner of the screen +2. Typing questions in natural language +3. Receiving immediate, helpful responses + +### Sample Questions + +- "How do I access courses?" +- "Where can I find free courses?" +- "How do I log in to my account?" +- "Where is the placement panel?" +- "How can I contact support?" +- "What courses are available?" +- "How do I watch course videos?" + +## Customization + +To modify Shakthi Bot responses: + +1. Edit `public/shakti-bot.js` +2. Modify the response functions: + - `getCoursesResponse()` - For courses page responses + - `getLoginResponse()` - For login page responses + - `getFreeCoursesResponse()` - For free courses page responses + - `getGeneralResponse()` - For general responses + +## Technical Details + +### Class Structure + +The bot is implemented as a JavaScript class with the following methods: + +- `initialize()` - Sets up the chatbot UI and event listeners +- `createChatElements()` - Dynamically creates chatbot HTML elements +- `addEventListeners()` - Attaches click and keyboard events +- `appendMessage()` - Adds messages to the chat log +- `showWelcome()` - Displays context-aware welcome message +- `getResponse()` - Processes user input and returns appropriate response +- Context-specific response methods for different pages + +### Context Detection + +The bot determines the current page by examining the URL path: +- `/courses` - Courses context +- `/login` - Login context +- `/free` - Free courses context +- `/register` - Registration context +- `/placement` - Placement context +- Default - General context + +## Future Enhancements + +Potential improvements for Shakthi Bot: + +1. **Integration with Backend**: Connect to Campus Bridge APIs for real-time data +2. **Machine Learning**: Implement more sophisticated NLP for better understanding +3. **Voice Support**: Add voice input/output capabilities +4. **Multilingual Support**: Offer assistance in multiple languages +5. **Personalization**: Customize responses based on user history and preferences + +## Troubleshooting + +If Shakthi Bot doesn't appear: + +1. Ensure `shakti-bot.js` is properly loaded +2. Check browser console for JavaScript errors +3. Verify that the HTML includes the chatbot elements and script reference + +If responses seem incorrect: + +1. Check the context detection logic in `shakti-bot.js` +2. Verify that the appropriate response function is being called +3. Ensure the response text is accurate and helpful \ No newline at end of file diff --git a/db.js b/db.js index 60e2d24..4606233 100644 --- a/db.js +++ b/db.js @@ -1,11 +1,12 @@ const mysql = require('mysql2'); +// Use Render's environment variables or fallback to local settings const connection = mysql.createConnection({ - host: 'caboose.proxy.rlwy.net', // Railway Public Host - port: 52684, // Railway Public Port - user: 'root', // Railway User - password: 'FVbvwMquwHxLDaCnoYPETPTLJEjxgBPb', // Railway Password - database: 'railway' // Railway DB name + host: process.env.MYSQL_HOST || process.env.PLANETSCALE_HOST || 'localhost', + port: process.env.MYSQL_PORT || 3306, + user: process.env.MYSQL_USER || process.env.PLANETSCALE_USER || 'root', + password: process.env.MYSQL_PASSWORD || process.env.PLANETSCALE_PASSWORD || '', + database: process.env.MYSQL_DATABASE || process.env.PLANETSCALE_DATABASE || 'lms' }); connection.connect((err) => { @@ -16,4 +17,4 @@ connection.connect((err) => { console.log('β Connected to MySQL database'); }); -module.exports = connection; +module.exports = connection; \ No newline at end of file diff --git a/init-db.js b/init-db.js new file mode 100644 index 0000000..cfe07fe --- /dev/null +++ b/init-db.js @@ -0,0 +1,111 @@ +// Database initialization script for Campus Bridge +// This script creates the necessary tables if they don't exist + +const db = require('./db'); + +// Create users table +const createUsersTable = ` + CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + email VARCHAR(255) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + is_verified TINYINT(1) DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) +`; + +// Create learning_resources table (if it doesn't exist) +const createLearningResourcesTable = ` + CREATE TABLE IF NOT EXISTS learning_resources ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + file_path VARCHAR(255) NOT NULL + ) +`; + +console.log('Initializing database tables...'); + +// Create users table +db.query(createUsersTable, (err, result) => { + if (err) { + console.error('Error creating users table:', err); + return; + } + console.log('Users table created or already exists'); + + // Create learning_resources table + db.query(createLearningResourcesTable, (err, result) => { + if (err) { + console.error('Error creating learning_resources table:', err); + return; + } + console.log('Learning resources table created or already exists'); + + // Check if is_verified column exists + const checkColumnQuery = "SHOW COLUMNS FROM users LIKE 'is_verified'"; + + db.query(checkColumnQuery, (err, results) => { + if (err) { + console.error('Error checking for is_verified column:', err); + return; + } + + if (results.length === 0) { + // Column doesn't exist, add it + const addColumnQuery = "ALTER TABLE users ADD COLUMN is_verified TINYINT(1) DEFAULT 0"; + + db.query(addColumnQuery, (err, result) => { + if (err) { + console.error('Error adding is_verified column:', err); + } else { + console.log('is_verified column added successfully'); + } + + // Continue with sample user creation + createSampleUser(); + }); + } else { + console.log('is_verified column already exists'); + // Continue with sample user creation + createSampleUser(); + } + }); + }); +}); + +function createSampleUser() { + // Check if sample user already exists + const checkUserExists = "SELECT COUNT(*) as count FROM users WHERE email = 'test@example.com'"; + + db.query(checkUserExists, (err, results) => { + if (err) { + console.error('Error checking for sample user:', err); + db.end(); + return; + } + + if (results[0].count === 0) { + // User doesn't exist, insert it + const insertSampleUser = ` + INSERT INTO users (name, email, password, is_verified) + VALUES ('Test User', 'test@example.com', 'password123', 1) + `; + + db.query(insertSampleUser, (err, result) => { + if (err) { + console.error('Error inserting sample user:', err); + db.end(); + return; + } + console.log('Sample user created successfully'); + console.log('Database initialization complete!'); + db.end(); + }); + } else { + console.log('Sample user already exists'); + console.log('Database initialization complete!'); + db.end(); + } + }); +} \ No newline at end of file diff --git a/middleware.js b/middleware.js new file mode 100644 index 0000000..3b1f95d --- /dev/null +++ b/middleware.js @@ -0,0 +1,67 @@ +// Middleware for Campus Bridge application + +// Simple in-memory session store (in production, use a proper session store like Redis) +const sessions = new Map(); + +// Generate a random session ID +function generateSessionId() { + return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); +} + +// Middleware to check if user is authenticated +function requireAuth(req, res, next) { + const sessionId = req.headers['x-session-id'] || req.query.sessionId; + + if (!sessionId) { + return res.status(401).json({ + success: false, + message: 'Authentication required' + }); + } + + const session = sessions.get(sessionId); + if (!session) { + return res.status(401).json({ + success: false, + message: 'Invalid session' + }); + } + + // Attach user info to request + req.user = session.user; + next(); +} + +// Create a new session for a user +function createSession(user) { + const sessionId = generateSessionId(); + const session = { + user: { + id: user.id, + name: user.name, + email: user.email + }, + createdAt: new Date() + }; + + sessions.set(sessionId, session); + return sessionId; +} + +// Destroy a session +function destroySession(sessionId) { + sessions.delete(sessionId); +} + +// Get user info from session +function getUserFromSession(sessionId) { + const session = sessions.get(sessionId); + return session ? session.user : null; +} + +module.exports = { + requireAuth, + createSession, + destroySession, + getUserFromSession +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0b55a0f..146a439 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,20 +11,21 @@ "dependencies": { "cors": "^2.8.5", "dotenv": "^17.2.1", - "express": "^5.1.0", + "express": "^4.18.2", "multer": "^2.0.2", "mysql": "^2.18.1", - "mysql2": "^3.14.3" + "mysql2": "^3.14.3", + "nodemailer": "^7.0.6" } }, "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -36,6 +37,12 @@ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, "node_modules/aws-ssl-profiles": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", @@ -55,23 +62,27 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">=18" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/buffer-from": { @@ -145,9 +156,9 @@ } }, "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -166,22 +177,19 @@ } }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/core-util-is": { "version": "1.0.3", @@ -203,20 +211,12 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "2.0.0" } }, "node_modules/denque": { @@ -237,10 +237,20 @@ "node": ">= 0.8" } }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", + "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -270,9 +280,9 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -324,59 +334,66 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "license": "MIT", "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "license": "MIT" + }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -392,12 +409,12 @@ } }, "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, "node_modules/function-bind": { @@ -507,22 +524,13 @@ "node": ">= 0.8" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" @@ -543,12 +551,6 @@ "node": ">= 0.10" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, "node_modules/is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", @@ -601,42 +603,57 @@ } }, "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4" } }, "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { - "mime-db": "^1.54.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -664,9 +681,9 @@ } }, "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, "node_modules/multer": { @@ -687,49 +704,6 @@ "node": ">= 10.16.0" } }, - "node_modules/multer/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/multer/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/multer/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/multer/node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mysql": { "version": "2.18.1", "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", @@ -766,15 +740,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, - "node_modules/mysql/node_modules/sqlstring": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", - "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mysql/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -785,15 +750,15 @@ } }, "node_modules/mysql2": { - "version": "3.14.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.3.tgz", - "integrity": "sha512-fD6MLV8XJ1KiNFIF0bS7Msl8eZyhlTDCDl75ajU5SJtpdx9ZPEACulJcqJWr1Y8OYyxsFc4j3+nflpmhxCU5aQ==", + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.1.tgz", + "integrity": "sha512-WZMIRZstT2MFfouEaDz/AGFnGi1A2GwaDe7XvKTdRJEYiAHbOrh4S3d8KFmQeh11U85G+BFjIvS1Di5alusZsw==", "license": "MIT", "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", @@ -804,6 +769,31 @@ "node": ">= 8.0" } }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mysql2/node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/named-placeholders": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", @@ -817,14 +807,23 @@ } }, "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/nodemailer": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.6.tgz", + "integrity": "sha512-F44uVzgwo49xboqbFgBGkRaiMgtoBrBEWCVincJPK9+S9Adkzt/wXCLKbf7dxucmxfTI5gHGB+bEmdyzN6QKjw==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -858,15 +857,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -876,15 +866,6 @@ "node": ">= 0.8" } }, - "node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -905,12 +886,12 @@ } }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "side-channel": "^1.0.4" }, "engines": { "node": ">=0.6" @@ -929,14 +910,14 @@ } }, "node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", - "iconv-lite": "0.6.3", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "engines": { @@ -957,22 +938,6 @@ "node": ">= 6" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1000,45 +965,53 @@ "license": "MIT" }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "license": "MIT", "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">= 18" + "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "license": "MIT", "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { - "node": ">= 18" + "node": ">= 0.8.0" } }, "node_modules/setprototypeof": { @@ -1120,18 +1093,18 @@ } }, "node_modules/sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -1164,14 +1137,13 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "license": "MIT", "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, "engines": { "node": ">= 0.6" @@ -1198,6 +1170,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1207,12 +1188,6 @@ "node": ">= 0.8" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index e5cbcce..6fa2438 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "start": "node server.js", "dev": "nodemon server.js", + "init-db": "node init-db.js", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -30,9 +31,10 @@ "dependencies": { "cors": "^2.8.5", "dotenv": "^17.2.1", - "express": "^5.1.0", + "express": "^4.18.2", "multer": "^2.0.2", "mysql": "^2.18.1", - "mysql2": "^3.14.3" + "mysql2": "^3.14.3", + "nodemailer": "^7.0.6" } } diff --git a/public/aiassistant.html b/public/aiassistant.html index a0c113c..7102796 100644 --- a/public/aiassistant.html +++ b/public/aiassistant.html @@ -43,5 +43,18 @@
+