diff --git a/README.md b/README.md index 255b7cd..ed3ec38 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,147 @@ -# Garuda Hacks 6.0 Web Back-End +# Garuda Hacks Backend 🚀 -This repository contains Cloud Functions for Firebase, written in TypeScript. +The official backend service for Garuda Hacks 6.0, providing robust and scalable APIs for the hackathon platform. Built with Firebase Cloud Functions and TypeScript to ensure reliability and maintainability. -## Setup +## 🛠️ Tech Stack + +- **Backend** + + - Firebase Cloud Functions + - TypeScript + - Node.js + - Express.js + - Firebase Admin SDK + +- **Database** + + - Firebase Firestore + +- **Authentication** + + - Firebase Authentication + +- **Deployment** + - Firebase Hosting + - Firebase Cloud Functions + +## 🚀 Getting Started ### Prerequisites -- Node.js 20+ -- Firebase CLI installed (`npm install -g firebase-tools`) -- A Firebase project set up +- Node.js (v20 or higher) +- npm or yarn +- Firebase CLI (`npm install -g firebase-tools`) +- Firebase account ### Installation -```sh +1. Clone the repository + +```bash +git clone https://github.com/your-username/web-be.git +cd web-be +``` + +2. Install dependencies + +```bash npm install ``` -### Environment Variables +3. Set up environment variables -Create a `.env` file and add your environment variables as needed. +```bash +cp .env.example .env +``` -## Development +Fill in your Firebase configuration in `.env`: -### Lint +```bash +# Firebase Configuration +FIREBASE_PROJECT_ID=your-project-id +FIREBASE_PRIVATE_KEY=your-private-key +FIREBASE_CLIENT_EMAIL=your-client-email -```sh -npm run lint +# Other Configuration +NODE_ENV=development ``` -### Build +4. Start development server -```sh -npm run build +```bash +npm run serve ``` -### Watch Mode +### Building for Production -```sh -npm run build:watch +```bash +npm run build ``` -### Serve Locally +## 📁 Project Structure -```sh -npm run serve +``` +web-be/ +├── src/ +│ ├── functions/ # Cloud Functions +│ │ ├── auth/ # Authentication related functions +│ │ ├── users/ # User management functions +│ │ └── utils/ # Utility functions +│ ├── config/ # Configuration files +│ ├── types/ # TypeScript type definitions +│ └── utils/ # Helper functions +├── tests/ # Test files +└── firebase.json # Firebase configuration ``` -### Firebase Shell +## 🔧 Configuration -```sh -npm run shell -``` +### Environment Variables -## Deployment +Required environment variables: -```sh -npm run deploy -``` +- `FIREBASE_PROJECT_ID` +- `FIREBASE_PRIVATE_KEY` +- `FIREBASE_CLIENT_EMAIL` +- `NODE_ENV` -## Logs +## 🤝 Contributing -```sh -npm run logs -``` +1. Fork the repository +2. Create your feature branch (`git checkout -b feat/amazing-feature`) +3. Make your changes following our commit conventions: + + ```bash + # Format + (): + + # Examples + feat(auth): add user authentication middleware + fix(api): resolve CORS configuration + docs(readme): update deployment steps + style(code): improve error handling + refactor(functions): optimize database queries + test(auth): add authentication tests + chore(deps): update dependencies + ``` + + Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore` + Scope: optional, indicates the module affected + +4. Push to the branch (`git push origin feat/amazing-feature`) +5. Open a Pull Request + +## 📝 License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## 🙏 Acknowledgments + +- [Firebase](https://firebase.google.com/) +- [TypeScript](https://www.typescriptlang.org/) +- [Node.js](https://nodejs.org/) +- [Express.js](https://expressjs.com/) + +--- +Made with ❤️ by the Garuda Hacks Team diff --git a/functions/src/controllers/application_controller.ts b/functions/src/controllers/application_controller.ts index def613a..da9d151 100644 --- a/functions/src/controllers/application_controller.ts +++ b/functions/src/controllers/application_controller.ts @@ -462,8 +462,7 @@ function validateStringValue(fieldValue: string | any, question: Question) { message: `Must be less than ${validation.maxLength} character(s)`, }); } - // other string validation if needed - // ... + return errors; } diff --git a/functions/src/controllers/auth_controller.ts b/functions/src/controllers/auth_controller.ts index 395e1c0..8ba6210 100644 --- a/functions/src/controllers/auth_controller.ts +++ b/functions/src/controllers/auth_controller.ts @@ -445,17 +445,7 @@ const createMailOptions = (email: string, link: string): MailOptions => ({
-
- Garuda Hacks Logo -
-

Reset Your Password

+

Reset Your Password

You requested a password reset. Click the button below to choose a new password:

Reset Password

@@ -469,7 +459,7 @@ const createMailOptions = (email: string, link: string): MailOptions => ({

© ${new Date().getFullYear()} Garuda Hacks. All rights reserved.

Visit our website | - Contact Support + Contact Support

diff --git a/functions/src/routes/auth.ts b/functions/src/routes/auth.ts index 7d5f4de..ebab38e 100644 --- a/functions/src/routes/auth.ts +++ b/functions/src/routes/auth.ts @@ -12,7 +12,7 @@ const router = express.Router(); router.post("/login", (req: Request, res: Response) => login(req, res)); router.post("/register", (req: Request, res: Response) => register(req, res)); -router.post("/request-reset", requestPasswordReset); +router.post("/reset-password", requestPasswordReset); router.post("/session-login", (req: Request, res: Response) => sessionLogin(req, res) ); diff --git a/functions/src/server.ts b/functions/src/server.ts index 671a9c8..3cdb290 100644 --- a/functions/src/server.ts +++ b/functions/src/server.ts @@ -13,8 +13,8 @@ const allowedOrigins = [ "http://localhost:3001", "http://localhost:5173", "https://garudahacks.com", - "https://portal-ochre-iota.vercel.app", "https://portal.garudahacks.com", + "https://preview.portal.garudahacks.com", ]; const corsOptions: CorsOptions = { diff --git a/functions/src/types/application_types.ts b/functions/src/types/application_types.ts index 182ef08..a54595f 100644 --- a/functions/src/types/application_types.ts +++ b/functions/src/types/application_types.ts @@ -1,4 +1,4 @@ -import {Request} from "express"; +import { Request } from "express"; export enum APPLICATION_STATUS { NOT_APPLICABLE = "not applicable", @@ -6,7 +6,8 @@ export enum APPLICATION_STATUS { SUBMITTED = "submitted", WAITLISTED = "waitlisted", REJECTED = "rejected", - ACCEPTED = "accepted" + ACCEPTED = "accepted", + CONFIRMED_RSVP = "confirmed rsvp", } /** @@ -24,13 +25,14 @@ export enum QUESTION_TYPE { TEXTAREA = "textarea", DATE = "datetime", DROPDOWN = "dropdown", - FILE = "file" + FILE = "file", } export interface StringValidation { required?: boolean; minLength?: number; maxLength?: number; + pattern?: string; } export interface NumberValidation { @@ -64,14 +66,14 @@ export type ValidationTypeMap = { }; export interface Question { - id?: string; + id: string; order: number; - state: APPLICATION_STATES; text: string; type: QUESTION_TYPE; validation: ValidationTypeMap[Question["type"]]; - + placeholder?: string; options?: string[]; // for dropdown only + state: APPLICATION_STATES; } export interface FileInfo { @@ -89,4 +91,4 @@ export interface FileData { export interface ExtendedRequest extends Request { rawBody?: Buffer; -} \ No newline at end of file +} diff --git a/functions/src/utils/fake_data_populator.ts b/functions/src/utils/fake_data_populator.ts index 9cb62dd..ce6836d 100644 --- a/functions/src/utils/fake_data_populator.ts +++ b/functions/src/utils/fake_data_populator.ts @@ -90,18 +90,21 @@ export class FakeDataPopulator { // string example q = { + id: faker.string.uuid(), order: 1, state: APPLICATION_STATES.PROFILE, text: "Name", type: QUESTION_TYPE.STRING, validation: { required: true, + pattern: "^[a-zA-Z\\s'-]+$", }, }; await this.createQuestionDocument(q); // number example q = { + id: faker.string.uuid(), order: 2, state: APPLICATION_STATES.PROFILE, text: "Age", @@ -110,30 +113,35 @@ export class FakeDataPopulator { required: true, minValue: 16, maxValue: 45, + pattern: "^[0-9]+$", }, }; await this.createQuestionDocument(q); // date example q = { + id: faker.string.uuid(), order: 3, state: APPLICATION_STATES.PROFILE, text: "Birthday", type: QUESTION_TYPE.DATE, validation: { required: true, + pattern: "^\\d{4}-\\d{2}-\\d{2}$", }, }; await this.createQuestionDocument(q); // dropdown example q = { + id: faker.string.uuid(), order: 4, state: APPLICATION_STATES.PROFILE, text: "Education Level", type: QUESTION_TYPE.DROPDOWN, validation: { required: true, + pattern: "^(Undergraduate|High School)$", }, options: ["Undergraduate", "High School"], }; @@ -141,6 +149,7 @@ export class FakeDataPopulator { // file example q = { + id: faker.string.uuid(), order: 4, state: APPLICATION_STATES.PROFILE, text: "Profile Photo", @@ -149,30 +158,35 @@ export class FakeDataPopulator { required: true, allowedTypes: "image/jpg,image/jpeg,image/png", maxSize: 5, + pattern: "\\.(jpg|jpeg|png)$", }, }; await this.createQuestionDocument(q); // string example q = { + id: faker.string.uuid(), order: 1, state: APPLICATION_STATES.INQUIRY, text: "What's your motivation in joining GarudaHacks?", type: QUESTION_TYPE.TEXTAREA, validation: { required: true, + pattern: "^[\\w\\s\\.,!?-]+$", }, }; await this.createQuestionDocument(q); // string example q = { + id: faker.string.uuid(), order: 1, state: APPLICATION_STATES.INQUIRY, text: "Do you have any limitation that we should be concern about?", type: QUESTION_TYPE.TEXTAREA, validation: { required: true, + pattern: "^[\\w\\s\\.,!?-]+$", }, }; await this.createQuestionDocument(q);