From fca03869fdf90afd727af8cf7890958a5fb4daf6 Mon Sep 17 00:00:00 2001 From: Harsh Yadav <161936085+HarshYadav152@users.noreply.github.com> Date: Sun, 19 Oct 2025 13:56:46 +0530 Subject: [PATCH 001/150] Add Contributor Covenant Code of Conduct Added Contributor Covenant Code of Conduct to promote a positive community environment. --- CODE_OF_CONDUCT.md | 128 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..49b61aa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +HarshYadav152@outlook.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. From 59b3f7f86155f037aa42863218d81881110c60fe Mon Sep 17 00:00:00 2001 From: Harsh Yadav <161936085+HarshYadav152@users.noreply.github.com> Date: Sun, 19 Oct 2025 13:58:12 +0530 Subject: [PATCH 002/150] Add MIT License to the project --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f4960d8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Harsh Yadav + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. From 95f5f9fb4cd4a747d1049bb3d1b1ca445a427a87 Mon Sep 17 00:00:00 2001 From: Harsh Yadav <161936085+HarshYadav152@users.noreply.github.com> Date: Sun, 19 Oct 2025 13:58:42 +0530 Subject: [PATCH 003/150] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 4ab450c13b5bc51c86e851832ff24d35d12995f0 Mon Sep 17 00:00:00 2001 From: harshyadav152 Date: Sun, 19 Oct 2025 14:10:29 +0530 Subject: [PATCH 004/150] issue template documentation --- .../documentation_improvement.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/documentation_improvement.md diff --git a/.github/ISSUE_TEMPLATE/documentation_improvement.md b/.github/ISSUE_TEMPLATE/documentation_improvement.md new file mode 100644 index 0000000..d4f1ed3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation_improvement.md @@ -0,0 +1,19 @@ +--- +name: Documentation improvement +about: Suggest improvements to our documentation +title: '[DOCS] ' +labels: documentation +assignees: '' +--- + +**Which documentation needs improvement?** +Provide links or describe the documentation that needs to be improved. + +**What is the issue with the current documentation?** +Describe what's missing, unclear, or incorrect about the current documentation. + +**What would you like to see instead?** +Describe your suggestion for how to improve the documentation. + +**Additional context** +Add any other context or screenshots about the documentation improvement here. \ No newline at end of file From 49db4ce68046477685e718224d6b5f8081dfcdc5 Mon Sep 17 00:00:00 2001 From: harshyadav152 Date: Sun, 19 Oct 2025 14:10:48 +0530 Subject: [PATCH 005/150] added pull request template --- .github/PULL_REQUEST_TEMPLATE.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..b9bfa0b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ +## Description + +Please include a summary of the change and which issue is fixed. Include relevant motivation and context. + +Fixes # (issue number) + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update + +## How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. + +## Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes \ No newline at end of file From 0914ac82d3ee31358831a800aee30249bc64e177 Mon Sep 17 00:00:00 2001 From: harshyadav152 Date: Sun, 19 Oct 2025 14:11:06 +0530 Subject: [PATCH 006/150] added contributing and security file --- CONTRIBUTING.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ SECURITY.md | 29 ++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1c0b280 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,66 @@ +# Contributing to Our Project + +Thank you for your interest in contributing to our project! This document provides guidelines and instructions to help you get started. + +## Code of Conduct + +Please review our [Code of Conduct](CODE_OF_CONDUCT.md) before contributing to the project. + +## How to Contribute + +### Reporting Bugs + +If you find a bug, please open an issue using the bug report template. Include as much detail as possible: + +- A clear and descriptive title +- Steps to reproduce the issue +- Expected and actual behavior +- Screenshots if applicable +- Environment details + +### Suggesting Features + +Feature suggestions are welcome! Use the feature request template and provide: + +- A clear description of the feature +- The problem it solves +- Any implementation ideas you have + +### Pull Requests + +1. Fork the repository +2. Create a new branch from `main` +3. Make your changes +4. Test your changes +5. Submit a pull request using our pull request template + +## Development Setup + +1. Clone the repository +2. Install dependencies with `npm install` +3. Copy `.env.local.example` to `.env.local` and configure as needed +4. Run the development server with `npm run dev` + +## Coding Standards + +- Follow the existing code style +- Write tests for new features +- Update documentation as needed + +## Commit Guidelines + +We follow [Conventional Commits](https://www.conventionalcommits.org/): + +- `feat:` for new features +- `fix:` for bug fixes +- `docs:` for documentation changes +- `style:` for formatting changes +- `refactor:` for code refactoring +- `test:` for tests +- `chore:` for maintenance tasks + +## License + +By contributing, you agree that your contributions will be licensed under the project's license. + +Thank you for contributing! \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..e75e958 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy + +## Supported Versions + +We currently support the following versions with security updates: + +| Version | Supported | +| ------- | ------------------ | +| latest | :white_check_mark: | + +## Reporting a Vulnerability + +We take the security of our project seriously. If you discover a security vulnerability, please follow these steps: + +1. **Do not** disclose the vulnerability publicly +2. Email us at [HarshYadav152@outlook.com](mailto:HarshYadav152@outlook.com) with: + - A description of the vulnerability + - Steps to reproduce + - Potential impact + - Any suggestions for mitigation + +## What to Expect + +- We will acknowledge receipt of your report within 48 hours +- We will provide a more detailed response within 7 days with our assessment +- We will work with you to understand and address the issue +- Once the vulnerability is fixed, we will publicly acknowledge your responsible disclosure (unless you prefer to remain anonymous) + +Thank you for helping keep our project and users secure! \ No newline at end of file From 4f90338c159ef2c730e39812d8b4bd480acadaad Mon Sep 17 00:00:00 2001 From: harshyadav152 Date: Sun, 19 Oct 2025 14:22:24 +0530 Subject: [PATCH 007/150] undate gitignore and env example --- .env.local.example | 3 +++ .gitignore | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .env.local.example diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..62787cc --- /dev/null +++ b/.env.local.example @@ -0,0 +1,3 @@ +MONGODB_URI=mongodb_uri +ACCESS_TOKEN_SECRET=access_token_secret +ACCESS_TOKEN_EXPIRY=access_token_expiry \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5ef6a52..24c06b8 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,7 @@ yarn-error.log* .pnpm-debug.log* # env files (can opt-in for committing if needed) -.env* +.env.local # vercel .vercel From 11d390165a2a673dab2ddd96fdacf90fcc8cdb74 Mon Sep 17 00:00:00 2001 From: harshyadav152 Date: Sun, 19 Oct 2025 14:23:25 +0530 Subject: [PATCH 008/150] Readme file update --- README.md | 107 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 66bb426..0256400 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,105 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +# SaveBook +A modern web application for note-taking and knowledge management built with Next.js. -## Getting Started +## โœจ Features -First, run the development server: +- **Modern UI**: Clean and responsive design for optimal user experience +- **Note Organization**: Create, edit, and organize your notes efficiently +- **Fast Performance**: Built on Next.js for optimal loading and rendering +- **Responsive Design**: Works seamlessly across desktop, tablet, and mobile devices + +## ๐Ÿ“‹ Prerequisites + +- Node.js 18.x or later +- npm, yarn, pnpm, or bun + +## ๐Ÿš€ Getting Started + +### Installation + +1. Clone the repository: + ```bash + git clone https://github.com/HarshYadav152/SaveBook.git + cd SaveNook + ``` + +2. Install dependencies: + ```bash + npm install + ``` + +3. Create a .env.local file in the root directory based on `.env.local.example` and set up your environment variables. + +### Development + +Start the development server: ```bash npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev ``` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. -You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. +### Building for Production + +```bash +npm run build +``` + +### Running Production Build + +```bash +npm start +``` + +## ๐Ÿ“ Project Structure + +``` +notebook/ +โ”œโ”€โ”€ .github/ # GitHub templates for issues and PRs +โ”œโ”€โ”€ .next/ # Next.js build output +โ”œโ”€โ”€ app/ # Application routes and pages +โ”œโ”€โ”€ components/ # Reusable React components +โ”œโ”€โ”€ context/ # React context for state management +โ”œโ”€โ”€ lib/ # Utility functions and shared code +โ”œโ”€โ”€ public/ # Static assets +โ”œโ”€โ”€ .env.local # Environment variables (not in git) +โ”œโ”€โ”€ .gitignore # Git ignore file +โ”œโ”€โ”€ CODE_OF_CONDUCT.md # Community guidelines +โ”œโ”€โ”€ CONTRIBUTING.md # Contribution guidelines +โ”œโ”€โ”€ LICENSE # Project license +โ”œโ”€โ”€ README.md # Project documentation +โ”œโ”€โ”€ SECURITY.md # Security policies +โ””โ”€โ”€ package.json # Project dependencies and scripts +``` + +## ๐Ÿงช Testing + +-- soon + +## ๐Ÿค Contributing + +We welcome contributions! Please see our Contributing Guidelines for details on how to submit pull requests, report issues, and suggest enhancements. + +All contributors are expected to follow our Code of Conduct. + +## ๐Ÿ”’ Security + +If you discover a security vulnerability, please follow our Security Policy for responsible disclosure. -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +## ๐Ÿ“„ License -## Learn More +This project is licensed under the MIT [License](LICENCE). -To learn more about Next.js, take a look at the following resources: +## ๐Ÿ™ Acknowledgments -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- [Next.js](https://nextjs.org/) - The React framework for production +- [Geist Font](https://vercel.com/font) - Modern and minimal typeface -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +## ๐Ÿ“ž Support -## Deploy on Vercel +For questions and support, please open an issue or contact the maintainers. -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +--- -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +Built with โค๏ธ using [Next.js](https://nextjs.org/) \ No newline at end of file From b1c3f4411051c4204c4440d2b47e3159baef36a4 Mon Sep 17 00:00:00 2001 From: Harsh Yadav <161936085+HarshYadav152@users.noreply.github.com> Date: Sun, 19 Oct 2025 14:23:58 +0530 Subject: [PATCH 009/150] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0256400..271737a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ A modern web application for note-taking and knowledge management built with Nex 1. Clone the repository: ```bash git clone https://github.com/HarshYadav152/SaveBook.git - cd SaveNook + cd SaveBook ``` 2. Install dependencies: @@ -102,4 +102,4 @@ For questions and support, please open an issue or contact the maintainers. --- -Built with โค๏ธ using [Next.js](https://nextjs.org/) \ No newline at end of file +Built with โค๏ธ using [Next.js](https://nextjs.org/) From 23550de3fb62328f53bdbb3b87d2bc004d76e1d1 Mon Sep 17 00:00:00 2001 From: Harsh Yadav <161936085+HarshYadav152@users.noreply.github.com> Date: Tue, 18 Nov 2025 22:28:58 +0530 Subject: [PATCH 010/150] Create index.html --- docs/index.html | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..f5782f0 --- /dev/null +++ b/docs/index.html @@ -0,0 +1 @@ +docs page From 4079bb8f6f3daa97698f8e9429a456752e8b84c7 Mon Sep 17 00:00:00 2001 From: Harsh Yadav <161936085+HarshYadav152@users.noreply.github.com> Date: Tue, 18 Nov 2025 22:32:47 +0530 Subject: [PATCH 011/150] Update docs/index.html Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/index.html | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index f5782f0..6cc4880 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1 +1,37 @@ -docs page + + + + + + Project Documentation + + +

Project Documentation

+

Welcome to the documentation page for this project. This page provides an overview, usage instructions, API references, and links to further resources.

+ +

Overview

+

This project is designed to ... (provide a brief description of the project's purpose and features).

+ +

Installation & Usage

+
+# Install
+npm install your-package-name
+
+# Usage
+import { yourFunction } from 'your-package-name';
+yourFunction();
+
+ +

API Reference

+
    +
  • yourFunction(): Brief description of what this function does.
  • + +
+ +

Further Resources

+ + + From cf33ae6f8afc4c8fce6f4b24c2ecd4a291907937 Mon Sep 17 00:00:00 2001 From: HarshYadav152 Date: Fri, 5 Dec 2025 12:32:54 +0530 Subject: [PATCH 012/150] move lib to savebook --- savebook/lib/db/mongodb.js | 13 +++ savebook/lib/middlewares/verify.js | 52 ++++++++++++ savebook/lib/models/Notes.js | 27 ++++++ savebook/lib/models/User.js | 40 +++++++++ savebook/lib/utils/JWT.js | 128 +++++++++++++++++++++++++++++ 5 files changed, 260 insertions(+) create mode 100644 savebook/lib/db/mongodb.js create mode 100644 savebook/lib/middlewares/verify.js create mode 100644 savebook/lib/models/Notes.js create mode 100644 savebook/lib/models/User.js create mode 100644 savebook/lib/utils/JWT.js diff --git a/savebook/lib/db/mongodb.js b/savebook/lib/db/mongodb.js new file mode 100644 index 0000000..1bab7b1 --- /dev/null +++ b/savebook/lib/db/mongodb.js @@ -0,0 +1,13 @@ +import mongoose from "mongoose"; + +const MONGODB_URI = process.env.MONGODB_URI; + +if (!MONGODB_URI) { + throw new Error("Please define the MONGODB_URI environment variable"); +} + +async function dbConnect() { + await mongoose.connect(MONGODB_URI); +} + +export default dbConnect; \ No newline at end of file diff --git a/savebook/lib/middlewares/verify.js b/savebook/lib/middlewares/verify.js new file mode 100644 index 0000000..b1f40d8 --- /dev/null +++ b/savebook/lib/middlewares/verify.js @@ -0,0 +1,52 @@ +import { NextResponse } from 'next/server'; +import { verifyJwtToken } from '../utils/JWT'; + +export function middleware(request) { + // Paths that require authentication + const protectedPaths = ['/api/notes', '/notes']; + const path = request.nextUrl.pathname; + + // Check if the path is protected + const isProtectedPath = protectedPaths.some(prefix => + path === prefix || path.startsWith(`${prefix}/`) + ); + + if (!isProtectedPath) { + return NextResponse.next(); + } + + // Get auth token from cookie + const token = request.cookies.get('authtoken')?.value; + + if (!token) { + // If accessing API route, return error response + if (path.startsWith('/api/')) { + return NextResponse.json( + { error: 'Authentication token is required' }, + { status: 401 } + ); + } + // For page routes, redirect to login + return NextResponse.redirect(new URL('/login', request.url)); + } + + // Verify the token + // Verify the token + const tokenInfo = verifyJwtToken(authToken); + if (!tokenInfo.success) { + if (path.startsWith('/api/')) { + return NextResponse.json( + { success: false, message: tokenInfo.error }, + { status: 401 } + ); + } + return NextResponse.redirect(new URL('/login', request.url)); + } + + // Allow the request to proceed + return NextResponse.next(); +} + +export const config = { + matcher: ['/api/notes/:path*', '/notes/:path*'], +}; \ No newline at end of file diff --git a/savebook/lib/models/Notes.js b/savebook/lib/models/Notes.js new file mode 100644 index 0000000..24bed48 --- /dev/null +++ b/savebook/lib/models/Notes.js @@ -0,0 +1,27 @@ +import mongoose from 'mongoose'; +const { Schema } = mongoose; + +const NotesSchema = new Schema({ + user: { + type: mongoose.Schema.Types.ObjectId, + ref: 'user' + }, + title: { + type: String, + required: true + }, + description: { + type: String, + required: true + }, + tag: { + type: String, + default: "General" + }, + date: { + type: Date, + default: Date.now + }, +}); + +export default mongoose.models.Notes || mongoose.model('Notes', NotesSchema); \ No newline at end of file diff --git a/savebook/lib/models/User.js b/savebook/lib/models/User.js new file mode 100644 index 0000000..7476e47 --- /dev/null +++ b/savebook/lib/models/User.js @@ -0,0 +1,40 @@ +import mongoose from 'mongoose'; +const { Schema } = mongoose; +import bcrypt from 'bcryptjs'; + +const UserSchema = new Schema({ + username: { + type: String, + required: true, + lowercase:true, + unique: true + }, + password: { + type: String, + required: true + }, + date: { + type: Date, + default: Date.now + }, +}); + +// Password hashing middleware +UserSchema.pre("save", async function (next) { + if (!this.isModified("password")) return next(); + + try { + const salt = await bcrypt.genSalt(10); + this.password = await bcrypt.hash(this.password, salt); + next(); + } catch (error) { + next(error); + } +}); + +// Method to check if password matches +UserSchema.methods.comparePassword = async function (candidatePassword) { + return await bcrypt.compare(candidatePassword, this.password); +}; + +export default mongoose.models.User || mongoose.model('User', UserSchema); \ No newline at end of file diff --git a/savebook/lib/utils/JWT.js b/savebook/lib/utils/JWT.js new file mode 100644 index 0000000..e39cbf7 --- /dev/null +++ b/savebook/lib/utils/JWT.js @@ -0,0 +1,128 @@ +import jwt from 'jsonwebtoken'; +import crypto from 'crypto'; +import User from '../models/User'; + +// Generate access token +export const generateAuthToken = async (userId) => { + try { + const authToken = jwt.sign( + { _id: userId }, + process.env.ACCESS_TOKEN_SECRET, + { expiresIn: process.env.ACCESS_TOKEN_EXPIRY || '7d' } + ); + + return { authToken: authToken }; + } catch (error) { + return { + success: false, + error: "Error generating access token", + status: 500 + }; + } +}; + +export const generateResetToken = () => { + return crypto.randomBytes(32).toString('hex'); +}; + +// Verify token from request +export const verifyToken = async (request) => { + try { + // Get token from cookies + const token = request.cookies.get('authToken')?.value; + + if (!token) { + return { + success: false, + error: "Unauthorized - No token provided", + status: 401 + }; + } + + // Verify token + const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); + + // Get user from database + const user = await User.findById(decodedToken._id).select("-password"); + + if (!user) { + return { + success: false, + error: "Unauthorized - Invalid token", + status: 401 + }; + } + return { + success: true, + user, + userId: user._id + }; + } catch (error) { + if (error.name === 'JsonWebTokenError') { + return { + success: false, + error: "Invalid token", + status: 401 + }; + } + + if (error.name === 'TokenExpiredError') { + return { + success: false, + error: "Token expired", + status: 401 + }; + } + + return { + success: false, + error: error.message || "Authentication failed", + status: 401 + }; + } +}; + +// Verify token directly without request +export const verifyJwtToken = (token) => { + try { + if (!token) { + return { + success: false, + error: "No token provided", + status: 401 + }; + } + + const decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); + return { + success: true, + userId: decodedToken._id + }; + } catch (error) { + if (error.name === 'TokenExpiredError') { + return { + success: false, + error: "Token expired", + status: 401 + }; + } + return { + success: false, + error: "Invalid token", + status: 401 + }; + } +}; + +// Create token cookie +export const createTokenCookie = (token) => { + return { + name: 'authToken', + value: token, + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'strict', + maxAge: 60 * 60 * 24 * 7, // 1 week + path: '/' + }; +}; \ No newline at end of file From bf361995928b80c4f118d0f21ad13ec6513da6d2 Mon Sep 17 00:00:00 2001 From: HarshYadav152 Date: Fri, 5 Dec 2025 12:33:16 +0530 Subject: [PATCH 013/150] move app/ files to savebook --- savebook/app/(auth)/login/page.js | 254 ++++++++++++ savebook/app/(auth)/register/page.js | 274 +++++++++++++ savebook/app/(legal)/privacy/page.js | 417 +++++++++++++++++++ savebook/app/(legal)/terms/page.js | 517 ++++++++++++++++++++++++ savebook/app/api/auth/login/route.js | 65 +++ savebook/app/api/auth/logout/route.js | 25 ++ savebook/app/api/auth/register/route.js | 39 ++ savebook/app/api/auth/user/route.js | 40 ++ savebook/app/api/notes/[id]/route.js | 155 +++++++ savebook/app/api/notes/route.js | 48 +++ savebook/app/favicon.ico | Bin 0 -> 25931 bytes savebook/app/globals.css | 5 + savebook/app/layout.js | 53 +++ savebook/app/not-found.js | 53 +++ savebook/app/page.js | 9 + 15 files changed, 1954 insertions(+) create mode 100644 savebook/app/(auth)/login/page.js create mode 100644 savebook/app/(auth)/register/page.js create mode 100644 savebook/app/(legal)/privacy/page.js create mode 100644 savebook/app/(legal)/terms/page.js create mode 100644 savebook/app/api/auth/login/route.js create mode 100644 savebook/app/api/auth/logout/route.js create mode 100644 savebook/app/api/auth/register/route.js create mode 100644 savebook/app/api/auth/user/route.js create mode 100644 savebook/app/api/notes/[id]/route.js create mode 100644 savebook/app/api/notes/route.js create mode 100644 savebook/app/favicon.ico create mode 100644 savebook/app/globals.css create mode 100644 savebook/app/layout.js create mode 100644 savebook/app/not-found.js create mode 100644 savebook/app/page.js diff --git a/savebook/app/(auth)/login/page.js b/savebook/app/(auth)/login/page.js new file mode 100644 index 0000000..aa7a3cc --- /dev/null +++ b/savebook/app/(auth)/login/page.js @@ -0,0 +1,254 @@ +"use client" +import { useAuth } from '@/context/auth/authContext'; +import { useRouter, usePathname } from 'next/navigation'; +import React, { useState, useEffect } from 'react'; +import toast from 'react-hot-toast'; +import Link from 'next/link'; + +// Login Form Component +const LoginForm = () => { + const { login, isAuthenticated } = useAuth(); + const [credentials, setCredentials] = useState({ username: '', password: '' }); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + + // Handle redirection based on authentication status + useEffect(() => { + if (isAuthenticated) { + router.push("/"); + } + }, [isAuthenticated, router]); + + useEffect(()=>{ + if(isAuthenticated){ + router.push("/") + } + },[]) + + const handleSubmit = async (e) => { + e.preventDefault(); + + // Prevent submission if already authenticated + if (isAuthenticated) { + router.push("/"); + return; + } + + setIsLoading(true); + + try { + const result = await login(credentials.username, credentials.password); + + if (result.success) { + toast.success("Welcome back! ๐ŸŽ‰"); + router.push("/") + // The useEffect will handle the redirect + } else { + toast.error(result.message || "Invalid credentials. Please try again."); + } + } catch (error) { + console.error("Login error:", error); + toast.error("Something went wrong. Please try again."); + } finally { + setIsLoading(false); + } + } + + const onchange = (e) => { + setCredentials({ ...credentials, [e.target.name]: e.target.value }); + } + + // Show loading state while checking authentication + if (isAuthenticated === undefined) { + return ; + } + + return ( +
+ {/* Username Field */} +
+ +
+ +
+ + + +
+
+
+ + {/* Password Field */} +
+
+ + + Forgot password? + +
+
+ +
+ + + +
+
+
+ + {/* Submit Button */} + + + {/* Sign up link */} +
+ + Don't have an account?{' '} + { + if (isLoading) { + e.preventDefault(); + } + }} + > + Register + + +
+
+ ); +}; + +// Loading component +const LoginFormSkeleton = () => { + return ( +
+ {/* Username Field Skeleton */} +
+
+
+
+ + {/* Password Field Skeleton */} +
+
+
+
+
+
+
+ + {/* Button Skeleton */} +
+ + {/* Sign up link Skeleton */} +
+
+
+
+ ); +}; + +// Main component +const LoginPage = () => { + const { isAuthenticated } = useAuth(); + + // Show loading while checking initial auth state + if (isAuthenticated === undefined) { + return ( +
+
+
+
+
+
+
+
+ +
+
+
+ ); + } + + // // Redirect if already authenticated + // if (isAuthenticated) { + // return ( + //
+ //
+ //
+ //

Redirecting...

+ //
+ //
+ // ); + // } + + return ( +
+
+ {/* Header */} +
+
+ + + +
+

+ Welcome back +

+

+ Sign in to your account +

+
+ + {/* Login Form */} +
+ +
+
+
+ ); +} + +export default LoginPage; \ No newline at end of file diff --git a/savebook/app/(auth)/register/page.js b/savebook/app/(auth)/register/page.js new file mode 100644 index 0000000..d3ddf2b --- /dev/null +++ b/savebook/app/(auth)/register/page.js @@ -0,0 +1,274 @@ +"use client" +import { useAuth } from '@/context/auth/authContext'; +import { useRouter } from 'next/navigation'; +import React, { useState, useEffect } from 'react'; +import toast from 'react-hot-toast'; +import Link from 'next/link'; + +// Signup Form Component +const SignupForm = () => { + const { register, isAuthenticated } = useAuth(); + const [credentials, setCredentials] = useState({ + username: '', + password: '', + confirmPassword: '' + }); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + + // Handle redirection based on authentication status + useEffect(() => { + if (isAuthenticated) { + router.push("/"); + } + }, [isAuthenticated, router]); + + const handleSubmit = async (e) => { + e.preventDefault(); + + // Prevent submission if already authenticated + if (isAuthenticated) { + router.push("/"); + return; + } + + if (!credentials.username || !credentials.password || !credentials.confirmPassword) { + toast.error('Please fill in all fields'); + return; + } + + if (credentials.password !== credentials.confirmPassword) { + toast.error('Passwords do not match'); + return; + } + + if (credentials.password.length < 6) { + toast.error('Password must be at least 6 characters'); + return; + } + + setIsLoading(true); + + try { + // Use the register method from AuthContext + const result = await register( + credentials.username, + credentials.password + ); + + if (result.success) { + toast.success("Account created successfully! ๐ŸŽ‰"); + router.push("/login") + // The useEffect will handle the redirect + } else { + toast.error(result.message || "Registration failed"); + } + } catch (error) { + console.error("Registration error:", error); + toast.error("Something went wrong"); + } finally { + setIsLoading(false); + } + }; + + const onchange = (e) => { + setCredentials({ ...credentials, [e.target.name]: e.target.value }); + }; + + // Show loading state while checking authentication + if (isAuthenticated === undefined) { + return ; + } + + return ( +
+ {/* Username Field */} +
+ + +
+ + {/* Password Field */} +
+ + +
+ + {/* Confirm Password Field */} +
+ + +
+ + {/* Submit Button */} + + + {/* Login link */} +
+ + Already have an account?{' '} + { + if (isLoading || isAuthenticated) { + e.preventDefault(); + } + }} + > + Login + + +
+
+ ); +} + +// Signup Skeleton Component for loading state +const SignupFormSkeleton = () => { + return ( +
+ {/* Username Field Skeleton */} +
+
+
+
+ + {/* Password Field Skeleton */} +
+
+
+
+ + {/* Confirm Password Field Skeleton */} +
+
+
+
+ + {/* Button Skeleton */} +
+ + {/* Sign up link Skeleton */} +
+
+
+
+ ); +}; + +// Main component +export default function Signup() { + const { isAuthenticated } = useAuth(); + + // Show loading while checking initial auth state + if (isAuthenticated === undefined) { + return ( +
+
+ {/* Header Skeleton */} +
+
+
+
+
+ + {/* Form Skeleton */} +
+ +
+
+
+ ); + } + + // // Redirect if already authenticated + // if (isAuthenticated) { + // return ( + //
+ //
+ //
+ //

Redirecting...

+ //
+ //
+ // ); + // } + + return ( +
+
+ {/* Header */} +
+
+ + + +
+

+ Create Account +

+

+ Join us and get started +

+
+ + {/* Signup Form */} +
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/savebook/app/(legal)/privacy/page.js b/savebook/app/(legal)/privacy/page.js new file mode 100644 index 0000000..f434038 --- /dev/null +++ b/savebook/app/(legal)/privacy/page.js @@ -0,0 +1,417 @@ +"use client" +import React, { Suspense } from 'react' +import Link from 'next/link' + +// Loading component specifically styled for privacy page +const PrivacyPageLoading = () => { + return ( +
+
+ {/* Header loading state */} +
+
+ +
+ +
+
+ +
+
+
+
+
+
+ + {/* Last Updated loading state */} +
+ + {/* Content loading state */} +
+
+ {[...Array(5)].map((_, i) => ( +
+
+
+
+
+
+
+
+
+
+
+ ))} +
+
+
+
+ ); +}; + +// Main content component +const PrivacyPolicyContent = () => { + return ( +
+
+ {/* Header */} +
+ + + + + Back to App + + +
+ + + +
+ +

+ Privacy Policy +

+

+ How we protect and handle your data in Notebook +

+ +
+
+
๐Ÿ”’
+
Encrypted
+
+
+
๐Ÿ”
+
Secure
+
+
+
๐Ÿ“
+
Private
+
+
+
+ + {/* Last Updated */} +
+
+
+

Last Updated

+

October 2025

+
+
+

Version

+

1.0

+
+
+
+ + {/* Main Content */} +
+
+ + {/* Introduction */} +
+

+
+ Introduction +

+

+ Welcome to Notebook. We are committed to protecting your privacy and ensuring the security of your personal notes and data. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you use our notebook application. +

+

+ By using Notebook, you consent to the data practices described in this policy. If you do not agree with the data practices described in this Privacy Policy, you should not use our application. +

+
+ + {/* Information We Collect */} +
+

+
+ Information We Collect +

+ +
+
+

+ + + + Personal Information +

+
    +
  • + โ€ข + Username and email address +
  • +
  • + โ€ข + Account creation date +
  • +
  • + โ€ข + Last login information +
  • +
+
+ +
+

+ + + + Note Content +

+
    +
  • + โ€ข + Note titles and descriptions +
  • +
  • + โ€ข + Tags and categories +
  • +
  • + โ€ข + Creation and modification dates +
  • +
+
+
+ +
+

+ + + + Technical Information +

+
    +
  • + โ€ข + IP address and browser type +
  • +
  • + โ€ข + Device information and operating system +
  • +
  • + โ€ข + Usage patterns and app interactions +
  • +
+
+
+ + {/* How We Use Your Information */} +
+

+
+ How We Use Your Information +

+ +
+
+
+ 1 +
+
+

Provide Core Services

+

To create, store, and manage your notes, and to provide you with a personalized notebook experience.

+
+
+ +
+
+ 2 +
+
+

Security & Authentication

+

To verify your identity, protect your account, and prevent unauthorized access to your notes.

+
+
+ +
+
+ 3 +
+
+

Improve Our Service

+

To understand how users interact with our app and make improvements to enhance your experience.

+
+
+ +
+
+ 4 +
+
+

Communication

+

To send you important updates about our service, security notifications, and support responses.

+
+
+
+
+ + {/* Data Security */} +
+

+
+ Data Security +

+ +
+
+
+

+ + + + Security Measures +

+
    +
  • + โœ“ + End-to-end encryption for note content +
  • +
  • + โœ“ + Secure HTTPS connections +
  • +
  • + โœ“ + Regular security audits +
  • +
  • + โœ“ + Data encryption at rest +
  • +
+
+ +
+

+ + + + Access Control +

+
    +
  • + โœ“ + Only you can access your notes +
  • +
  • + โœ“ + No employee access to note content +
  • +
  • + โœ“ + Secure authentication tokens +
  • +
+
+
+
+
+ + {/* Data Retention & Your Rights */} +
+

+
+ Your Rights & Control +

+ +
+
+

Data Retention

+

+ We retain your notes for as long as your account is active. If you delete your account, all associated notes and personal information will be permanently deleted from our servers within 30 days. +

+
+ + + + Account data deleted within 30 days of account closure +
+
+ +
+

Your Rights

+
+
+ + + + Access your data +
+
+ + + + Correct inaccurate data +
+
+ + + + Delete your account +
+
+ + + + Export your notes +
+
+
+
+
+ + {/* Contact Information */} +
+

+
+ Contact Us +

+ +
+

+ If you have any questions about this Privacy Policy or our data practices, please contact us: +

+
+ + + + HarshYadav152@outlook.com +
+
+
+ + {/* Policy Updates */} +
+

+ + + + Policy Updates +

+

+ We may update this Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page and updating the "Last Updated" date. You are advised to review this Privacy Policy periodically for any changes. +

+
+
+
+
+
+ ); +}; + +// Main component with Suspense +export default function PrivacyPolicy() { + return ( + }> + + + ); +} \ No newline at end of file diff --git a/savebook/app/(legal)/terms/page.js b/savebook/app/(legal)/terms/page.js new file mode 100644 index 0000000..df59f44 --- /dev/null +++ b/savebook/app/(legal)/terms/page.js @@ -0,0 +1,517 @@ +"use client" +import React, { Suspense } from 'react' +import Link from 'next/link' + +// Loading component for the Terms of Service page +const TermsPageLoading = () => { + return ( +
+
+ {/* Header loading skeleton */} +
+
+ +
+ +
+
+ +
+ {[1, 2, 3].map((i) => ( +
+
+
+
+ ))} +
+
+ + {/* Quick Summary loading skeleton */} +
+
+ {[1, 2, 3].map((i) => ( +
+
+
+
+ ))} +
+
+ + {/* Main Content loading skeleton */} +
+
+ {/* Section loading skeletons */} + {[1, 2, 3, 4, 5].map((i) => ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ))} +
+
+ + {/* Acceptance Section loading skeleton */} +
+
+
+
+
+
+ ); +}; + +// Terms of Service content component +const TermsOfServiceContent = () => { + return ( +
+
+ {/* Header */} +
+ + + + + Back to App + + +
+ + + +
+ +

+ Terms of Service +

+

+ Guidelines and rules for using Notebook +

+ +
+
+
๐Ÿ“
+
Acceptable Use
+
+
+
โš–๏ธ
+
User Rights
+
+
+
๐Ÿšซ
+
Prohibited Content
+
+
+
+ + {/* Quick Summary */} +
+
+
+
18+
+
Minimum Age
+
+
+
๐Ÿ“ฑ
+
Personal Use
+
+
+
๐Ÿ”’
+
Content Ownership
+
+
+
+ + {/* Main Content */} +
+
+ + {/* Agreement Section */} +
+
+
+
+

1. Agreement to Terms

+

Last Updated: October 2025

+
+
+

+ By accessing or using Notebook ("the Service"), you agree to be bound by these Terms of Service and all applicable laws and regulations. If you do not agree with any of these terms, you are prohibited from using or accessing this Service. +

+
+

+ Note: These terms affect your legal rights and responsibilities. Please read them carefully. +

+
+
+ + {/* User Accounts */} +
+

+
+ 2. User Accounts +

+ +
+
+

+ + + + Account Registration +

+
    +
  • + โ€ข + You must be at least 18 years old to use this Service +
  • +
  • + โ€ข + Provide accurate and complete registration information +
  • +
  • + โ€ข + Maintain the security of your password and account +
  • +
  • + โ€ข + You are responsible for all activities under your account +
  • +
+
+ +
+

+ + + + Account Termination +

+

+ We reserve the right to suspend or terminate your account if: +

+
    +
  • + โ€ข + You violate these Terms of Service +
  • +
  • + โ€ข + You engage in fraudulent or illegal activities +
  • +
  • + โ€ข + Your use poses security risks to our Service +
  • +
+
+
+
+ + {/* Acceptable Use */} +
+

+
+ 3. Acceptable Use +

+ +
+
+

+ + + + You May +

+
    +
  • + โœ“ + Create and manage personal notes +
  • +
  • + โœ“ + Use for personal and business organization +
  • +
  • + โœ“ + Access your notes across multiple devices +
  • +
  • + โœ“ + Export your data for personal use +
  • +
+
+ +
+

+ + + + You May Not +

+
    +
  • + โœ— + Store illegal or harmful content +
  • +
  • + โœ— + Share copyrighted material without permission +
  • +
  • + โœ— + Attempt to hack or disrupt the service +
  • +
  • + โœ— + Use for spam or malicious activities +
  • +
+
+
+ +
+

+ + + + Prohibited Content +

+
+
+ โ€ข + Illegal activities +
+
+ โ€ข + Malware or viruses +
+
+ โ€ข + Hate speech +
+
+ โ€ข + Spam content +
+
+
+
+ + {/* Intellectual Property */} +
+

+
+ 4. Intellectual Property +

+ +
+
+

+ + + + Your Content +

+

+ You retain all ownership rights to the content you create and store in Notebook. We claim no intellectual property rights over the material you provide to the Service. +

+
+

+ You own your notes. We simply provide the platform for you to create, store, and manage them. +

+
+
+ +
+

+ + + + Our Service +

+

+ The Notebook service, including its features, design, code, and branding, is protected by copyright, trademark, and other laws. You may not copy, modify, or create derivative works without our explicit permission. +

+
+
+
+ + {/* Service Terms */} +
+

+
+ 5. Service Terms +

+ +
+
+

+ + + + Availability +

+

+ We strive to maintain 99.9% uptime but cannot guarantee uninterrupted service. We may perform maintenance that temporarily affects availability. +

+
+ +
+

+ + + + Modifications +

+

+ We reserve the right to modify or discontinue the Service at any time. We will provide notice of significant changes. +

+
+
+
+ + {/* Limitation of Liability */} +
+

+
+ 6. Limitation of Liability +

+ +
+

+ To the fullest extent permitted by law, Notebook shall not be liable for any indirect, incidental, special, consequential, or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses. +

+
+
+
We Are Not Liable For:
+
    +
  • + โ€ข + Data loss due to user error +
  • +
  • + โ€ข + Service interruptions +
  • +
  • + โ€ข + Third-party actions +
  • +
+
+
+
Your Responsibility:
+
    +
  • + โ€ข + Regular data backups +
  • +
  • + โ€ข + Account security +
  • +
  • + โ€ข + Content compliance +
  • +
+
+
+
+
+ + {/* Termination */} +
+

+
+ 7. Termination +

+ +
+

+ You may stop using our Service at any time. You can delete your account and all associated data through your account settings. +

+
+

+ Note: Account deletion is permanent and cannot be undone. All your notes and data will be permanently removed from our servers. +

+
+
+
+ + {/* Governing Law */} +
+

+
+ 8. Governing Law +

+ +
+

+ These Terms shall be governed by and construed in accordance with the laws of the United States, without regard to its conflict of law provisions. +

+

+ Any disputes arising from these Terms or your use of the Service shall be resolved in the courts of the United States. +

+
+
+ + {/* Contact Information */} +
+

+ + + + Contact Us +

+

+ If you have any questions about these Terms of Service, please contact us: +

+
+ + + + HarshYadav152@outlook.com +
+
+
+
+ + {/* Acceptance Section */} +
+

+ By using SaveBook, you acknowledge that you have read, understood, and agree to be bound by these Terms of Service. +

+

+ Continued use of the Service constitutes acceptance of any future updates to these terms. +

+
+
+
+ ) +} + +// Main component with Suspense +export default function TermsOfService() { + return ( + }> + + + ); +} \ No newline at end of file diff --git a/savebook/app/api/auth/login/route.js b/savebook/app/api/auth/login/route.js new file mode 100644 index 0000000..37c47b4 --- /dev/null +++ b/savebook/app/api/auth/login/route.js @@ -0,0 +1,65 @@ +import dbConnect from '@/lib/db/mongodb'; +import User from '@/lib/models/User'; +import { generateAuthToken } from '@/lib/utils/JWT'; +import { NextResponse } from 'next/server'; + +export async function POST(request) { + try { + await dbConnect(); + + const { username, password } = await request.json(); + + // Find user + const user = await User.findOne({ username }).select("+password"); + if (!user) { + return NextResponse.json( + { success: false, message: "Invalid email or password" }, + { status: 401 } + ); + } + + // Verify password + const isPasswordValid = await user.comparePassword(password); + if (!isPasswordValid) { + return NextResponse.json( + { success: false, message: "Invalid email or password" }, + { status: 401 } + ); + } + + // Generate token + const {authToken} = await generateAuthToken(user._id); + + // Create response + const response = NextResponse.json( + { + success: true, + data: { + user: { + username:user.username + }, + authToken + }, + message: "Login successful" + }, + { status: 200 } + ); + + // Set cookie + response.cookies.set('authToken', authToken, { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'strict', + maxAge: 60 * 60 * 24 * 7, // 1 week + path: '/' + }); + + return response; + } catch (error) { + console.error("Login error:", error); + return NextResponse.json( + { success: false, message: error.message || "Internal server error" }, + { status: error.statusCode || 500 } + ); + } +} \ No newline at end of file diff --git a/savebook/app/api/auth/logout/route.js b/savebook/app/api/auth/logout/route.js new file mode 100644 index 0000000..04dc280 --- /dev/null +++ b/savebook/app/api/auth/logout/route.js @@ -0,0 +1,25 @@ +import { NextResponse } from "next/server"; + +export async function GET() { + try { + // Create a response + const response = NextResponse.json( + { success: true, message: "Logged out successfully" }, + { status: 200 } + ); + + // Clear the auth token cookie + response.cookies.set("authToken", "", { + httpOnly: true, + expires: new Date(0), + path: "/" + }); + + return response; + } catch (error) { + return NextResponse.json( + { success: false, message: error.message || "Logout failed" }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/savebook/app/api/auth/register/route.js b/savebook/app/api/auth/register/route.js new file mode 100644 index 0000000..735937f --- /dev/null +++ b/savebook/app/api/auth/register/route.js @@ -0,0 +1,39 @@ +import { NextResponse } from 'next/server'; +import User from '@/lib/models/User'; +import dbConnect from '@/lib/db/mongodb'; + +export async function POST(request) { + await dbConnect(); + + try { + const { username, password } = await request.json(); + + // Check if user exists + let user = await User.findOne({ username }); + if (user) { + return NextResponse.json( + { error: "User with this username already exists" }, + { status: 400 } + ); + } + + // Create user + await User.create({ + username, + password + }); + + // Set cookie and return response + const response = NextResponse.json({ + success: true + }); + + return response; + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Server error" }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/savebook/app/api/auth/user/route.js b/savebook/app/api/auth/user/route.js new file mode 100644 index 0000000..049a3f0 --- /dev/null +++ b/savebook/app/api/auth/user/route.js @@ -0,0 +1,40 @@ +import dbConnect from "@/lib/db/mongodb"; +import User from "@/lib/models/User"; +import { verifyJwtToken } from "@/lib/utils/JWT"; +import { NextResponse } from "next/server"; + +export async function GET(request) { + try { + // Connect to database + await dbConnect(); + + // Get token from authorization header + const authtoken = request.cookies.get("authToken"); + console.log("authtoken from cookies : ",authtoken) + // Verify token + const decoded = verifyJwtToken(authtoken.value); + console.log("decoded user : ",decoded) + if (!decoded) { + return NextResponse.json({ error: "Unauthorized - Invalid token" }, { status: 401 }); + } + + // Find user by ID but exclude the password + const user = await User.findById(decoded.userId).select("-password"); + + if (!user) { + return NextResponse.json({ error: "User not found" }, { status: 404 }); + } + + // Return user data + return NextResponse.json({ + success: true, + user: { + username:user.username + } + }, { status: 200 }); + + } catch (error) { + console.error("Error fetching user:", error); + return NextResponse.json({ error: "Internal Server Error" }, { status: 500 }); + } +} \ No newline at end of file diff --git a/savebook/app/api/notes/[id]/route.js b/savebook/app/api/notes/[id]/route.js new file mode 100644 index 0000000..083f295 --- /dev/null +++ b/savebook/app/api/notes/[id]/route.js @@ -0,0 +1,155 @@ +import { NextResponse } from 'next/server'; +import mongoose from 'mongoose'; +import dbConnect from '@/lib/db/mongodb'; +import Notes from '@/lib/models/Notes'; +import { verifyJwtToken } from '@/lib/utils/JWT'; + +// Get a specific note by ID +export async function GET(request, { params }) { + await dbConnect(); + + try { + const { id } = params; + + // Validate ID format + if (!mongoose.Types.ObjectId.isValid(id)) { + return NextResponse.json( + { error: "Invalid note ID" }, + { status: 400 } + ); + } + + const token = request.cookies.get('authToken'); + const { userId } = verifyJwtToken(token.value) + + const note = await Notes.findOne({ _id: id, user: userId }); + + if (!note) { + return NextResponse.json( + { error: "Note not found" }, + { status: 404 } + ); + } + + return NextResponse.json(note); + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Server error" }, + { status: 500 } + ); + } +} + +// Update a note by ID +export async function PUT(request, { params }) { + await dbConnect(); + + try { + const { id } = params; + + // Validate ID format + if (!mongoose.Types.ObjectId.isValid(id)) { + return NextResponse.json( + { error: "Invalid note ID" }, + { status: 400 } + ); + } + + const token = request.cookies.get('authToken'); + const { userId } = verifyJwtToken(token.value) + + const { title, description, tag } = await request.json(); + + // Create updated note object + const updatedNote = {}; + if (title) updatedNote.title = title; + if (description) updatedNote.description = description; + if (tag) updatedNote.tag = tag; + + // Find note and verify ownership + let note = await Notes.findById(id); + + if (!note) { + return NextResponse.json( + { error: "Note not found" }, + { status: 404 } + ); + } + + // Verify user owns this note + if (note.user.toString() !== userId) { + return NextResponse.json( + { error: "Not authorized" }, + { status: 401 } + ); + } + + // Update the note + note = await Notes.findByIdAndUpdate( + id, + { $set: updatedNote }, + { new: true } + ); + + return NextResponse.json(note); + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Server error" }, + { status: 500 } + ); + } +} + +// Delete a note by ID +export async function DELETE(request, { params }) { + await dbConnect(); + + try { + const { id } = params; + + // Validate ID format + if (!mongoose.Types.ObjectId.isValid(id)) { + return NextResponse.json( + { error: "Invalid note ID" }, + { status: 400 } + ); + } + + const token = request.cookies.get('authToken'); + const { userId } = verifyJwtToken(token.value) + + // Find note and verify ownership + let note = await Notes.findById(id); + + if (!note) { + return NextResponse.json( + { error: "Note not found" }, + { status: 404 } + ); + } + + // Verify user owns this note + if (note.user.toString() !== userId) { + return NextResponse.json( + { error: "Not authorized" }, + { status: 401 } + ); + } + + // Delete the note + await Notes.findByIdAndDelete(id); + + return NextResponse.json({ + success: true, + message: "Note deleted successfully" + }); + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Server error" }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/savebook/app/api/notes/route.js b/savebook/app/api/notes/route.js new file mode 100644 index 0000000..5cc86f6 --- /dev/null +++ b/savebook/app/api/notes/route.js @@ -0,0 +1,48 @@ +import { NextResponse } from 'next/server'; +import dbConnect from '@/lib/db/mongodb'; +import Notes from '@/lib/models/Notes'; +import { verifyJwtToken } from '@/lib/utils/JWT'; + +export async function GET(request) { + await dbConnect(); + + try { + const token = request.cookies.get('authToken'); + const {userId} = verifyJwtToken(token.value) + + const notes = await Notes.find({ user: userId }); + return NextResponse.json(notes); + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Server error" }, + { status: 500 } + ); + } +} + +export async function POST(request) { + await dbConnect(); + + try { + + const { title, description, tag } = await request.json(); + const token = request.cookies.get('authToken'); + + const {userId} = verifyJwtToken(token.value) + const note = await Notes.create({ + title, + description, + tag, + user: userId + }); + + return NextResponse.json(note, { status: 201 }); + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Server error" }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/savebook/app/favicon.ico b/savebook/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/savebook/app/globals.css b/savebook/app/globals.css new file mode 100644 index 0000000..2a6d5cd --- /dev/null +++ b/savebook/app/globals.css @@ -0,0 +1,5 @@ +@import "tailwindcss"; + +body{ + background-color:#101828; +} \ No newline at end of file diff --git a/savebook/app/layout.js b/savebook/app/layout.js new file mode 100644 index 0000000..905d88a --- /dev/null +++ b/savebook/app/layout.js @@ -0,0 +1,53 @@ +import { Inter, Roboto_Mono } from "next/font/google"; +import "./globals.css"; +import { Toaster } from "react-hot-toast"; +import NoteState from "@/context/NoteState"; +import AuthProvider from "@/context/auth/AuthState"; +import Navbar from "@/components/common/Navbar"; +import Footer from "@/components/common/Footer"; +import LoadingProvider from "@/components/providers/LoadingProvider"; +import { Suspense } from "react"; + +// Replace Geist with Inter (similar clean sans-serif) +const inter = Inter({ + subsets: ["latin"], + display: "swap", + variable: "--font-sans", +}); + +// Replace Geist Mono with Roboto Mono +const robotoMono = Roboto_Mono({ + subsets: ["latin"], + display: "swap", + variable: "--font-mono", +}); + +export const metadata = { + title: "SaveBook | Your Personal Notebook", + description: "Save Notebook on the cloud", +}; + +export default function RootLayout({ children }) { + return ( + + + + }> + + + + + {/*
*/} + {children} + {/*
*/} +
+