diff --git a/RIT-EMS-main/EMS_DOCUMENTATION.md b/RIT-EMS-main/EMS_DOCUMENTATION.md index 46a5dcb..11c7fff 100644 --- a/RIT-EMS-main/EMS_DOCUMENTATION.md +++ b/RIT-EMS-main/EMS_DOCUMENTATION.md @@ -24,7 +24,7 @@ The EMS platform addresses these challenges by offering: ## 2. System Architecture & Tech Stack -The platform is designed around a modern decoupled client-server architecture. +The platform runs on a serverless, database-first architecture using Firebase. All backend endpoints are intercepted and resolved client-side in the browser. ```mermaid graph LR @@ -33,31 +33,24 @@ graph LR Router[Component & Context Routing] Tailwind[Tailwind CSS & Glassmorphism UI] Framer[Framer Motion Animations] + Interceptor[Fetch Interceptor firebaseBackend.ts] end - subgraph Backend [Spring Boot API Server] - Controller[REST API Controllers] - Security[Spring Security Config] - Services[JPA / Hibernate Data Access] + subgraph Backend [Firebase Cloud Platform] + Firestore[(Cloud Firestore Database)] + Auth[Firebase Authentication] end - subgraph Database [Relational Storage] - MySQL[(Local MySQL ems_db)] - end - - React <-->|REST over HTTP| Controller - Controller <--> Services - Services <--> MySQL + React <--> Interceptor + Interceptor <-->|Firebase Client SDK| Firestore + Interceptor <-->|Firebase Client SDK| Auth ``` -### Backend Specifications -* **Core Framework:** Spring Boot 3.2.5 (Java 17) -* **ORM & Data Access:** Spring Data JPA with Hibernate -* **Database Driver:** MySQL Connector/J (`com.mysql.cj.jdbc.Driver`) -* **Security:** Spring Security (Permit-all filter bypass, with role-based checks and authorization handling verified inside the controller/service scope). -* **Cryptographic Hashing:** `BCryptPasswordEncoder` for storing/verifying user passwords. -* **Dev Tools:** Project Lombok, Spring Boot DevTools. -* **Port Configuration:** Runs on port `8081` (CORS-enabled for frontend origins). +### Firebase Backend Specifications +* **Database Service:** Cloud Firestore for real-time document storage. +* **Data Access & Interception:** A client-side fetch interceptor implemented in `firebaseBackend.ts` intercepts all `/api/*` REST HTTP requests and handles the queries/transactions natively using the Firebase Client SDK. +* **Authentication:** Google OAuth 2.0 and email/passcode flows, integrated with Firebase Auth and sync'd to the `ems_users` Firestore collection. +* **Security & Roles:** Verified inside frontend routing handlers and secured using Firestore Security Rules. ### Frontend Specifications * **Core Framework:** React 19, TypeScript, Vite @@ -73,7 +66,7 @@ graph LR ## 3. Database Schema & Architecture -The database contains four primary entities managed via Spring Data JPA. +The database contains four primary collections managed in Cloud Firestore. ```mermaid erDiagram @@ -338,16 +331,16 @@ graph TD ## 6. Key Workflows & Logic Specs ### A. Real-time Conflict Auditing Engine -During event creation, the backend validates for timing and location conflicts. -1. The backend runs the custom JPA method `findConflictingEvents()` matching location, institution, status (`APPROVED`), and overlapping times: +During event creation, the application validates for timing and location conflicts directly against Firestore. +1. The frontend query helper scan the `ems_events` collection to identify overlapping bookings: $$\text{Start}_A < \text{End}_B \quad \text{and} \quad \text{End}_A > \text{Start}_B$$ 2. **Placement Override Case:** If the proposer is a `PLACEMENT` coordinator and `cancelConflicting=true` is checked: - * The backend sets all conflicting events to `CANCELLED`. - * The backend registers a rejection/displacement reason on the cancelled events. + * The fetch interceptor updates all conflicting Firestore event documents' status to `CANCELLED`. + * It registers a rejection/displacement reason on the cancelled events. * The placement event is saved in `PENDING_PR` (for Principal review). 3. **General Case:** - If conflicts exist and it is not an overridden placement, the backend throws a `409 Conflict` HTTP exception with conflicting details. + If conflicts exist and it is not an overridden placement, a conflict message is returned and flagged to the user. ### B. Event Approval Pipeline The approval flow routes events dynamically depending on the proposer: @@ -387,27 +380,9 @@ This tool allows admins/HODs/Principals to duplicate schedules for new semesters ## 7. Developer & Local Deployment Guide ### Prerequisites -* Java JDK 17 * Node.js (v18+) -* MySQL Database Server -### 1. Database Setup -1. Start your local MySQL instance. -2. Create the target schema (automatic if configuration is active): - ```sql - CREATE DATABASE ems_db; - ``` -3. Update the credentials in `backend/src/main/resources/application.properties` (defaults: username `root`, password `Abiram@07`). - -### 2. Launch Backend Server -1. Navigate to the `backend` folder. -2. Compile and run using Maven: - ```bash - mvnw spring-boot:run - ``` -3. The server starts at `http://localhost:8081`. The `DataInitializer` runs on startup to seed the default user accounts. - -### 3. Launch Frontend Client +### 1. Launch Frontend Client 1. Navigate to the `frontend` folder. 2. Install dependencies: ```bash @@ -419,7 +394,11 @@ This tool allows admins/HODs/Principals to duplicate schedules for new semesters ``` 4. The frontend runs at `http://localhost:5173`. -### 4. Seed User Accounts & Logins +### 2. Firebase Configurations +* The Firebase client config is hardcoded in `frontend/src/lib/firebaseBackend.ts` to connect directly to the Firestore backend. +* On first load, if the database collections (`ems_users` or `ems_classes`) are empty, `firebaseBackend.ts` automatically seeds default institutional accounts and mock classes. + +### 3. Seed User Accounts & Logins On startup, the system seeds accounts with their default passwords: * **Faculty Member:** `faculty@rit.edu` / `faculty123` * **HOD:** `hod@rit.edu` / `hod123` diff --git a/RIT-EMS-main/EMS_DOCUMENTATION_SUPABASE.md b/RIT-EMS-main/EMS_DOCUMENTATION_SUPABASE.md deleted file mode 100644 index 4526239..0000000 --- a/RIT-EMS-main/EMS_DOCUMENTATION_SUPABASE.md +++ /dev/null @@ -1,358 +0,0 @@ -# Rajalakshmi Institute of Technology (RIT) Events Hub — System Documentation - -Welcome to the comprehensive system documentation for the **RIT Events Hub**, a premium, high-fidelity academic event management, tracking, and auditing portal designed for Rajalakshmi Institute of Technology. - -This document provides a complete breakdown of the website's architecture, user roles, file structures, database schema, operational workflows, and features, accompanied by a detailed site map. - ---- - -## 1. Overview & Core Mission - -The **RIT Events Hub** is an institutional web application designed to digitize and manage the entire lifecycle of college events. It replaces manual event scheduling, paper registrations, physical ticket checks, and fragmented certificate auditing with a unified, secure portal. - -### Key Objectives: -* **Decentralized Event Creation:** Enable faculty members to coordinate, schedule, and estimate budgets for departmental activities. -* **Hierarchical Approvals:** Ensure events undergo appropriate institutional oversight through a HOD-to-Admin approval pipeline. -* **Intelligent Resource Management:** Prevent venue conflicts and respect departmental/sectional seat quotas. -* **Continuous Verification for Students:** Link student attendance, certificate uploads, and On-Duty (OD) approvals step-by-step. -* **Security & Accessibility:** Provide separate, secure authentication models for internal students, external students, coordinators (faculty/HOD), and administrators. - ---- - -## 2. Technology Stack & Integrations - -The platform is built using a modern, fast, and secure web development stack: - -| Layer | Technology | Description | -| :--- | :--- | :--- | -| **Frontend Framework** | React (v19), TypeScript, Vite | Multi-page single-page application (SPA) state-managed structure. | -| **Styling & Icons** | Tailwind CSS (CDN), FontAwesome | Curated responsive styling using professional color palettes (Deep Blue `#004a99` and Academic Orange `#f97316`). | -| **Backend & Auth** | Supabase (PostgreSQL, Storage, Auth) | Manages authentication, row-level security (RLS), document uploads, and database queries. | -| **PDF Generation** | `jspdf` & `jspdf-autotable` | Compiles detailed, printable event proposals containing budget sheets, schedules, and resource details. | -| **Layout Tools** | `html2canvas` | Used to capture ticket layouts for student downloads. | -| **Fonts** | Google Fonts (Inter, Playfair Display) | Custom typography reflecting academic elegance. | - ---- - -## 3. Database Schema - -The database relies on a PostgreSQL schema managed via Supabase. Below are the primary tables and relations: - -### `Studentusers` (Internal Students) -* `id` (UUID, Primary Key, references auth.users) -* `name` (Text) -* `email` (Text, Unique) -* `reg_no` (Text, Unique) -* `phone` (Text) -* `department` (Text) -* `year` (Text) -* `section` (Text) -* `college_name` (Text - Default: 'RAJALAKSHMI INSTITUTE OF TECHNOLOGY') -* `updated_at` (Timestamp) - -### `externalusers` (External Students) -* `id` (UUID, Primary Key, references auth.users) -* `name` (Text) -* `email` (Text, Unique) -* `reg_no` (Text) -* `phone` (Text) -* `department` (Text) -* `year` (Text) -* `section` (Text) -* `college` (Text) -* `college_location` (Text) -* `gender` (Text) -* `updated_at` (Timestamp) - -### `Facultyusers` (Coordinators & HODs) -* `id` (UUID, Primary Key, references auth.users) -* `name` (Text) -* `email` (Text, Unique) -* `dept` (Text) -* `role` (Text - e.g., 'Faculty', 'HOD', 'System Admin') -* `phone` (Text) -* `profile_photo` (Text - URL) -* `updated_at` (Timestamp) - -### `Adminusers` (Principal / Director / Administrators) -* `id` (UUID, Primary Key, references auth.users) -* `name` (Text) -* `email` (Text, Unique) -* `dept` (Text - 'Administration') -* `updated_at` (Timestamp) - -### `events` -* `id` (UUID, Primary Key) -* `title` (Text) -* `location` (Text - Venue name) -* `date` (Text - Standard format) -* `category` (Text - 'TECHNICAL' \| 'NON-TECHNICAL' \| 'WORKSHOP' \| 'CENTRE-ACTIVITY') -* `domain` (Text - references domains.name) -* `pricing_type` (Text - 'FREE' \| 'PAID') -* `coordinator` (Text - Coordinator Name) -* `club` (Text) -* `image` (Text - Supabase storage URL) -* `status` (Text - 'Scheduled' \| 'Event Ongoing' \| 'Completed') -* `max_participants` (Integer) -* `registration_deadline` (Timestamp) -* `duration_days` (Integer) -* `event_summary` (Text) -* `is_team_event` (Boolean) -* `team_size_limit` (Integer) -* `team_composition` (Text - 'MIXED' \| 'INTER_DEPT') -* `participant_type` (Text - 'INTERNAL' \| 'EXTERNAL' \| 'BOTH') -* `verification_status` (Text - 'PENDING' \| 'PENDING_HOD' \| 'PENDING_ADMIN' \| 'APPROVED' \| 'REJECTED') -* `refreshment_expense` (Numeric) -* `transportation_expense` (Numeric) -* `session_coverage_fee` (Numeric) -* `total_expense` (Numeric) -* `conducting_dept` (Text) -* `created_by` (UUID, references auth.users) -* `request_by_faculty` (Timestamp) -* `request_by_hod` (Timestamp) - -### `event_schedule` (Session/Batch Slots) -* `id` (UUID, Primary Key) -* `event_id` (UUID, references events.id) -* `day_idx` (Integer) -* `batch_idx` (Integer) -* `date` (Text) -* `start_time` (Text) -* `end_time` (Text) - -### `resource_persons` (Guest Details) -* `id` (UUID, Primary Key) -* `event_id` (UUID, references events.id) -* `day_idx` (Integer) -* `batch_idx` (Integer) -* `schedule_id` (UUID, references event_schedule.id) -* `type` (Text - 'INTERNAL' \| 'EXTERNAL') -* `name` (Text) -* `dept` (Text) -* `college_name` (Text) -* `phone` (Text) -* `email` (Text) - -### `event_dept_limits` (Departmental Seat Allocations) -* `id` (UUID, Primary Key) -* `event_id` (UUID, references events.id) -* `department` (Text) -* `max_seats` (Integer) -* `section_limits` (JSONB - Maps sections (A, B, C...) to integer limits) - -### `registrations` (Student Bookings) -* `id` (Text, Primary Key - Structured as `${userId}_${eventId}`) -* `user_id` (UUID, references auth.users) -* `event_id` (UUID, references events.id) -* `user_email` (Text) -* `user_name` (Text) -* `reg_no` (Text) -* `phone` (Text) -* `gender` (Text) -* `dept` (Text) -* `section` (Text) -* `year` (Text) -* `college` (Text) -* `payment_status` (Text - 'PENDING' \| 'COMPLETED') -* `registered_at` (Timestamp) -* `team_code` (Text) -* `team_name` (Text) -* `is_team_leader` (Boolean) -* `certification_url` (Text) -* `certification_status` (Text - 'PENDING' \| 'APPROVED' \| 'REJECTED') -* `od_url` (Text) -* `od` (Boolean - OD approval) - -### `announcements` (Notice Board) -* `id` (UUID, Primary Key) -* `title` (Text) -* `message` (Text) -* `type` (Text - 'DELAY' \| 'INFO' \| 'URGENT' \| 'ENDED' \| 'ONGOING') -* `event_id` (UUID, references events.id) -* `timestamp` (Timestamp) -* `expires_at` (Timestamp) - -### `special_events` (Symposiums & External Links) -* `id` (UUID, Primary Key) -* `title` (Text) -* `description` (Text) -* `link` (Text) -* `created_by` (UUID) -* `is_active` (Boolean) -* `verification_status` (Text - 'PENDING' \| 'APPROVED' \| 'REJECTED') - -### `domains` -* `id` (UUID, Primary Key) -* `name` (Text, Unique) -* `category` (Text) -* `image` (Text) -* `status` (Text - 'PENDING' \| 'APPROVED' \| 'REJECTED') -* `description` (Text) - ---- - -## 4. Operational Workflows & Key Logic - -### A. Core Blockage (Preventing Registration Overhead) -To maintain academic integrity, a student **cannot register for any new events** if they have an unfinalized event from the past. -* **Condition:** If a student is registered for an event that has completed (`status === 'Completed'`), they must upload their certificate and obtain coordinator approval (`certification_status === 'APPROVED'`) and OD status before the system allows them to click "Register" on any future catalog events. - -### B. Overlap Prevention (Intelligent Venue Booking) -During event creation, coordinates are validated against active bookings: -* **Conflict Condition:** When a coordinator selects a venue and date, the system queries existing approved/pending events. If another event occupies the same location, and the date ranges overlap based on the `durationDays`, that venue will be flagged as "Booked" or "Under Verification" in the dropdown, disabling selection. - -### C. Quota-Constrained Bookings (Sectional & Departmental Caps) -The event organizer can set constraints for RIT students: -1. **Department Limits:** Limits registration to `X` seats per department. -2. **Section Limits:** Further restricts seats down to individual sections (e.g., CSE section `A` gets 10 seats, section `B` gets 5 seats). -3. **Validation:** When a student attempts registration, the system evaluates their profile (department, section) and checks the respective quota counts in the `registrations` table. If the quota is full, booking is blocked. - -### D. Team play Alliance (Team Registrations) -* For team events, the first student registers and clicks "Form Team", which inserts a random 6-character alphanumeric code (`team_code`) and designates them as `is_team_leader`. -* Subsequent students register for the event, click "Join Team", and input the code. The system verifies the team is not full (respecting `teamSizeLimit`) and matches `INTER_DEPT` composition requirements before assigning the `team_code` to their registration. - -### E. Proposal PDF Compile -Coordinators and Admin can generate a standardized PDF proposal containing: -1. General overview (departments, clubs, metadata). -2. Logistical details (location, dates, capacity, formats). -3. Day-by-day itineraries mapped to guest resource persons and timings. -4. Departmental seat allocation tables. -5. Financial projections (Refreshment + Transportation + Session Fees = Total projected budget). -6. Signature/Verification box showing HOD & Admin approval timestamps. - ---- - -## 5. Portal Flow & Visual Site Map - -### A. Navigational Site Map Structure - -``` -[WELCOME GATEWAY] - │ - ├── STUDENT PORTAL ────► [STUDENT AUTH (Login / Sign Up)] - │ │ - │ ├── HOME DASHBOARD (Notices, Banner, Stats) - │ ├── EVENTS CATALOG (Details, Booking, Team Play) - │ ├── REGISTRATIONS (QR Tickets, Track Progress) - │ ├── STATUS TRACKER (Detailed Lifecycle Step Visualizer) - │ └── PROFILE VIEW (Update Info, Uploaded Credentials) - │ - ├── FACULTY PORTAL ────► [COORDINATOR AUTH (Faculty / HOD)] - │ │ - │ ├── OVERVIEW (Metrics & Quick Gateways) - │ ├── GENERATE EVENTS (Normal, Special, Domains) - │ ├── CREATIONS REGISTRY (Manage Owned Events, Edit/Delete) - │ ├── STATUS TRACKER (Verify Certificates, Audit ODs) - │ ├── EVENT STATUS CONTROL (Announcements, Status Updates) - │ ├── ATTENDANCE CONSOLE (Mark Student Attendance) - │ ├── PARTICIPANTS console (Download Rosters) - │ ├── PROFILE / LOG OUT - │ └── HOD VERIFICATION (HOD only - Review Departmental Proposals) - │ - └── ADMIN PORTAL ──────► [ADMIN AUTH (Principal / Director / System Admin)] - │ - ├── OVERVIEW (System Metrics) - ├── VERIFICATION QUEUE (Standard Events, Special Events, Domains) - ├── USER MANAGEMENT CONSOLE (Update Profiles, Change Roles) - ├── VENUE TRACKER CALENDAR (Visual Schedule & Collision Map) - ├── STATUS TRACKER (Audit all college certifications) - ├── GLOBAL NOTICES (Institutional notices) - └── PROFILE / LOG OUT -``` - -### B. High-Fidelity Mermaid Routing Diagram - -```mermaid -graph TD - %% Base Gateways - Welcome[Welcome Screen] -->|Select STUDENT| StudentAuth[Student Authentication] - Welcome -->|Select COORDINATOR| FacultyAuth[Faculty / HOD Authentication] - Welcome -->|Select ADMIN| AdminAuth[System Admin Authentication] - - %% Student Pathways - StudentAuth -->|Authenticated| StudentDash[Student Dashboard] - StudentDash --> SHome[Home Dashboard] - StudentDash --> SEvents[Events Catalog] - StudentDash --> SRegs[Registrations & QR Tickets] - StudentDash --> STrack[Event Status Tracker] - StudentDash --> SProfile[Student Profile] - - SEvents -->|Register & Form/Join Team| STrack - SRegs -->|Verify Status / Upload Certificate| STrack - - %% Faculty Pathways - FacultyAuth -->|Select Access Level| FacultyLvl{Access Level} - FacultyLvl -->|Faculty| FacultyOverview[Faculty Dashboard] - FacultyLvl -->|HOD| HODOverview[Faculty Dashboard + HOD Verification] - - FacultyOverview --> FHome[Overview & Statistics] - FacultyOverview --> FCreate[Create Event Form] - FacultyOverview --> FCreations[Manage Creations] - FacultyOverview --> FTracker[Status Tracker - Certificate Audit] - FacultyOverview --> FStatus[Event Status & Notices] - FacultyOverview --> FAttendance[Attendance Console] - FacultyOverview --> FParticipants[Participants Console] - FacultyOverview --> FProfile[Faculty Profile] - - HODOverview --> HVerify[HOD Verification Panel] - HVerify -->|Accept Department Request| FTracker - HVerify -->|Reject Request| FCreations - - %% Admin Pathways - AdminAuth --> AdminOverview[Admin Hub] - AdminOverview --> AHome[System Overview] - AdminOverview --> AVerifyQueue[Verification Queue - Events/Domains/Special] - AdminOverview --> AUsers[User Management Console] - AdminOverview --> AVenue[Venue Tracker Calendar] - AdminOverview --> ATracker[Status Tracker] - AdminOverview --> ANotices[Global Announcements] - AdminOverview --> AProfile[Admin Profile] - - %% Cross-Links - FCreations -->|Submit Proposal| HVerify - HVerify -->|Send to Admin Queue| AVerifyQueue - AVerifyQueue -->|Approve Event| SEvents -``` - ---- - -## 6. Directory Layout & Components Guide - -### File & Component Inventory - -* `App.tsx`: Main routing and authentication portal manager. Resolves session state, verifies metadata credentials, performs portal security checks, and loads global states. -* `supabase.ts`: Supabase client configuration, administrative client helper, and helper functions for uploading media (images, certificates) directly to Supabase storage. -* `types.ts`: TypeScript interfaces defining `Event`, `AppState`, `UserRole`, `StudentRequest`, `Ticket`, `ResourcePerson`, `EventSchedule`, `Announcement`, and `UserProfile`. -* `constants.tsx`: Lists static categories, default college domain mappings, clubs, and default showcase events. -* `utils/pdfGenerator.ts`: Handles compiling and exporting the official document proposals for verified events using `jspdf`. - -#### Components Directory (`/components/`): -1. `WelcomeScreen.tsx`: Entrance portal page displaying entry gates for students, faculty coordinators, and admins. -2. `LoginForm.tsx`: sliding dual-panel login and sign up form handling internal/external student data collection and role checks. -3. `Dashboard.tsx`: Base container routing student pages. -4. `HomeDashboard.tsx`: Displays active announcements, stats, special events, and links to catalogs. -5. `Hero.tsx`: Dynamic slide search and welcome banner for students. -6. `UpcomingEventsSlider.tsx`: Auto-scrolling showcase slider displaying upcoming events. -7. `AboutHubSection.tsx`: Summary presentation card describing the Events Hub platform. -8. `StatsSection.tsx`: Shows real-time totals of events, participants, and clubs. -9. `AboutSection.tsx`: Institutional overview details, college details, and guidelines. -10. `ContactSection.tsx`: Map coordinates, support addresses, and telephone details for college portals. -11. `EventList.tsx`: Searchable list displaying approved events by domain filter and category. -12. `EventCard.tsx`: Display card for events containing metadata triggers, register commands, and status links. -13. `RegistrationsView.tsx`: Displays registered ticket vouchers. Generates ticket QR code cards capturing registration details, allowing downloading ticket PDFs. -14. `StatusTrackerView.tsx`: visual step progress checker showing the student their certificate review, attendance logs, and OD approvals. -15. `ProfileView.tsx`: Form for students to edit profile settings and view academic transcripts. -16. `AdminLandingPage.tsx`: Base dashboard routing all Coordinator actions. -17. `CreateEventForm.tsx`: Multi-step event proposal compiler managing budgets, itineraries, and quotas. -18. `CreateSpecialEventsView.tsx`: Allows coordinators to publish external program links. -19. `CreateDomainView.tsx`: Form to submit new technical/non-technical domains for college audit. -20. `AdminStatusTrackerView.tsx`: Review board for coordinators/admins to check student certificate uploads, verify details, and approve OD statuses. -21. `AdminEventStatusView.tsx`: Controls notifications, notice updates, and events status transitions. -22. `FacultyParticipantsView.tsx`: Table listing students registered for an event with search/filter. -23. `FacultyAttendanceView.tsx`: Logs session-by-session student attendance check-ins. -24. `FacultyProfileView.tsx`: Base profile for faculty. -25. `FacultyDashboard.tsx`: Console routing Admin actions. -26. `UserManagementView.tsx`: Table displaying all registered users. Admins can edit profile metadata, manually add students, or alter roles. -27. `TicketVerificationView.tsx`: Camera/code scanner allowing organizers to scan student ticket QR codes and update status in real-time. -28. `Footer.tsx`: Institutional styled footer. -29. `PortalAnimation.tsx`: Page transitions and loading animation overlays. diff --git a/RIT-EMS-main/PROJECT_OVERVIEW.md b/RIT-EMS-main/PROJECT_OVERVIEW.md index c926342..90f419d 100644 --- a/RIT-EMS-main/PROJECT_OVERVIEW.md +++ b/RIT-EMS-main/PROJECT_OVERVIEW.md @@ -21,12 +21,10 @@ The system addresses critical administrative bottlenecks such as: ## 2. Technology Stack ### Backend -* **Core Framework:** Spring Boot 3.2.5 (Java 17) -* **API Architecture:** RESTful Controllers -* **Data Access Layer:** Spring Data JPA with Hibernate -* **Database:** MySQL (local schema: `ems_db`) -* **Security:** Spring Security (endpoints are permit-all at filter level, but validation and role checks occur inside controller services; password encryption via `BCryptPasswordEncoder`) -* **Developer Tools:** Project Lombok, Spring Boot DevTools +* **Core Backend Service:** Firebase (Firestore Database, Firebase Authentication) +* **API Architecture:** Serverless client-side interceptor via `firebaseBackend.ts` which intercepts `/api/*` requests in the browser and processes them directly against Firestore collections. +* **Database:** Cloud Firestore (Collections: `ems_users`, `ems_events`, `ems_notes`, `ems_classes`) +* **Security:** Checked via frontend role verification and Firestore Security Rules. ### Frontend * **Core Framework:** React 19, TypeScript, Vite @@ -42,7 +40,7 @@ The system addresses critical administrative bottlenecks such as: ## 3. Database Schema & Architecture -The system contains four principal entities mapped via JPA. +The system contains four principal Firestore collections. ### A. User Entity (`users`) Holds institutional account profiles, login credentials, permissions, and roles. @@ -133,37 +131,6 @@ Used for pinning warnings, reminders, or notifications on the main calendar. ## 5. Directory Layout & Architecture -### Backend Layout -```text -backend/src/main/java/com/ems/backend/ -├── BackendApplication.java # Boot Entry Point -├── config/ -│ ├── DataInitializer.java # Verify and populate seed users on startup -│ ├── DataSeeder.java # Verify and seed mock events on startup -│ ├── SecurityConfig.java # CORS and filter rules configuration -│ └── CustomUserDetailsService # Loads core user details for Spring Security -├── controller/ -│ ├── AdminController.java # CRUD endpoints for Users (/api/admin/users) -│ ├── AuthController.java # Login endpoints (/api/auth) -│ ├── ClassController.java # Class mappings and promotions (/api/classes) -│ ├── EventController.java # Propose, approve, batch-create events (/api/events) -│ ├── HealthController.java # System and database connectivity check (/api/health) -│ └── NoteController.java # Board notices and institutional logs (/api/notes) -├── dto/ -│ └── LoginRequest.java # Login DTO container -├── model/ -│ ├── BaseEntity.java # Audited fields ID superclass -│ ├── ClassMapping.java # Class config model -│ ├── Event.java # Core event proposal model -│ ├── InstitutionalNote.java # Date-based board notices model -│ └── User.java # Account profiles model -└── repository/ - ├── ClassRepository.java - ├── EventRepository.java # Custom JPA Query for timing conflict resolution - ├── InstitutionalNoteRepository.java - └── UserRepository.java -``` - ### Frontend Layout ```text frontend/src/ diff --git a/RIT-EMS-main/backend/.gitattributes b/RIT-EMS-main/backend/.gitattributes deleted file mode 100644 index 3b41682..0000000 --- a/RIT-EMS-main/backend/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -/mvnw text eol=lf -*.cmd text eol=crlf diff --git a/RIT-EMS-main/backend/.gitignore b/RIT-EMS-main/backend/.gitignore deleted file mode 100644 index 667aaef..0000000 --- a/RIT-EMS-main/backend/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/RIT-EMS-main/backend/.mvn/wrapper/maven-wrapper.properties b/RIT-EMS-main/backend/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index c595b00..0000000 --- a/RIT-EMS-main/backend/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,3 +0,0 @@ -wrapperVersion=3.3.4 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip diff --git a/RIT-EMS-main/backend/mvnw b/RIT-EMS-main/backend/mvnw deleted file mode 100644 index bd8896b..0000000 --- a/RIT-EMS-main/backend/mvnw +++ /dev/null @@ -1,295 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.4 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -scriptDir="$(dirname "$0")" -scriptName="$(basename "$0")" - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi - -# Find the actual extracted directory name (handles snapshots where filename != directory name) -actualDistributionDir="" - -# First try the expected directory name (for regular distributions) -if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then - if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then - actualDistributionDir="$distributionUrlNameMain" - fi -fi - -# If not found, search for any directory with the Maven executable (for snapshots) -if [ -z "$actualDistributionDir" ]; then - # enable globbing to iterate over items - set +f - for dir in "$TMP_DOWNLOAD_DIR"/*; do - if [ -d "$dir" ]; then - if [ -f "$dir/bin/$MVN_CMD" ]; then - actualDistributionDir="$(basename "$dir")" - break - fi - fi - done - set -f -fi - -if [ -z "$actualDistributionDir" ]; then - verbose "Contents of $TMP_DOWNLOAD_DIR:" - verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" - die "Could not find Maven distribution directory in extracted archive" -fi - -verbose "Found extracted Maven distribution directory: $actualDistributionDir" -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/RIT-EMS-main/backend/mvnw.cmd b/RIT-EMS-main/backend/mvnw.cmd deleted file mode 100644 index 92450f9..0000000 --- a/RIT-EMS-main/backend/mvnw.cmd +++ /dev/null @@ -1,189 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.4 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' - -$MAVEN_M2_PATH = "$HOME/.m2" -if ($env:MAVEN_USER_HOME) { - $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" -} - -if (-not (Test-Path -Path $MAVEN_M2_PATH)) { - New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null -} - -$MAVEN_WRAPPER_DISTS = $null -if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { - $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" -} else { - $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" -} - -$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" -$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null - -# Find the actual extracted directory name (handles snapshots where filename != directory name) -$actualDistributionDir = "" - -# First try the expected directory name (for regular distributions) -$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" -$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" -if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { - $actualDistributionDir = $distributionUrlNameMain -} - -# If not found, search for any directory with the Maven executable (for snapshots) -if (!$actualDistributionDir) { - Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { - $testPath = Join-Path $_.FullName "bin/$MVN_CMD" - if (Test-Path -Path $testPath -PathType Leaf) { - $actualDistributionDir = $_.Name - } - } -} - -if (!$actualDistributionDir) { - Write-Error "Could not find Maven distribution directory in extracted archive" -} - -Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/RIT-EMS-main/backend/pom.xml b/RIT-EMS-main/backend/pom.xml deleted file mode 100644 index 80b6e47..0000000 --- a/RIT-EMS-main/backend/pom.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.2.5 - - - com.ems - backend - 0.0.1-SNAPSHOT - backend - - - - - - - - - - - - - - - - 17 - - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-web - - - com.mysql - mysql-connector-j - runtime - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - org.projectlombok - lombok - 1.18.36 - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/BackendApplication.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/BackendApplication.java deleted file mode 100644 index 12aa683..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/BackendApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ems.backend; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class BackendApplication { - - public static void main(String[] args) { - SpringApplication.run(BackendApplication.class, args); - } - -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/CustomUserDetailsService.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/CustomUserDetailsService.java deleted file mode 100644 index 3590a71..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/CustomUserDetailsService.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.ems.backend.config; - -import com.ems.backend.model.User; -import com.ems.backend.repository.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -import java.util.Collections; - -@Service -public class CustomUserDetailsService implements UserDetailsService { - - @Autowired - private UserRepository userRepository; - - @Override - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - User user = userRepository.findByEmail(email) - .orElseThrow(() -> new UsernameNotFoundException("User not found with email: " + email)); - - return new org.springframework.security.core.userdetails.User( - user.getEmail(), - user.getPassword(), - Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + user.getRole())) - ); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/DataInitializer.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/DataInitializer.java deleted file mode 100644 index dc9f517..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/DataInitializer.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.ems.backend.config; - -import com.ems.backend.model.User; -import com.ems.backend.repository.UserRepository; -import org.springframework.boot.CommandLineRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.crypto.password.PasswordEncoder; - -@Configuration -public class DataInitializer { - - @Bean - public CommandLineRunner initData(UserRepository userRepository, PasswordEncoder passwordEncoder) { - return args -> { - updateOrCreateUser(userRepository, passwordEncoder, "admin@rit.edu", "admin123", "System Administrator", "ADMIN", "ADMIN"); - updateOrCreateUser(userRepository, passwordEncoder, "faculty@rit.edu", "faculty123", "Dr. Faculty Member", "FACULTY", "CSE"); - updateOrCreateUser(userRepository, passwordEncoder, "hod@rit.edu", "hod123", "Prof. Head of Dept", "HOD", "AI&ML"); - updateOrCreateUser(userRepository, passwordEncoder, "principal@rit.edu", "principal123", "Dr. College Principal", "PRINCIPAL", null); - updateOrCreateUser(userRepository, passwordEncoder, "placement@rit.edu", "placement123", "Placement Coordinator", "PLACEMENT", "Placement Department"); - - // Newly added users based on request - updateOrCreateUser(userRepository, passwordEncoder, "admin2@rit.edu", "admin123", "Secondary Admin", "ADMIN", "ADMIN"); - updateOrCreateUser(userRepository, passwordEncoder, "principal2@rit.edu", "principal123", "Vice Principal", "PRINCIPAL", null); - updateOrCreateUser(userRepository, passwordEncoder, "hod_cse@rit.edu", "hod123", "CSE HOD", "HOD", "CSE"); - updateOrCreateUser(userRepository, passwordEncoder, "faculty2@rit.edu", "faculty123", "Assistant Professor CSE", "FACULTY", "CSE"); - - System.out.println("Demo users verified and updated."); - }; - } - - private void updateOrCreateUser(UserRepository repo, PasswordEncoder encoder, String email, String pass, String name, String role, String dept) { - User user = repo.findByEmail(email).orElse(new User()); - user.setEmail(email); - user.setPassword(encoder.encode(pass)); - user.setFullName(name); - user.setRole(role); - user.setDepartment(dept); - - // Synchronize flags with roles/departments - if ("PLACEMENT".equals(role) || "Placement Department".equals(dept)) { - user.setPlacementStaff(true); - } - - if ("FACULTY".equals(role)) { - user.setClassIncharge(true); - user.setInchargeClass("CSE"); - user.setInchargeBatch("3rd Year"); - user.setInchargeSection("A"); - if (user.getClassStrength() == null || user.getClassStrength() == 0) { - user.setClassStrength(60); - } - } - - // Ensure new fields are initialized if new - if (user.getAssignedClubs() == null) { - user.setAssignedClubs(new java.util.ArrayList<>()); - } - repo.save(user); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/DataSeeder.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/DataSeeder.java deleted file mode 100644 index 92b78d9..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/DataSeeder.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.ems.backend.config; - -import com.ems.backend.model.Event; -import com.ems.backend.model.User; -import com.ems.backend.repository.EventRepository; -import com.ems.backend.repository.UserRepository; -import org.springframework.boot.CommandLineRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -@Configuration -public class DataSeeder { - - @Bean - CommandLineRunner initDatabase(EventRepository eventRepository, UserRepository userRepository) { - return args -> { - System.out.println("DataSeeder: Dummy events seeding disabled."); - }; - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/SecurityConfig.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/SecurityConfig.java deleted file mode 100644 index 81e2287..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/config/SecurityConfig.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ems.backend.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -import java.util.Arrays; -import java.util.List; - -@Configuration -@EnableWebSecurity -public class SecurityConfig { - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http - .csrf(csrf -> csrf.disable()) - .cors(cors -> cors.configurationSource(corsConfigurationSource())) - .authorizeHttpRequests(auth -> auth - .anyRequest().permitAll() - ) - .httpBasic(basic -> basic.disable()) - .formLogin(form -> form.disable()); - - return http.build(); - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { - return config.getAuthenticationManager(); - } - - @Bean - public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(List.of("*")); // For development - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); - configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With")); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); - return source; - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/AdminController.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/AdminController.java deleted file mode 100644 index fa8d5bd..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/AdminController.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.ems.backend.controller; - -import com.ems.backend.model.User; -import com.ems.backend.repository.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.Map; - -@RestController -@RequestMapping("/api/admin") -@CrossOrigin(origins = "*") -public class AdminController { - - @Autowired - private UserRepository userRepository; - - @Autowired - private PasswordEncoder passwordEncoder; - - @GetMapping("/users") - public ResponseEntity> getAllUsers() { - return ResponseEntity.ok(userRepository.findAll()); - } - - @PostMapping("/users") - public ResponseEntity createUser(@RequestBody User user) { - if (user == null || user.getEmail() == null || user.getEmail().trim().isEmpty()) { - return ResponseEntity.status(400).body(Map.of("message", "Email is required")); - } - if (user.getFullName() == null || user.getFullName().trim().isEmpty()) { - return ResponseEntity.status(400).body(Map.of("message", "Full name is required")); - } - if (user.getPassword() == null || user.getPassword().trim().isEmpty()) { - return ResponseEntity.status(400).body(Map.of("message", "Password is required")); - } - - user.setEmail(user.getEmail().trim().toLowerCase()); - user.setFullName(user.getFullName().trim()); - if (user.getRole() == null || user.getRole().trim().isEmpty()) { - user.setRole("FACULTY"); - } - - String role = user.getRole(); - if ("HOD".equals(role) || "FACULTY".equals(role)) { - if (user.getDepartment() == null || user.getDepartment().trim().isEmpty()) { - user.setDepartment("H&S Dept"); - } else { - user.setDepartment(user.getDepartment().trim()); - } - } else { - user.setDepartment(""); - } - - if (userRepository.findByEmail(user.getEmail()).isPresent()) { - return ResponseEntity.status(400).body(Map.of("message", "User with this email already exists")); - } - user.setPassword(passwordEncoder.encode(user.getPassword())); - userRepository.save(user); - return ResponseEntity.ok(user); - } - - @PutMapping("/users/{id}") - public ResponseEntity updateUser(@PathVariable Long id, @RequestBody User userDetails) { - User user = userRepository.findById(id).orElseThrow(); - user.setFullName(userDetails.getFullName()); - user.setEmail(userDetails.getEmail()); - user.setRole(userDetails.getRole()); - - String role = user.getRole(); - if ("HOD".equals(role) || "FACULTY".equals(role)) { - user.setDepartment(userDetails.getDepartment() != null ? userDetails.getDepartment().trim() : ""); - } else { - user.setDepartment(""); - } - - user.setClubCoordinator(userDetails.isClubCoordinator()); - user.setPlacementStaff(userDetails.isPlacementStaff()); - user.setClassIncharge(userDetails.isClassIncharge()); - user.setClassStrength(userDetails.getClassStrength()); - user.setInchargeClass(userDetails.getInchargeClass()); - user.setInchargeBatch(userDetails.getInchargeBatch()); - user.setInchargeSection(userDetails.getInchargeSection()); - user.setAssignedClubs(userDetails.getAssignedClubs()); - if (userDetails.getPassword() != null && !userDetails.getPassword().isEmpty()) { - user.setPassword(passwordEncoder.encode(userDetails.getPassword())); - } - userRepository.save(user); - return ResponseEntity.ok(user); - } - - @DeleteMapping("/users/{id}") - public ResponseEntity deleteUser(@PathVariable Long id) { - userRepository.deleteById(id); - return ResponseEntity.ok(Map.of("message", "User deleted successfully")); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/AuthController.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/AuthController.java deleted file mode 100644 index e67d90d..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/AuthController.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.ems.backend.controller; - -import com.ems.backend.dto.LoginRequest; -import com.ems.backend.model.User; -import com.ems.backend.repository.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; -import java.util.Optional; - -@RestController -@RequestMapping("/api/auth") -@CrossOrigin(origins = "*") -public class AuthController { - - @Autowired - private UserRepository userRepository; - - @Autowired - private PasswordEncoder passwordEncoder; - - @PostMapping("/login") - public ResponseEntity login(@RequestBody LoginRequest loginRequest) { - Optional userOptional = userRepository.findByEmail(loginRequest.getEmail()); - - if (userOptional.isPresent()) { - User user = userOptional.get(); - if (passwordEncoder.matches(loginRequest.getPassword(), user.getPassword())) { - java.util.Map responseMap = new java.util.HashMap<>(); - responseMap.put("id", user.getId()); - responseMap.put("email", user.getEmail()); - responseMap.put("fullName", user.getFullName()); - responseMap.put("role", user.getRole()); - responseMap.put("department", user.getDepartment() != null ? user.getDepartment() : "N/A"); - responseMap.put("isClubCoordinator", user.isClubCoordinator()); - responseMap.put("isPlacementStaff", user.isPlacementStaff()); - responseMap.put("isClassIncharge", user.isClassIncharge()); - responseMap.put("inchargeClass", user.getInchargeClass()); - responseMap.put("inchargeBatch", user.getInchargeBatch()); - responseMap.put("inchargeSection", user.getInchargeSection()); - responseMap.put("classStrength", user.getClassStrength()); - responseMap.put("assignedClubs", user.getAssignedClubs() != null ? user.getAssignedClubs() : java.util.List.of()); - - return ResponseEntity.ok(responseMap); - } - } - - return ResponseEntity.status(401).body(Map.of("message", "Invalid email or passcode")); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/ClassController.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/ClassController.java deleted file mode 100644 index af284c9..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/ClassController.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.ems.backend.controller; - -import com.ems.backend.model.ClassMapping; -import com.ems.backend.repository.ClassRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.Map; - -@RestController -@RequestMapping("/api/classes") -@CrossOrigin(origins = "*") -public class ClassController { - - @Autowired - private ClassRepository classRepository; - - @GetMapping - public ResponseEntity> getAllClasses() { - return ResponseEntity.ok(classRepository.findAll()); - } - - @PostMapping - public ResponseEntity createClass(@RequestBody ClassMapping classMapping) { - classRepository.save(classMapping); - return ResponseEntity.ok(classMapping); - } - - @DeleteMapping("/{id}") - public ResponseEntity deleteClass(@PathVariable Long id) { - classRepository.deleteById(id); - return ResponseEntity.ok(Map.of("message", "Class mapping deleted successfully")); - } - - @PostMapping("/promote") - public ResponseEntity promoteAcademicYear(@RequestParam String institution) { - List allClasses = classRepository.findAll(); - - for (ClassMapping cm : allClasses) { - if (!cm.getInstitution().trim().equalsIgnoreCase(institution.trim())) { - continue; - } - - String currentYear = cm.getAcademicYear(); - - switch (currentYear) { - case "1st Year": - cm.setAcademicYear("2nd Year"); - classRepository.save(cm); - break; - case "2nd Year": - cm.setAcademicYear("3rd Year"); - classRepository.save(cm); - break; - case "3rd Year": - cm.setAcademicYear("4th Year"); - classRepository.save(cm); - break; - case "4th Year": - classRepository.delete(cm); - break; - default: - break; - } - } - return ResponseEntity.ok(Map.of("message", "Academic year promotion completed for " + institution)); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/EventController.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/EventController.java deleted file mode 100644 index f677772..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/EventController.java +++ /dev/null @@ -1,446 +0,0 @@ -package com.ems.backend.controller; - -import com.ems.backend.model.Event; -import com.ems.backend.model.User; -import com.ems.backend.repository.EventRepository; -import com.ems.backend.repository.UserRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.http.HttpStatus; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; -import java.time.LocalDateTime; - -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -@RestController -@RequestMapping("/api/events") -@CrossOrigin(origins = "*") -public class EventController { - - @Autowired - private EventRepository eventRepository; - - @Autowired - private UserRepository userRepository; - - @PostMapping("/propose") - @Transactional - public ResponseEntity proposeEvent(@RequestBody Map payload) { - try { - Long userId = Long.valueOf(payload.get("userId").toString()); - User proposer = userRepository.findById(userId).orElseThrow(); - - if (!"FACULTY".equals(proposer.getRole()) && - !"HOD".equals(proposer.getRole()) && - !"PRINCIPAL".equals(proposer.getRole()) && - !"PLACEMENT".equals(proposer.getRole()) && - !"ADMIN".equals(proposer.getRole())) { - return ResponseEntity.status(403).body(Map.of("message", "Only authorized users can propose events")); - } - - Event event = new Event(); - event.setTitle(payload.get("eventName").toString()); - event.setStartDate(parseDateTime(payload.get("startDate"))); - event.setEndDate(parseDateTime(payload.get("endDate"))); - event.setType(payload.get("eventType") != null ? payload.get("eventType").toString() : "Institutional"); - event.setInstitution(payload.get("institution").toString()); - event.setDepartment(payload.get("department").toString()); - event.setAcademicYears((List) payload.get("academicYears")); - event.setLocation(payload.get("venue").toString()); - event.setGuestName(payload.get("guestName") != null ? payload.get("guestName").toString() : null); - event.setGuestSocialProfile(payload.get("socialProfile") != null ? payload.get("socialProfile").toString() : null); - event.setRequirements((List) payload.get("requirements")); - event.setTargetedSections((List) payload.get("targetedSections")); - event.setGroupRequestId(payload.get("groupRequestId") != null ? payload.get("groupRequestId").toString() : null); - - // New Fields - event.setDescription(payload.get("description") != null ? payload.get("description").toString() : null); - event.setSponsors((List) payload.get("sponsors")); - - String budgetStr = payload.get("budget") != null ? payload.get("budget").toString() : ""; - event.setBudget(budgetStr.isEmpty() ? 0.0 : Double.valueOf(budgetStr)); - - event.setHasRegistrationFee(payload.get("hasRegistrationFee") != null && (boolean) payload.get("hasRegistrationFee")); - - String feeStr = payload.get("registrationFee") != null ? payload.get("registrationFee").toString() : ""; - event.setRegistrationFee(feeStr.isEmpty() ? 0.0 : Double.valueOf(feeStr)); - String category = payload.get("category") != null ? payload.get("category").toString() : "ACADEMIC"; - event.setCategory(category); - - event.setCentreName(payload.get("centreName") != null ? payload.get("centreName").toString() : null); - if (payload.containsKey("isPublicEvent")) { - event.setPublicEvent((boolean) payload.get("isPublicEvent")); - } - if (payload.containsKey("image")) { - event.setImage(payload.get("image") != null ? payload.get("image").toString() : null); - } - - // Workflow Logic - if ("PRINCIPAL".equals(proposer.getRole())) { - event.setStatus("APPROVED"); - } else if ("HOD".equals(proposer.getRole()) || - "CLUB".equals(category) || - "PLACEMENT".equals(category) || - "INSTITUTIONAL".equals(category) || - "PLACEMENT".equals(proposer.getRole()) || - proposer.isPlacementStaff() || - "Placement Department".equals(proposer.getDepartment())) { - event.setStatus("PENDING_PR"); - } else { - event.setStatus("REQUESTED"); - } - - event.setProposer(proposer); - - if (event.getStartDate().isBefore(LocalDateTime.now())) { - return ResponseEntity.status(400).body(Map.of("message", "Cannot schedule events in the past")); - } - - if (event.getEndDate().isBefore(event.getStartDate()) || event.getEndDate().isEqual(event.getStartDate())) { - return ResponseEntity.status(400).body(Map.of("message", "End date must be after start date")); - } - - event.setLocation(event.getLocation().trim()); - event.setInstitution(event.getInstitution().trim()); - - // Priority & Conflict Logic - List conflicts = eventRepository.findConflictingEvents( - event.getInstitution(), - event.getLocation(), - event.getStartDate(), - event.getEndDate(), - -1L, - event.getGroupRequestId() - ); - - if (!conflicts.isEmpty()) { - if ("PLACEMENT".equals(category) && Boolean.TRUE.equals(payload.get("cancelConflicting"))) { - for (Event conflict : conflicts) { - conflict.setStatus("CANCELLED"); - conflict.setRejectionReason("This event is cancelled due to the placement activity happening at the venue at this timing."); - eventRepository.save(conflict); - } - } else { - String conflictMsg = getConflictMessage(event); - return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of( - "message", conflictMsg, - "conflicts", conflicts, - "canOverride", "PLACEMENT".equals(category) - )); - } - } - - eventRepository.save(event); - return ResponseEntity.ok(Map.of("message", "Event proposed successfully", "id", event.getId())); - } catch (Exception e) { - return ResponseEntity.status(400).body(Map.of("message", "Failed to propose event: " + e.getMessage())); - } - } - - @GetMapping - public List getAllEvents() { - List events = eventRepository.findAll(); - populateConflictMessages(events); - return events; - } - - @PostMapping("/batch-create") - @Transactional - public ResponseEntity batchCreateEvents(@RequestBody List> eventsPayload) { - try { - if (eventsPayload == null || eventsPayload.isEmpty()) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", "No events provided for import")); - } - - List eventsToSave = new ArrayList<>(); - for (Map payload : eventsPayload) { - Event event = new Event(); - String title = payload.get("title") != null ? payload.get("title").toString() : "Untitled Event"; - event.setTitle(title); - - Object dateObj = payload.get("startDate") != null ? payload.get("startDate") : payload.get("finalDate"); - if (dateObj == null) { - throw new RuntimeException("Missing date for event: " + title); - } - - LocalDateTime start = parseDateTime(dateObj); - event.setStartDate(start); - - // Try to calculate duration from original event if available - if (payload.get("startDate") != null && payload.get("endDate") != null) { - try { - LocalDateTime origStart = parseDateTime(payload.get("startDate")); - LocalDateTime origEnd = parseDateTime(payload.get("endDate")); - java.time.Duration duration = java.time.Duration.between(origStart, origEnd); - event.setEndDate(start.plus(duration)); - } catch (Exception e) { - event.setEndDate(start.plusHours(2)); - } - } else { - event.setEndDate(start.plusHours(2)); - } - - event.setType(payload.get("type") != null ? payload.get("type").toString() : "Seminar"); - event.setInstitution(payload.get("institution") != null ? payload.get("institution").toString().trim() : "RIT"); - - String dept = payload.get("targetDepartment") != null ? payload.get("targetDepartment").toString() : - (payload.get("department") != null ? payload.get("department").toString() : "General"); - event.setDepartment(dept); - - Object ay = payload.get("targetBatch") != null ? List.of(payload.get("targetBatch").toString()) : payload.get("academicYears"); - event.setAcademicYears((List) ay); - - String venue = payload.get("venue") != null ? payload.get("venue").toString() : - (payload.get("location") != null ? payload.get("location").toString() : "TBD"); - event.setLocation(venue.trim()); - - event.setCategory(payload.get("category") != null ? payload.get("category").toString() : "ACADEMIC"); - event.setStatus(payload.get("status") != null ? payload.get("status").toString() : "APPROVED"); - - if (payload.containsKey("requirements")) { - event.setRequirements((List) payload.get("requirements")); - } - if (payload.containsKey("image")) { - event.setImage(payload.get("image") != null ? payload.get("image").toString() : null); - } - - if (payload.get("proposer") != null) { - try { - Object proposerObj = payload.get("proposer"); - if (proposerObj instanceof Map) { - Map prop = (Map) proposerObj; - Object idObj = prop.get("id"); - if (idObj != null) { - Long propId = Long.valueOf(idObj.toString()); - userRepository.findById(propId).ifPresent(event::setProposer); - } - } - } catch (Exception e) { - System.err.println("Warning: Could not map proposer for batch event: " + e.getMessage()); - } - } - - if (event.getStartDate() == null || event.getEndDate() == null) { - throw new RuntimeException("Missing start or end date for event: " + title); - } - - if (event.getEndDate().isBefore(event.getStartDate()) || event.getEndDate().isEqual(event.getStartDate())) { - throw new RuntimeException("End date must be after start date for event: " + title); - } - - eventsToSave.add(event); - } - - for (Event event : eventsToSave) { - String conflictMsg = getConflictMessage(event); - if (conflictMsg != null) { - throw new RuntimeException("Conflict in batch item '" + event.getTitle() + "': " + conflictMsg); - } - } - - for (int i = 0; i < eventsToSave.size(); i++) { - Event current = eventsToSave.get(i); - for (int j = i + 1; j < eventsToSave.size(); j++) { - Event other = eventsToSave.get(j); - if (isVenueTimingConflict(current, other)) { - throw new RuntimeException("Conflict between imported events '" + current.getTitle() + "' and '" + other.getTitle() + "' at " + current.getLocation()); - } - } - } - - for (Event event : eventsToSave) { - eventRepository.save(event); - } - return ResponseEntity.ok(Map.of("message", "Batch events created successfully", "count", eventsToSave.size())); - } catch (Exception e) { - String errorMsg = e.getMessage() != null ? e.getMessage() : "Unknown error during batch creation"; - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", "Failed to create batch events: " + errorMsg)); - } - } - - @PostMapping("/{id}/approve") - @Transactional - public ResponseEntity approveEvent(@PathVariable Long id, @RequestParam Long userId) { - User user = userRepository.findById(userId).orElseThrow(); - Event event = eventRepository.findById(id).orElseThrow(); - - String conflictMsg = getConflictMessage(event); - if (conflictMsg != null) { - return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", conflictMsg)); - } - - if ("HOD".equals(user.getRole())) { - event.setStatus("PENDING_PR"); - } else if ("PRINCIPAL".equals(user.getRole())) { - event.setStatus("APPROVED"); - } else { - return ResponseEntity.status(403).body(Map.of("message", "Only HoD or Principal can approve events")); - } - - eventRepository.save(event); - return ResponseEntity.ok(Map.of("message", "Event action completed successfully", "status", event.getStatus())); - } - - @PostMapping("/{id}/reject") - public ResponseEntity rejectEvent(@PathVariable Long id, @RequestParam Long userId, @RequestBody(required = false) Map payload) { - User user = userRepository.findById(userId).orElseThrow(); - Event event = eventRepository.findById(id).orElseThrow(); - - String reason = payload != null ? payload.get("reason") : null; - if (reason == null || reason.trim().isEmpty()) { - return ResponseEntity.status(400).body(Map.of("message", "Rejection reason is mandatory")); - } - - if ("HOD".equals(user.getRole())) { - event.setStatus("HOD_REJECTED"); - } else if ("PRINCIPAL".equals(user.getRole())) { - event.setStatus("PRINCIPAL_REJECTED"); - } else { - return ResponseEntity.status(403).body(Map.of("message", "Only HoD or Principal can reject events")); - } - - event.setRejectionReason(reason); - eventRepository.save(event); - return ResponseEntity.ok(Map.of("message", "Event rejected successfully", "status", event.getStatus())); - } - - @PutMapping("/{id}") - @Transactional - public ResponseEntity updateEvent(@PathVariable Long id, @RequestBody Map payload) { - try { - Event event = eventRepository.findById(id).orElseThrow(); - Long userId = Long.valueOf(payload.get("userId").toString()); - User user = userRepository.findById(userId).orElseThrow(); - boolean isAdmin = "ADMIN".equals(user.getRole()); - - if (!isAdmin) { - if (!event.getProposer().getId().equals(userId)) { - return ResponseEntity.status(403).body(Map.of("message", "Only the proposer can edit this event")); - } - - if (!"REQUESTED".equals(event.getStatus())) { - return ResponseEntity.status(403).body(Map.of("message", "Event cannot be edited once it moves past the initial request stage")); - } - } - - if (payload.containsKey("title")) event.setTitle(payload.get("title").toString()); - if (payload.containsKey("startDate")) event.setStartDate(parseDateTime(payload.get("startDate"))); - if (payload.containsKey("endDate")) event.setEndDate(parseDateTime(payload.get("endDate"))); - if (payload.containsKey("eventType")) event.setType(payload.get("eventType").toString()); - if (payload.containsKey("institution")) event.setInstitution(payload.get("institution").toString()); - if (payload.containsKey("department")) event.setDepartment(payload.get("department").toString()); - if (payload.containsKey("venue")) event.setLocation(payload.get("venue").toString()); - if (payload.containsKey("guestName")) event.setGuestName(payload.get("guestName").toString()); - if (payload.containsKey("socialProfile")) event.setGuestSocialProfile(payload.get("socialProfile").toString()); - - if (payload.containsKey("academicYears")) event.setAcademicYears((List) payload.get("academicYears")); - if (payload.containsKey("targetedSections")) event.setTargetedSections((List) payload.get("targetedSections")); - if (payload.containsKey("requirements")) event.setRequirements((List) payload.get("requirements")); - if (payload.containsKey("sponsors")) event.setSponsors((List) payload.get("sponsors")); - if (payload.containsKey("description")) event.setDescription(payload.get("description").toString()); - - if (payload.containsKey("budget")) { - String budgetStr = payload.get("budget").toString(); - event.setBudget(budgetStr.isEmpty() ? 0.0 : Double.valueOf(budgetStr)); - } - if (payload.containsKey("hasRegistrationFee")) event.setHasRegistrationFee((boolean) payload.get("hasRegistrationFee")); - if (payload.containsKey("registrationFee")) { - String feeStr = payload.get("registrationFee").toString(); - event.setRegistrationFee(feeStr.isEmpty() ? 0.0 : Double.valueOf(feeStr)); - } - - if (payload.containsKey("centreName")) event.setCentreName(payload.get("centreName").toString()); - if (payload.containsKey("isPublicEvent")) event.setPublicEvent((boolean) payload.get("isPublicEvent")); - if (payload.containsKey("image")) { - event.setImage(payload.get("image") != null ? payload.get("image").toString() : null); - } - if (payload.containsKey("status") && isAdmin) { - event.setStatus(payload.get("status").toString()); - } - - if (event.getEndDate().isBefore(event.getStartDate()) || event.getEndDate().isEqual(event.getStartDate())) { - return ResponseEntity.status(400).body(Map.of("message", "End date must be after start date")); - } - - event.setLocation(event.getLocation().trim()); - event.setInstitution(event.getInstitution().trim()); - - String conflictMsg = getConflictMessage(event); - if (conflictMsg != null) { - return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of("message", conflictMsg)); - } - - eventRepository.save(event); - return ResponseEntity.ok(Map.of("message", "Event updated successfully")); - } catch (Exception e) { - return ResponseEntity.status(400).body(Map.of("message", "Failed to update event: " + e.getMessage())); - } - } - - private void populateConflictMessages(List events) { - for (Event event : events) { - if (!"APPROVED".equals(event.getStatus()) && !"COMPLETED".equals(event.getStatus()) && !"CANCELLED".equals(event.getStatus())) { - event.setConflictMessage(getConflictMessage(event)); - } - } - } - - private String getConflictMessage(Event event) { - LocalDateTime start = event.getStartDate(); - LocalDateTime end = event.getEndDate(); - String location = event.getLocation().trim(); - String institution = event.getInstitution().trim(); - - List conflicts = eventRepository.findConflictingEvents( - institution, - location, - start, - end, - event.getId() != null ? event.getId() : -1L, - event.getGroupRequestId() - ); - - if (!conflicts.isEmpty()) { - Event conflict = conflicts.get(0); - DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm"); - return String.format("Venue Conflict: '%s' is already booked for '%s' from %s to %s", - location, conflict.getTitle(), - conflict.getStartDate().format(timeFormatter), - conflict.getEndDate().format(timeFormatter)); - } - return null; - } - - private boolean isVenueTimingConflict(Event first, Event second) { - if ("CANCELLED".equals(first.getStatus()) || "CANCELLED".equals(second.getStatus())) { - return false; - } - return first.getInstitution().trim().equals(second.getInstitution().trim()) - && first.getLocation().trim().equalsIgnoreCase(second.getLocation().trim()) - && first.getStartDate().isBefore(second.getEndDate()) - && first.getEndDate().isAfter(second.getStartDate()); - } - - private LocalDateTime parseDateTime(Object value) { - if (value == null) return null; - String str = value.toString().trim(); - if (str.isEmpty()) return null; - str = str.replace(" ", "T"); - if (str.length() == 10) str += "T00:00:00"; - if (str.length() == 16) str += ":00"; - if (str.contains("+")) str = str.substring(0, str.indexOf("+")); - if (str.contains("Z")) str = str.replace("Z", ""); - if (str.contains(".")) str = str.substring(0, str.indexOf(".")); - try { - return LocalDateTime.parse(str); - } catch (Exception e) { - System.err.println("Failed to parse date: " + str); - throw e; - } - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/HealthController.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/HealthController.java deleted file mode 100644 index eb3d3a1..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/HealthController.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.ems.backend.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.util.Map; - -@RestController -public class HealthController { - - @Autowired - private DataSource dataSource; - - @GetMapping("/api/health") - public Map health() { - String dbStatus = "DOWN"; - try (Connection connection = dataSource.getConnection()) { - if (connection.isValid(1)) { - dbStatus = "UP"; - } - } catch (Exception e) { - dbStatus = "DOWN: " + e.getMessage(); - } - - return Map.of( - "status", "UP", - "message", "EMS Backend is running", - "database", dbStatus - ); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/NoteController.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/NoteController.java deleted file mode 100644 index c4ef0d5..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/controller/NoteController.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ems.backend.controller; - -import com.ems.backend.model.InstitutionalNote; -import com.ems.backend.repository.InstitutionalNoteRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/api/notes") -@CrossOrigin(origins = "*") -public class NoteController { - - @Autowired - private InstitutionalNoteRepository noteRepository; - - @GetMapping - public List getAllNotes() { - return noteRepository.findAll(); - } - - @PostMapping - public InstitutionalNote createNote(@RequestBody InstitutionalNote note) { - return noteRepository.save(note); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/dto/LoginRequest.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/dto/LoginRequest.java deleted file mode 100644 index cef1e9a..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/dto/LoginRequest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ems.backend.dto; - -import lombok.Data; - -public class LoginRequest { - private String email; - private String password; - - public String getEmail() { return email; } - public void setEmail(String email) { this.email = email; } - public String getPassword() { return password; } - public void setPassword(String password) { this.password = password; } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/BaseEntity.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/BaseEntity.java deleted file mode 100644 index 4706370..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/BaseEntity.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.ems.backend.model; - -import jakarta.persistence.*; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; -import java.time.LocalDateTime; - -@MappedSuperclass -public abstract class BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @CreationTimestamp - @Column(updatable = false) - private LocalDateTime createdAt; - - @UpdateTimestamp - private LocalDateTime updatedAt; - - public BaseEntity() {} - - public BaseEntity(Long id, LocalDateTime createdAt, LocalDateTime updatedAt) { - this.id = id; - this.createdAt = createdAt; - this.updatedAt = updatedAt; - } - - public Long getId() { return id; } - public void setId(Long id) { this.id = id; } - public LocalDateTime getCreatedAt() { return createdAt; } - public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } - public LocalDateTime getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/ClassMapping.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/ClassMapping.java deleted file mode 100644 index c16340e..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/ClassMapping.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.ems.backend.model; - -import jakarta.persistence.*; -import lombok.*; - -import java.util.List; - -@Entity -@Table(name = "classes") -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class ClassMapping extends BaseEntity { - - @Column(nullable = false) - private String institution; // RIT, RSB - - @Column(nullable = false) - private String department; - - @Column(nullable = false) - private String academicYear; // 1st Year, 2nd Year, etc. - - @ElementCollection - @CollectionTable(name = "class_sections", joinColumns = @JoinColumn(name = "class_id")) - @Column(name = "section_name") - private List sections; - - @Builder.Default - private String status = "Ready"; - - public String getInstitution() { return institution; } - public void setInstitution(String institution) { this.institution = institution; } - public String getDepartment() { return department; } - public void setDepartment(String department) { this.department = department; } - public String getAcademicYear() { return academicYear; } - public void setAcademicYear(String academicYear) { this.academicYear = academicYear; } - public java.util.List getSections() { return sections; } - public void setSections(java.util.List sections) { this.sections = sections; } - public String getStatus() { return status; } - public void setStatus(String status) { this.status = status; } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/Event.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/Event.java deleted file mode 100644 index c5ef37d..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/Event.java +++ /dev/null @@ -1,218 +0,0 @@ -package com.ems.backend.model; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import java.time.LocalDateTime; -import java.util.List; - -@Entity -@Table(name = "events") -public class Event extends BaseEntity { - - @Column(nullable = false) - private String title; - - @Column(columnDefinition = "TEXT") - private String description; - - @Column(nullable = false) - private LocalDateTime startDate; - - @Column(nullable = false) - private LocalDateTime endDate; - - @Column(nullable = false) - private String location; - - @Column(nullable = false) - private String category; // ACADEMIC, CLUB, etc. - - @Column(nullable = false) - private String type; // Workshop, Seminar, etc. - - @Column(nullable = false) - private String institution; // RIT, RSB - - @Column(nullable = false) - private String department; - - @jakarta.persistence.ElementCollection - private List academicYears; - - @Column(nullable = false) - private String status; // PENDING, APPROVED, COMPLETED, CANCELLED - - private String guestName; - private String guestSocialProfile; - - @jakarta.persistence.ElementCollection - private List requirements; - - @jakarta.persistence.ElementCollection - private List targetedSections; - - private Double budget; - @Column(columnDefinition = "boolean default false") - private boolean hasRegistrationFee; - private Double registrationFee; - - @jakarta.persistence.ElementCollection - private List sponsors; - - @jakarta.persistence.ManyToOne - @jakarta.persistence.JoinColumn(name = "user_id") - private User proposer; - - @Column(columnDefinition = "TEXT") - private String rejectionReason; - - private String groupRequestId; - - private String centreName; - @Column(columnDefinition = "boolean default false") - private boolean isPublicEvent; - - @Column(columnDefinition = "LONGTEXT") - private String image; - - @jakarta.persistence.Transient - private String conflictMessage; - - public Event() {} - - public Event(String title, String description, LocalDateTime startDate, LocalDateTime endDate, String location, String category, String type, String institution, String department, List academicYears, String status, String guestName, String guestSocialProfile, List requirements, List targetedSections, Double budget, boolean hasRegistrationFee, Double registrationFee, User proposer, String centreName, boolean isPublicEvent) { - this.title = title; - this.description = description; - this.startDate = startDate; - this.endDate = endDate; - this.location = location; - this.category = category; - this.type = type; - this.institution = institution; - this.department = department; - this.academicYears = academicYears; - this.status = status; - this.guestName = guestName; - this.guestSocialProfile = guestSocialProfile; - this.requirements = requirements; - this.targetedSections = targetedSections; - this.budget = budget; - this.hasRegistrationFee = hasRegistrationFee; - this.registrationFee = registrationFee; - this.proposer = proposer; - this.centreName = centreName; - this.isPublicEvent = isPublicEvent; - } - - // Manual Getters and Setters - public String getTitle() { return title; } - public void setTitle(String title) { this.title = title; } - public String getDescription() { return description; } - public void setDescription(String description) { this.description = description; } - public LocalDateTime getStartDate() { return startDate; } - public void setStartDate(LocalDateTime startDate) { this.startDate = startDate; } - public LocalDateTime getEndDate() { return endDate; } - public void setEndDate(LocalDateTime endDate) { this.endDate = endDate; } - public String getLocation() { return location; } - public void setLocation(String location) { this.location = location; } - public String getCategory() { return category; } - public void setCategory(String category) { this.category = category; } - public String getType() { return type; } - public void setType(String type) { this.type = type; } - public String getInstitution() { return institution; } - public void setInstitution(String institution) { this.institution = institution; } - public String getDepartment() { return department; } - public void setDepartment(String department) { this.department = department; } - public List getAcademicYears() { return academicYears; } - public void setAcademicYears(List academicYears) { this.academicYears = academicYears; } - public String getStatus() { return status; } - public void setStatus(String status) { this.status = status; } - public String getGuestName() { return guestName; } - public void setGuestName(String guestName) { this.guestName = guestName; } - public String getGuestSocialProfile() { return guestSocialProfile; } - public void setGuestSocialProfile(String guestSocialProfile) { this.guestSocialProfile = guestSocialProfile; } - public List getRequirements() { return requirements; } - public void setRequirements(List requirements) { this.requirements = requirements; } - public List getTargetedSections() { return targetedSections; } - public void setTargetedSections(List targetedSections) { this.targetedSections = targetedSections; } - public Double getBudget() { return budget; } - public void setBudget(Double budget) { this.budget = budget; } - public boolean isHasRegistrationFee() { return hasRegistrationFee; } - public void setHasRegistrationFee(boolean hasRegistrationFee) { this.hasRegistrationFee = hasRegistrationFee; } - public Double getRegistrationFee() { return registrationFee; } - public void setRegistrationFee(Double registrationFee) { this.registrationFee = registrationFee; } - public List getSponsors() { return sponsors; } - public void setSponsors(List sponsors) { this.sponsors = sponsors; } - - public User getProposer() { return proposer; } - public void setProposer(User proposer) { this.proposer = proposer; } - public String getRejectionReason() { return rejectionReason; } - public void setRejectionReason(String rejectionReason) { this.rejectionReason = rejectionReason; } - - public String getGroupRequestId() { return groupRequestId; } - public void setGroupRequestId(String groupRequestId) { this.groupRequestId = groupRequestId; } - - public String getConflictMessage() { return conflictMessage; } - public void setConflictMessage(String conflictMessage) { this.conflictMessage = conflictMessage; } - - public String getCentreName() { - return centreName; - } - - public void setCentreName(String centreName) { - this.centreName = centreName; - } - - public boolean isPublicEvent() { - return isPublicEvent; - } - - public void setPublicEvent(boolean publicEvent) { - isPublicEvent = publicEvent; - } - - public String getImage() { - return image; - } - - public void setImage(String image) { - this.image = image; - } - - // Manual Builder - public static EventBuilder builder() { - return new EventBuilder(); - } - - public static class EventBuilder { - private Event event = new Event(); - - public EventBuilder title(String title) { event.setTitle(title); return this; } - public EventBuilder description(String description) { event.setDescription(description); return this; } - public EventBuilder startDate(LocalDateTime startDate) { event.setStartDate(startDate); return this; } - public EventBuilder endDate(LocalDateTime endDate) { event.setEndDate(endDate); return this; } - public EventBuilder location(String location) { event.setLocation(location); return this; } - public EventBuilder category(String category) { event.setCategory(category); return this; } - public EventBuilder type(String type) { event.setType(type); return this; } - public EventBuilder institution(String institution) { event.setInstitution(institution); return this; } - public EventBuilder department(String department) { event.setDepartment(department); return this; } - public EventBuilder academicYears(List academicYears) { event.setAcademicYears(academicYears); return this; } - public EventBuilder status(String status) { event.setStatus(status); return this; } - public EventBuilder guestName(String guestName) { event.setGuestName(guestName); return this; } - public EventBuilder guestSocialProfile(String guestSocialProfile) { event.setGuestSocialProfile(guestSocialProfile); return this; } - public EventBuilder requirements(List requirements) { event.setRequirements(requirements); return this; } - public EventBuilder targetedSections(List targetedSections) { event.setTargetedSections(targetedSections); return this; } - public EventBuilder budget(Double budget) { event.setBudget(budget); return this; } - public EventBuilder hasRegistrationFee(boolean hasRegistrationFee) { event.setHasRegistrationFee(hasRegistrationFee); return this; } - public EventBuilder registrationFee(Double registrationFee) { event.setRegistrationFee(registrationFee); return this; } - public EventBuilder sponsors(List sponsors) { event.setSponsors(sponsors); return this; } - public EventBuilder proposer(User proposer) { event.setProposer(proposer); return this; } - public EventBuilder groupRequestId(String groupRequestId) { event.setGroupRequestId(groupRequestId); return this; } - public EventBuilder image(String image) { event.setImage(image); return this; } - - public Event build() { - return event; - } - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/InstitutionalNote.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/InstitutionalNote.java deleted file mode 100644 index d5e3d97..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/InstitutionalNote.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.ems.backend.model; - -import jakarta.persistence.*; -import lombok.Data; -import java.time.LocalDate; -import java.time.LocalDateTime; - -@Entity -@Data -@Table(name = "institutional_notes") -public class InstitutionalNote { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private String content; - - @Column(nullable = false) - private LocalDate targetDate; - - private String authorName; - private String authorEmail; - - private LocalDateTime createdAt; - - @PrePersist - protected void onCreate() { - createdAt = LocalDateTime.now(); - } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/User.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/User.java deleted file mode 100644 index ad7f4d4..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/model/User.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.ems.backend.model; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -@Entity -@Table(name = "users") -public class User extends BaseEntity { - - @Column(unique = true, nullable = false) - private String email; - - @Column(nullable = false) - private String password; - - @Column(nullable = false) - private String fullName; - - @Column(nullable = false) - private String role; // FACULTY, HOD, PRINCIPAL - - private String department; - - @Column(columnDefinition = "boolean default false") - @JsonProperty("isClubCoordinator") - private boolean isClubCoordinator; - - @Column(columnDefinition = "boolean default false") - @JsonProperty("isPlacementStaff") - private boolean isPlacementStaff; - - @Column(columnDefinition = "boolean default false") - @JsonProperty("isClassIncharge") - private boolean isClassIncharge; - - @Column - private Integer classStrength; - - @Column - private String inchargeClass; - - @Column - private String inchargeBatch; - - @Column - private String inchargeSection; - - @jakarta.persistence.ElementCollection - @JsonProperty("assignedClubs") - private List assignedClubs; - - public User() {} - - public User(String email, String password, String fullName, String role, String department, boolean isClubCoordinator, boolean isPlacementStaff, List assignedClubs) { - this.email = email; - this.password = password; - this.fullName = fullName; - this.role = role; - this.department = department; - this.isClubCoordinator = isClubCoordinator; - this.isPlacementStaff = isPlacementStaff; - this.assignedClubs = assignedClubs; - } - - public String getEmail() { return email; } - public void setEmail(String email) { this.email = email; } - public String getPassword() { return password; } - public void setPassword(String password) { this.password = password; } - public String getFullName() { return fullName; } - public void setFullName(String fullName) { this.fullName = fullName; } - public String getRole() { return role; } - public void setRole(String role) { this.role = role; } - public String getDepartment() { return department; } - public void setDepartment(String department) { this.department = department; } - public boolean isClubCoordinator() { return isClubCoordinator; } - public void setClubCoordinator(boolean clubCoordinator) { isClubCoordinator = clubCoordinator; } - public boolean isPlacementStaff() { return isPlacementStaff; } - public void setPlacementStaff(boolean placementStaff) { isPlacementStaff = placementStaff; } - public boolean isClassIncharge() { return isClassIncharge; } - public void setClassIncharge(boolean classIncharge) { isClassIncharge = classIncharge; } - public Integer getClassStrength() { return classStrength; } - public void setClassStrength(Integer classStrength) { this.classStrength = classStrength; } - public String getInchargeClass() { return inchargeClass; } - public void setInchargeClass(String inchargeClass) { this.inchargeClass = inchargeClass; } - public String getInchargeBatch() { return inchargeBatch; } - public void setInchargeBatch(String inchargeBatch) { this.inchargeBatch = inchargeBatch; } - public String getInchargeSection() { return inchargeSection; } - public void setInchargeSection(String inchargeSection) { this.inchargeSection = inchargeSection; } - public List getAssignedClubs() { return assignedClubs; } - public void setAssignedClubs(List assignedClubs) { this.assignedClubs = assignedClubs; } -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/ClassRepository.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/ClassRepository.java deleted file mode 100644 index 28aba4b..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/ClassRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.ems.backend.repository; - -import com.ems.backend.model.ClassMapping; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface ClassRepository extends JpaRepository { -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/EventRepository.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/EventRepository.java deleted file mode 100644 index 932e93f..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/EventRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ems.backend.repository; - -import com.ems.backend.model.Event; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import java.time.LocalDateTime; -import java.util.List; - -@Repository -public interface EventRepository extends JpaRepository { - List findByCategory(String category); - List findByStatus(String status); - - @Query("SELECT e FROM Event e WHERE e.status = 'APPROVED' AND e.institution = :institution AND e.location = :location " + - "AND e.startDate < :endDate AND e.endDate > :startDate AND e.id != :eventId " + - "AND (e.groupRequestId IS NULL OR :groupRequestId IS NULL OR e.groupRequestId != :groupRequestId)") - List findConflictingEvents(@Param("institution") String institution, - @Param("location") String location, - @Param("startDate") LocalDateTime startDate, - @Param("endDate") LocalDateTime endDate, - @Param("eventId") Long eventId, - @Param("groupRequestId") String groupRequestId); -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/InstitutionalNoteRepository.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/InstitutionalNoteRepository.java deleted file mode 100644 index af3162c..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/InstitutionalNoteRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.ems.backend.repository; - -import com.ems.backend.model.InstitutionalNote; -import org.springframework.data.jpa.repository.JpaRepository; -import java.time.LocalDate; -import java.util.List; - -public interface InstitutionalNoteRepository extends JpaRepository { - List findByTargetDate(LocalDate targetDate); -} diff --git a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/UserRepository.java b/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/UserRepository.java deleted file mode 100644 index b0ce4b9..0000000 --- a/RIT-EMS-main/backend/src/main/java/com/ems/backend/repository/UserRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.ems.backend.repository; - -import com.ems.backend.model.User; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -public interface UserRepository extends JpaRepository { - Optional findByEmail(String email); -} diff --git a/RIT-EMS-main/backend/src/main/resources/application.properties b/RIT-EMS-main/backend/src/main/resources/application.properties deleted file mode 100644 index ed888a6..0000000 --- a/RIT-EMS-main/backend/src/main/resources/application.properties +++ /dev/null @@ -1,14 +0,0 @@ -server.port=8081 -spring.application.name=backend - -# Database Configuration -spring.datasource.url=jdbc:mysql://localhost:3306/ems_db?createDatabaseIfNotExist=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC -spring.datasource.username=root -spring.datasource.password=Abiram@07 -spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver - -# JPA Configuration -spring.jpa.hibernate.ddl-auto=create -spring.jpa.show-sql=true -spring.jpa.properties.hibernate.format_sql=true -spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect diff --git a/RIT-EMS-main/backend/src/test/java/com/ems/backend/BackendApplicationTests.java b/RIT-EMS-main/backend/src/test/java/com/ems/backend/BackendApplicationTests.java deleted file mode 100644 index 426c179..0000000 --- a/RIT-EMS-main/backend/src/test/java/com/ems/backend/BackendApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ems.backend; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class BackendApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/RIT-EMS-main/frontend/src/lib/firebaseBackend.ts b/RIT-EMS-main/frontend/src/lib/firebaseBackend.ts index 789ea53..626f8fc 100644 --- a/RIT-EMS-main/frontend/src/lib/firebaseBackend.ts +++ b/RIT-EMS-main/frontend/src/lib/firebaseBackend.ts @@ -132,58 +132,17 @@ async function seedDatabaseIfEmpty() { } } + // Clean up existing dummy events with "Sample event for" description const eventsSnap = await getDocs(collection(db, 'ems_events')); - if (eventsSnap.empty) { - console.log("[Firebase Backend] Seeding events..."); - const venues = [ - "GB 4th floor auditorium", - "Wozniak Auditorium", - "C6-02 Indoor Theatre", - "H Block Guest Lecture Theatre" - ]; - const categories = ["ACADEMIC", "CLUB", "PLACEMENT", "SPORTS"]; - const types = ["Workshop", "Seminar", "Guest Lecture", "Competition"]; - const statuses = ["REQUESTED", "APPROVED", "COMPLETED"]; - - let evId = 100; - const now = new Date(); - - for (let month = now.getMonth() - 2; month <= now.getMonth() + 2; month++) { - const targetMonth = (month + 12) % 12; - const targetYear = now.getFullYear() + (month < 0 ? -1 : (month > 11 ? 1 : 0)); - - for (const dept of ["CSE", "AI&ML"]) { - const start = new Date(targetYear, targetMonth, 15, 10, 0); - const end = new Date(targetYear, targetMonth, 15, 13, 0); - const venue = venues[Math.floor(Math.random() * venues.length)]; - const cat = categories[Math.floor(Math.random() * categories.length)]; - const type = types[Math.floor(Math.random() * types.length)]; - const status = statuses[Math.floor(Math.random() * statuses.length)]; - - const event = { - id: evId++, - title: `${dept} ${type} - ${targetMonth + 1}/15`, - description: `Sample event for ${dept} department.`, - startDate: start.toISOString(), - endDate: end.toISOString(), - location: venue, - category: cat, - type: type, - institution: "RIT", - department: dept, - academicYears: ["3rd Year"], - status: status, - budget: 5000, - hasRegistrationFee: false, - registrationFee: 0, - proposer: { id: 2, fullName: "Dr. Faculty Member", email: "faculty@rit.edu", role: "FACULTY" } - }; - await setDoc(doc(db, 'ems_events', String(event.id)), event); - } + for (const d of eventsSnap.docs) { + const data = d.data(); + if (data.description && data.description.startsWith("Sample event for")) { + console.log("[Firebase Backend] Deleting dummy event:", data.title); + await deleteDoc(d.ref); } } } catch (err) { - console.error("Seeding failed:", err); + console.error("Cleanup failed:", err); } } @@ -678,6 +637,7 @@ window.fetch = async function(input: RequestInfo | URL, init?: RequestInit): Pro registrationFee: feeStr === "" ? 0.0 : parseFloat(feeStr), centreName: payload.centreName || null, isPublicEvent: !!payload.isPublicEvent, + image: payload.image || null, proposer: { id: proposer.id, fullName: proposer.fullName, @@ -740,6 +700,7 @@ window.fetch = async function(input: RequestInfo | URL, init?: RequestInit): Pro academicYears: ay, status: payload.status || "APPROVED", requirements: payload.requirements || [], + image: payload.image || null, proposer }; @@ -925,6 +886,7 @@ window.fetch = async function(input: RequestInfo | URL, init?: RequestInit): Pro } if (payload.centreName !== undefined) updatedFields.centreName = payload.centreName; if (payload.isPublicEvent !== undefined) updatedFields.isPublicEvent = !!payload.isPublicEvent; + if (payload.image !== undefined) updatedFields.image = payload.image; if (payload.status !== undefined && isAdmin) { updatedFields.status = payload.status; }