├── Frontend ├── public │ ├── robots.txt │ └── favicon.ico ├── src │ ├── samples │ │ ├── index.html │ │ ├── style.css │ │ ├── rust.rs │ │ ├── script.js │ │ ├── kotlin.kt │ │ ├── javascript.js │ │ ├── ruby.rb │ │ ├── scala.scala │ │ ├── typescript.ts │ │ ├── go.go │ │ ├── julia.jl │ │ ├── verilog.v │ │ ├── swift.swift │ │ ├── mongodb.js │ │ ├── cpp.cpp │ │ ├── dart.dart │ │ ├── perl.pl │ │ ├── bash.sh │ │ ├── java.java │ │ ├── python.py │ │ ├── c.c │ │ ├── csharp.cs │ │ └── sql.sql │ ├── main.jsx │ ├── index.css │ ├── components │ │ ├── Footer.jsx │ │ ├── MainBody.jsx │ │ ├── NavigationLinks.jsx │ │ ├── Header.jsx │ │ ├── ShareEditor.jsx │ │ └── SharedLinks.jsx │ ├── App.jsx │ ├── utils │ │ ├── constants.js │ │ ├── InputField.jsx │ │ ├── blocker.js │ │ ├── ShareLinkModal.js │ │ └── OtpInputForm.jsx │ ├── context │ │ └── ThemeProvider.jsx │ ├── pages │ │ ├── NotFound.jsx │ │ ├── Login.jsx │ │ ├── Register.jsx │ │ ├── ForgotPassword.jsx │ │ └── Accounts.jsx │ └── routes │ │ └── EditorRoutes.jsx ├── index.html ├── vite.config.js ├── eslint.config.js ├── package.json └── .gitignore ├── Backend ├── TempFile │ ├── requirements.txt │ ├── templates │ │ └── index.html │ └── app.py ├── Genai │ ├── requirements.txt │ ├── templates │ │ └── index.html │ └── app.py └── Login │ ├── utils │ ├── otpGenerator.js │ ├── useLogger.js │ ├── updateLanguageCount.js │ └── validation.js │ ├── config │ ├── corsOptions.js │ └── db.js │ ├── templates │ └── index.html │ ├── smtp │ ├── transporter.js │ ├── delEmail.js │ └── sendMail.js │ ├── middlewares │ └── cleanExpired.js │ ├── package.json │ └── models │ ├── Log.js │ └── User.js ├── Images ├── C.png ├── Go.png ├── Dart.png ├── Java.png ├── Julia.png ├── Login.png ├── Perl.png ├── Ruby.png ├── Rust.png ├── Scala.png ├── Sql.png ├── Swift.png ├── CSharp.png ├── Diagram.png ├── Kotlin.png ├── MongoDB.png ├── Python.png ├── Verilog.png ├── Accounts.png ├── Cplusplus.png ├── Homepage.png ├── HtmlCssJs.png ├── Javascript.png ├── Register.png └── Typescript.png ├── LICENSE ├── .gitignore └── README.md /Frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /Backend/TempFile/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | flask-cors 3 | redis 4 | python-dotenv 5 | pyjwt -------------------------------------------------------------------------------- /Frontend/src/samples/index.html: -------------------------------------------------------------------------------- 1 |

This is a Heading

2 |

This is a paragraph.

-------------------------------------------------------------------------------- /Images/C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/C.png -------------------------------------------------------------------------------- /Images/Go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Go.png -------------------------------------------------------------------------------- /Backend/Genai/requirements.txt: -------------------------------------------------------------------------------- 1 | google-genai 2 | python-dotenv 3 | flask-cors 4 | flask 5 | pyjwt -------------------------------------------------------------------------------- /Images/Dart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Dart.png -------------------------------------------------------------------------------- /Images/Java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Java.png -------------------------------------------------------------------------------- /Images/Julia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Julia.png -------------------------------------------------------------------------------- /Images/Login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Login.png -------------------------------------------------------------------------------- /Images/Perl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Perl.png -------------------------------------------------------------------------------- /Images/Ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Ruby.png -------------------------------------------------------------------------------- /Images/Rust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Rust.png -------------------------------------------------------------------------------- /Images/Scala.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Scala.png -------------------------------------------------------------------------------- /Images/Sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Sql.png -------------------------------------------------------------------------------- /Images/Swift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Swift.png -------------------------------------------------------------------------------- /Images/CSharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/CSharp.png -------------------------------------------------------------------------------- /Images/Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Diagram.png -------------------------------------------------------------------------------- /Images/Kotlin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Kotlin.png -------------------------------------------------------------------------------- /Images/MongoDB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/MongoDB.png -------------------------------------------------------------------------------- /Images/Python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Python.png -------------------------------------------------------------------------------- /Images/Verilog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Verilog.png -------------------------------------------------------------------------------- /Images/Accounts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Accounts.png -------------------------------------------------------------------------------- /Images/Cplusplus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Cplusplus.png -------------------------------------------------------------------------------- /Images/Homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Homepage.png -------------------------------------------------------------------------------- /Images/HtmlCssJs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/HtmlCssJs.png -------------------------------------------------------------------------------- /Images/Javascript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Javascript.png -------------------------------------------------------------------------------- /Images/Register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Register.png -------------------------------------------------------------------------------- /Images/Typescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Images/Typescript.png -------------------------------------------------------------------------------- /Frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightingale-evening/online-ide/HEAD/Frontend/public/favicon.ico -------------------------------------------------------------------------------- /Backend/Login/utils/otpGenerator.js: -------------------------------------------------------------------------------- 1 | const crypto = require('node:crypto'); 2 | 3 | function generateOtp() { 4 | return crypto.randomBytes(3).toString('hex'); 5 | } 6 | 7 | module.exports = { generateOtp }; 8 | -------------------------------------------------------------------------------- /Backend/Genai/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GenAi 7 | 8 | -------------------------------------------------------------------------------- /Backend/Login/config/corsOptions.js: -------------------------------------------------------------------------------- 1 | const corsOptions = { 2 | origin: '*', 3 | methods: ['GET', 'POST', 'PUT', 'DELETE'], 4 | allowedHeaders: ['Content-Type', 'Authorization'], 5 | credentials: true, 6 | }; 7 | 8 | module.exports = corsOptions; 9 | -------------------------------------------------------------------------------- /Backend/Login/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Online IDE back 7 | 8 | -------------------------------------------------------------------------------- /Backend/TempFile/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Temp File 7 | 8 | -------------------------------------------------------------------------------- /Frontend/src/main.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import './index.css' 4 | import App from './App.jsx' 5 | 6 | createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /Backend/Login/smtp/transporter.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require('nodemailer'); 2 | 3 | const transporter = nodemailer.createTransport({ 4 | service: process.env.OTP_EMAIL_SERVICE, 5 | auth: { 6 | user: process.env.OTP_EMAIL_USER, 7 | pass: process.env.OTP_EMAIL_PASS, 8 | }, 9 | }); 10 | 11 | module.exports = transporter; 12 | -------------------------------------------------------------------------------- /Frontend/src/index.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | @plugin "tailwindcss-motion"; 3 | @custom-variant dark (&:where(.dark, .dark *)); 4 | 5 | .dark div:where(.swal2-container) div:where(.swal2-popup) { 6 | background: #333; 7 | color: #e8e6e3; 8 | } 9 | 10 | .dark div:where(.swal2-container) div:where(.swal2-validation-message) { 11 | background: #8b8b8b47; 12 | color: #d3d3d3; 13 | } -------------------------------------------------------------------------------- /Frontend/src/samples/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial, sans-serif; 3 | background-color: #f4f4f4; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | h1 { 9 | color: #333; 10 | text-align: center; 11 | margin-top: 50px; 12 | } 13 | 14 | p { 15 | color: #555; 16 | text-align: center; 17 | font-size: 18px; 18 | } 19 | -------------------------------------------------------------------------------- /Frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /Frontend/src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Footer = () => { 4 | const currentYear = new Date().getFullYear(); 5 | 6 | return ( 7 | 12 | ); 13 | }; 14 | 15 | export default Footer; -------------------------------------------------------------------------------- /Frontend/src/samples/rust.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let num1: f64 = 10.5; 3 | let num2: f64 = 2.0; 4 | 5 | let addition = num1 + num2; 6 | let subtraction = num1 - num2; 7 | let multiplication = num1 * num2; 8 | let division = num1 / num2; 9 | 10 | println!("{} + {} = {}", num1, num2, addition); 11 | println!("{} - {} = {}", num1, num2, subtraction); 12 | println!("{} * {} = {}", num1, num2, multiplication); 13 | println!("{} / {} = {}", num1, num2, division); 14 | } -------------------------------------------------------------------------------- /Backend/Login/middlewares/cleanExpired.js: -------------------------------------------------------------------------------- 1 | const {checkAndConnectDB} = require('../config/db') 2 | 3 | const User = require('../models/User') 4 | 5 | async function cleanExpired(req, res, next) { 6 | try { 7 | await checkAndConnectDB(); 8 | 9 | await User.deleteMany({ 10 | isEmailVerified: false, 11 | otpExpires: { $lte: new Date() }, 12 | }); 13 | 14 | next(); 15 | } catch (err) { 16 | console.error('Error cleaning up expired users:', err); 17 | next(); 18 | } 19 | } 20 | 21 | module.exports = { cleanExpired }; 22 | -------------------------------------------------------------------------------- /Frontend/src/samples/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | // Select the h1 and p elements 3 | const heading = document.querySelector('h1'); 4 | const paragraph = document.querySelector('p'); 5 | 6 | // Add click event listener to the h1 7 | heading.addEventListener('click', function() { 8 | heading.textContent = 'Heading Clicked!'; 9 | }); 10 | 11 | // Add click event listener to the p 12 | paragraph.addEventListener('click', function() { 13 | paragraph.textContent = 'Paragraph Clicked!'; 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /Frontend/src/components/MainBody.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Header from "./Header"; 3 | import Footer from "./Footer"; 4 | import EditorRoutes from "../routes/EditorRoutes"; 5 | 6 | const MainBody = ({ isDarkMode, toggleTheme }) => { 7 | return ( 8 |
9 |
10 | 11 |
13 | ); 14 | }; 15 | 16 | export default MainBody; 17 | -------------------------------------------------------------------------------- /Backend/Login/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "main": "server.js", 5 | "scripts": { 6 | "start": "node server.js", 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "glad432", 11 | "license": "MIT", 12 | "description": "", 13 | "dependencies": { 14 | "bcryptjs": "^3.0.2", 15 | "body-parser": "^2.2.0", 16 | "cors": "^2.8.5", 17 | "dotenv": "^17.2.1", 18 | "express": "^5.1.0", 19 | "jsonwebtoken": "^9.0.2", 20 | "mongoose": "^8.17.1", 21 | "nodemailer": "^7.0.5" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Frontend/src/samples/kotlin.kt: -------------------------------------------------------------------------------- 1 | data class Node(var data: Int, var next: Node?) 2 | 3 | fun main() { 4 | // Create a sample linked list 5 | val head = Node(1, Node(2, Node(3, Node(4, null)))) 6 | 7 | // Print the linked list 8 | printLinkedList(head) //Prints the list to console 9 | } 10 | 11 | fun printLinkedList(head: Node?) { 12 | var current = head //Initialize a current node 13 | while (current != null) { 14 | print("${current.data} ") //Prints current node's data 15 | current = current.next //Moves to the next node 16 | } 17 | println() //Adds a newline at the end 18 | } 19 | -------------------------------------------------------------------------------- /Frontend/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter as Router } from "react-router-dom"; 3 | import { ThemeProvider, ThemeContext } from "./context/ThemeProvider"; 4 | import MainBody from "./components/MainBody"; 5 | 6 | const App = () => { 7 | return ( 8 | 9 | 10 | 11 | {({ isDarkMode, toggleTheme }) => ( 12 | 13 | )} 14 | 15 | 16 | 17 | ); 18 | }; 19 | 20 | export default App; 21 | -------------------------------------------------------------------------------- /Frontend/src/samples/javascript.js: -------------------------------------------------------------------------------- 1 | // 1. Declare variables 2 | let name = 'Alice'; 3 | let age = 30; 4 | 5 | // 2. Create a function that greets a person 6 | function greet(person) { 7 | console.log(`Hello, ${person}!`); 8 | } 9 | 10 | // 3. Call the greeting function 11 | greet(name); 12 | 13 | // 4. Use a conditional to check age 14 | if (age >= 18) { 15 | console.log(`${name} is an adult.`); 16 | } else { 17 | console.log(`${name} is a minor.`); 18 | } 19 | 20 | // 5. Loop through an array and log each item 21 | let fruits = ['apple', 'banana', 'cherry']; 22 | fruits.forEach(fruit => { 23 | console.log(fruit); 24 | }); -------------------------------------------------------------------------------- /Frontend/src/samples/ruby.rb: -------------------------------------------------------------------------------- 1 | # Initialize an array to store numbers 2 | numbers = [] 3 | 4 | # Generate 20 random numbers between 1 and 100 5 | 20.times { numbers << rand(1..100) } # Add 20 random numbers to the array 6 | 7 | # Calculate the sum of the numbers 8 | sum = numbers.sum # Calculate the sum of all numbers in the array 9 | 10 | # Calculate the average of the numbers 11 | average = sum.to_f / numbers.length # Calculate the average 12 | 13 | # Print the numbers, sum, and average 14 | puts "Numbers: #{numbers.join(', ')}" # Print the numbers separated by commas 15 | puts "Sum: #{sum}" # Print the sum 16 | puts "Average: #{average}" # Print the average 17 | 18 | -------------------------------------------------------------------------------- /Backend/Login/config/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const MONGO_URI = process.env.MONGO_URI; 3 | 4 | async function checkAndConnectDB() { 5 | if (mongoose.connection.readyState === 0) { 6 | try { 7 | await mongoose 8 | .connect(MONGO_URI) 9 | .then(() => console.log('MongoDB connected')) 10 | .catch((err) => console.log('Error connecting to MongoDB:', err)); 11 | console.log('MongoDB connected'); 12 | } catch (err) { 13 | console.error('Error connecting to MongoDB:', err); 14 | throw new Error('Database connection failed'); 15 | } 16 | } 17 | } 18 | 19 | module.exports = { checkAndConnectDB }; 20 | -------------------------------------------------------------------------------- /Frontend/src/samples/scala.scala: -------------------------------------------------------------------------------- 1 | import scala.collection.mutable.Queue 2 | 3 | object QueueProgram extends App { 4 | val queue = new Queue[Int]() // Create a mutable queue of integers 5 | 6 | queue.enqueue(1) // Add elements to the queue 7 | queue.enqueue(2) 8 | queue.enqueue(3) 9 | 10 | println(s"Queue: $queue") // Print the queue 11 | 12 | println(s"Dequeue: ${queue.dequeue()}") // Dequeue and print the first element 13 | 14 | println(s"Queue after dequeue: $queue") // Print the queue after dequeueing 15 | 16 | println(s"Queue size: ${queue.size}") // Print the size of the queue 17 | 18 | if (queue.isEmpty) println("Queue is empty") else println("Queue is not empty") // Check if the queue is empty 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Frontend/src/samples/typescript.ts: -------------------------------------------------------------------------------- 1 | function bubbleSort(arr: number[]): number[] { // function to perform bubble sort 2 | const len = arr.length; 3 | for (let i = 0; i < len; i++) { // iterate through the array 4 | for (let j = 0; j < len - i - 1; j++) { // iterate through the unsorted portion 5 | if (arr[j] > arr[j + 1]) { // compare adjacent elements 6 | // swap elements if they are in the wrong order 7 | [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; 8 | } 9 | } 10 | } 11 | return arr; // return the sorted array 12 | } 13 | 14 | const unsortedArray = [64, 34, 25, 12, 22, 11, 90]; 15 | const sortedArray = bubbleSort(unsortedArray); 16 | console.log("Sorted array:", sortedArray); // print the sorted array 17 | -------------------------------------------------------------------------------- /Frontend/src/utils/constants.js: -------------------------------------------------------------------------------- 1 | export const BACKEND_API_URL = import.meta.env.VITE_BACKEND_API_URL; 2 | export const GENAI_API_URL = import.meta.env.VITE_GEMINI_API_URL; 3 | export const TEMP_SHARE_API_URL = import.meta.env.VITE_TEMP_SHARE_URL; 4 | 5 | export const LOCAL_STORAGE_USERNAME_KEY = '__username__'; 6 | export const LOCAL_STORAGE_TOKEN_KEY = '__token__'; 7 | export const LOCAL_STORAGE_LOGIN_KEY = '__login__'; 8 | export const LOCAL_STORAGE_THEME_KEY = '__theme__'; 9 | 10 | export const SESSION_STORAGE_SHARELINKS_KEY = '__sharelinks__'; 11 | export const SESSION_STORAGE_FETCH_STATUS_KEY = '__fetchstatus__'; 12 | 13 | export const USERNAME_REGEX = /^[a-zA-Z0-9_.-]{5,30}$/; 14 | export const EMAIL_REGEX = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/; 15 | export const PASSWORD_REGEX = /^.{8,}$/; -------------------------------------------------------------------------------- /Backend/Login/smtp/delEmail.js: -------------------------------------------------------------------------------- 1 | const transporter = require('./transporter'); 2 | 3 | async function sendDelEmail(email) { 4 | const mailOptions = { 5 | from: process.env.OTP_EMAIL_USER, 6 | to: email, 7 | subject: 'Online IDE - Account Deletion Notice', 8 | html: ` 9 | 10 | 11 |

Account Deleted

12 |

Your Online IDE account has been deleted.

13 |

Thank you for having been a part of Online IDE.

14 | 15 | 16 | `, 17 | }; 18 | 19 | try { 20 | await transporter.sendMail(mailOptions); 21 | } catch (error) { 22 | throw new Error('Failed to send account deletion email'); 23 | } 24 | } 25 | 26 | module.exports = { sendDelEmail }; 27 | -------------------------------------------------------------------------------- /Frontend/src/samples/go.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | // Declare and initialize variables 9 | var name string 10 | var age int 11 | 12 | // Ask for user input 13 | fmt.Print("Enter your name: ") 14 | fmt.Scanln(&name) 15 | 16 | fmt.Print("Enter your age: ") 17 | fmt.Scanln(&age) 18 | 19 | // Display a greeting message 20 | fmt.Printf("Hello, %s! You are %d years old.\n", name, age) 21 | 22 | // Call a function to calculate the year of birth 23 | yearOfBirth := calculateYearOfBirth(age) 24 | 25 | // Print the calculated year of birth 26 | fmt.Printf("You were born in the year %d.\n", yearOfBirth) 27 | } 28 | 29 | // Function to calculate the year of birth 30 | func calculateYearOfBirth(age int) int { 31 | currentYear := 2024 32 | return currentYear - age 33 | } 34 | -------------------------------------------------------------------------------- /Frontend/src/samples/julia.jl: -------------------------------------------------------------------------------- 1 | struct Node 2 | data::Int 3 | prev::Union{Node,Nothing} 4 | next::Union{Node,Nothing} 5 | end 6 | 7 | function create_list(arr) # create a doubly linked list from an array 8 | head = nothing 9 | tail = nothing 10 | for x in arr 11 | new_node = Node(x, tail, nothing) 12 | if tail != nothing 13 | tail.next = new_node 14 | end 15 | tail = new_node 16 | if head == nothing 17 | head = new_node 18 | end 19 | end 20 | return head 21 | end 22 | 23 | function print_list(head) # print the list 24 | curr = head 25 | while curr != nothing 26 | print(curr.data, " ") 27 | curr = curr.next 28 | end 29 | println() 30 | end 31 | 32 | 33 | head = create_list([1, 2, 3, 4, 5]) # create a sample list 34 | print_list(head) # print the list 35 | 36 | -------------------------------------------------------------------------------- /Frontend/src/samples/verilog.v: -------------------------------------------------------------------------------- 1 | module half_adder(input a, input b, output sum, output carry); 2 | 3 | // Define the logic for sum (XOR of inputs) 4 | assign sum = a ^ b; 5 | 6 | // Define the logic for carry (AND of inputs) 7 | assign carry = a & b; 8 | 9 | endmodule 10 | 11 | // Testbench to verify the half adder 12 | module half_adder_tb; 13 | reg a, b; 14 | wire sum, carry; 15 | 16 | half_adder ha( 17 | .a(a), 18 | .b(b), 19 | .sum(sum), 20 | .carry(carry) 21 | ); 22 | 23 | initial begin 24 | // Display header 25 | $display("a b | sum carry"); 26 | $display("-----------"); 27 | 28 | // Test cases 29 | a = 0; b = 0; #1; $display("%b %b | %b %b", a, b, sum, carry); 30 | a = 0; b = 1; #1; $display("%b %b | %b %b", a, b, sum, carry); 31 | a = 1; b = 0; #1; $display("%b %b | %b %b", a, b, sum, carry); 32 | a = 1; b = 1; #1; $display("%b %b | %b %b", a, b, sum, carry); 33 | 34 | // End simulation 35 | $finish; 36 | end 37 | 38 | endmodule 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 - present GLAD432 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | import { createHtmlPlugin } from 'vite-plugin-html'; 4 | import tailwindcss from '@tailwindcss/vite' 5 | 6 | export default defineConfig({ 7 | base: "/", 8 | plugins: [react(), 9 | tailwindcss(), 10 | createHtmlPlugin({ 11 | minify: { 12 | collapseWhitespace: true, 13 | removeComments: true, 14 | removeRedundantAttributes: true, 15 | useShortDoctype: true, 16 | removeEmptyAttributes: true, 17 | removeScriptTypeAttributes: true, 18 | removeStyleTypeAttributes: true, 19 | minifyCSS: true, 20 | minifyJS: true, 21 | }, 22 | }), 23 | ], 24 | build: { 25 | chunkSizeWarningLimit: 1000, 26 | minify: 'terser', 27 | terserOptions: { 28 | compress: { 29 | drop_debugger: true 30 | }, 31 | output: { 32 | comments: false 33 | }, 34 | mangle: { 35 | toplevel: true 36 | } 37 | } 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /Frontend/src/samples/swift.swift: -------------------------------------------------------------------------------- 1 | class Node { 2 | var value: T 3 | var next: Node? 4 | var prev: Node? 5 | init(value: T) { self.value = value } 6 | } 7 | 8 | class DoublyLinkedList { 9 | var head: Node? 10 | var tail: Node? 11 | 12 | func append(value: T) { // Add a node to the end 13 | let newNode = Node(value: value) 14 | if let tail = tail { 15 | tail.next = newNode 16 | newNode.prev = tail 17 | self.tail = newNode 18 | } else { 19 | head = newNode 20 | tail = newNode 21 | } 22 | } 23 | 24 | func printList() { // Print the list values 25 | var currentNode = head 26 | while let node = currentNode { 27 | print(node.value, terminator: " ") 28 | currentNode = node.next 29 | } 30 | print() 31 | } 32 | } 33 | 34 | let list = DoublyLinkedList() 35 | list.append(value: 1) 36 | list.append(value: 2) 37 | list.append(value: 3) 38 | list.append(value: 4) 39 | list.printList() // Output: 1 2 3 4 40 | 41 | -------------------------------------------------------------------------------- /Backend/Login/models/Log.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const logsSchema = new mongoose.Schema({ 4 | username: { 5 | type: String, 6 | required: true, 7 | }, 8 | email: { 9 | type: String, 10 | required: true, 11 | }, 12 | lastLogin: { 13 | type: Date, 14 | default: null, 15 | }, 16 | createdDate: { 17 | type: Date, 18 | default: Date.now, 19 | }, 20 | generateCodeCount: { 21 | type: Map, 22 | of: Number, 23 | default: {}, 24 | }, 25 | refactorCodeCount: { 26 | type: Map, 27 | of: Number, 28 | default: {}, 29 | }, 30 | runCodeCount: { 31 | type: Map, 32 | of: Number, 33 | default: {}, 34 | }, 35 | sharedLinks: { 36 | type: Object, 37 | default: {}, 38 | }, 39 | actionType: { 40 | type: String, 41 | required: true, 42 | }, 43 | timestamp: { 44 | type: Date, 45 | default: Date.now, 46 | }, 47 | }); 48 | 49 | module.exports = mongoose.model('log', logsSchema); -------------------------------------------------------------------------------- /Backend/Login/utils/useLogger.js: -------------------------------------------------------------------------------- 1 | const Log = require('../models/Log.js'); 2 | 3 | async function logUserAction(user, actionType) { 4 | try { 5 | let log = await Log.findOne({ 6 | username: user.username, 7 | email: user.email, 8 | }); 9 | 10 | if (log) { 11 | log.lastLogin = user.lastLogin; 12 | log.createdDate = user.createdDate; 13 | log.generateCodeCount = user.generateCodeCount; 14 | log.refactorCodeCount = user.refactorCodeCount; 15 | log.runCodeCount = user.runCodeCount; 16 | log.sharedLinks = user.sharedLinks; 17 | log.actionType = actionType; 18 | } else { 19 | log = new Log({ 20 | username: user.username, 21 | email: user.email, 22 | lastLogin: user.lastLogin, 23 | createdDate: user.createdDate, 24 | generateCodeCount: user.generateCodeCount, 25 | refactorCodeCount: user.refactorCodeCount, 26 | runCodeCount: user.runCodeCount, 27 | sharedLinks: user.sharedLinks, 28 | actionType: actionType, 29 | }); 30 | } 31 | 32 | await log.save(); 33 | } catch (err) { 34 | console.error('Error logging user action:', err); 35 | } 36 | } 37 | 38 | module.exports = { logUserAction }; -------------------------------------------------------------------------------- /Frontend/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import react from 'eslint-plugin-react' 4 | import reactHooks from 'eslint-plugin-react-hooks' 5 | import reactRefresh from 'eslint-plugin-react-refresh' 6 | 7 | export default [ 8 | { ignores: ['dist'] }, 9 | { 10 | files: ['**/*.{js,jsx}'], 11 | languageOptions: { 12 | ecmaVersion: 2020, 13 | globals: globals.browser, 14 | parserOptions: { 15 | ecmaVersion: 'latest', 16 | ecmaFeatures: { jsx: true }, 17 | sourceType: 'module', 18 | }, 19 | }, 20 | settings: { react: { version: '18.3' } }, 21 | plugins: { 22 | react, 23 | 'react-hooks': reactHooks, 24 | 'react-refresh': reactRefresh, 25 | }, 26 | rules: { 27 | ...js.configs.recommended.rules, 28 | ...react.configs.recommended.rules, 29 | ...react.configs['jsx-runtime'].rules, 30 | ...reactHooks.configs.recommended.rules, 31 | 'react/jsx-no-target-blank': 'off', 32 | 'react-refresh/only-export-components': [ 33 | 'warn', 34 | { allowConstantExport: true }, 35 | ], 36 | }, 37 | }, 38 | ] 39 | -------------------------------------------------------------------------------- /Frontend/src/samples/mongodb.js: -------------------------------------------------------------------------------- 1 | // Sample data (replace with your actual employee collection) 2 | db.employees.insertMany([ 3 | { empId: 1, name: "John Doe", department: "Sales", salary: 60000 }, 4 | { empId: 2, name: "Jane Smith", department: "Marketing", salary: 75000 }, 5 | { empId: 3, name: "Peter Jones", department: "Sales", salary: 65000 }, 6 | { empId: 4, name: "Mary Brown", department: "IT", salary: 80000 } 7 | ]); 8 | 9 | // Find all employees in the Sales department 10 | db.employees.find({ department: "Sales" }).forEach(printjson); 11 | 12 | // Find the highest salary 13 | db.employees.aggregate([ 14 | { $group: { _id: null, maxSalary: { $max: "$salary" } } } 15 | ]).forEach(printjson); 16 | 17 | // Find the average salary of all employees 18 | db.employees.aggregate([ 19 | { $group: { _id: null, avgSalary: { $avg: "$salary" } } } 20 | ]).forEach(printjson); 21 | 22 | // Increase salary of all employees in IT by 10% 23 | db.employees.updateMany( 24 | { department: "IT" }, 25 | [ 26 | { $set: { salary: { $multiply: ["$salary", 1.1] } } } 27 | ] 28 | ); 29 | 30 | // Verify the salary increase 31 | db.employees.find({ department: "IT" }).forEach(printjson); 32 | 33 | -------------------------------------------------------------------------------- /Frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "online-ide", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@monaco-editor/react": "^4.7.0", 14 | "@tailwindcss/vite": "^4.1.11", 15 | "lodash": "^4.17.21", 16 | "react": "^19.1.1", 17 | "react-dom": "^19.1.1", 18 | "react-icons": "^5.5.0", 19 | "react-router-dom": "^7.8.0", 20 | "sweetalert2": "^11.22.3", 21 | "vite-plugin-html": "^3.2.2" 22 | }, 23 | "devDependencies": { 24 | "@eslint/js": "^9.32.0", 25 | "@types/react": "^19.1.9", 26 | "@types/react-dom": "^19.1.7", 27 | "@vitejs/plugin-react": "^5.0.0", 28 | "eslint": "^9.32.0", 29 | "eslint-plugin-react": "^7.37.5", 30 | "eslint-plugin-react-hooks": "^5.2.0", 31 | "eslint-plugin-react-refresh": "^0.4.20", 32 | "globals": "^16.3.0", 33 | "install": "^0.13.0", 34 | "sass": "^1.90.0", 35 | "tailwindcss": "^4.1.11", 36 | "tailwindcss-motion": "^1.1.1", 37 | "terser": "^5.43.1", 38 | "vite": "^7.1.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Backend/Login/smtp/sendMail.js: -------------------------------------------------------------------------------- 1 | const transporter = require('./transporter') 2 | 3 | async function sendOtpEmail(email, otp) { 4 | const mailOptions = { 5 | from: process.env.OTP_EMAIL_USER, 6 | to: email, 7 | subject: 'Online IDE - Your OTP for Email Verification', 8 | html: ` 9 | 10 | 11 |

Welcome to Our Online IDE!

12 |

We received a request to verify your email address.

13 |

To complete your email verification, please use the OTP below:

14 |

Your OTP: ${otp}

15 |

This OTP will expire in 10 minutes. If you did not request this, please ignore this email.

16 |

Online IDE

17 |

Thank you for choosing our service!

18 | 19 | 20 | `, 21 | }; 22 | 23 | try { 24 | await transporter.sendMail(mailOptions); 25 | } catch (error) { 26 | throw new Error('Failed to send OTP email'); 27 | } 28 | } 29 | 30 | module.exports = {sendOtpEmail}; -------------------------------------------------------------------------------- /Frontend/src/samples/cpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void reverseArray(int arr[], int size) { 6 | int start = 0, end = size - 1; 7 | while (start < end) { 8 | std::swap(arr[start], arr[end]); 9 | start++; 10 | end--; 11 | } 12 | } 13 | 14 | void printArray(const int arr[], int size) { 15 | std::cout << "Array elements: "; 16 | for (int i = 0; i < size; i++) { 17 | std::cout << arr[i] << " "; 18 | } 19 | std::cout << std::endl; 20 | } 21 | 22 | int main() { 23 | int n; 24 | std::cout << "Enter the size of the array: "; 25 | std::cin >> n; 26 | 27 | std::vector arr(n); 28 | std::cout << "Enter " << n << " elements: "; 29 | for (int i = 0; i < n; i++) { 30 | std::cin >> arr[i]; 31 | } 32 | 33 | std::cout << "Original "; 34 | printArray(arr.data(), n); 35 | 36 | reverseArray(arr.data(), n); 37 | 38 | std::cout << "Reversed "; 39 | printArray(arr.data(), n); 40 | 41 | int sum = 0; 42 | for (int i = 0; i < n; i++) { 43 | sum += arr[i]; 44 | } 45 | 46 | std::cout << "Sum of elements: " << sum << std::endl; 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /Frontend/src/context/ThemeProvider.jsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useState, useEffect } from "react"; 2 | import { LOCAL_STORAGE_THEME_KEY } from "../utils/constants"; 3 | 4 | const ThemeContext = createContext(); 5 | 6 | const ThemeProvider = ({ children }) => { 7 | const [isDarkMode, setIsDarkMode] = useState(() => { 8 | const savedTheme = localStorage.getItem(LOCAL_STORAGE_THEME_KEY); 9 | if (savedTheme) { 10 | return savedTheme === "dark"; 11 | } 12 | return window.matchMedia("(prefers-color-scheme: dark)").matches; 13 | }); 14 | 15 | const toggleTheme = () => { 16 | setIsDarkMode((prev) => { 17 | const newMode = !prev; 18 | localStorage.setItem(LOCAL_STORAGE_THEME_KEY, newMode ? "dark" : "light"); 19 | return newMode; 20 | }); 21 | }; 22 | 23 | useEffect(() => { 24 | const htmlElement = document.documentElement; 25 | if (isDarkMode) { 26 | htmlElement.classList.add("dark"); 27 | } else { 28 | htmlElement.classList.remove("dark"); 29 | } 30 | }, [isDarkMode]); 31 | 32 | return ( 33 | 34 | {children} 35 | 36 | ); 37 | }; 38 | 39 | export { ThemeProvider, ThemeContext }; 40 | -------------------------------------------------------------------------------- /Frontend/src/samples/dart.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | void main() { 4 | stdout.write('Enter the first number: '); // Prompt for first number 5 | double num1 = double.parse(stdin.readLineSync()!); // Read and parse first number 6 | 7 | stdout.write('Enter the operator (+, -, *, /): '); // Prompt for operator 8 | String operator = stdin.readLineSync()!; // Read operator 9 | 10 | stdout.write('Enter the second number: '); // Prompt for second number 11 | double num2 = double.parse(stdin.readLineSync()!); // Read and parse second number 12 | 13 | double result; // Variable to store the result 14 | 15 | switch (operator) { // Perform calculation based on operator 16 | case '+': 17 | result = num1 + num2; 18 | break; 19 | case '-': 20 | result = num1 - num2; 21 | break; 22 | case '*': 23 | result = num1 * num2; 24 | break; 25 | case '/': 26 | if (num2 == 0) { 27 | print('Error: Cannot divide by zero.'); // Handle division by zero 28 | return; 29 | } 30 | result = num1 / num2; 31 | break; 32 | default: 33 | print('Error: Invalid operator.'); // Handle invalid operator 34 | return; 35 | } 36 | 37 | print('Result: $result'); // Print the result 38 | } 39 | -------------------------------------------------------------------------------- /Frontend/src/samples/perl.pl: -------------------------------------------------------------------------------- 1 | use strict; # enforce strict mode 2 | use warnings; # enable warnings 3 | 4 | print "Enter the first number: "; 5 | my $num1 = ; # read first number from user input 6 | chomp $num1; # remove newline character 7 | 8 | print "Enter the operator (+, -, *, /): "; 9 | my $operator = ; # read operator from user input 10 | chomp $operator; # remove newline character 11 | 12 | print "Enter the second number: "; 13 | my $num2 = ; # read second number from user input 14 | chomp $num2; # remove newline character 15 | 16 | my $result; # variable to store the result 17 | 18 | if ($operator eq '+') { # check if operator is '+' 19 | $result = $num1 + $num2; # add numbers 20 | } elsif ($operator eq '-') { # check if operator is '-' 21 | $result = $num1 - $num2; # subtract numbers 22 | } elsif ($operator eq '*') { # check if operator is '*' 23 | $result = $num1 * $num2; # multiply numbers 24 | } elsif ($operator eq '/') { # check if operator is '/' 25 | if ($num2 == 0) { # handle division by zero 26 | print "Error: Division by zero!\n"; 27 | exit; # exit the program 28 | } 29 | $result = $num1 / $num2; # divide numbers 30 | } else { # handle invalid operator 31 | print "Error: Invalid operator!\n"; 32 | exit; # exit the program 33 | } 34 | 35 | print "Result: $result\n"; # print the result 36 | -------------------------------------------------------------------------------- /Frontend/src/samples/bash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Simulate a "Person" class in Bash 4 | 5 | # Define the Person "class" 6 | Person() { 7 | # Attributes 8 | local name 9 | local age 10 | 11 | # Constructor to initialize a Person object 12 | init() { 13 | name="$1" 14 | age="$2" 15 | } 16 | 17 | # Method to print details about the person 18 | display_info() { 19 | echo "Name: $name" 20 | echo "Age: $age" 21 | } 22 | 23 | # Method to check if the person is an adult 24 | is_adult() { 25 | if [ "$age" -ge 18 ]; then 26 | echo "$name is an adult." 27 | else 28 | echo "$name is a minor." 29 | fi 30 | } 31 | } 32 | 33 | # Create two "Person" objects 34 | person1=() 35 | person2=() 36 | 37 | # Initialize the objects 38 | Person person1 39 | person1[init] "Alice" 30 40 | Person person2 41 | person2[init] "Bob" 16 42 | 43 | # Use methods on the objects 44 | echo "Person 1 Info:" 45 | person1[display_info] 46 | person1[is_adult] 47 | 48 | echo "Person 2 Info:" 49 | person2[display_info] 50 | person2[is_adult] 51 | 52 | # Simulate a "greet" method 53 | greet() { 54 | local person_name="$1" 55 | echo "Hello, $person_name!" 56 | } 57 | 58 | # Call greet 59 | greet "${person1[name]}" 60 | greet "${person2[name]}" 61 | 62 | # Exit 63 | echo "Exiting the script." 64 | exit 0 65 | -------------------------------------------------------------------------------- /Frontend/src/pages/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { VscHome } from "react-icons/vsc"; 3 | import { useNavigate } from "react-router-dom"; 4 | 5 | const NotFound = () => { 6 | const navigate = useNavigate(); 7 | 8 | useEffect(() => { 9 | document.title = "404 - Page Not Found"; 10 | }, []); 11 | 12 | const handleGoHome = () => { 13 | navigate("/"); 14 | }; 15 | 16 | return ( 17 |
18 |
19 |

20 | 404 - Page Not Found 21 |

22 |

23 | The page you are looking for does not exist. 24 |

25 |
26 | 33 |
34 |
35 |
36 | ); 37 | }; 38 | 39 | export default NotFound; 40 | -------------------------------------------------------------------------------- /Frontend/src/samples/java.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | 3 | public class ArrayOperations { 4 | 5 | public static void reverseArray(int[] arr) { 6 | int start = 0, end = arr.length - 1; 7 | while (start < end) { 8 | int temp = arr[start]; 9 | arr[start] = arr[end]; 10 | arr[end] = temp; 11 | start++; 12 | end--; 13 | } 14 | } 15 | 16 | public static void printArray(int[] arr) { 17 | System.out.print("Array elements: "); 18 | for (int i = 0; i < arr.length; i++) { 19 | System.out.print(arr[i] + " "); 20 | } 21 | System.out.println(); 22 | } 23 | 24 | public static void main(String[] args) { 25 | Scanner sc = new Scanner(System.in); 26 | 27 | System.out.print("Enter the size of the array: "); 28 | int n = sc.nextInt(); 29 | 30 | int[] arr = new int[n]; 31 | System.out.print("Enter " + n + " elements: "); 32 | for (int i = 0; i < n; i++) { 33 | arr[i] = sc.nextInt(); 34 | } 35 | 36 | System.out.print("Original "); 37 | printArray(arr); 38 | 39 | reverseArray(arr); 40 | 41 | System.out.print("Reversed "); 42 | printArray(arr); 43 | 44 | int sum = 0; 45 | for (int i = 0; i < n; i++) { 46 | sum += arr[i]; 47 | } 48 | 49 | System.out.println("Sum of elements: " + sum); 50 | sc.close(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Frontend/src/samples/python.py: -------------------------------------------------------------------------------- 1 | class Person: 2 | def __init__(self, name, age): 3 | self.name = name 4 | self.age = age 5 | 6 | def greet(self): 7 | print(f"Hello, my name is {self.name} and I'm {self.age} years old.") 8 | 9 | 10 | """ 11 | The Person class represents an individual with a name and age. 12 | It includes an initializer to set these attributes and a greet method 13 | that prints a greeting message with the person's name and age. 14 | """ 15 | 16 | 17 | def fibonacci(n): 18 | if n <= 0: 19 | return 0 20 | elif n == 1: 21 | return 1 22 | else: 23 | return fibonacci(n - 1) + fibonacci(n - 2) 24 | 25 | 26 | # Lambda function to calculate the square of a number 27 | square = lambda x: x * x 28 | 29 | # Main program 30 | if __name__ == "__main__": 31 | print("Welcome to the Online IDE!") 32 | 33 | person = Person("Glad", 20) 34 | person.greet() 35 | 36 | num_terms = 10 37 | 38 | try: 39 | if num_terms <= 0: 40 | raise ValueError("Number of terms must be positive.") 41 | 42 | print("Fibonacci sequence:") 43 | for i in range(num_terms): 44 | fib_value = fibonacci(i) 45 | print(f"Term {i}: {fib_value}") 46 | except ValueError as e: 47 | print(f"Error: {e}") 48 | 49 | # Using the square lambda function 50 | number = 5 51 | print(f"The square of {number} is {square(number)}") 52 | -------------------------------------------------------------------------------- /Frontend/src/samples/c.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void printEvenNumbers(int start, int end) { 4 | printf("Even numbers between %d and %d:\n", start, end); 5 | for (int i = start; i <= end; i++) { 6 | if (i % 2 == 0) { 7 | printf("%d ", i); 8 | } 9 | } 10 | printf("\n"); 11 | } 12 | 13 | int factorial(int n) { 14 | int result = 1; 15 | for (int i = 1; i <= n; i++) { 16 | result *= i; 17 | } 18 | return result; 19 | } 20 | 21 | int main() { 22 | int start = 1, end = 20; 23 | printEvenNumbers(start, end); 24 | 25 | int num = 5; 26 | printf("Factorial of %d is %d\n", num, factorial(num)); 27 | 28 | int number1, number2; 29 | printf("Enter two numbers to add: "); 30 | scanf("%d %d", &number1, &number2); 31 | printf("Sum: %d\n", number1 + number2); 32 | 33 | int choice; 34 | printf("Enter a number (1-5) to see your choice: "); 35 | scanf("%d", &choice); 36 | switch(choice) { 37 | case 1: 38 | printf("You selected choice 1\n"); 39 | break; 40 | case 2: 41 | printf("You selected choice 2\n"); 42 | break; 43 | case 3: 44 | printf("You selected choice 3\n"); 45 | break; 46 | case 4: 47 | printf("You selected choice 4\n"); 48 | break; 49 | case 5: 50 | printf("You selected choice 5\n"); 51 | break; 52 | default: 53 | printf("Invalid choice\n"); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules directory 2 | **/node_modules/ 3 | 4 | # Build output 5 | dist/ 6 | 7 | # Vite cache 8 | .vite/ 9 | 10 | # Dependency directories 11 | .pnp/ 12 | .pnp.js 13 | 14 | # Optional npm cache directory 15 | .npm/ 16 | 17 | # Environment variables file 18 | .env 19 | .env.*.local 20 | 21 | # Log files 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # IDE/editor-specific files 27 | # Visual Studio Code 28 | .vscode/ 29 | 30 | # JetBrains IDEs (e.g., WebStorm, IntelliJ IDEA) 31 | .idea/ 32 | 33 | # Eclipse 34 | .project 35 | .classpath 36 | .settings/ 37 | 38 | # NetBeans 39 | nbproject/ 40 | 41 | # Sublime Text 42 | *.sublime-workspace 43 | *.sublime-project 44 | 45 | # Atom 46 | .atom/ 47 | 48 | # Emacs 49 | *~ 50 | \#*\# 51 | .\#* 52 | 53 | # Vim 54 | *.swp 55 | *.swo 56 | *.swn 57 | 58 | # IntelliJ IDEA (other configurations) 59 | *.iml 60 | *.ipr 61 | *.iws 62 | 63 | # Xcode 64 | *.xcuserstate 65 | *.xcworkspace/ 66 | *.xcuserdatad/ 67 | 68 | # Visual Studio 69 | .vs/ 70 | *.suo 71 | *.user 72 | *.userosscache 73 | *.sln.docstates 74 | 75 | # Google Cloud SDK 76 | .gcloud/ 77 | .gcloudignore 78 | *.gcloud 79 | 80 | # Ignore .idx files 81 | *.idx 82 | 83 | # Operating system-specific files 84 | .DS_Store 85 | Thumbs.db 86 | Desktop.ini 87 | 88 | # Miscellaneous 89 | *.log 90 | *.tmp 91 | *.bak 92 | *.swp 93 | *.swo 94 | *.pot 95 | *.pyc 96 | 97 | # Package distribution 98 | *.tgz 99 | *.gz 100 | *.zip 101 | 102 | # Documentation 103 | *.pdf 104 | *.docx 105 | *.xlsx 106 | *.pptx 107 | 108 | # Bun 109 | bun.lockb 110 | 111 | # Byte-compiled files 112 | __pycache__/ 113 | 114 | # Virtual environment 115 | venv/ 116 | env/ 117 | 118 | # Distribution / packaging 119 | .Python 120 | develop-eggs/ 121 | egg-info/ 122 | 123 | # Vercel 124 | vercel.json -------------------------------------------------------------------------------- /Frontend/src/utils/InputField.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const InputField = ({ 4 | label, 5 | type, 6 | value, 7 | onChange, 8 | required, 9 | name, 10 | showPassword, 11 | onTogglePassword, 12 | }) => { 13 | const isPasswordField = [ 14 | "password", 15 | "newPassword", 16 | "confirmPassword", 17 | "currentPassword", 18 | ].includes(name); 19 | 20 | const getAutoCompleteValue = () => { 21 | switch (name) { 22 | case "email": 23 | return "email"; 24 | case "username": 25 | return "username"; 26 | case "password": 27 | return "current-password"; 28 | case "newPassword": 29 | case "confirmPassword": 30 | return "new-password"; 31 | default: 32 | return "off"; 33 | } 34 | }; 35 | 36 | return ( 37 |
38 | 44 | 45 | 55 | 56 | {isPasswordField && ( 57 | 64 | )} 65 |
66 | ); 67 | }; 68 | 69 | export default InputField; 70 | -------------------------------------------------------------------------------- /Frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules directory 2 | node_modules/ 3 | 4 | # Build output 5 | dist/ 6 | 7 | # Vite cache 8 | .vite/ 9 | 10 | # Dependency directories 11 | .pnp/ 12 | .pnp.js 13 | 14 | # Optional npm cache directory 15 | .npm/ 16 | 17 | # Environment variables file 18 | .env 19 | .env.*.local 20 | 21 | # Log files 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # IDE/editor-specific files 27 | # Visual Studio Code 28 | .vscode/ 29 | 30 | # JetBrains IDEs (e.g., WebStorm, IntelliJ IDEA) 31 | .idea/ 32 | 33 | # Eclipse 34 | .project 35 | .classpath 36 | .settings/ 37 | 38 | # NetBeans 39 | nbproject/ 40 | 41 | # Sublime Text 42 | *.sublime-workspace 43 | *.sublime-project 44 | 45 | # Atom 46 | .atom/ 47 | 48 | # Emacs 49 | *~ 50 | \#*\# 51 | .\#* 52 | 53 | # Vim 54 | *.swp 55 | *.swo 56 | *.swn 57 | 58 | # IntelliJ IDEA (other configurations) 59 | *.iml 60 | *.ipr 61 | *.iws 62 | 63 | # Xcode 64 | *.xcuserstate 65 | *.xcworkspace/ 66 | *.xcuserdatad/ 67 | 68 | # Visual Studio 69 | .vs/ 70 | *.suo 71 | *.user 72 | *.userosscache 73 | *.sln.docstates 74 | 75 | # Google Cloud SDK 76 | .gcloud/ 77 | .gcloudignore 78 | *.gcloud 79 | 80 | # Ignore .idx files 81 | *.idx 82 | 83 | # Operating system-specific files 84 | .DS_Store 85 | Thumbs.db 86 | Desktop.ini 87 | 88 | # Miscellaneous 89 | *.log 90 | *.tmp 91 | *.bak 92 | *.swp 93 | *.swo 94 | *.pot 95 | *.pyc 96 | 97 | # Package distribution 98 | *.tgz 99 | *.gz 100 | *.zip 101 | 102 | # Documentation 103 | *.pdf 104 | *.docx 105 | *.xlsx 106 | *.pptx 107 | 108 | # Bun 109 | bun.lockb 110 | 111 | # Byte-compiled files 112 | __pycache__/ 113 | 114 | # Virtual environment 115 | venv/ 116 | env/ 117 | 118 | # Distribution / packaging 119 | .Python 120 | develop-eggs/ 121 | egg-info/ 122 | 123 | # Vercel 124 | vercel.json 125 | .vercel 126 | -------------------------------------------------------------------------------- /Frontend/src/utils/blocker.js: -------------------------------------------------------------------------------- 1 | import { BACKEND_API_URL, GENAI_API_URL } from "./constants.js"; 2 | 3 | const blocker = ` 4 | (() => { 5 | const blockedHosts = [ 6 | new URL("${BACKEND_API_URL}").hostname, 7 | new URL("${GENAI_API_URL}").hostname, 8 | ]; 9 | 10 | const isBlocked = (url) => { 11 | try { 12 | const parsedUrl = new URL(url, location.href); 13 | return blockedHosts.includes(parsedUrl.hostname); 14 | } catch { 15 | return false; 16 | } 17 | }; 18 | 19 | const originalFetch = window.fetch; 20 | window.fetch = function(input, init) { 21 | const url = input instanceof Request ? input.url : input; 22 | if (isBlocked(url)) { 23 | return Promise.reject(new Error("Failed to fetch")); 24 | } 25 | return originalFetch(input, init); 26 | }; 27 | 28 | const OriginalXHR = window.XMLHttpRequest; 29 | class PatchedXHR extends OriginalXHR { 30 | open(method, url, ...args) { 31 | if (isBlocked(url)) { 32 | throw new Error("Failed to fetch"); 33 | } 34 | return super.open(method, url, ...args); 35 | } 36 | } 37 | window.XMLHttpRequest = PatchedXHR; 38 | 39 | const OriginalWebSocket = window.WebSocket; 40 | window.WebSocket = class extends OriginalWebSocket { 41 | constructor(url, protocols) { 42 | if (isBlocked(url)) { 43 | throw new Error("Failed to fetch"); 44 | } 45 | return new OriginalWebSocket(url, protocols); 46 | } 47 | }; 48 | 49 | const OriginalEventSource = window.EventSource; 50 | window.EventSource = class extends OriginalEventSource { 51 | constructor(url, ...args) { 52 | if (isBlocked(url)) { 53 | throw new Error("Failed to fetch"); 54 | } 55 | return new OriginalEventSource(url, ...args); 56 | } 57 | }; 58 | 59 | const originalSendBeacon = navigator.sendBeacon.bind(navigator); 60 | navigator.sendBeacon = function(url, data) { 61 | if (isBlocked(url)) { 62 | return false; 63 | } 64 | return originalSendBeacon(url, data); 65 | }; 66 | })();`; 67 | 68 | export default blocker; 69 | -------------------------------------------------------------------------------- /Frontend/src/samples/csharp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SampleApp 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | Console.WriteLine("Welcome to the Simple Calculator!"); 10 | 11 | // Get the first number 12 | Console.Write("Enter the first number: "); 13 | double num1 = Convert.ToDouble(Console.ReadLine()); 14 | 15 | // Get the second number 16 | Console.Write("Enter the second number: "); 17 | double num2 = Convert.ToDouble(Console.ReadLine()); 18 | 19 | // Choose an operation 20 | Console.WriteLine("Choose an operation (+, -, *, /): "); 21 | string operation = Console.ReadLine(); 22 | 23 | double result = 0; 24 | bool validOperation = true; 25 | 26 | // Perform the operation 27 | switch (operation) 28 | { 29 | case "+": 30 | result = Add(num1, num2); 31 | break; 32 | case "-": 33 | result = Subtract(num1, num2); 34 | break; 35 | case "*": 36 | result = Multiply(num1, num2); 37 | break; 38 | case "/": 39 | if (num2 != 0) 40 | result = Divide(num1, num2); 41 | else 42 | { 43 | Console.WriteLine("Error: Division by zero!"); 44 | validOperation = false; 45 | } 46 | break; 47 | default: 48 | Console.WriteLine("Invalid operation!"); 49 | validOperation = false; 50 | break; 51 | } 52 | 53 | // Display the result 54 | if (validOperation) 55 | { 56 | Console.WriteLine("The result is: " + result); 57 | } 58 | } 59 | 60 | static double Add(double a, double b) => a + b; 61 | static double Subtract(double a, double b) => a - b; 62 | static double Multiply(double a, double b) => a * b; 63 | static double Divide(double a, double b) => a / b; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Frontend/src/utils/ShareLinkModal.js: -------------------------------------------------------------------------------- 1 | const ShareLinkModal = (defaultTitle) => { 2 | const modalContent = document.createElement('div'); 3 | 4 | const titleInput = document.createElement('input'); 5 | titleInput.id = 'titleInput'; 6 | titleInput.className = 'w-full mt-1 p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:bg-gray-100 dark:focus:bg-gray-700 dark:border-gray-600 dark:text-white dark:focus:ring-blue-400'; 7 | titleInput.placeholder = defaultTitle; 8 | 9 | modalContent.appendChild(titleInput); 10 | 11 | setTimeout(() => { 12 | titleInput.focus(); 13 | }, 0); 14 | 15 | const expiryContainer = document.createElement('div'); 16 | expiryContainer.className = 'mt-4 select-none'; 17 | 18 | const expiryOptions = [{ 19 | value: '10', 20 | label: '10 minutes' 21 | }, 22 | { 23 | value: '30', 24 | label: '30 minutes' 25 | }, 26 | { 27 | value: '60', 28 | label: '1 hour' 29 | }, 30 | { 31 | value: '1440', 32 | label: '1 day' 33 | }, 34 | { 35 | value: '10080', 36 | label: '1 week' 37 | }, 38 | ]; 39 | 40 | expiryOptions.forEach((option, index) => { 41 | const expiryWrapper = document.createElement('div'); 42 | expiryWrapper.className = 'flex items-center ps-3 border border-gray-200 rounded-sm has-checked:bg-gray-200 dark:has-checked:bg-gray-700 dark:border-gray-700'; 43 | 44 | const radioButton = document.createElement('input'); 45 | radioButton.id = `expiry${option.value}`; 46 | radioButton.type = 'radio'; 47 | radioButton.value = option.value; 48 | radioButton.name = 'expiryTime'; 49 | radioButton.className = 'text-blue-600 bg-gray-100 border-gray-300 cursor-pointer dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600'; 50 | if (index === 1) radioButton.checked = true; 51 | 52 | const label = document.createElement('label'); 53 | label.setAttribute('for', radioButton.id); 54 | label.className = 'py-3 ms-2 w-full text-left text-sm font-medium cursor-pointer text-gray-900 dark:text-gray-300'; 55 | label.textContent = option.label; 56 | 57 | expiryWrapper.appendChild(radioButton); 58 | expiryWrapper.appendChild(label); 59 | expiryContainer.appendChild(expiryWrapper); 60 | }); 61 | 62 | modalContent.appendChild(expiryContainer); 63 | 64 | return modalContent; 65 | }; 66 | 67 | export default ShareLinkModal; -------------------------------------------------------------------------------- /Backend/Login/utils/updateLanguageCount.js: -------------------------------------------------------------------------------- 1 | const updateLanguageCount = (user, countType, language) => { 2 | switch (language) { 3 | case 'python': 4 | user[countType].set('py', (user[countType].get('py') || 0) + 1); 5 | break; 6 | case 'javascript': 7 | user[countType].set('js', (user[countType].get('js') || 0) + 1); 8 | break; 9 | case 'HtmlJsCss': 10 | user[countType].set( 11 | 'HtmlJsCss', 12 | (user[countType].get('HtmlJsCss') || 0) + 1 13 | ); 14 | break; 15 | case 'c': 16 | user[countType].set('c', (user[countType].get('c') || 0) + 1); 17 | break; 18 | case 'cpp': 19 | user[countType].set('cpp', (user[countType].get('cpp') || 0) + 1); 20 | break; 21 | case 'java': 22 | user[countType].set('java', (user[countType].get('java') || 0) + 1); 23 | break; 24 | case 'csharp': 25 | user[countType].set('cs', (user[countType].get('cs') || 0) + 1); 26 | break; 27 | case 'rust': 28 | user[countType].set('rust', (user[countType].get('rust') || 0) + 1); 29 | break; 30 | case 'go': 31 | user[countType].set('go', (user[countType].get('go') || 0) + 1); 32 | break; 33 | case 'verilog': 34 | user[countType].set('verilog', (user[countType].get('verilog') || 0) + 1); 35 | break; 36 | case 'sql': 37 | user[countType].set('sql', (user[countType].get('sql') || 0) + 1); 38 | break; 39 | case 'mongodb': 40 | user[countType].set('mongodb', (user[countType].get('mongodb') || 0) + 1); 41 | break; 42 | case 'swift': 43 | user[countType].set('swift', (user[countType].get('swift') || 0) + 1); 44 | break; 45 | case 'ruby': 46 | user[countType].set('ruby', (user[countType].get('ruby') || 0) + 1); 47 | break; 48 | case 'typescript': 49 | user[countType].set('ts', (user[countType].get('ts') || 0) + 1); 50 | break; 51 | case 'dart': 52 | user[countType].set('dart', (user[countType].get('dart') || 0) + 1); 53 | break; 54 | case 'kotlin': 55 | user[countType].set('kt', (user[countType].get('kt') || 0) + 1); 56 | break; 57 | case 'perl': 58 | user[countType].set('perl', (user[countType].get('perl') || 0) + 1); 59 | break; 60 | case 'scala': 61 | user[countType].set('scala', (user[countType].get('scala') || 0) + 1); 62 | break; 63 | case 'julia': 64 | user[countType].set('julia', (user[countType].get('julia') || 0) + 1); 65 | break; 66 | default: 67 | return false; 68 | } 69 | return true; 70 | }; 71 | 72 | module.exports = { updateLanguageCount }; 73 | -------------------------------------------------------------------------------- /Frontend/src/utils/OtpInputForm.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from "react"; 2 | 3 | const OtpInputForm = ({ onOtpChange }) => { 4 | const otpInputs = useRef([]); 5 | 6 | useEffect(() => { 7 | const filledInput = otpInputs.current.find( 8 | (input) => input.value.trim() !== "" 9 | ); 10 | if (filledInput) { 11 | filledInput.focus(); 12 | } else { 13 | otpInputs.current[0].focus(); 14 | } 15 | }, []); 16 | 17 | const handleInputChange = (e, index) => { 18 | const value = e.target.value; 19 | if (value.length === 1) { 20 | if (index === 5) { 21 | return; 22 | } else { 23 | otpInputs.current[index + 1].focus(); 24 | } 25 | } 26 | const otpValue = otpInputs.current.map((input) => input.value).join(""); 27 | onOtpChange(otpValue); 28 | }; 29 | 30 | const handleKeyDown = (e, index) => { 31 | if (e.key === "Backspace" && otpInputs.current[index].value === "") { 32 | if (index > 0) { 33 | otpInputs.current[index - 1].focus(); 34 | } 35 | } 36 | 37 | if (e.key === "ArrowRight" && index < otpInputs.current.length - 1) { 38 | otpInputs.current[index + 1].focus(); 39 | } 40 | if (e.key === "ArrowLeft" && index > 0) { 41 | otpInputs.current[index - 1].focus(); 42 | } 43 | }; 44 | 45 | const handlePaste = (e) => { 46 | e.preventDefault(); 47 | const pasteData = e.clipboardData.getData("text").trim(); 48 | const pasteArray = pasteData.split("").slice(0, 6); 49 | 50 | pasteArray.forEach((char, i) => { 51 | if (otpInputs.current[i]) { 52 | otpInputs.current[i].value = char; 53 | } 54 | }); 55 | 56 | const nextIndex = 57 | pasteArray.length < otpInputs.current.length 58 | ? pasteArray.length 59 | : otpInputs.current.length - 1; 60 | otpInputs.current[nextIndex].focus(); 61 | 62 | const otpValue = otpInputs.current.map((input) => input.value).join(""); 63 | onOtpChange(otpValue); 64 | }; 65 | 66 | const handleBlur = () => { 67 | const otpValue = otpInputs.current.map((input) => input.value).join(""); 68 | onOtpChange(otpValue); 69 | }; 70 | 71 | return ( 72 |
73 | {Array.from({ length: 6 }).map((_, index) => ( 74 | (otpInputs.current[index] = el)} 79 | className="w-12 h-12 text-center text-xl border-2 border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:focus:ring-blue-400" 80 | onChange={(e) => handleInputChange(e, index)} 81 | onKeyDown={(e) => handleKeyDown(e, index)} 82 | onPaste={handlePaste} 83 | onBlur={handleBlur} 84 | required 85 | /> 86 | ))} 87 |
88 | ); 89 | }; 90 | 91 | export default OtpInputForm; 92 | -------------------------------------------------------------------------------- /Backend/Login/utils/validation.js: -------------------------------------------------------------------------------- 1 | const usernameRegex = /^[a-zA-Z0-9_.-]{5,30}$/; 2 | 3 | const emailRegex = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/; 4 | 5 | const pwdRegex = /^.{8,}$/; 6 | 7 | const reservedUsernames = [ 8 | 'admin', 'root', 'support', 'system', 'null', 'undefined', 9 | 'moderator', 'mod', 'administrator', 'webmaster', 'contact', 10 | 'help', 'about', 'info', 'owner', 'superuser', 'staff', 'api', 11 | 'account', 'user', 'users', 'me', 'you', 'settings', 'config', 12 | 'dashboard', 'login', 'logout', 'register', 'signup', 'signin', 13 | 'signout', 'profile', 'home', 'security', 'terms', 'privacy', 14 | 'tos', 'faq', 'feedback', 'reports', 'report', 'adminpanel', 15 | 'console', 'auth', 'v1', 'v2', 'internal', 'public', 'private', 16 | 'guest', 'anonymous', 'developer', 'dev', 'ops', 'beta', 'test', 17 | 'testing', 'demo', 'rootadmin', 'superadmin', 'sysadmin', 18 | 'master', 'operator', 'staffer', 'moderat0r', 'founder', 'ceo', 19 | 'cto', 'cfo', 'coo', 'hr', 'securityteam', 'supportteam', 20 | 'billing', 'payments', 'invoice', 'shop', 'store', 'cart', 21 | 'checkout', 'subscribe', 'unsubscribe', 'apiadmin', 'apikey', 22 | 'service', 'systemadmin', 'nulluser', 'undefineduser', 23 | 'supervisor', 'manager', 'leader', 'team', 'project', 'partner', 24 | 'affiliate', 'marketing', 'sales', 'contactus', 'post', 'posts', 25 | 'article', 'articles', 'news', 'blog', 'blogs', 'events', 26 | 'calendar', 'schedule', 'status', 'error', 'errors', 'bug', 27 | 'bugs', 'patch', 'update', 'upgrade', 'downgrade', 'version', 28 | 'release', 'devops', 'analytics', 'stats', 'statistics', 29 | 'metrics', 'metricsadmin', 'adminstats', 'supportdesk', 30 | 'helpline', 'helpdesk', 'moderation', 'moderate', 'superuser', 31 | 'usersupport', 'client', 'clients', 'customer', 'customers', 32 | 'apiuser', 'systemuser', 'bot', 'bots', 'crawler', 'spider', 33 | 'seo', 'spam', 'phishing', 'blacklist', 'whitelist', 'admin123', 34 | 'testuser', 'demoaccount', 'trial', 'betauser', 'alpha', 35 | 'alphatest', 'sandbox', 'sandboxuser', 'readonly', 'readwrite', 36 | 'writeonly', 'masterkey', 'access', 'permission', 'permissions', 37 | 'role', 'roles', 'group', 'groups', 'cron', 'daemon', 'task', 38 | 'jobs', 'worker', 'queue', 'scheduler', 'cache', 'temp', 'tmp', 39 | 'backup', 'restore', 'http', 'https', 'ftp', 'ssh', 'smtp', 40 | 'pop3', 'imap', 'dns', 'tcp', 'udp', 'ip', 'json', 'xml', 'csv', 41 | 'html', 'css', 'js', 'javascript', 'node', 'npm', 'yarn', 'fatal', 42 | 'panic', 'crash', 'fail', 'failure', 'exception', 'bugreport', 43 | 'trace', 'stack', 'overflow', 'memory', 'analyst', 'consultant', 44 | 'engineer', 'designer', 'architect', 'tester', 'qa', 'qaengineer', 45 | 'nullify', 'void', 'undefinedvariable', 'delete', 'remove', 46 | 'drop', 'truncate', 'rootuser', 'super', 'god', 'admin1', 'julia', 47 | 'administrator1', 'sys', 'html', 'css', 'jspython', 'javascript', 48 | 'cc++', 'java', 'c#', 'rust', 'go', 'verilog', 'sql', 'mongodb', 49 | 'swift', 'ruby', 'typescript', 'dart', 'kotlin', 'perl', 'scala' 50 | ]; 51 | 52 | module.exports = { 53 | usernameRegex, 54 | emailRegex, 55 | pwdRegex, 56 | reservedUsernames 57 | }; 58 | -------------------------------------------------------------------------------- /Frontend/src/samples/sql.sql: -------------------------------------------------------------------------------- 1 | -- Drop the emp table if it already exists to avoid errors during creation 2 | DROP TABLE IF EXISTS emp; 3 | 4 | -- Create the emp table to store employee data 5 | CREATE TABLE emp ( 6 | empno decimal(4,0) NOT NULL, -- Employee number, primary key, cannot be NULL 7 | ename varchar(10) default NULL, -- Employee name, can be NULL by default 8 | job varchar(9) default NULL, -- Job title, can be NULL by default 9 | mgr decimal(4,0) default NULL, -- Manager's employee number, can be NULL by default 10 | hiredate date default NULL, -- Date of hiring, can be NULL by default 11 | sal decimal(7,2) default NULL, -- Salary, can be NULL by default 12 | comm decimal(7,2) default NULL, -- Commission, can be NULL by default 13 | deptno decimal(2,0) default NULL -- Department number, can be NULL by default 14 | ); 15 | 16 | -- Drop the dept table if it already exists to avoid errors during creation 17 | DROP TABLE IF EXISTS dept; 18 | 19 | -- Create the dept table to store department data 20 | CREATE TABLE dept ( 21 | deptno decimal(2,0) default NULL, -- Department number, primary key, can be NULL by default 22 | dname varchar(14) default NULL, -- Department name, can be NULL by default 23 | loc varchar(13) default NULL -- Location, can be NULL by default 24 | ); 25 | 26 | -- Insert records into the emp table (employee data) 27 | INSERT INTO emp VALUES ('7369','SMITH','CLERK','7902','1980-12-17','800.00',NULL,'20'); 28 | INSERT INTO emp VALUES ('7499','ALLEN','SALESMAN','7698','1981-02-20','1600.00','300.00','30'); 29 | INSERT INTO emp VALUES ('7521','WARD','SALESMAN','7698','1981-02-22','1250.00','500.00','30'); 30 | INSERT INTO emp VALUES ('7566','JONES','MANAGER','7839','1981-04-02','2975.00',NULL,'20'); 31 | INSERT INTO emp VALUES ('7654','MARTIN','SALESMAN','7698','1981-09-28','1250.00','1400.00','30'); 32 | INSERT INTO emp VALUES ('7698','BLAKE','MANAGER','7839','1981-05-01','2850.00',NULL,'30'); 33 | INSERT INTO emp VALUES ('7782','CLARK','MANAGER','7839','1981-06-09','2450.00',NULL,'10'); 34 | INSERT INTO emp VALUES ('7788','SCOTT','ANALYST','7566','1982-12-09','3000.00',NULL,'20'); 35 | INSERT INTO emp VALUES ('7839','KING','PRESIDENT',NULL,'1981-11-17','5000.00',NULL,'10'); 36 | INSERT INTO emp VALUES ('7844','TURNER','SALESMAN','7698','1981-09-08','1500.00','0.00','30'); 37 | INSERT INTO emp VALUES ('7876','ADAMS','CLERK','7788','1983-01-12','1100.00',NULL,'20'); 38 | INSERT INTO emp VALUES ('7900','JAMES','CLERK','7698','1981-12-03','950.00',NULL,'30'); 39 | INSERT INTO emp VALUES ('7902','FORD','ANALYST','7566','1981-12-03','3000.00',NULL,'20'); 40 | INSERT INTO emp VALUES ('7934','MILLER','CLERK','7782','1982-01-23','1300.00',NULL,'10'); 41 | 42 | -- Insert records into the dept table (department data) 43 | INSERT INTO dept VALUES ('10','ACCOUNTING','NEW YORK'); 44 | INSERT INTO dept VALUES ('20','RESEARCH','DALLAS'); 45 | INSERT INTO dept VALUES ('30','SALES','CHICAGO'); 46 | INSERT INTO dept VALUES ('40','OPERATIONS','BOSTON'); 47 | 48 | -- Select all records from the dept table 49 | SELECT * FROM dept; 50 | 51 | -- Select all employees who are SALESMAN from the emp table 52 | SELECT * FROM emp WHERE job = 'SALESMAN'; 53 | -------------------------------------------------------------------------------- /Frontend/src/components/NavigationLinks.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { Link } from "react-router-dom"; 3 | import SharedLinks from "./SharedLinks"; 4 | 5 | const navLinks = [ 6 | { 7 | to: "/htmlcssjs", 8 | text: "HTML, CSS, JS", 9 | classes: "bg-blue-500 motion-delay-[400ms]", 10 | }, 11 | { 12 | to: "/python", 13 | text: "Python", 14 | classes: "bg-green-500 motion-delay-[450ms]", 15 | }, 16 | { 17 | to: "/javascript", 18 | text: "Javascript", 19 | classes: "bg-purple-500 motion-delay-[500ms]", 20 | }, 21 | { 22 | to: "/c", 23 | text: "C", 24 | classes: "bg-red-500 motion-delay-[550ms]", 25 | }, 26 | { 27 | to: "/cpp", 28 | text: "C++", 29 | classes: "bg-blue-700 motion-delay-[600ms]", 30 | }, 31 | { 32 | to: "/java", 33 | text: "Java", 34 | classes: "bg-orange-500 motion-delay-[650ms]", 35 | }, 36 | { 37 | to: "/csharp", 38 | text: "C#", 39 | classes: "bg-teal-500 motion-delay-[700ms]", 40 | }, 41 | { 42 | to: "/rust", 43 | text: "Rust", 44 | classes: "bg-yellow-600 motion-delay-[750ms]", 45 | }, 46 | { 47 | to: "/go", 48 | text: "Go", 49 | classes: "bg-green-700 motion-delay-[800ms]", 50 | }, 51 | { 52 | to: "/verilog", 53 | text: "Verilog", 54 | classes: "bg-gray-600 motion-delay-[850ms]", 55 | }, 56 | { 57 | to: "/sql", 58 | text: "SQL", 59 | classes: "bg-indigo-500 motion-delay-[900ms]", 60 | }, 61 | { 62 | to: "/mongodb", 63 | text: "MongoDB", 64 | classes: "bg-teal-600 motion-delay-[950ms]", 65 | }, 66 | { 67 | to: "/swift", 68 | text: "Swift", 69 | classes: "bg-pink-500 motion-delay-[1000ms]", 70 | }, 71 | { 72 | to: "/ruby", 73 | text: "Ruby", 74 | classes: "bg-red-600 motion-delay-[1050ms]", 75 | }, 76 | { 77 | to: "/typescript", 78 | text: "Typescript", 79 | classes: "bg-blue-600 motion-delay-[1100ms]", 80 | }, 81 | { 82 | to: "/dart", 83 | text: "Dart", 84 | classes: "bg-cyan-500 motion-delay-[1150ms]", 85 | }, 86 | { 87 | to: "/kotlin", 88 | text: "Kotlin", 89 | classes: "bg-teal-700 motion-delay-[1200ms]", 90 | }, 91 | { 92 | to: "/perl", 93 | text: "Perl", 94 | classes: "bg-pink-700 motion-delay-[1250ms]", 95 | }, 96 | { 97 | to: "/scala", 98 | text: "Scala", 99 | classes: "bg-green-500 motion-delay-[1300ms]", 100 | }, 101 | { 102 | to: "/julia", 103 | text: "Julia", 104 | classes: "bg-yellow-500 motion-delay-[1350ms]", 105 | }, 106 | ]; 107 | 108 | const NavigationLinks = () => { 109 | const baseUrl = window.location.origin; 110 | 111 | useEffect(() => { 112 | document.title = "Online IDE - Glad432"; 113 | }, []); 114 | 115 | return ( 116 | <> 117 |
118 |
119 | {navLinks.map(({ to, text, classes }) => ( 120 | 127 | {text} 128 | 129 | ))} 130 |
131 |
132 | 133 | 134 | ); 135 | }; 136 | 137 | export default NavigationLinks; 138 | -------------------------------------------------------------------------------- /Backend/Login/models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const { logUserAction } = require('../utils/useLogger') 3 | 4 | const userSchema = new mongoose.Schema({ 5 | username: { 6 | type: String, 7 | required: true, 8 | unique: true, 9 | trim: true, 10 | minlength: 5, 11 | maxlength: 30, 12 | }, 13 | email: { 14 | type: String, 15 | required: true, 16 | unique: true, 17 | lowercase: true, 18 | match: [/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/, 'Please provide a valid email address'], 19 | }, 20 | password: { 21 | type: String, 22 | required: true, 23 | }, 24 | lastLogin: { 25 | type: Date, 26 | default: null, 27 | }, 28 | createdDate: { 29 | type: Date, 30 | default: Date.now, 31 | }, 32 | isEmailVerified: { 33 | type: Boolean, 34 | default: false, 35 | }, 36 | otp: { 37 | type: String, 38 | default: null, 39 | }, 40 | otpExpires: { 41 | type: Date, 42 | default: null, 43 | }, 44 | generateCodeCount: { 45 | type: Map, 46 | of: Number, 47 | default: () => ({ 48 | py: 0, 49 | js: 0, 50 | HtmlJsCss: 0, 51 | c: 0, 52 | cpp: 0, 53 | java: 0, 54 | cs: 0, 55 | rust: 0, 56 | go: 0, 57 | sql: 0, 58 | mongodb: 0, 59 | swift: 0, 60 | ruby: 0, 61 | ts: 0, 62 | dart: 0, 63 | kt: 0, 64 | perl: 0, 65 | scala: 0, 66 | julia: 0, 67 | verilog: 0, 68 | }), 69 | }, 70 | refactorCodeCount: { 71 | type: Map, 72 | of: Number, 73 | default: () => ({ 74 | py: 0, 75 | js: 0, 76 | HtmlJsCss: 0, 77 | c: 0, 78 | cpp: 0, 79 | java: 0, 80 | cs: 0, 81 | rust: 0, 82 | go: 0, 83 | sql: 0, 84 | mongodb: 0, 85 | swift: 0, 86 | ruby: 0, 87 | ts: 0, 88 | dart: 0, 89 | kt: 0, 90 | perl: 0, 91 | scala: 0, 92 | julia: 0, 93 | verilog: 0, 94 | }), 95 | }, 96 | runCodeCount: { 97 | type: Map, 98 | of: Number, 99 | default: () => ({ 100 | py: 0, 101 | js: 0, 102 | c: 0, 103 | cpp: 0, 104 | java: 0, 105 | cs: 0, 106 | rust: 0, 107 | go: 0, 108 | sql: 0, 109 | mongodb: 0, 110 | swift: 0, 111 | ruby: 0, 112 | ts: 0, 113 | dart: 0, 114 | kt: 0, 115 | perl: 0, 116 | scala: 0, 117 | julia: 0, 118 | verilog: 0, 119 | }), 120 | }, 121 | sharedLinks: { 122 | type: [{ 123 | shareId: { 124 | type: String, 125 | required: true, 126 | unique: true, 127 | }, 128 | title: { 129 | type: String, 130 | required: true, 131 | }, 132 | expiryTime: { 133 | type: Date, 134 | required: true, 135 | }, 136 | }, ], 137 | default: [], 138 | }, 139 | }); 140 | 141 | userSchema.pre('save', function(next) { 142 | const user = this; 143 | const actionType = user.isNew ? 'create' : 'update'; 144 | logUserAction(user, actionType); 145 | next(); 146 | }); 147 | 148 | userSchema.pre('remove', function(next) { 149 | const user = this; 150 | logUserAction(user, 'delete'); 151 | next(); 152 | }); 153 | 154 | module.exports = mongoose.model('User', userSchema); -------------------------------------------------------------------------------- /Frontend/src/pages/Login.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | import { TbLoader } from "react-icons/tb"; 4 | import InputField from "../utils/InputField"; 5 | import { 6 | SESSION_STORAGE_SHARELINKS_KEY, 7 | LOCAL_STORAGE_TOKEN_KEY, 8 | LOCAL_STORAGE_USERNAME_KEY, 9 | LOCAL_STORAGE_LOGIN_KEY, 10 | BACKEND_API_URL, 11 | EMAIL_REGEX, 12 | PASSWORD_REGEX, 13 | } from "../utils/constants"; 14 | 15 | const Login = () => { 16 | const [formData, setFormData] = useState({ 17 | email: "", 18 | password: "", 19 | }); 20 | const [error, setError] = useState(""); 21 | const [loading, setLoading] = useState(false); 22 | const [showPassword, setShowPassword] = useState(false); 23 | 24 | const navigate = useNavigate(); 25 | 26 | useEffect(() => { 27 | document.title = "Login"; 28 | }, []); 29 | 30 | const handleInputChange = (e) => { 31 | const { name, value } = e.target; 32 | setFormData((prevData) => ({ 33 | ...prevData, 34 | [name]: value, 35 | })); 36 | 37 | if (error) { 38 | setError(""); 39 | } 40 | }; 41 | 42 | const validateForm = () => { 43 | if (!EMAIL_REGEX.test(formData.email.trim())) { 44 | setError("Invalid email format"); 45 | return false; 46 | } 47 | 48 | if (formData.password.trim().length < 8) { 49 | setError("Password must be at least 8 characters long"); 50 | return false; 51 | } 52 | 53 | if (!PASSWORD_REGEX.test(formData.password.trim())) { 54 | setError("Invalid password format"); 55 | return false; 56 | } 57 | 58 | return true; 59 | }; 60 | 61 | const handleSubmit = async (e) => { 62 | e.preventDefault(); 63 | 64 | if (!validateForm()) return; 65 | 66 | setLoading(true); 67 | 68 | const { email, password } = formData; 69 | 70 | try { 71 | const response = await fetch(`${BACKEND_API_URL}/api/login`, { 72 | method: "POST", 73 | headers: { 74 | "Content-Type": "application/json", 75 | }, 76 | body: JSON.stringify({ 77 | email: email.trim(), 78 | password: password.trim(), 79 | }), 80 | }); 81 | 82 | if (!response.ok) { 83 | const data = await response.json(); 84 | if (data.msg === "Email not verified") { 85 | setError( 86 | "Email is not verified. Go to the register page and verify the email." 87 | ); 88 | return; 89 | } 90 | throw new Error("Invalid credentials!"); 91 | } 92 | 93 | const data = await response.json(); 94 | 95 | localStorage.setItem(LOCAL_STORAGE_TOKEN_KEY, data.token); 96 | localStorage.setItem(LOCAL_STORAGE_USERNAME_KEY, data.username); 97 | localStorage.setItem(LOCAL_STORAGE_LOGIN_KEY, "true"); 98 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 99 | 100 | navigate(window.history.length > 2 ? -1 : "/"); 101 | location.reload(); 102 | } catch (err) { 103 | setError(err.message || "Server error, please try again."); 104 | } finally { 105 | setLoading(false); 106 | } 107 | }; 108 | 109 | return ( 110 |
111 |
112 |

113 | Login 114 |

115 |
116 | 124 | 125 | setShowPassword((prev) => !prev)} 134 | /> 135 | 136 | {error && ( 137 |

138 | {error} 139 |

140 | )} 141 | 142 | 156 | 157 | 158 |
159 |

160 | Don't have an account?{" "} 161 | 167 |

168 |

169 | 175 |

176 |
177 |
178 |
179 | ); 180 | }; 181 | 182 | export default Login; 183 | -------------------------------------------------------------------------------- /Frontend/src/routes/EditorRoutes.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Routes, Route, Navigate } from "react-router-dom"; 3 | import { IoLogoPython, IoHardwareChipOutline } from "react-icons/io5"; 4 | import { 5 | SiJavascript, 6 | SiRust, 7 | SiMongodb, 8 | SiSwift, 9 | SiRuby, 10 | SiDart, 11 | SiPerl, 12 | SiScala, 13 | SiJulia, 14 | } from "react-icons/si"; 15 | import { FaGolang } from "react-icons/fa6"; 16 | import { RiJavaFill } from "react-icons/ri"; 17 | import { 18 | PiFileCppFill, 19 | PiFileCSharpFill, 20 | PiFileCFill, 21 | PiFileSqlFill, 22 | } from "react-icons/pi"; 23 | import { TbBrandKotlin } from "react-icons/tb"; 24 | import { BiLogoTypescript } from "react-icons/bi"; 25 | import Register from "../pages/Register"; 26 | import Login from "../pages/Login"; 27 | import ForgotPassword from "../pages/ForgotPassword"; 28 | import Accounts from "../pages/Accounts"; 29 | import NotFound from "../pages/NotFound"; 30 | import NavigationLinks from "../components/NavigationLinks"; 31 | import Editor from "../components/Editor"; 32 | import CodeEditor from "../components/CodeEditor"; 33 | import ShareEditor from "../components/ShareEditor"; 34 | import { 35 | LOCAL_STORAGE_TOKEN_KEY, 36 | GENAI_API_URL, 37 | LOCAL_STORAGE_USERNAME_KEY, 38 | } from "../utils/constants"; 39 | import samplePy from "../samples/python.py?raw"; 40 | import sampleJs from "../samples/javascript.js?raw"; 41 | import sampleC from "../samples/c.c?raw"; 42 | import sampleCpp from "../samples/cpp.cpp?raw"; 43 | import sampleJava from "../samples/java.java?raw"; 44 | import sampleCsharp from "../samples/csharp.cs?raw"; 45 | import sampleRust from "../samples/rust.rs?raw"; 46 | import sampleGo from "../samples/go.go?raw"; 47 | import sampleVerilog from "../samples/verilog.v?raw"; 48 | import sampleSQL from "../samples/sql.sql?raw"; 49 | import sampleMongoDB from "../samples/mongodb.js?raw"; 50 | import sampleSwift from "../samples/swift.swift?raw"; 51 | import sampleRuby from "../samples/ruby.rb?raw"; 52 | import sampleTypeScript from "../samples/typescript.ts?raw"; 53 | import sampleDart from "../samples/dart.dart?raw"; 54 | import sampleKotlin from "../samples/kotlin.kt?raw"; 55 | import samplePerl from "../samples/perl.pl?raw"; 56 | import sampleScala from "../samples/scala.scala?raw"; 57 | import sampleJulia from "../samples/julia.jl?raw"; 58 | import sampleHtml from "../samples/index.html?raw"; 59 | import sampleCSS from "../samples/style.css?raw"; 60 | import sampleJavaScript from "../samples/script.js?raw"; 61 | 62 | const isAuthenticated = () => !!localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 63 | 64 | const htmlCode = { 65 | html: sampleHtml, 66 | css: sampleCSS, 67 | javascript: sampleJavaScript, 68 | }; 69 | 70 | const ProtectedRoute = ({ element }) => { 71 | return isAuthenticated() ? element : ; 72 | }; 73 | 74 | const RedirectedRoute = ({ element }) => { 75 | return !isAuthenticated() ? element : ; 76 | }; 77 | 78 | const GetUsername = () => { 79 | return localStorage.getItem(LOCAL_STORAGE_USERNAME_KEY) || ""; 80 | }; 81 | 82 | const languages = [ 83 | { 84 | path: "/python", 85 | language: "python", 86 | icon: IoLogoPython, 87 | sampleCode: samplePy, 88 | }, 89 | { 90 | path: "/javascript", 91 | language: "javascript", 92 | icon: SiJavascript, 93 | sampleCode: sampleJs, 94 | }, 95 | { 96 | path: "/c", 97 | language: "c", 98 | icon: PiFileCFill, 99 | sampleCode: sampleC, 100 | }, 101 | { 102 | path: "/cpp", 103 | language: "cpp", 104 | icon: PiFileCppFill, 105 | sampleCode: sampleCpp, 106 | }, 107 | { 108 | path: "/java", 109 | language: "java", 110 | icon: RiJavaFill, 111 | sampleCode: sampleJava, 112 | }, 113 | { 114 | path: "/csharp", 115 | language: "csharp", 116 | icon: PiFileCSharpFill, 117 | sampleCode: sampleCsharp, 118 | }, 119 | { 120 | path: "/rust", 121 | language: "rust", 122 | icon: SiRust, 123 | sampleCode: sampleRust, 124 | }, 125 | { 126 | path: "/go", 127 | language: "go", 128 | icon: FaGolang, 129 | sampleCode: sampleGo, 130 | }, 131 | { 132 | path: "/verilog", 133 | language: "verilog", 134 | icon: IoHardwareChipOutline, 135 | sampleCode: sampleVerilog, 136 | }, 137 | { 138 | path: "/sql", 139 | language: "sql", 140 | icon: PiFileSqlFill, 141 | sampleCode: sampleSQL, 142 | }, 143 | { 144 | path: "/mongodb", 145 | language: "mongodb", 146 | icon: SiMongodb, 147 | sampleCode: sampleMongoDB, 148 | }, 149 | { 150 | path: "/swift", 151 | language: "swift", 152 | icon: SiSwift, 153 | sampleCode: sampleSwift, 154 | }, 155 | { 156 | path: "/ruby", 157 | language: "ruby", 158 | icon: SiRuby, 159 | sampleCode: sampleRuby, 160 | }, 161 | { 162 | path: "/typescript", 163 | language: "typescript", 164 | icon: BiLogoTypescript, 165 | sampleCode: sampleTypeScript, 166 | }, 167 | { 168 | path: "/dart", 169 | language: "dart", 170 | icon: SiDart, 171 | sampleCode: sampleDart, 172 | }, 173 | { 174 | path: "/kotlin", 175 | language: "kotlin", 176 | icon: TbBrandKotlin, 177 | sampleCode: sampleKotlin, 178 | }, 179 | { 180 | path: "/perl", 181 | language: "perl", 182 | icon: SiPerl, 183 | sampleCode: samplePerl, 184 | }, 185 | { 186 | path: "/scala", 187 | language: "scala", 188 | icon: SiScala, 189 | sampleCode: sampleScala, 190 | }, 191 | { 192 | path: "/julia", 193 | language: "julia", 194 | icon: SiJulia, 195 | sampleCode: sampleJulia, 196 | }, 197 | ]; 198 | 199 | const EditorRoutes = ({ isDarkMode }) => ( 200 |
201 | 202 | } />} 205 | /> 206 | 207 | } />} /> 208 | 209 | } /> 210 | 211 | } />} 214 | /> 215 | 216 | } /> 217 | 218 | } 221 | /> 222 | 223 | } 226 | /> 227 | 228 | {languages.map(({ path, language, icon, sampleCode }) => ( 229 | 240 | } 241 | /> 242 | ))} 243 | 244 | } /> 245 | 246 |
247 | ); 248 | 249 | export default EditorRoutes; 250 | -------------------------------------------------------------------------------- /Backend/TempFile/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify, render_template, redirect, url_for 2 | from flask_cors import CORS 3 | import redis 4 | import os 5 | import uuid 6 | import json 7 | import jwt 8 | from functools import wraps 9 | from datetime import datetime, timedelta 10 | from dotenv import load_dotenv 11 | 12 | load_dotenv() 13 | 14 | app = Flask(__name__) 15 | CORS(app) 16 | 17 | TEMP_FILE_URL = os.getenv("TEMP_FILE_URL") 18 | SECRET_KEY = os.getenv("JWT_SECRET") 19 | 20 | 21 | def get_redis_connection(): 22 | try: 23 | redis_client = redis.StrictRedis( 24 | host=os.getenv("REDIS_HOST"), 25 | port=int(os.getenv("REDIS_PORT")), 26 | password=os.getenv("REDIS_PASSWORD"), 27 | ssl=True, 28 | ) 29 | redis_client.ping() 30 | return redis_client 31 | except redis.ConnectionError as e: 32 | app.logger.error(f"Redis connection error: {e}") 33 | return None 34 | 35 | 36 | def token_required(f): 37 | @wraps(f) 38 | def decorator(*args, **kwargs): 39 | token = None 40 | if "Authorization" in request.headers: 41 | auth_header = request.headers["Authorization"] 42 | if auth_header.startswith("Bearer "): 43 | token = auth_header.split(" ")[1] 44 | 45 | if not token: 46 | return jsonify({"message": "Token is missing!"}), 403 47 | 48 | try: 49 | decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS512"]) 50 | request.user_data = decoded 51 | except jwt.InvalidTokenError as e: 52 | return jsonify({"message": "Invalid token!"}), 401 53 | 54 | return f(*args, **kwargs) 55 | 56 | return decorator 57 | 58 | 59 | @app.route("/", methods=["GET"]) 60 | def index(): 61 | return render_template("index.html") 62 | 63 | 64 | @app.route("/temp-file-upload", methods=["POST"]) 65 | @token_required 66 | def upload_file(): 67 | redis_client = get_redis_connection() 68 | if not redis_client: 69 | return jsonify({"error": "Failed to connect to Redis"}), 503 70 | 71 | try: 72 | data = request.get_json() 73 | 74 | if ( 75 | not data 76 | or not data.get("code") 77 | or not data.get("language") 78 | or not data.get("title") 79 | or not data.get("expiryTime") 80 | ): 81 | return ( 82 | jsonify( 83 | {"error": "Code, language, title, and expiry time are required"} 84 | ), 85 | 400, 86 | ) 87 | 88 | valid_expiry_times = (10, 30, 60, 1440, 10080) 89 | expiry_time_minutes = int(data["expiryTime"]) 90 | 91 | if expiry_time_minutes not in valid_expiry_times: 92 | return ( 93 | jsonify({"error": "Invalid expiry time. Please choose a valid value."}), 94 | 400, 95 | ) 96 | 97 | code = data["code"] 98 | language = data["language"] 99 | title = data["title"] 100 | 101 | current_time = datetime.utcnow() 102 | expiry_time = current_time + timedelta(minutes=expiry_time_minutes) 103 | formatted_expiry_time = expiry_time.strftime("%Y-%m-%d %H:%M:%S UTC") 104 | 105 | file_id = str(uuid.uuid4()) 106 | 107 | file_data = { 108 | "title": title, 109 | "code": code, 110 | "language": language, 111 | "expiry_time": formatted_expiry_time, 112 | } 113 | 114 | redis_client.set( 115 | f"file:{language}-{file_id}:data", 116 | json.dumps(file_data), 117 | ex=expiry_time_minutes * 60, 118 | ) 119 | 120 | file_url = f"{TEMP_FILE_URL}/file/{language}-{file_id}" 121 | 122 | return jsonify( 123 | { 124 | "message": "Code uploaded successfully", 125 | "fileUrl": file_url, 126 | "expiry_time": formatted_expiry_time, 127 | } 128 | ) 129 | 130 | except redis.RedisError as e: 131 | app.logger.error(f"Redis error during file upload: {e}") 132 | return jsonify({"error": "Failed to store code in Redis"}), 500 133 | 134 | except Exception as e: 135 | app.logger.error(f"Unexpected error during file upload: {e}") 136 | return jsonify({"error": "An unexpected error occurred"}), 500 137 | 138 | finally: 139 | redis_client.close() 140 | 141 | 142 | @app.route("/file/", methods=["GET"]) 143 | def get_file(shareId): 144 | redis_client = get_redis_connection() 145 | if not redis_client: 146 | return jsonify({"error": "Failed to connect to Redis"}), 503 147 | 148 | try: 149 | header_shareId = request.headers.get("X-File-ID") 150 | 151 | if not header_shareId or header_shareId != shareId: 152 | return redirect(url_for('index')) 153 | 154 | try: 155 | language, file_id = shareId.split("-", 1) 156 | except ValueError: 157 | return jsonify({"error": "Invalid 'shareId' format. It should be 'language-file_id'."}), 400 158 | 159 | file_key = f"file:{language}-{file_id}:data" 160 | file_data = redis_client.get(file_key) 161 | ttl = redis_client.ttl(file_key) 162 | 163 | if ttl == -2: 164 | return jsonify({"error": "File not found"}), 404 165 | elif ttl == -1 or ttl == 0: 166 | return jsonify({"error": "File has expired"}), 410 167 | 168 | if file_data: 169 | file_data = json.loads(file_data) 170 | return jsonify(file_data), 200 171 | 172 | return jsonify({"error": "File not found"}), 404 173 | 174 | except redis.RedisError as e: 175 | app.logger.error(f"Redis error during file retrieval: {e}") 176 | return jsonify({"error": "Failed to retrieve code from Redis"}), 500 177 | 178 | except Exception as e: 179 | app.logger.error(f"Unexpected error during file retrieval: {e}") 180 | return jsonify({"error": "An unexpected error occurred"}), 500 181 | 182 | finally: 183 | redis_client.close() 184 | 185 | 186 | @app.route("/file//delete", methods=["DELETE"]) 187 | @token_required 188 | def delete_file(file_id): 189 | redis_client = get_redis_connection() 190 | if not redis_client: 191 | return jsonify({"error": "Failed to connect to Redis"}), 503 192 | 193 | try: 194 | language, file_id = file_id.split("-", 1) 195 | 196 | file_key = f"file:{language}-{file_id}:data" 197 | file_data = redis_client.get(file_key) 198 | 199 | if file_data: 200 | redis_client.delete(file_key) 201 | return jsonify({"message": "File deleted successfully"}), 200 202 | else: 203 | return jsonify({"error": "File not found"}), 404 204 | 205 | except redis.RedisError as e: 206 | app.logger.error(f"Redis error during file deletion: {e}") 207 | return jsonify({"error": "Failed to delete file from Redis"}), 500 208 | 209 | except Exception as e: 210 | app.logger.error(f"Unexpected error during file deletion: {e}") 211 | return jsonify({"error": "An unexpected error occurred"}), 500 212 | 213 | finally: 214 | redis_client.close() 215 | 216 | 217 | if __name__ == "__main__": 218 | app.run(debug=False) 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An Online IDE with login functionality enables users to run code, generate new code refactor existing code through secure login and share the code with anyone. 2 | 3 | ![Homepage](Images/Homepage.png) 4 | 5 | ![Lines of code](https://sloc.xyz/github/gladw-in/online-ide) 6 | 7 | ## Structure of a `.env` File 8 | 9 | ```dotenv 10 | #Frontend 11 | VITE_GEMINI_API_URL= 12 | VITE_BACKEND_API_URL= 13 | VITE_TEMP_SHARE_URL= #same as TEMP_FILE_URL 14 | 15 | #Login 16 | MONGO_URI= 17 | JWT_SECRET= 18 | PORT= 19 | OTP_EMAIL_SERVICE= 20 | OTP_EMAIL_USER= 21 | OTP_EMAIL_PASS= 22 | 23 | #GenAi 24 | GEMINI_API_KEY= 25 | GEMINI_MODEL= 26 | GEMINI_MODEL_1= 27 | JWT_SECRET= #same from Login 28 | 29 | #TempFile 30 | REDIS_HOST= 31 | REDIS_PASSWORD= 32 | REDIS_PORT=6379 33 | TEMP_FILE_URL= #same as VITE_TEMP_SHARE_URL 34 | JWT_SECRET= #same from Login 35 | ``` 36 | 37 | ## Diagram 38 | 39 | ![Diagram](Images/Diagram.png) 40 | 41 | ## Frontend Dependencies: 42 | - **[monaco-editor](https://microsoft.github.io/monaco-editor/)**: A fast code editor React wrapper, commonly used in applications like Visual Studio Code. 43 | - **[lodash](https://lodash.com/)**: A utility library with helpful functions for working with arrays, objects, and other JavaScript data types. 44 | - **[react](https://reactjs.org/)**: A JavaScript library for building declarative, component-based user interfaces. 45 | - **[react-icons](https://react-icons.github.io/react-icons/)**: A collection of customizable icons for React applications. 46 | - **[react-router](https://reactrouter.com/)**: A library for adding dynamic routing and navigation capabilities to React applications. 47 | - **[terser](https://github.com/terser/terser)**: A fast JavaScript minifier used with bundlers like Rollup to optimize file sizes. 48 | - **[sweetalert2](https://sweetalert2.github.io/)**: A customizable library for creating responsive, beautiful popup alerts in JavaScript applications. 49 | - **[sass](https://github.com/sass/sass)**: A modern version of Sass embedded for improved performance and support for advanced CSS features. 50 | - **[tailwindcss](https://tailwindcss.com/)**: A utility-first CSS framework designed for rapid styling with predefined classes. 51 | - **[tailwindcss-motion](https://github.com/romboHQ/tailwindcss-motion)**: A plugin for adding animations and transitions to Tailwind CSS projects. 52 | - **[vite](https://vitejs.dev/)**: A fast build tool and development server for modern frontend development, featuring hot module replacement (HMR). 53 | 54 | ## Backend Dependencies: 55 | - **[bcryptjs](https://github.com/dcodeIO/bcrypt.js)**: A JavaScript library for securely hashing passwords using the bcrypt algorithm. 56 | - **[body-parser](https://github.com/expressjs/body-parser)**: Middleware to parse incoming request bodies in JSON or URL-encoded format. 57 | - **[cors](https://expressjs.com/en/resources/middleware/cors.html)**: A Node.js package that enables Cross-Origin Resource Sharing (CORS) for handling requests from different origins. 58 | - **[dotenv](https://dotenvx.com/)**: A module that loads environment variables from a `.env` file into `process.env`. 59 | - **[express](https://expressjs.com/)**: A minimal and flexible Node.js web framework for building web and mobile applications. 60 | - **[jsonwebtoken](https://github.com/auth0/node-jsonwebtoken)**: A library for creating and verifying JSON Web Tokens (JWT) to securely transmit data between parties. 61 | - **[mongoose](https://mongoosejs.com/)**: A MongoDB Object Data Modeling (ODM) library for Node.js, offering schema-based data modeling. 62 | - **[crypto](https://nodejs.org/api/crypto.html)**: A Node.js core module that provides cryptographic functionality, such as hashing, HMAC, and encryption. 63 | - **[nodemailer](https://nodemailer.com/)**: A module for sending emails from Node.js applications using SMTP, with support for attachments and HTML content. 64 | - **[path](https://nodejs.org/api/path.html)**: A Node.js core module for working with file and directory paths. 65 | 66 | ## Python Libraries: 67 | - **[google-genai](https://ai.google.dev/gemini-api/docs/quickstart?lang=python)**: A collection of Google APIs and tools for integrating generative AI models into applications. 68 | - **[python-dotenv](https://pypi.org/project/python-dotenv/)**: A Python library for loading environment variables from a `.env` file into the environment. 69 | - **[flask_cors](https://flask-cors.readthedocs.io/en/latest/)**: A Flask extension to handle Cross-Origin Resource Sharing (CORS) and allow requests from different origins. 70 | - **[flask](https://flask.palletsprojects.com/)**: A lightweight Python web framework used for building web applications. 71 | - **[os](https://docs.python.org/3/library/os.html)**: A module in Python providing a way of using operating system-dependent functionality, such as reading or writing to the file system. 72 | - **[re](https://docs.python.org/3/library/re.html)**: A module in Python used for working with regular expressions, allowing pattern matching and text manipulation. 73 | - **[redis](https://pypi.org/project/redis/)**: A Python client for interacting with Redis, an in-memory data structure store, used for caching, message brokering, and more. 74 | - **[uuid](https://docs.python.org/3/library/uuid.html)**: A Python module for generating universally unique identifiers (UUIDs), useful for creating unique keys or identifiers. 75 | - **[datetime](https://docs.python.org/3/library/datetime.html)**: A module in Python for manipulating dates and times, including working with time zones and formatting. 76 | - **[pyjwt](https://pyjwt.readthedocs.io/en/stable/)**: A library for encoding and decoding JSON Web Tokens (JWT), commonly used for authentication in web applications. 77 | - **[functools](https://docs.python.org/3/library/functools.html)**: A module in Python providing higher-order functions to work with functions and callable objects, such as `wraps`. 78 | 79 | ## How to Set Up and Use 80 | 81 | To set up and run: 82 | 83 | ### What You Need 84 | 85 | - [Node.js](https://nodejs.org/) (latest version) 86 | - npm (usually comes with Node.js) 87 | - [Git](https://git-scm.com/) (version control system) 88 | - [Python](https://www.python.org/) (latest version) 89 | - [Pip](https://pip.pypa.io/en/stable/) Python package installer 90 | 91 | ## Clone the repository: 92 | ``` 93 | git clone --depth 1 https://github.com/gladw-in/online-ide.git 94 | ``` 95 | 96 | ## Backend Login 97 | 98 | 1. Go to the Backend/Login folder: 99 | ``` 100 | cd Backend/Login 101 | ``` 102 | 103 | 2. Install dependencies: 104 | ``` 105 | npm install 106 | ``` 107 | 108 | 3. Remember to have the **.env**. 109 | 110 | 4. Run the server: 111 | ``` 112 | node server.js 113 | ``` 114 | 115 | ### Note: 116 | Ensure that **Genai** and **TempFile** are assigned different ports. 117 | 118 | *You can modify the port by:* 119 | ```python 120 | if __name__ == "__main__": 121 | app.run(debug=False, port = ) 122 | ``` 123 | 124 | ## GenAi 125 | 126 | 1. Go to the Backend/Genai folder: 127 | ``` 128 | cd Backend/Genai 129 | ``` 130 | 131 | 2. Install packages: 132 | ``` 133 | pip install -r requirements.txt 134 | ``` 135 | 136 | 3. Remember to have the **.env**. 137 | 138 | 4. Run it: 139 | ``` 140 | python app.py 141 | ``` 142 | 143 | ## TempFile 144 | 145 | 1. Go to the Backend/TempFile folder: 146 | ``` 147 | cd Backend/TempFile 148 | ``` 149 | 150 | 2. Install packages: 151 | ``` 152 | pip install -r requirements.txt 153 | ``` 154 | 155 | 3. Remember to have the **.env**. 156 | 157 | 4. Run it: 158 | ``` 159 | python app.py 160 | ``` 161 | 162 | ## Frontend 163 | 164 | 1. Go to the Frontend folder: 165 | ``` 166 | cd ./Frontend 167 | ``` 168 | 169 | 2. Install dependencies: 170 | ``` 171 | npm install 172 | ``` 173 | 174 | 3. Remember to have the **.env**. 175 | 176 | ### For Development 177 | 178 | To start working on the project: 179 | 180 | ``` 181 | npm run dev 182 | ``` 183 | 184 | This starts the development server. Open your web browser and go to `http://localhost:5173` (or the address shown in your terminal) to see the app. 185 | 186 | ### Building for Release 187 | 188 | To make the project ready for release: 189 | 190 | ``` 191 | npm run build 192 | ``` 193 | 194 | This creates optimized files in the `dist` folder. 195 | 196 | ### Looking at the Release Version 197 | 198 | To see how the release version looks: 199 | 200 | ``` 201 | npm run preview 202 | ``` 203 | 204 | # Screenshots 205 | 206 | ### Homepage 207 | ![Homepage](Images/Homepage.png) 208 | 209 | ### HTML, CSS, JS 210 | ![HTML, CSS, JS](Images/HtmlCssJs.png) 211 | 212 | ### Python 213 | ![Python](Images/Python.png) 214 | 215 | ### JavaScript 216 | ![JavaScript](Images/Javascript.png) 217 | 218 | ### C 219 | ![C](Images/C.png) 220 | 221 | ### C++ 222 | ![C++](Images/Cplusplus.png) 223 | 224 | ### Java 225 | ![Java](Images/Java.png) 226 | 227 | ### C# 228 | ![C#](Images/CSharp.png) 229 | 230 | ### Rust 231 | ![Rust](Images/Rust.png) 232 | 233 | ### Go 234 | ![Go](Images/Go.png) 235 | 236 | ### Verilog 237 | ![Verilog](Images/Verilog.png) 238 | 239 | ### SQL 240 | ![SQL](Images/Sql.png) 241 | 242 | ### MongoDB 243 | ![MongoDB](Images/MongoDB.png) 244 | 245 | ### Swift 246 | ![Swift](Images/Swift.png) 247 | 248 | ### Typescript 249 | ![Typescript](Images/Typescript.png) 250 | 251 | ### Dart 252 | ![Dart](Images/Dart.png) 253 | 254 | ### Kotlin 255 | ![Kotlin](Images/Kotlin.png) 256 | 257 | ### Perl 258 | ![Perl](Images/Perl.png) 259 | 260 | ### Scala 261 | ![Scala](Images/Scala.png) 262 | 263 | ### Julia 264 | ![Julia](Images/Julia.png) 265 | 266 | ### Accounts 267 | ![Accounts](Images/Accounts.png) 268 | 269 | ### Login 270 | ![Login](Images/Login.png) 271 | 272 | ### Register 273 | ![Register](Images/Register.png) 274 | 275 | ## License 276 | 277 | You can use this under the MIT License. See [LICENSE](LICENSE) for more details. -------------------------------------------------------------------------------- /Frontend/src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { Link } from "react-router-dom"; 3 | import { FaSpinner, FaBarsStaggered } from "react-icons/fa6"; 4 | import { RxMoon, RxSun } from "react-icons/rx"; 5 | import Swal from "sweetalert2/dist/sweetalert2.js"; 6 | import "sweetalert2/src/sweetalert2.scss"; 7 | import { 8 | SESSION_STORAGE_SHARELINKS_KEY, 9 | SESSION_STORAGE_FETCH_STATUS_KEY, 10 | LOCAL_STORAGE_TOKEN_KEY, 11 | LOCAL_STORAGE_USERNAME_KEY, 12 | LOCAL_STORAGE_LOGIN_KEY, 13 | LOCAL_STORAGE_THEME_KEY, 14 | BACKEND_API_URL, 15 | } from "../utils/constants"; 16 | 17 | const Header = ({ isDarkMode, toggleTheme }) => { 18 | const [username, setUsername] = useState(""); 19 | const [isLoggedIn, setIsLoggedIn] = useState(false); 20 | const [isDropdownOpen, setIsDropdownOpen] = useState(false); 21 | const [isLoading, setLoading] = useState(true); 22 | 23 | const baseUrl = window.location.origin; 24 | 25 | const clearAuthState = () => { 26 | localStorage.removeItem(LOCAL_STORAGE_TOKEN_KEY); 27 | localStorage.removeItem(LOCAL_STORAGE_USERNAME_KEY); 28 | localStorage.removeItem(LOCAL_STORAGE_LOGIN_KEY); 29 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 30 | sessionStorage.removeItem(SESSION_STORAGE_FETCH_STATUS_KEY); 31 | }; 32 | 33 | useEffect(() => { 34 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 35 | const storedUsername = localStorage.getItem(LOCAL_STORAGE_USERNAME_KEY); 36 | const login = localStorage.getItem(LOCAL_STORAGE_LOGIN_KEY); 37 | 38 | if (token && storedUsername && login === "true") { 39 | fetchUserData(token, storedUsername); 40 | } else { 41 | clearAuthState(); 42 | setIsLoggedIn(false); 43 | setLoading(false); 44 | } 45 | }, []); 46 | 47 | useEffect(() => { 48 | (() => { 49 | const savedTheme = localStorage.getItem(LOCAL_STORAGE_THEME_KEY); 50 | const isDarkMode = savedTheme === "dark"; 51 | document.documentElement.classList.toggle("dark", isDarkMode); 52 | 53 | const validKeys = [ 54 | LOCAL_STORAGE_THEME_KEY, 55 | LOCAL_STORAGE_TOKEN_KEY, 56 | LOCAL_STORAGE_USERNAME_KEY, 57 | LOCAL_STORAGE_LOGIN_KEY, 58 | ]; 59 | 60 | window.addEventListener("storage", (event) => { 61 | if (validKeys.includes(event.key)) { 62 | location.reload(); 63 | } 64 | }); 65 | })(); 66 | }, []); 67 | 68 | const fetchUserData = async (token, storedUsername) => { 69 | try { 70 | const response = await fetch(`${BACKEND_API_URL}/api/protected`, { 71 | headers: { 72 | Authorization: `Bearer ${token}`, 73 | }, 74 | }); 75 | 76 | const data = await response.json(); 77 | 78 | if (data.username) { 79 | if (data.username !== storedUsername) { 80 | clearAuthState(); 81 | setIsLoggedIn(false); 82 | setUsername(""); 83 | location.reload(); 84 | return; 85 | } 86 | 87 | setUsername(data.username); 88 | setIsLoggedIn(true); 89 | } else { 90 | clearAuthState(); 91 | setIsLoggedIn(false); 92 | setUsername(""); 93 | location.reload(); 94 | } 95 | } catch (error) { 96 | location.reload(); 97 | } finally { 98 | setLoading(false); 99 | } 100 | }; 101 | 102 | const handleLogout = () => { 103 | Swal.fire({ 104 | title: "Are you sure?", 105 | icon: "warning", 106 | showCancelButton: true, 107 | confirmButtonText: "Yes, log me out!", 108 | cancelButtonText: "No, cancel!", 109 | confirmButtonColor: "#da4242", 110 | reverseButtons: true, 111 | allowOutsideClick: false, 112 | }).then((result) => { 113 | if (result.isConfirmed) { 114 | clearAuthState(); 115 | setIsLoggedIn(false); 116 | setUsername(""); 117 | location.reload(); 118 | } 119 | }); 120 | }; 121 | 122 | const formatUsername = (username) => { 123 | if (username.length > 15) { 124 | return `${username.slice(0, 5)}...${username.slice(-5)}`; 125 | } 126 | return username; 127 | }; 128 | 129 | useEffect(() => { 130 | if (isLoading) { 131 | document.body.classList.add("overflow-hidden"); 132 | } else { 133 | document.body.classList.remove("overflow-hidden"); 134 | } 135 | }, [isLoading]); 136 | 137 | return ( 138 | <> 139 | {isLoading && ( 140 |
141 |
142 | 143 | 144 | Loading... 145 | 146 |
147 |
148 | )} 149 | 150 |
151 |
152 | 157 | Online IDE 158 | 159 | 160 | 198 | 199 |
200 | 210 | 211 | 217 |
218 |
219 | 220 | 271 |
272 | 273 | ); 274 | }; 275 | 276 | export default Header; 277 | -------------------------------------------------------------------------------- /Frontend/src/components/ShareEditor.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState, useCallback, useRef } from "react"; 2 | import { useParams } from "react-router-dom"; 3 | import NotFound from "../pages/NotFound"; 4 | import CodeEditor from "./CodeEditor"; 5 | import Editor from "./Editor"; 6 | import { 7 | SESSION_STORAGE_FETCH_STATUS_KEY, 8 | SESSION_STORAGE_SHARELINKS_KEY, 9 | TEMP_SHARE_API_URL, 10 | GENAI_API_URL, 11 | BACKEND_API_URL, 12 | } from "../utils/constants"; 13 | import { FaSpinner, FaGolang } from "react-icons/fa6"; 14 | import { IoLogoPython, IoHardwareChipOutline } from "react-icons/io5"; 15 | import { 16 | SiJavascript, 17 | SiRust, 18 | SiMongodb, 19 | SiSwift, 20 | SiRuby, 21 | SiDart, 22 | SiPerl, 23 | SiScala, 24 | SiJulia, 25 | } from "react-icons/si"; 26 | import { RiJavaFill } from "react-icons/ri"; 27 | import { 28 | PiFileCppFill, 29 | PiFileCSharpFill, 30 | PiFileCFill, 31 | PiFileSqlFill, 32 | } from "react-icons/pi"; 33 | import { TbBrandKotlin } from "react-icons/tb"; 34 | import { BiLogoTypescript } from "react-icons/bi"; 35 | import { FiClipboard } from "react-icons/fi"; 36 | import { MdDone } from "react-icons/md"; 37 | 38 | const languageIcons = { 39 | python: IoLogoPython, 40 | javascript: SiJavascript, 41 | rust: SiRust, 42 | mongodb: SiMongodb, 43 | swift: SiSwift, 44 | ruby: SiRuby, 45 | dart: SiDart, 46 | perl: SiPerl, 47 | scala: SiScala, 48 | julia: SiJulia, 49 | go: FaGolang, 50 | java: RiJavaFill, 51 | cpp: PiFileCppFill, 52 | csharp: PiFileCSharpFill, 53 | c: PiFileCFill, 54 | sql: PiFileSqlFill, 55 | verilog: IoHardwareChipOutline, 56 | typescript: BiLogoTypescript, 57 | kotlin: TbBrandKotlin, 58 | }; 59 | 60 | const isUUIDMatch = (inputString) => { 61 | const regex = 62 | /(c|cpp|csharp|dart|go|htmlcssjs|java|javascript|julia|kotlin|mongodb|perl|python|ruby|rust|scala|sql|swift|typescript|verilog)-([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/; 63 | return regex.test(inputString); 64 | }; 65 | 66 | const ShareEditor = ({ isDarkMode }) => { 67 | const { shareId } = useParams(); 68 | const [copiedLink, setCopiedLink] = useState(false); 69 | const [state, setState] = useState({ 70 | code: "", 71 | language: "", 72 | expiryTime: null, 73 | title: "", 74 | shareIdNotFound: false, 75 | loading: true, 76 | }); 77 | 78 | const copyBtnTimeout = useRef(null); 79 | 80 | const { code, language, expiryTime, title, shareIdNotFound, loading } = state; 81 | 82 | const icon = languageIcons[language] || null; 83 | 84 | const formattedTitle = title 85 | ? `${title.charAt(0).toUpperCase()}${ 86 | title.length > 30 87 | ? title.slice(1, 30) + "..." + title.slice(-3) 88 | : title.slice(1) 89 | }` 90 | : ""; 91 | 92 | const formattedExpiryTime = expiryTime 93 | ? new Date(expiryTime).toLocaleString() 94 | : ""; 95 | 96 | const fetchCode = useCallback(async () => { 97 | if (!shareId) { 98 | setState((prev) => ({ 99 | ...prev, 100 | shareIdNotFound: true, 101 | loading: false, 102 | })); 103 | return; 104 | } 105 | 106 | const fetchStatus = sessionStorage.getItem( 107 | SESSION_STORAGE_FETCH_STATUS_KEY 108 | ); 109 | 110 | if (fetchStatus === "true") { 111 | const cachedData = sessionStorage.getItem(shareId); 112 | 113 | if (cachedData) { 114 | const { code, language, expiry_time, title } = JSON.parse(cachedData); 115 | 116 | setState({ 117 | code, 118 | language, 119 | expiryTime: expiry_time, 120 | title, 121 | shareIdNotFound: false, 122 | loading: false, 123 | }); 124 | return; 125 | } 126 | } 127 | 128 | try { 129 | setState((prev) => ({ ...prev, loading: true })); 130 | const response = await fetch(`${TEMP_SHARE_API_URL}/file/${shareId}`, { 131 | method: "GET", 132 | headers: { 133 | "Content-Type": "application/json", 134 | "X-File-ID": `${shareId}`, 135 | }, 136 | }); 137 | 138 | if (response.ok) { 139 | const data = await response.json(); 140 | 141 | if (data.error) { 142 | if (data.error === "File has expired") { 143 | setState({ 144 | code: "", 145 | language: "", 146 | expiryTime: null, 147 | title: "", 148 | shareIdNotFound: false, 149 | loading: false, 150 | }); 151 | 152 | deleteSharedLink(shareId); 153 | } else if (response.status === 404) { 154 | setState({ 155 | code: "", 156 | language: "", 157 | expiryTime: null, 158 | title: "", 159 | shareIdNotFound: true, 160 | loading: false, 161 | }); 162 | 163 | deleteSharedLink(shareId); 164 | } 165 | } else { 166 | setState({ 167 | code: data.code, 168 | language: data.language, 169 | expiryTime: data.expiry_time, 170 | title: data.title, 171 | shareIdNotFound: false, 172 | loading: false, 173 | }); 174 | 175 | sessionStorage.setItem( 176 | shareId, 177 | JSON.stringify({ 178 | code: data.code, 179 | language: data.language, 180 | expiry_time: data.expiry_time, 181 | title: data.title, 182 | }) 183 | ); 184 | sessionStorage.setItem(SESSION_STORAGE_FETCH_STATUS_KEY, "true"); 185 | } 186 | } else { 187 | setState({ 188 | code: "", 189 | language: "", 190 | expiryTime: null, 191 | title: "", 192 | shareIdNotFound: true, 193 | loading: false, 194 | }); 195 | 196 | deleteSharedLink(shareId); 197 | sessionStorage.setItem(SESSION_STORAGE_FETCH_STATUS_KEY, "false"); 198 | } 199 | } catch (error) { 200 | setState({ 201 | code: "", 202 | language: "", 203 | expiryTime: null, 204 | title: "", 205 | shareIdNotFound: true, 206 | loading: false, 207 | }); 208 | 209 | deleteSharedLink(shareId); 210 | sessionStorage.setItem(SESSION_STORAGE_FETCH_STATUS_KEY, "false"); 211 | } 212 | }, [shareId]); 213 | 214 | const deleteSharedLink = async (shareId) => { 215 | const linkResponse = await fetch(`${BACKEND_API_URL}/api/sharedLink`, { 216 | method: "DELETE", 217 | headers: { 218 | "Content-Type": "application/json", 219 | }, 220 | body: JSON.stringify({ shareId }), 221 | }); 222 | 223 | const responseJson = await linkResponse.json(); 224 | 225 | if (!linkResponse.ok) { 226 | throw new Error( 227 | `Error deleting shared link: ${linkResponse.status} - ${responseJson.msg}` 228 | ); 229 | } else { 230 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 231 | } 232 | }; 233 | 234 | useEffect(() => { 235 | if (!isUUIDMatch(shareId)) { 236 | setState({ 237 | code: "", 238 | language: "", 239 | expiryTime: null, 240 | title: "", 241 | shareIdNotFound: true, 242 | loading: false, 243 | }); 244 | return; 245 | } 246 | 247 | const cachedData = sessionStorage.getItem(shareId); 248 | 249 | if (cachedData) { 250 | const { expiry_time } = JSON.parse(cachedData); 251 | const expiryDate = new Date(expiry_time); 252 | const currentDate = new Date(); 253 | 254 | if (expiryDate < currentDate) { 255 | sessionStorage.removeItem(shareId); 256 | sessionStorage.setItem(SESSION_STORAGE_FETCH_STATUS_KEY, "false"); 257 | setState({ 258 | code: "", 259 | language: "", 260 | expiryTime: null, 261 | title: "", 262 | shareIdNotFound: true, 263 | loading: false, 264 | }); 265 | return; 266 | } 267 | 268 | const { code, language, title } = JSON.parse(cachedData); 269 | setState({ 270 | code, 271 | language, 272 | expiryTime: expiry_time, 273 | title, 274 | shareIdNotFound: false, 275 | loading: false, 276 | }); 277 | return; 278 | } 279 | 280 | fetchCode(); 281 | }, [shareId, fetchCode]); 282 | 283 | const handleCopyLink = async () => { 284 | if (!loading) { 285 | try { 286 | const shareLink = new URL(`${window.location.origin}/${shareId}`); 287 | await navigator.clipboard.writeText(shareLink.toString()); 288 | } catch (err) { 289 | Swal.fire({ 290 | title: "Failed to copy", 291 | text: "Could not copy the URL to clipboard.", 292 | icon: "error", 293 | }); 294 | } 295 | } 296 | 297 | if (copyBtnTimeout.current) { 298 | clearTimeout(copyBtnTimeout.current); 299 | } 300 | 301 | setCopiedLink(true); 302 | 303 | copyBtnTimeout.current = setTimeout(() => { 304 | setCopiedLink(false); 305 | }, 1500); 306 | }; 307 | 308 | if (loading) { 309 | return ( 310 |
311 |
312 | Loading 313 | 314 |
315 |
316 | ); 317 | } 318 | 319 | if (shareIdNotFound) { 320 | return ; 321 | } 322 | 323 | return ( 324 |
325 | {expiryTime && title && ( 326 |
327 |
328 | Title: 329 | {formattedTitle} 330 |
331 |
332 | Expires on: 333 | {formattedExpiryTime} 334 |
335 |
336 | 349 |
350 |
351 | )} 352 | 353 | {language === "htmlcssjs" ? ( 354 | 360 | ) : ( 361 | 370 | )} 371 |
372 | ); 373 | }; 374 | 375 | export default ShareEditor; 376 | -------------------------------------------------------------------------------- /Frontend/src/components/SharedLinks.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { 3 | SESSION_STORAGE_SHARELINKS_KEY, 4 | LOCAL_STORAGE_TOKEN_KEY, 5 | LOCAL_STORAGE_USERNAME_KEY, 6 | LOCAL_STORAGE_LOGIN_KEY, 7 | BACKEND_API_URL, 8 | TEMP_SHARE_API_URL, 9 | } from "../utils/constants"; 10 | import { Link } from "react-router-dom"; 11 | import { CgTrash } from "react-icons/cg"; 12 | import { HiRefresh } from "react-icons/hi"; 13 | import { FiClipboard, FiArrowLeft, FiArrowRight } from "react-icons/fi"; 14 | import { MdDone } from "react-icons/md"; 15 | import Swal from "sweetalert2/dist/sweetalert2.js"; 16 | 17 | const SharedLinks = () => { 18 | const [sharedLinks, setSharedLinks] = useState([]); 19 | const [isLoggedIn, setIsLoggedIn] = useState(false); 20 | const [buttonStates, setButtonStates] = useState({}); 21 | const [currentPage, setCurrentPage] = useState(1); 22 | const [isRefreshing, setIsRefreshing] = useState(false); 23 | 24 | const getItemsPerPage = () => { 25 | const width = window.innerWidth; 26 | if (width >= 1024) return 8; 27 | if (width >= 768) return 6; 28 | if (width >= 640) return 4; 29 | return 8; 30 | }; 31 | 32 | const [itemsPerPage, setItemsPerPage] = useState(getItemsPerPage()); 33 | 34 | const baseUrl = window.location.origin; 35 | 36 | const buttonColors = [ 37 | "bg-indigo-400", 38 | "bg-teal-400", 39 | "bg-yellow-400", 40 | "bg-red-400", 41 | "bg-purple-400", 42 | "bg-lime-400", 43 | "bg-green-400", 44 | "bg-pink-400", 45 | "bg-orange-400", 46 | "bg-blue-400", 47 | ]; 48 | 49 | const fetchSharedLinks = async () => { 50 | try { 51 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 52 | const isLogin = localStorage.getItem(LOCAL_STORAGE_LOGIN_KEY); 53 | 54 | if (!token || !isLogin) { 55 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 56 | return; 57 | } 58 | 59 | const response = await fetch(`${BACKEND_API_URL}/api/user/sharedLinks`, { 60 | method: "POST", 61 | headers: { 62 | "Content-Type": "application/json", 63 | Authorization: `Bearer ${token}`, 64 | }, 65 | }); 66 | 67 | if (!response.ok) 68 | throw new Error(`HTTP error! status: ${response.status}`); 69 | 70 | const data = await response.json(); 71 | 72 | if (data.sharedLinks && Array.isArray(data.sharedLinks)) { 73 | const reversedLinks = data.sharedLinks.reverse(); 74 | sessionStorage.setItem( 75 | SESSION_STORAGE_SHARELINKS_KEY, 76 | JSON.stringify(reversedLinks) 77 | ); 78 | setSharedLinks(reversedLinks); 79 | } 80 | } catch { 81 | Swal.fire("Error", "Error fetching shared links.", "error"); 82 | } 83 | }; 84 | 85 | const clearSessionData = (shareId) => { 86 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 87 | sessionStorage.removeItem(shareId); 88 | sessionStorage.removeItem(`__${shareId}Code__`); 89 | sessionStorage.removeItem(`__${shareId}Output__`); 90 | }; 91 | 92 | const handleDelete = async (shareId) => { 93 | Swal.fire({ 94 | title: "Are you sure?", 95 | text: "You won't be able to revert this action!", 96 | icon: "warning", 97 | reverseButtons: true, 98 | showCancelButton: true, 99 | confirmButtonText: "Yes, delete it!", 100 | confirmButtonColor: "#da4242", 101 | cancelButtonText: "Cancel", 102 | allowOutsideClick: false, 103 | }).then(async (result) => { 104 | if (result.isConfirmed) { 105 | Swal.fire({ 106 | title: "Deleting...", 107 | text: "Please wait while your code is being deleted.", 108 | allowOutsideClick: false, 109 | didOpen: () => { 110 | Swal.showLoading(); 111 | }, 112 | }); 113 | 114 | const linkResponse = await fetch( 115 | `${BACKEND_API_URL}/api/user/sharedLink/${shareId}`, 116 | { 117 | method: "DELETE", 118 | } 119 | ); 120 | 121 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 122 | 123 | const fileResponse = await fetch( 124 | `${TEMP_SHARE_API_URL}/file/${shareId}/delete`, 125 | { 126 | method: "DELETE", 127 | headers: { 128 | Authorization: `Bearer ${token}`, 129 | }, 130 | } 131 | ); 132 | 133 | if (!fileResponse.ok && !linkResponse.ok) { 134 | Swal.close(); 135 | Swal.fire("Error", "There was an issue deleting the link.", "error"); 136 | clearSessionData(shareId); 137 | return; 138 | } 139 | 140 | if (fileResponse.ok || linkResponse.ok) { 141 | Swal.close(); 142 | Swal.fire({ 143 | title: "Deleted!", 144 | text: "The link has been deleted.", 145 | icon: "success", 146 | timer: 3000, 147 | }); 148 | 149 | sessionStorage.removeItem(shareId); 150 | sessionStorage.removeItem(`__${shareId}Code__`); 151 | sessionStorage.removeItem(`__${shareId}Output__`); 152 | 153 | setSharedLinks((prevLinks) => 154 | prevLinks.filter((link) => link.shareId !== shareId) 155 | ); 156 | 157 | const updatedLinks = sharedLinks.filter( 158 | (link) => link.shareId !== shareId 159 | ); 160 | 161 | const totalPages = Math.ceil(updatedLinks.length / itemsPerPage); 162 | 163 | if (currentPage > totalPages) { 164 | setCurrentPage(totalPages); 165 | } else { 166 | const currentPageStartIndex = (currentPage - 1) * itemsPerPage; 167 | if (updatedLinks.length <= currentPageStartIndex) { 168 | setCurrentPage(Math.max(currentPage - 1, 1)); 169 | } 170 | } 171 | clearSessionData(shareId); 172 | } else { 173 | Swal.close(); 174 | Swal.fire( 175 | "Error", 176 | "Failed to delete link. Refresh and try again.", 177 | "error" 178 | ); 179 | } 180 | clearSessionData(shareId); 181 | } 182 | }); 183 | }; 184 | 185 | const handleCopy = async (shareId) => { 186 | try { 187 | const url = `${baseUrl}/${shareId}`; 188 | await navigator.clipboard.writeText(url.toString()); 189 | } catch (err) { 190 | Swal.fire({ 191 | icon: "error", 192 | title: "Failed to copy", 193 | text: "Could not copy the URL to clipboard.", 194 | }); 195 | } 196 | 197 | if (buttonStates[shareId]?.timeout) { 198 | clearTimeout(buttonStates[shareId].timeout); 199 | } 200 | 201 | setButtonStates((prev) => ({ 202 | ...prev, 203 | [shareId]: { text: "Copied", icon: , timeout: null }, 204 | })); 205 | 206 | const timeout = setTimeout(() => { 207 | setButtonStates((prev) => ({ 208 | ...prev, 209 | [shareId]: { text: "Copy", icon: }, 210 | })); 211 | }, 1500); 212 | 213 | setButtonStates((prev) => ({ 214 | ...prev, 215 | [shareId]: { ...prev[shareId], timeout }, 216 | })); 217 | }; 218 | 219 | const handleRefresh = () => { 220 | let refreshTimeout; 221 | 222 | if (refreshTimeout) { 223 | clearTimeout(refreshTimeout); 224 | } 225 | 226 | setIsRefreshing(true); 227 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 228 | fetchSharedLinks(); 229 | 230 | refreshTimeout = setTimeout(() => { 231 | setIsRefreshing(false); 232 | }, 500); 233 | }; 234 | 235 | const handleNext = () => { 236 | setCurrentPage((prev) => 237 | Math.min(prev + 1, Math.ceil(sharedLinks.length / itemsPerPage)) 238 | ); 239 | }; 240 | 241 | const handlePrev = () => { 242 | setCurrentPage((prev) => Math.max(prev - 1, 1)); 243 | }; 244 | 245 | useEffect(() => { 246 | const isLogin = localStorage.getItem(LOCAL_STORAGE_LOGIN_KEY); 247 | 248 | if (!isLogin) { 249 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 250 | setIsLoggedIn(false); 251 | return; 252 | } 253 | 254 | const username = localStorage.getItem(LOCAL_STORAGE_USERNAME_KEY); 255 | if (username) { 256 | setIsLoggedIn(true); 257 | } else { 258 | setIsLoggedIn(false); 259 | } 260 | 261 | if (!isLoggedIn) { 262 | return; 263 | } 264 | 265 | const sharedLink = sessionStorage.getItem(SESSION_STORAGE_SHARELINKS_KEY); 266 | if (sharedLink === null || sharedLink === "[]") { 267 | fetchSharedLinks(); 268 | } else { 269 | setSharedLinks(JSON.parse(sharedLink)); 270 | } 271 | 272 | const handleResize = () => { 273 | setItemsPerPage(getItemsPerPage()); 274 | }; 275 | 276 | window.addEventListener("resize", handleResize); 277 | 278 | return () => { 279 | window.removeEventListener("resize", handleResize); 280 | }; 281 | }, [isLoggedIn]); 282 | 283 | const startIndex = (currentPage - 1) * itemsPerPage; 284 | const visibleLinks = sharedLinks.slice(startIndex, startIndex + itemsPerPage); 285 | 286 | return ( 287 |
288 |
289 |
290 | {isLoggedIn && visibleLinks.length > 0 && ( 291 |
292 |

293 | Shared Links 294 |

295 | 305 |
306 | )} 307 | 308 | {isLoggedIn && visibleLinks.length > 0 && ( 309 |
310 | {visibleLinks.map(({ title, shareId, expiryTime }, index) => { 311 | const colorClass = buttonColors[index % buttonColors.length]; 312 | return ( 313 |
314 |
315 | 323 | {title 324 | ? `${title.charAt(0).toUpperCase()}${ 325 | title.length > 30 326 | ? title.slice(1, 30) + "..." + title.slice(-3) 327 | : title.slice(1) 328 | }` 329 | : "Untitled"} 330 | 331 | 332 |
333 | 344 | 345 | 352 |
353 |
354 |
355 | ); 356 | })} 357 |
358 | )} 359 | 360 | {isLoggedIn && sharedLinks.length > itemsPerPage && ( 361 |
362 | 370 | 378 |
379 | )} 380 |
381 |
382 |
383 | ); 384 | }; 385 | 386 | export default SharedLinks; 387 | -------------------------------------------------------------------------------- /Frontend/src/pages/Register.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | import { AiOutlineExclamationCircle } from "react-icons/ai"; 4 | import { TbLoader } from "react-icons/tb"; 5 | import InputField from "../utils/InputField"; 6 | import OtpInputForm from "../utils/OtpInputForm"; 7 | import { 8 | SESSION_STORAGE_SHARELINKS_KEY, 9 | LOCAL_STORAGE_TOKEN_KEY, 10 | LOCAL_STORAGE_USERNAME_KEY, 11 | LOCAL_STORAGE_LOGIN_KEY, 12 | BACKEND_API_URL, 13 | USERNAME_REGEX, 14 | EMAIL_REGEX, 15 | PASSWORD_REGEX, 16 | } from "../utils/constants"; 17 | 18 | const Register = () => { 19 | const [formData, setFormData] = useState({ 20 | username: "", 21 | email: "", 22 | newPassword: "", 23 | }); 24 | const [error, setError] = useState(""); 25 | const [loading, setLoading] = useState(false); 26 | const [showPassword, setShowPassword] = useState(false); 27 | const [isRegistered, setIsRegistered] = useState(false); 28 | const [otpSent, setOtpSent] = useState(false); 29 | const [otp, setOtp] = useState(""); 30 | const [otpError, setOtpError] = useState(""); 31 | const [otpResent, setOtpResent] = useState(false); 32 | const [otpResendError, setOtpResendError] = useState(""); 33 | const [canResendOtp, setCanResendOtp] = useState(true); 34 | const [countdown, setCountdown] = useState(30); 35 | const [otpLoading, setOtpLoading] = useState(false); 36 | const [resendOtpLoading, setResendOtpLoading] = useState(false); 37 | const [wrongEmailLoading, setWrongEmailLoading] = useState(false); 38 | 39 | const navigate = useNavigate(); 40 | 41 | useEffect(() => { 42 | document.title = "Register"; 43 | }, []); 44 | 45 | const handleInputChange = (e) => { 46 | const { name, value } = e.target; 47 | setFormData((prevData) => ({ 48 | ...prevData, 49 | [name]: value, 50 | })); 51 | 52 | if (error) { 53 | setError(""); 54 | } 55 | }; 56 | 57 | const handleClearOTPEror = () => { 58 | if (otpError) { 59 | setOtpError(""); 60 | } 61 | 62 | if (otpResendError) { 63 | setOtpResent(false); 64 | setOtpResendError(""); 65 | } 66 | }; 67 | 68 | const validateForm = () => { 69 | const email = formData.email.trim(); 70 | const username = formData.username.trim(); 71 | const newPassword = formData.newPassword.trim(); 72 | 73 | if (!EMAIL_REGEX.test(email)) { 74 | setError("Invalid email format"); 75 | return false; 76 | } 77 | 78 | if (!USERNAME_REGEX.test(username)) { 79 | setError( 80 | "Username can only contain letters, numbers, underscores, hyphens, and periods (5-30 characters)." 81 | ); 82 | return false; 83 | } 84 | 85 | if (username.length < 5 || username.length > 30) { 86 | setError("Username should be between 5 and 30 characters"); 87 | return false; 88 | } 89 | 90 | if (newPassword.length < 8) { 91 | setError("Password must be at least 8 characters long"); 92 | return false; 93 | } 94 | 95 | if (!PASSWORD_REGEX.test(newPassword)) { 96 | setError("Invalid password format"); 97 | return false; 98 | } 99 | 100 | return true; 101 | }; 102 | 103 | const handleOtpChange = (newOtp) => { 104 | setOtp(newOtp); 105 | if (error) { 106 | setError(""); 107 | } 108 | }; 109 | 110 | const handleSubmit = async (e) => { 111 | e.preventDefault(); 112 | 113 | if (!validateForm()) return; 114 | 115 | setLoading(true); 116 | 117 | const { username, email, newPassword } = formData; 118 | 119 | try { 120 | const response = await fetch(`${BACKEND_API_URL}/api/register`, { 121 | method: "POST", 122 | headers: { 123 | "Content-Type": "application/json", 124 | }, 125 | body: JSON.stringify({ 126 | username: username.trim(), 127 | email: email.trim(), 128 | password: newPassword.trim(), 129 | }), 130 | }); 131 | 132 | if (!response.ok) { 133 | const errorData = await response.json(); 134 | 135 | if (errorData.msg === "Email not verified.") { 136 | setOtpSent(true); 137 | setLoading(false); 138 | setIsRegistered(true); 139 | return; 140 | } else { 141 | throw new Error(errorData.msg || "Server error, please try again."); 142 | } 143 | } 144 | 145 | setOtpSent(true); 146 | setLoading(false); 147 | setIsRegistered(true); 148 | setOtpResent(true); 149 | } catch (err) { 150 | setError(err.message || "Server error, please try again."); 151 | setLoading(false); 152 | } 153 | }; 154 | 155 | const handleOtpSubmit = async (e) => { 156 | e.preventDefault(); 157 | setOtpLoading(true); 158 | 159 | try { 160 | const response = await fetch(`${BACKEND_API_URL}/api/verify-otp`, { 161 | method: "POST", 162 | headers: { 163 | "Content-Type": "application/json", 164 | }, 165 | body: JSON.stringify({ 166 | email: formData.email.trim(), 167 | otp: otp.trim?.() ?? otp, 168 | password: formData.newPassword.trim(), 169 | }), 170 | }); 171 | 172 | if (!response.ok) { 173 | const errorData = await response.json(); 174 | throw new Error(errorData.msg || "OTP verification failed."); 175 | } 176 | 177 | const data = await response.json(); 178 | 179 | localStorage.setItem(LOCAL_STORAGE_TOKEN_KEY, data.token); 180 | localStorage.setItem(LOCAL_STORAGE_USERNAME_KEY, data.username); 181 | localStorage.setItem(LOCAL_STORAGE_LOGIN_KEY, "true"); 182 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 183 | 184 | navigate(window.history.length > 2 ? -1 : "/"); 185 | location.reload(); 186 | } catch (err) { 187 | setOtpError(err.msg || "OTP verification failed."); 188 | } finally { 189 | setOtpLoading(false); 190 | } 191 | }; 192 | 193 | const handleResendOtp = async () => { 194 | setResendOtpLoading(true); 195 | setOtpResent(false); 196 | setOtpResendError(""); 197 | 198 | try { 199 | const response = await fetch(`${BACKEND_API_URL}/api/resend-otp`, { 200 | method: "POST", 201 | headers: { 202 | "Content-Type": "application/json", 203 | }, 204 | body: JSON.stringify({ 205 | email: formData.email.trim(), 206 | }), 207 | }); 208 | 209 | if (!response.ok) { 210 | const errorData = await response.json(); 211 | throw new Error(errorData.msg || "Error resending OTP."); 212 | } 213 | 214 | setOtpResent(true); 215 | setCanResendOtp(false); 216 | setCountdown(30); 217 | } catch (err) { 218 | setOtpResent(false); 219 | setOtpResendError(err.message || "Server error while resending OTP."); 220 | } finally { 221 | handleClearOTPEror(); 222 | setResendOtpLoading(false); 223 | } 224 | }; 225 | 226 | const handleWrongEmail = async () => { 227 | try { 228 | setWrongEmailLoading(true); 229 | 230 | const response = await fetch(`${BACKEND_API_URL}/api/wrong-email`, { 231 | method: "DELETE", 232 | headers: { 233 | "Content-Type": "application/json", 234 | }, 235 | body: JSON.stringify({ 236 | email: formData.email.trim(), 237 | }), 238 | }); 239 | 240 | const data = await response.json(); 241 | 242 | if (response.ok || data.msg == "User not found") { 243 | setTimeout(() => { 244 | navigate("/register"); 245 | location.reload(); 246 | }, 200); 247 | } else { 248 | setError(data.msg); 249 | } 250 | } catch (err) { 251 | setError("Error deleting the account, please try again."); 252 | } finally { 253 | setWrongEmailLoading(false); 254 | } 255 | }; 256 | 257 | useEffect(() => { 258 | let timer; 259 | if (!canResendOtp) { 260 | timer = setInterval(() => { 261 | setCountdown((prev) => { 262 | if (prev === 1) { 263 | clearInterval(timer); 264 | setCanResendOtp(true); 265 | } 266 | return prev - 1; 267 | }); 268 | }, 1000); 269 | } 270 | return () => clearInterval(timer); 271 | }, [canResendOtp]); 272 | 273 | return ( 274 |
275 |
276 |

277 | {isRegistered ? "Email Verification" : "Register"} 278 |

279 | 280 | {isRegistered && ( 281 |
282 |
283 | 284 |

285 | Please check your email for the OTP. If you don't see it, be 286 | sure to check your{" "} 287 | spam folder.{" "} 288 | 289 | If the OTP doesn't appear in your inbox, try using a different 290 | email address. 291 | 292 |

293 |
294 |
295 | )} 296 | 297 | {!otpSent ? ( 298 |
299 | 307 | 308 |
309 | 317 |
318 | 319 | setShowPassword((prev) => !prev)} 328 | /> 329 | 330 | {error && ( 331 |

332 | {error} 333 |

334 | )} 335 | 336 | 350 | 351 | ) : ( 352 | 353 | )} 354 | 355 | {otpError && ( 356 |

357 | {otpError} 358 |

359 | )} 360 | 361 | {otpResent && !otpError && ( 362 |

363 | OTP resent successfully! Check your email. 364 |

365 | )} 366 | 367 | {otpResendError && ( 368 |

369 | {otpResendError} 370 |

371 | )} 372 | 373 | {otpSent && ( 374 | <> 375 | 390 |
391 | 408 | 409 | 424 |
425 | 426 | )} 427 | 428 | {!isRegistered && !otpSent && ( 429 |
430 |

431 | Already have an account?{" "} 432 | 438 |

439 |
440 | )} 441 |
442 |
443 | ); 444 | }; 445 | 446 | export default Register; 447 | -------------------------------------------------------------------------------- /Frontend/src/pages/ForgotPassword.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | import { AiOutlineExclamationCircle } from "react-icons/ai"; 4 | import { TbLoader } from "react-icons/tb"; 5 | import InputField from "../utils/InputField"; 6 | import OtpInputForm from "../utils/OtpInputForm"; 7 | import { 8 | SESSION_STORAGE_SHARELINKS_KEY, 9 | SESSION_STORAGE_FETCH_STATUS_KEY, 10 | LOCAL_STORAGE_TOKEN_KEY, 11 | LOCAL_STORAGE_USERNAME_KEY, 12 | LOCAL_STORAGE_LOGIN_KEY, 13 | BACKEND_API_URL, 14 | EMAIL_REGEX, 15 | PASSWORD_REGEX, 16 | } from "../utils/constants"; 17 | 18 | const ForgotPassword = () => { 19 | const [email, setEmail] = useState(""); 20 | const [otp, setOtp] = useState(""); 21 | const [showConfirmPassword, setShowconfirmPassword] = useState(false); 22 | const [shownewPassword, setshownewPassword] = useState(false); 23 | const [newPassword, setNewPassword] = useState(""); 24 | const [confirmPassword, setConfirmPassword] = useState(""); 25 | const [isLogin, setIsLogin] = useState(false); 26 | const [error, setError] = useState(""); 27 | const [success, setSuccess] = useState(""); 28 | const [loading, setLoading] = useState(false); 29 | const [emailVerified, setEmailVerified] = useState(false); 30 | const [otpVerified, setOtpVerified] = useState(false); 31 | const [otpResent, setOtpResent] = useState(false); 32 | const [otpResendError, setOtpResendError] = useState(""); 33 | const [canResendOtp, setCanResendOtp] = useState(true); 34 | const [resendOtpLoading, setResendOtpLoading] = useState(false); 35 | const [countdown, setCountdown] = useState(30); 36 | 37 | const navigate = useNavigate(); 38 | 39 | useEffect(() => { 40 | document.title = 41 | emailVerified && !otpVerified 42 | ? "OTP Verification" 43 | : otpVerified 44 | ? "Set New Password" 45 | : "Forgot Password"; 46 | }, [emailVerified, otpVerified]); 47 | 48 | useEffect(() => { 49 | const token = localStorage.getItem(LOCAL_STORAGE_LOGIN_KEY); 50 | setIsLogin(!!token); 51 | }, []); 52 | 53 | const handleInputChange = (e) => { 54 | const { name, value } = e.target; 55 | if (name === "email") { 56 | setEmail(value); 57 | } else if (name === "newPassword") { 58 | setNewPassword(value); 59 | } else if (name === "confirmPassword") { 60 | setConfirmPassword(value); 61 | } 62 | if (error) { 63 | setError(""); 64 | } 65 | }; 66 | 67 | const handleClearOTPEror = () => { 68 | if (otpResendError) { 69 | setOtpResendError(""); 70 | } 71 | }; 72 | 73 | const handleOtpChange = (newOtp) => { 74 | setOtp(newOtp); 75 | if (error) { 76 | setError(""); 77 | } 78 | }; 79 | 80 | const handleSubmitEmail = async (e) => { 81 | e.preventDefault(); 82 | if (!email) { 83 | setError("Please enter your email."); 84 | return; 85 | } 86 | 87 | if (!EMAIL_REGEX.test(email)) { 88 | setError("Invalid email format"); 89 | return false; 90 | } 91 | 92 | setLoading(true); 93 | 94 | try { 95 | const emailCheckResponse = await fetch( 96 | `${BACKEND_API_URL}/api/check-email-exists`, 97 | { 98 | method: "POST", 99 | headers: { 100 | "Content-Type": "application/json", 101 | }, 102 | body: JSON.stringify({ email: email.trim() }), 103 | } 104 | ); 105 | 106 | if (!emailCheckResponse.ok) { 107 | const data = await emailCheckResponse.json(); 108 | setError(data.msg || "Email not found."); 109 | return; 110 | } 111 | 112 | const response = await fetch(`${BACKEND_API_URL}/api/forgot-password`, { 113 | method: "POST", 114 | headers: { 115 | "Content-Type": "application/json", 116 | }, 117 | body: JSON.stringify({ email: email.trim() }), 118 | }); 119 | 120 | if (!response.ok) { 121 | const data = await response.json(); 122 | setError(data.msg || "Server error, please try again."); 123 | return; 124 | } 125 | 126 | const data = await response.json(); 127 | setSuccess("OTP Sent Successfully"); 128 | setEmailVerified(true); 129 | setOtpResent(true); 130 | } catch (err) { 131 | setError("Server error, please try again."); 132 | } finally { 133 | setLoading(false); 134 | } 135 | }; 136 | 137 | const handleResendOtp = async () => { 138 | setResendOtpLoading(true); 139 | setOtpResendError(""); 140 | 141 | try { 142 | const response = await fetch( 143 | `${BACKEND_API_URL}/api/resend-otp?forgot-password=true`, 144 | { 145 | method: "POST", 146 | headers: { 147 | "Content-Type": "application/json", 148 | }, 149 | body: JSON.stringify({ 150 | email: email.trim(), 151 | }), 152 | } 153 | ); 154 | 155 | if (!response.ok) { 156 | const errorData = await response.json(); 157 | throw new Error(errorData.msg || "Error resending OTP."); 158 | } 159 | 160 | setOtpResent(true); 161 | setCanResendOtp(false); 162 | setCountdown(30); 163 | setSuccess("OTP resent successfully! Check your email."); 164 | } catch (err) { 165 | setOtpResendError(err.message || "Server error while resending OTP."); 166 | } finally { 167 | handleClearOTPEror(); 168 | setResendOtpLoading(false); 169 | } 170 | }; 171 | 172 | useEffect(() => { 173 | let timer; 174 | if (!canResendOtp) { 175 | timer = setInterval(() => { 176 | setCountdown((prev) => { 177 | if (prev === 1) { 178 | clearInterval(timer); 179 | setCanResendOtp(true); 180 | } 181 | return prev - 1; 182 | }); 183 | }, 1000); 184 | } 185 | return () => clearInterval(timer); 186 | }, [canResendOtp]); 187 | 188 | const handleSubmitOtp = async (e) => { 189 | e.preventDefault(); 190 | if (!otp) { 191 | setError("Please enter the OTP."); 192 | return; 193 | } 194 | 195 | setLoading(true); 196 | 197 | try { 198 | const response = await fetch(`${BACKEND_API_URL}/api/reset-password`, { 199 | method: "POST", 200 | headers: { 201 | "Content-Type": "application/json", 202 | }, 203 | body: JSON.stringify({ 204 | email: email.trim(), 205 | otp: otp.trim?.() ?? otp, 206 | }), 207 | }); 208 | 209 | if (!response.ok) { 210 | const data = await response.json(); 211 | setError(data.msg || "Invalid OTP or OTP expired."); 212 | return; 213 | } 214 | 215 | const data = await response.json(); 216 | setSuccess("OTP Verified Successfully"); 217 | setOtpVerified(true); 218 | } catch (err) { 219 | setError("Server error, please try again."); 220 | } finally { 221 | setLoading(false); 222 | } 223 | }; 224 | 225 | const handleSubmitNewPassword = async (e) => { 226 | e.preventDefault(); 227 | if (newPassword !== confirmPassword) { 228 | setError("Passwords do not match."); 229 | return; 230 | } 231 | 232 | if (newPassword.length < 8 || confirmPassword.length < 8) { 233 | setError("Password must be at least 8 characters long."); 234 | return; 235 | } 236 | 237 | if ( 238 | !PASSWORD_REGEX.test(newPassword) || 239 | !PASSWORD_REGEX.test(confirmPassword) 240 | ) { 241 | setError("Invalid password format"); 242 | return false; 243 | } 244 | 245 | setLoading(true); 246 | 247 | try { 248 | const response = await fetch(`${BACKEND_API_URL}/api/update-password`, { 249 | method: "POST", 250 | headers: { 251 | "Content-Type": "application/json", 252 | }, 253 | body: JSON.stringify({ 254 | email: email.trim(), 255 | otp: otp.trim?.() ?? otp, 256 | password: newPassword.trim(), 257 | }), 258 | }); 259 | 260 | if (!response.ok) { 261 | const data = await response.json(); 262 | setError(data.msg || "Error updating password."); 263 | return; 264 | } 265 | 266 | const data = await response.json(); 267 | setSuccess("Password reset successfully"); 268 | 269 | setTimeout(() => { 270 | navigate("/login"); 271 | localStorage.removeItem(LOCAL_STORAGE_TOKEN_KEY); 272 | localStorage.removeItem(LOCAL_STORAGE_USERNAME_KEY); 273 | localStorage.removeItem(LOCAL_STORAGE_LOGIN_KEY); 274 | sessionStorage.removeItem(SESSION_STORAGE_FETCH_STATUS_KEY); 275 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 276 | 277 | location.reload(); 278 | }, 500); 279 | } catch (err) { 280 | setError("Server error, please try again."); 281 | } finally { 282 | setLoading(false); 283 | } 284 | }; 285 | 286 | return ( 287 |
288 |
289 |

290 | {emailVerified && !otpVerified 291 | ? "OTP Verification" 292 | : otpVerified 293 | ? "Set New Password" 294 | : "Forgot Password"} 295 |

296 | 297 | {!emailVerified && ( 298 |
299 | 307 | 308 | {error && ( 309 |

310 | {error} 311 |

312 | )} 313 | 314 | {otpResent && !error && ( 315 |

316 | OTP resent successfully! Check your email. 317 |

318 | )} 319 | 320 | {success && ( 321 |

322 | {success} 323 |

324 | )} 325 | 326 | 340 | 341 | )} 342 | 343 | {emailVerified && !otpVerified && ( 344 |
345 |
346 |
347 | 348 |

349 | Please check your email for the OTP. If you don't see it, be 350 | sure to check your{" "} 351 | spam folder.{" "} 352 | 353 | If the OTP doesn't appear in your inbox, try using a 354 | different email address. 355 | 356 |

357 |
358 |
359 | {" "} 360 | {error && ( 361 |

362 | {error} 363 |

364 | )} 365 | {success && ( 366 |

367 | {success} 368 |

369 | )} 370 | 384 | 401 | 402 | )} 403 | 404 | {otpVerified && ( 405 |
406 | setshownewPassword((prev) => !prev)} 415 | /> 416 | 417 | setShowconfirmPassword((prev) => !prev)} 426 | /> 427 | 428 | {error && ( 429 |

430 | {error} 431 |

432 | )} 433 | 434 | {success && ( 435 |

436 | {success} 437 |

438 | )} 439 | 440 | 454 | 455 | )} 456 | 457 | {!isLogin && ( 458 |
459 |

460 | 466 |

467 |
468 | )} 469 |
470 |
471 | ); 472 | }; 473 | 474 | export default ForgotPassword; 475 | -------------------------------------------------------------------------------- /Frontend/src/pages/Accounts.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import InputField from "../utils/InputField"; 3 | import { 4 | SESSION_STORAGE_SHARELINKS_KEY, 5 | LOCAL_STORAGE_TOKEN_KEY, 6 | LOCAL_STORAGE_USERNAME_KEY, 7 | LOCAL_STORAGE_LOGIN_KEY, 8 | BACKEND_API_URL, 9 | USERNAME_REGEX, 10 | PASSWORD_REGEX, 11 | } from "../utils/constants"; 12 | import { useNavigate } from "react-router-dom"; 13 | import { TbLoader } from "react-icons/tb"; 14 | import Swal from "sweetalert2/dist/sweetalert2.js"; 15 | 16 | const Accounts = () => { 17 | const [formData, setFormData] = useState({ 18 | username: "", 19 | email: "", 20 | password: "", 21 | newPassword: "", 22 | confirmPassword: "", 23 | currentPassword: "", 24 | }); 25 | const [errorMessage, setErrorMessage] = useState(""); 26 | const [isPasswordVerified, setIsPasswordVerified] = useState(false); 27 | const [showCurrentPassword, setShowCurrentPassword] = useState(false); 28 | const [showNewPassword, setShowNewPassword] = useState(false); 29 | const [showConfirmPassword, setShowConfirmPassword] = useState(false); 30 | const [delBtnText, setDelBtnText] = useState("Delete Account"); 31 | const [btnState, setBtnState] = useState(false); 32 | 33 | const navigate = useNavigate(); 34 | 35 | useEffect(() => { 36 | const username = localStorage.getItem(LOCAL_STORAGE_USERNAME_KEY); 37 | 38 | document.title = `Account - ${ 39 | username.charAt(0).toUpperCase() + username.slice(1).toLowerCase() 40 | }`; 41 | fetchUserData(); 42 | }, []); 43 | 44 | const clearSession = () => { 45 | localStorage.removeItem(LOCAL_STORAGE_TOKEN_KEY); 46 | localStorage.removeItem(LOCAL_STORAGE_USERNAME_KEY); 47 | localStorage.removeItem(LOCAL_STORAGE_LOGIN_KEY); 48 | sessionStorage.removeItem(SESSION_STORAGE_SHARELINKS_KEY); 49 | }; 50 | 51 | const fetchUserData = async () => { 52 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 53 | if (!token) { 54 | navigate("/login"); 55 | location.reload(); 56 | return; 57 | } 58 | 59 | try { 60 | const response = await fetch( 61 | `${BACKEND_API_URL}/api/protected?email=true`, 62 | { 63 | method: "GET", 64 | headers: { 65 | Authorization: `Bearer ${token}`, 66 | }, 67 | } 68 | ); 69 | 70 | const data = await response.json(); 71 | if (response.ok) { 72 | setFormData((prevData) => ({ 73 | ...prevData, 74 | username: data.username.trim(), 75 | email: data.email.trim(), 76 | })); 77 | } else { 78 | setErrorMessage(data.msg || "Failed to fetch user data"); 79 | } 80 | } catch (error) { 81 | setErrorMessage("Failed to fetch user data"); 82 | } 83 | }; 84 | 85 | const handlePasswordVerification = async (e) => { 86 | e.preventDefault(); 87 | 88 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 89 | if (!token) { 90 | navigate("/login"); 91 | location.reload(); 92 | return; 93 | } 94 | 95 | const currentPassword = formData.currentPassword.trim(); 96 | 97 | if (currentPassword.length < 8) { 98 | setErrorMessage("Password must be at least 8 characters long"); 99 | return false; 100 | } 101 | 102 | if (!PASSWORD_REGEX.test(currentPassword)) { 103 | setErrorMessage("Invalid password format"); 104 | return false; 105 | } 106 | 107 | try { 108 | setBtnState(true); 109 | 110 | const response = await fetch(`${BACKEND_API_URL}/api/verify-password`, { 111 | method: "POST", 112 | headers: { 113 | "Content-Type": "application/json", 114 | Authorization: `Bearer ${token}`, 115 | }, 116 | body: JSON.stringify({ password: currentPassword.trim() }), 117 | }); 118 | 119 | const data = await response.json(); 120 | if (response.ok) { 121 | setIsPasswordVerified(true); 122 | setErrorMessage(""); 123 | } else { 124 | setErrorMessage(data.msg || "Password verification failed."); 125 | } 126 | } catch (error) { 127 | setErrorMessage("Error verifying password."); 128 | } finally { 129 | setBtnState(false); 130 | } 131 | }; 132 | 133 | const handleUpdateUsername = async (e) => { 134 | e.preventDefault(); 135 | 136 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 137 | if (!token) { 138 | navigate("/login"); 139 | location.reload(); 140 | return; 141 | } 142 | 143 | if (!isPasswordVerified) { 144 | setErrorMessage("Please verify your password first."); 145 | return; 146 | } 147 | 148 | const username = formData.username.trim(); 149 | 150 | if (!USERNAME_REGEX.test(username)) { 151 | setErrorMessage("Invalid username format"); 152 | return false; 153 | } 154 | 155 | if (username.length < 5 || username.length > 30) { 156 | setErrorMessage("Username should be between 5 and 30 characters"); 157 | return false; 158 | } 159 | 160 | Swal.fire({ 161 | title: "Are you sure?", 162 | text: "Do you want to update your username?", 163 | icon: "question", 164 | showCancelButton: true, 165 | confirmButtonText: "Yes, update it!", 166 | cancelButtonText: "No, keep it", 167 | allowOutsideClick: false, 168 | }).then(async (result) => { 169 | if (result.isConfirmed) { 170 | try { 171 | const response = await fetch( 172 | `${BACKEND_API_URL}/api/change-username`, 173 | { 174 | method: "PUT", 175 | headers: { 176 | "Content-Type": "application/json", 177 | Authorization: `Bearer ${token}`, 178 | }, 179 | body: JSON.stringify({ newUsername: username.trim() }), 180 | } 181 | ); 182 | 183 | const data = await response.json(); 184 | if (response.ok) { 185 | localStorage.setItem(LOCAL_STORAGE_USERNAME_KEY, username); 186 | Swal.fire({ 187 | title: "Updated!", 188 | text: "Your username has been updated successfully.", 189 | icon: "success", 190 | timer: 1500, 191 | }).then(() => { 192 | navigate(`/account/${username}`); 193 | location.reload(); 194 | }); 195 | fetchUserData(); 196 | } else { 197 | setErrorMessage(data.msg || "Failed to update username"); 198 | } 199 | } catch (error) { 200 | setErrorMessage("Error updating username"); 201 | } 202 | } 203 | }); 204 | }; 205 | 206 | const handleUpdatePassword = async (e) => { 207 | e.preventDefault(); 208 | 209 | if (!isPasswordVerified) { 210 | setErrorMessage("Please verify your password first."); 211 | return; 212 | } 213 | 214 | const newPassword = formData.newPassword.trim(); 215 | const confirmPassword = formData.confirmPassword.trim(); 216 | 217 | if (!newPassword || !confirmPassword) { 218 | setErrorMessage("New password and confirm password are required."); 219 | return; 220 | } 221 | 222 | if (newPassword.length < 8 || confirmPassword.length < 8) { 223 | setErrorMessage("Password must be at least 8 characters long."); 224 | return; 225 | } 226 | 227 | if ( 228 | !PASSWORD_REGEX.test(newPassword) || 229 | !PASSWORD_REGEX.test(confirmPassword) 230 | ) { 231 | setErrorMessage("Invalid password format"); 232 | return false; 233 | } 234 | 235 | if (newPassword !== confirmPassword) { 236 | setErrorMessage("New password and confirm password do not match."); 237 | return; 238 | } 239 | 240 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 241 | if (!token) { 242 | navigate("/login"); 243 | location.reload(); 244 | return; 245 | } 246 | 247 | Swal.fire({ 248 | title: "Are you sure?", 249 | text: "Do you want to update your password?", 250 | icon: "question", 251 | showCancelButton: true, 252 | confirmButtonText: "Yes, update it!", 253 | cancelButtonText: "No, keep it", 254 | allowOutsideClick: false, 255 | }).then(async (result) => { 256 | if (result.isConfirmed) { 257 | try { 258 | const response = await fetch( 259 | `${BACKEND_API_URL}/api/change-password`, 260 | { 261 | method: "PUT", 262 | headers: { 263 | "Content-Type": "application/json", 264 | Authorization: `Bearer ${token}`, 265 | }, 266 | body: JSON.stringify({ 267 | newPassword: newPassword, 268 | confirmPassword: confirmPassword, 269 | }), 270 | } 271 | ); 272 | 273 | const data = await response.json(); 274 | 275 | if (response.ok) { 276 | Swal.fire({ 277 | title: "Updated!", 278 | text: "Your password has been updated successfully.", 279 | icon: "success", 280 | timer: 2000, 281 | }).then(() => { 282 | navigate(`/account/${username}`); 283 | location.reload(); 284 | 285 | setFormData({ 286 | username: "", 287 | email: "", 288 | password: "", 289 | newPassword: "", 290 | confirmPassword: "", 291 | currentPassword: "", 292 | }); 293 | 294 | clearSession(); 295 | 296 | navigate("/login"); 297 | location.reload(); 298 | }); 299 | } else { 300 | setErrorMessage(data.msg || "Failed to update password"); 301 | } 302 | } catch (error) { 303 | setErrorMessage("Error updating password"); 304 | } 305 | } 306 | }); 307 | }; 308 | 309 | const handleDeleteAccount = async () => { 310 | if (!isPasswordVerified) { 311 | setErrorMessage("Please verify your password first."); 312 | return; 313 | } 314 | 315 | Swal.fire({ 316 | title: "Are you sure?", 317 | text: "Once deleted, you will not be able to recover your account!", 318 | icon: "warning", 319 | showCancelButton: true, 320 | confirmButtonText: "Yes, delete it!", 321 | cancelButtonText: "No, keep it", 322 | confirmButtonColor: "#da4242", 323 | allowOutsideClick: false, 324 | }).then(async (result) => { 325 | if (result.isConfirmed) { 326 | const token = localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY); 327 | if (!token) { 328 | navigate("/"); 329 | location.reload(); 330 | return; 331 | } 332 | 333 | try { 334 | setDelBtnText("Deleting..."); 335 | 336 | const response = await fetch(`${BACKEND_API_URL}/api/account`, { 337 | method: "DELETE", 338 | headers: { 339 | Authorization: `Bearer ${token}`, 340 | }, 341 | }); 342 | 343 | const data = await response.json(); 344 | if (response.ok) { 345 | clearSession(); 346 | setDelBtnText("Delete Account"); 347 | 348 | Swal.fire({ 349 | title: "Deleted!", 350 | text: "Your account has been deleted.", 351 | icon: "success", 352 | timer: 1500, 353 | }).then(() => { 354 | navigate("/"); 355 | location.reload(); 356 | }); 357 | } else { 358 | setErrorMessage(data.msg || "Failed to delete account"); 359 | } 360 | } catch (error) { 361 | setErrorMessage("Error deleting account"); 362 | } 363 | } 364 | }); 365 | }; 366 | 367 | const handleInputChange = (e) => { 368 | const { name, value } = e.target; 369 | setFormData((prevData) => ({ 370 | ...prevData, 371 | [name]: value, 372 | })); 373 | 374 | if (errorMessage) { 375 | setErrorMessage(""); 376 | } 377 | }; 378 | 379 | return ( 380 |
381 |

Account Settings

382 | {errorMessage && ( 383 |

{errorMessage}

384 | )} 385 | 386 | {!isPasswordVerified && ( 387 |
388 | 397 | setShowCurrentPassword( 398 | (showCurrentPassword) => !showCurrentPassword 399 | ) 400 | } 401 | /> 402 | 403 | 416 | 417 |

418 | 424 |

425 | 426 | )} 427 | 428 | {isPasswordVerified && ( 429 |

430 | 431 | Email: 432 | 433 | 437 | {formData.email} 438 | 439 |

440 | )} 441 | 442 | {isPasswordVerified && ( 443 |
444 |
445 | 453 | 459 | 460 | 461 |
462 | 470 | setShowNewPassword((showNewPassword) => !showNewPassword) 471 | } 472 | /> 473 | 474 | 482 | setShowConfirmPassword( 483 | (showConfirmPassword) => !showConfirmPassword 484 | ) 485 | } 486 | /> 487 | 493 | 494 |
495 | )} 496 | 497 | {isPasswordVerified && ( 498 |
499 | 505 |
506 | )} 507 |
508 | ); 509 | }; 510 | 511 | export default Accounts; 512 | -------------------------------------------------------------------------------- /Backend/Genai/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import jwt 4 | from google import genai 5 | from google.genai import types 6 | from dotenv import load_dotenv 7 | from flask import ( 8 | Flask, 9 | Response, 10 | jsonify, 11 | render_template, 12 | request, 13 | stream_with_context, 14 | ) 15 | from flask_cors import CORS 16 | from functools import wraps 17 | from datetime import datetime, timezone 18 | from prompts import * 19 | 20 | valid_languages = { 21 | "python", 22 | "javascript", 23 | "rust", 24 | "mongodb", 25 | "swift", 26 | "ruby", 27 | "dart", 28 | "perl", 29 | "scala", 30 | "julia", 31 | "go", 32 | "java", 33 | "cpp", 34 | "csharp", 35 | "c", 36 | "sql", 37 | "typescript", 38 | "kotlin", 39 | "verilog", 40 | } 41 | 42 | app = Flask(__name__) 43 | 44 | CORS(app) 45 | 46 | load_dotenv() 47 | 48 | CODE_REGEX = r"```(?:\w+\n)?(.*?)```" 49 | 50 | gemini_model = os.getenv("GEMINI_MODEL") 51 | gemini_model_1 = os.getenv("GEMINI_MODEL_1") 52 | SECRET_KEY = os.getenv("JWT_SECRET") 53 | 54 | 55 | def token_required(f): 56 | @wraps(f) 57 | def decorator(*args, **kwargs): 58 | token = None 59 | if "Authorization" in request.headers: 60 | auth_header = request.headers["Authorization"] 61 | if auth_header.startswith("Bearer "): 62 | token = auth_header.split(" ")[1] 63 | 64 | if not token: 65 | return jsonify({"message": "Token is missing!"}), 403 66 | 67 | try: 68 | decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS512"]) 69 | request.user_data = decoded 70 | except jwt.InvalidTokenError as e: 71 | return jsonify({"message": "Invalid token!"}), 401 72 | 73 | return f(*args, **kwargs) 74 | 75 | return decorator 76 | 77 | 78 | def get_generated_code(problem_description, language): 79 | try: 80 | if language not in valid_languages: 81 | return "Error: Unsupported language." 82 | 83 | def stream(): 84 | client = genai.Client() 85 | 86 | response = client.models.generate_content_stream( 87 | model=gemini_model, 88 | contents=generate_code_prompt.format( 89 | problem_description=problem_description, language=language 90 | ), 91 | config=types.GenerateContentConfig( 92 | system_instruction=generate_instruction.format(language=language), 93 | ), 94 | ) 95 | 96 | for chunk in response: 97 | if chunk.text: 98 | yield chunk.text 99 | 100 | return Response(stream_with_context(stream()), mimetype="text/plain") 101 | 102 | except Exception as e: 103 | return "" 104 | 105 | 106 | def get_output(code, language): 107 | try: 108 | if language in languages_prompts: 109 | prompt = languages_prompts[language].format( 110 | code=code, time=utc_time_reference() 111 | ) 112 | else: 113 | return "Error: Language not supported." 114 | 115 | def stream(): 116 | client = genai.Client() 117 | 118 | response = client.models.generate_content_stream( 119 | model=gemini_model, 120 | contents=prompt, 121 | config=types.GenerateContentConfig( 122 | system_instruction=compiler_instruction.format(language=language), 123 | ), 124 | ) 125 | 126 | for chunk in response: 127 | if chunk.text: 128 | yield chunk.text 129 | 130 | return Response(stream_with_context(stream()), mimetype="text/plain") 131 | except Exception as e: 132 | return f"Error: Unable to process the code. {str(e)}" 133 | 134 | 135 | def refactor_code(code, language, output, problem_description=None): 136 | try: 137 | if language not in valid_languages: 138 | return "Error: Unsupported language." 139 | 140 | if problem_description: 141 | refactor_contnet = refactor_code_prompt_user.format( 142 | code=code, 143 | language=language, 144 | problem_description=problem_description or "", 145 | output=output, 146 | ) 147 | else: 148 | refactor_contnet = refactor_code_prompt.format( 149 | code=code, language=language, output=output 150 | ) 151 | 152 | def stream(): 153 | client = genai.Client() 154 | 155 | response = client.models.generate_content_stream( 156 | model=gemini_model, 157 | contents=refactor_contnet, 158 | config=types.GenerateContentConfig( 159 | system_instruction=refactor_instruction.format(language=language), 160 | ), 161 | ) 162 | 163 | for chunk in response: 164 | if chunk.text: 165 | yield chunk.text 166 | 167 | return Response(stream_with_context(stream()), mimetype="text/plain") 168 | 169 | except Exception as e: 170 | print(f"Error analyzing code: {e}") 171 | return "" 172 | 173 | 174 | def refactor_code_html_css_js(language, prompt, params, problem_description=None): 175 | try: 176 | 177 | if problem_description: 178 | formatted_prompt = prompt.format( 179 | **params, problem_description=problem_description 180 | ) 181 | else: 182 | formatted_prompt = prompt.format(**params) 183 | 184 | client = genai.Client() 185 | 186 | response = client.models.generate_content( 187 | model=gemini_model_1, 188 | contents=formatted_prompt, 189 | config=types.GenerateContentConfig( 190 | system_instruction=refactor_instruction.format(language=language), 191 | ), 192 | ) 193 | 194 | result = response.text.strip() 195 | return result 196 | except Exception as e: 197 | return f"Error: {e}" 198 | 199 | 200 | def generate_html(prompt): 201 | formatted_prompt = html_prompt.format(prompt=prompt, time=utc_time_reference()) 202 | 203 | def stream(): 204 | client = genai.Client() 205 | 206 | response = client.models.generate_content_stream( 207 | model=gemini_model_1, 208 | contents=formatted_prompt, 209 | config=types.GenerateContentConfig( 210 | system_instruction=html_generate_instruction, 211 | ), 212 | ) 213 | for chunk in response: 214 | if chunk.text: 215 | yield chunk.text 216 | 217 | return Response(stream_with_context(stream()), mimetype="text/plain") 218 | 219 | 220 | def generate_css(html_content, project_description): 221 | formatted_prompt = css_prompt.format( 222 | html_content=html_content, 223 | project_description=project_description, 224 | time=utc_time_reference(), 225 | ) 226 | 227 | def stream(): 228 | client = genai.Client() 229 | 230 | response = client.models.generate_content_stream( 231 | model=gemini_model_1, 232 | contents=formatted_prompt, 233 | config=types.GenerateContentConfig( 234 | system_instruction=css_generate_instruction, 235 | ), 236 | ) 237 | for chunk in response: 238 | if chunk.text: 239 | yield chunk.text 240 | 241 | return Response(stream_with_context(stream()), mimetype="text/plain") 242 | 243 | 244 | def generate_js(html_content, css_content, project_description): 245 | formatted_prompt = js_prompt.format( 246 | html_content=html_content, 247 | css_content=css_content, 248 | project_description=project_description, 249 | time=utc_time_reference(), 250 | ) 251 | 252 | def stream(): 253 | client = genai.Client() 254 | 255 | response = client.models.generate_content_stream( 256 | model=gemini_model_1, 257 | contents=formatted_prompt, 258 | config=types.GenerateContentConfig( 259 | system_instruction=js_generate_instruction, 260 | ), 261 | ) 262 | for chunk in response: 263 | if chunk.text: 264 | yield chunk.text 265 | 266 | return Response(stream_with_context(stream()), mimetype="text/plain") 267 | 268 | 269 | def utc_time_reference(): 270 | utc_now = datetime.now(timezone.utc) 271 | formatted_time = utc_now.strftime("%I:%M:%S %p on %B %d, %Y") 272 | return f"{formatted_time} UTC time zone" 273 | 274 | 275 | @app.route("/") 276 | def index(): 277 | return render_template("index.html") 278 | 279 | 280 | @app.route("/generate_code", methods=["POST"]) 281 | @token_required 282 | def generate_code(): 283 | try: 284 | problem_description = request.json["problem_description"] 285 | language = request.json["language"] 286 | 287 | return get_generated_code(problem_description, language) 288 | 289 | except Exception as e: 290 | return jsonify({"error": str(e)}), 400 291 | 292 | 293 | @app.route("/get-output", methods=["POST"]) 294 | def get_output_api(): 295 | try: 296 | code = request.json["code"] 297 | language = request.json["language"] 298 | 299 | if not code or not language: 300 | return jsonify({"error": "Missing code or language"}), 400 301 | 302 | return get_output(code, language) 303 | 304 | except Exception as e: 305 | return jsonify({"error": str(e)}), 400 306 | 307 | 308 | @app.route("/refactor_code", methods=["POST"]) 309 | @token_required 310 | def refactor_code_api(): 311 | try: 312 | code = request.json["code"] 313 | language = request.json["language"] 314 | problem_description = request.json["problem_description"] 315 | output = request.json["output"] 316 | 317 | if not code or not language: 318 | return jsonify({"error": "Missing code or language"}), 400 319 | 320 | if problem_description: 321 | return refactor_code(code, language, output, problem_description) 322 | else: 323 | return refactor_code(code, language, output) 324 | 325 | except Exception as e: 326 | return jsonify({"error": str(e)}), 400 327 | 328 | 329 | @app.route("/htmlcssjsgenerate-code", methods=["POST"]) 330 | @token_required 331 | def htmlcssjs_generate_stream(): 332 | data = request.get_json() 333 | project_description = data.get("prompt") 334 | code_type = data.get("type") 335 | html_content = data.get("htmlContent", "") 336 | css_content = data.get("cssContent", "") 337 | 338 | if not project_description: 339 | return jsonify({"error": "Project description is required"}), 400 340 | 341 | if code_type not in ["html", "css", "js"]: 342 | return jsonify({"error": "Invalid or missing 'type' parameter"}), 400 343 | 344 | try: 345 | if code_type == "html": 346 | return generate_html(project_description) 347 | elif code_type == "css": 348 | return generate_css(html_content, project_description) 349 | elif code_type == "js": 350 | return generate_js(html_content, css_content, project_description) 351 | else: 352 | return jsonify({"error": "Unsupported code type."}), 400 353 | 354 | except ValueError as e: 355 | return jsonify({"error": str(e)}), 400 356 | except Exception as e: 357 | return jsonify({"error": f"An unexpected error occurred: {str(e)}"}), 500 358 | 359 | 360 | @app.route("/htmlcssjsrefactor-code", methods=["POST"]) 361 | @token_required 362 | def htmlcssjs_refactor(): 363 | try: 364 | data = request.get_json() 365 | html_content = data.get("html") if len(data.get("html", "")) > 0 else "" 366 | css_content = data.get("css") if len(data.get("css", "")) > 0 else "" 367 | js_content = data.get("js") if len(data.get("js", "")) > 0 else "" 368 | code_type = data.get("type") 369 | problem_description_raw = data.get("problem_description") 370 | problem_description = ( 371 | problem_description_raw.strip().lower() if problem_description_raw else None 372 | ) 373 | 374 | if not code_type: 375 | return jsonify({"error": "Type is required."}), 400 376 | 377 | if code_type == "html" and html_content and problem_description: 378 | html_content_refactored = refactor_code_html_css_js( 379 | "html", 380 | refactor_html_prompt_user, 381 | {"html_content": html_content}, 382 | problem_description, 383 | ) 384 | html_content_refactored = re.search( 385 | CODE_REGEX, html_content_refactored, re.DOTALL 386 | ) 387 | html_content_refactored = ( 388 | html_content_refactored.group(1) 389 | if html_content_refactored 390 | else html_content 391 | ) 392 | return jsonify({"html": html_content_refactored}) 393 | 394 | elif code_type == "css" and html_content and problem_description: 395 | if not html_content: 396 | return ( 397 | jsonify({"error": "HTML content is required for CSS refactoring."}), 398 | 400, 399 | ) 400 | css_content_refactored = refactor_code_html_css_js( 401 | "css", 402 | refactor_css_prompt_user, 403 | {"html_content": html_content, "css_content": css_content}, 404 | problem_description, 405 | ) 406 | css_content_refactored = re.search( 407 | CODE_REGEX, css_content_refactored, re.DOTALL 408 | ) 409 | css_content_refactored = ( 410 | css_content_refactored.group(1) 411 | if css_content_refactored 412 | else css_content 413 | ) 414 | return jsonify({"css": css_content_refactored}) 415 | 416 | elif code_type == "js" and html_content and css_content and problem_description: 417 | if not html_content or not css_content: 418 | return ( 419 | jsonify( 420 | { 421 | "error": "Both HTML and CSS content are required for JS refactoring." 422 | } 423 | ), 424 | 400, 425 | ) 426 | js_content_refactored = refactor_code_html_css_js( 427 | "js", 428 | refactor_js_prompt_user, 429 | { 430 | "html_content": html_content, 431 | "css_content": css_content, 432 | "js_content": js_content, 433 | }, 434 | problem_description, 435 | ) 436 | js_content_refactored = re.search( 437 | CODE_REGEX, js_content_refactored, re.DOTALL 438 | ) 439 | js_content_refactored = ( 440 | js_content_refactored.group(1) if js_content_refactored else js_content 441 | ) 442 | 443 | return jsonify({"js": js_content_refactored}) 444 | 445 | elif code_type == "html" and html_content: 446 | html_content_refactored = refactor_code_html_css_js( 447 | "html", refactor_html_prompt, {"html_content": html_content} 448 | ) 449 | html_content_refactored = re.search( 450 | CODE_REGEX, html_content_refactored, re.DOTALL 451 | ) 452 | html_content_refactored = ( 453 | html_content_refactored.group(1) 454 | if html_content_refactored 455 | else html_content 456 | ) 457 | return jsonify({"html": html_content_refactored}) 458 | 459 | elif code_type == "css" and html_content: 460 | if not html_content: 461 | return ( 462 | jsonify({"error": "HTML content is required for CSS refactoring."}), 463 | 400, 464 | ) 465 | css_content_refactored = refactor_code_html_css_js( 466 | "css", 467 | refactor_css_prompt, 468 | {"html_content": html_content, "css_content": css_content}, 469 | ) 470 | css_content_refactored = re.search( 471 | CODE_REGEX, css_content_refactored, re.DOTALL 472 | ) 473 | css_content_refactored = ( 474 | css_content_refactored.group(1) 475 | if css_content_refactored 476 | else css_content 477 | ) 478 | return jsonify({"css": css_content_refactored}) 479 | 480 | elif code_type == "js" and html_content and css_content: 481 | if not html_content or not css_content: 482 | return ( 483 | jsonify( 484 | { 485 | "error": "Both HTML and CSS content are required for JS refactoring." 486 | } 487 | ), 488 | 400, 489 | ) 490 | js_content_refactored = refactor_code_html_css_js( 491 | "js", 492 | refactor_js_prompt, 493 | { 494 | "html_content": html_content, 495 | "css_content": css_content, 496 | "js_content": js_content, 497 | }, 498 | ) 499 | js_content_refactored = re.search( 500 | CODE_REGEX, js_content_refactored, re.DOTALL 501 | ) 502 | js_content_refactored = ( 503 | js_content_refactored.group(1) if js_content_refactored else js_content 504 | ) 505 | return jsonify({"js": js_content_refactored}) 506 | 507 | else: 508 | return ( 509 | jsonify( 510 | { 511 | "error": "Please provide the appropriate content for the requested type." 512 | } 513 | ), 514 | 400, 515 | ) 516 | 517 | except Exception as e: 518 | return jsonify({"error": f"An error occurred: {str(e)}"}), 500 519 | 520 | 521 | if __name__ == "__main__": 522 | app.run(debug=False) 523 | --------------------------------------------------------------------------------