From 4f433f4dba3450ce077c3233e7c0b08cb041a098 Mon Sep 17 00:00:00 2001 From: Amudieshwar A G Date: Tue, 21 Jul 2026 14:30:52 +0530 Subject: [PATCH] feat: implement database entities, repository, controllers, and data seeder for Notes & PYQs module --- backend/.vscode/settings.json | 3 + .../rit/portal/config/DataInitializer.java | 113 ++++++++++++++++++ .../portal/controller/NotePyqController.java | 52 ++++++++ .../java/com/rit/portal/entity/NotePyq.java | 46 +++++++ .../portal/repository/NotePyqRepository.java | 13 ++ .../src/main/resources/application.properties | 2 +- backend/target/classes/application.properties | 13 ++ .../com/rit/portal/PortalApplication.class | Bin 0 -> 735 bytes .../rit/portal/config/DataInitializer.class | Bin 0 -> 3625 bytes .../com/rit/portal/config/WebConfig.class | Bin 0 -> 1501 bytes .../portal/controller/NotePyqController.class | Bin 0 -> 4389 bytes .../entity/NotePyq$NotePyqBuilder.class | Bin 0 -> 3597 bytes .../com/rit/portal/entity/NotePyq.class | Bin 0 -> 4378 bytes .../portal/repository/NotePyqRepository.class | Bin 0 -> 845 bytes 14 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 backend/.vscode/settings.json create mode 100644 backend/src/main/java/com/rit/portal/config/DataInitializer.java create mode 100644 backend/src/main/java/com/rit/portal/controller/NotePyqController.java create mode 100644 backend/src/main/java/com/rit/portal/entity/NotePyq.java create mode 100644 backend/src/main/java/com/rit/portal/repository/NotePyqRepository.java create mode 100644 backend/target/classes/application.properties create mode 100644 backend/target/classes/com/rit/portal/PortalApplication.class create mode 100644 backend/target/classes/com/rit/portal/config/DataInitializer.class create mode 100644 backend/target/classes/com/rit/portal/config/WebConfig.class create mode 100644 backend/target/classes/com/rit/portal/controller/NotePyqController.class create mode 100644 backend/target/classes/com/rit/portal/entity/NotePyq$NotePyqBuilder.class create mode 100644 backend/target/classes/com/rit/portal/entity/NotePyq.class create mode 100644 backend/target/classes/com/rit/portal/repository/NotePyqRepository.class diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json new file mode 100644 index 0000000..7b016a8 --- /dev/null +++ b/backend/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/backend/src/main/java/com/rit/portal/config/DataInitializer.java b/backend/src/main/java/com/rit/portal/config/DataInitializer.java new file mode 100644 index 0000000..844a3f0 --- /dev/null +++ b/backend/src/main/java/com/rit/portal/config/DataInitializer.java @@ -0,0 +1,113 @@ +package com.rit.portal.config; + +import com.rit.portal.entity.NotePyq; +import com.rit.portal.repository.NotePyqRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; +import java.time.LocalDateTime; +import java.util.Arrays; + +@Component +public class DataInitializer implements CommandLineRunner { + + @Autowired + private NotePyqRepository noteRepository; + + @Override + public void run(String... args) throws Exception { + if (noteRepository.count() == 0) { + noteRepository.saveAll(Arrays.asList( + NotePyq.builder() + .title("Engineering Mathematics – Unit 1-5") + .subject("Mathematics") + .department("Computer Science & Engineering") + .semester(1) + .fileType("notes") + .downloadUrl("#") + .fileSize("4.2 MB") + .downloadsCount(348) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("Physics PYQ 2020-2024") + .subject("Physics") + .department("Computer Science & Engineering") + .semester(1) + .fileType("pyq") + .downloadUrl("#") + .fileSize("8.1 MB") + .downloadsCount(512) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("C Programming Complete Notes") + .subject("Programming") + .department("Computer Science & Engineering") + .semester(1) + .fileType("notes") + .downloadUrl("#") + .fileSize("6.3 MB") + .downloadsCount(734) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("Data Structures PYQ 2019-2024") + .subject("Data Structures") + .department("Computer Science & Engineering") + .semester(3) + .fileType("pyq") + .downloadUrl("#") + .fileSize("10.2 MB") + .downloadsCount(621) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("Circuit Theory Full Notes") + .subject("Circuit Theory") + .department("Electronics & Communication") + .semester(2) + .fileType("notes") + .downloadUrl("#") + .fileSize("5.7 MB") + .downloadsCount(289) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("Anna University Syllabus 2021") + .subject("Syllabus") + .department("All Departments") + .semester(1) + .fileType("syllabus") + .downloadUrl("#") + .fileSize("2.1 MB") + .downloadsCount(890) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("Thermodynamics Notes") + .subject("Thermodynamics") + .department("Mechanical Engineering") + .semester(3) + .fileType("notes") + .downloadUrl("#") + .fileSize("3.9 MB") + .downloadsCount(201) + .uploadedAt(LocalDateTime.now()) + .build(), + NotePyq.builder() + .title("Digital Electronics PYQ") + .subject("Digital Electronics") + .department("Electronics & Communication") + .semester(4) + .fileType("pyq") + .downloadUrl("#") + .fileSize("7.3 MB") + .downloadsCount(445) + .uploadedAt(LocalDateTime.now()) + .build() + )); + System.out.println("🌱 Database successfully seeded with Notes & PYQs test data!"); + } + } +} diff --git a/backend/src/main/java/com/rit/portal/controller/NotePyqController.java b/backend/src/main/java/com/rit/portal/controller/NotePyqController.java new file mode 100644 index 0000000..ebdad65 --- /dev/null +++ b/backend/src/main/java/com/rit/portal/controller/NotePyqController.java @@ -0,0 +1,52 @@ +package com.rit.portal.controller; + +import com.rit.portal.entity.NotePyq; +import com.rit.portal.repository.NotePyqRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.List; + +@RestController +@RequestMapping("/api/notes") +@CrossOrigin(origins = "*") // CrossOrigin configured globally, but added here for safety +public class NotePyqController { + + @Autowired + private NotePyqRepository noteRepository; + + // Get all notes + @GetMapping + public List getAllNotes() { + return noteRepository.findAll(); + } + + // Get notes by semester + @GetMapping("/semester/{semester}") + public List getNotesBySemester(@PathVariable Integer semester) { + return noteRepository.findBySemester(semester); + } + + // Get notes by department + @GetMapping("/department") + public List getNotesByDepartment(@RequestParam String dept) { + return noteRepository.findByDepartment(dept); + } + + // Add a new note metadata + @PostMapping + public NotePyq createNote(@RequestBody NotePyq note) { + return noteRepository.save(note); + } + + // Increment downloads count + @PostMapping("/{id}/download") + public ResponseEntity incrementDownloads(@PathVariable Long id) { + return noteRepository.findById(id).map(note -> { + note.setDownloadsCount(note.getDownloadsCount() + 1); + note.setFileType(note.getFileType()); // Keep dirty check + noteRepository.save(note); + return ResponseEntity.ok().build(); + }).orElse(ResponseEntity.notFound().build()); + } +} diff --git a/backend/src/main/java/com/rit/portal/entity/NotePyq.java b/backend/src/main/java/com/rit/portal/entity/NotePyq.java new file mode 100644 index 0000000..d71892b --- /dev/null +++ b/backend/src/main/java/com/rit/portal/entity/NotePyq.java @@ -0,0 +1,46 @@ +package com.rit.portal.entity; + +import jakarta.persistence.*; +import lombok.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "notes_pyqs") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class NotePyq { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String title; + + @Column(nullable = false) + private String subject; + + @Column(nullable = false) + private String department; + + @Column(nullable = false) + private Integer semester; + + @Column(name = "file_type", nullable = false) + private String fileType; // 'notes', 'pyq', 'syllabus', 'assignment' + + @Column(name = "download_url", nullable = false) + private String downloadUrl; + + @Column(name = "file_size", nullable = false) + private String fileSize; + + @Column(name = "downloads_count") + private Integer downloadsCount = 0; + + @Column(name = "uploaded_at") + private LocalDateTime uploadedAt = LocalDateTime.now(); +} diff --git a/backend/src/main/java/com/rit/portal/repository/NotePyqRepository.java b/backend/src/main/java/com/rit/portal/repository/NotePyqRepository.java new file mode 100644 index 0000000..6a9fd1d --- /dev/null +++ b/backend/src/main/java/com/rit/portal/repository/NotePyqRepository.java @@ -0,0 +1,13 @@ +package com.rit.portal.repository; + +import com.rit.portal.entity.NotePyq; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface NotePyqRepository extends JpaRepository { + List findBySemester(Integer semester); + List findByDepartment(String department); + List findByFileType(String fileType); +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 2599148..c24917f 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -1,7 +1,7 @@ # ─── DATABASE CONNECTION CONFIGURATION ─── spring.datasource.url=jdbc:postgresql://localhost:5432/rit_freshers_hub?sslmode=disable spring.datasource.username=postgres -spring.datasource.password=your_local_postgres_password_here +spring.datasource.password=Amudiesh22@. # ─── JPA / HIBERNATE SETTINGS ─── spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect diff --git a/backend/target/classes/application.properties b/backend/target/classes/application.properties new file mode 100644 index 0000000..c24917f --- /dev/null +++ b/backend/target/classes/application.properties @@ -0,0 +1,13 @@ +# ─── DATABASE CONNECTION CONFIGURATION ─── +spring.datasource.url=jdbc:postgresql://localhost:5432/rit_freshers_hub?sslmode=disable +spring.datasource.username=postgres +spring.datasource.password=Amudiesh22@. + +# ─── JPA / HIBERNATE SETTINGS ─── +spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.hibernate.ddl-auto=validate +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true + +# ─── SERVER PORT ─── +server.port=8080 diff --git a/backend/target/classes/com/rit/portal/PortalApplication.class b/backend/target/classes/com/rit/portal/PortalApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..9bc3c4044977df7cf64c21c1775dfaa5005f45cd GIT binary patch literal 735 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 literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/rit/portal/entity/NotePyq$NotePyqBuilder.class b/backend/target/classes/com/rit/portal/entity/NotePyq$NotePyqBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..5ba61c204eb3ad837cc92923f62b7f7cd8491fed GIT binary patch literal 3597 zcmd6pZC4vb6vzJ)9umUx6si?#AFyB{MS@jSNU4QX3Yr2IN^PqzmShTBHal^5f(O5a z@BA2gPCfP1bNbrjhw^x5XJR&N4hg*S#bjsh%>3@my>su)-~YUR17I27Cy`*7DTzwX zcVwam(CKqMKp(g?(h_T-)2vZSK9`CCQL*$|Nr~ zCW^w_&of+lSR-78uX{&M;Ox14+4F?7r6at6AyafkWltRD?sJd(w&Z2n(nIQ9t|l9_ zZRtB9FB#N~#&nriZC_UCxD2U)S9l<~&oCO&RIc*1eA`jOgCS7BU!QST}lGxb+;`KeaH53-pBdRJ1UR zPql&MlUQW9e5$|GSio)dkd_$UM9ma>I^ucbnKMf2#y;b=xUyzYD}z#Kq@>V087`1< zViBIEv{Xo9r76ki9Tx84ONQi;?bi6_b9zNlW9USbZ-LBEuDfqx4eJaSEA}BT2(M(z z$BsOpULb8x(i{IP3X5Ove=2ElT}oTqqUM+QDrGzd%jEA_WookOiV!l8zFpN}9;C5> ztt2)XCK}Fgyd!bQbNbTST&s3T3jbKy@f(I;qSi92HE_-L$}SHkib5RLs`A$%(bw@sE#Qos@te1;e;tD zs$Z`i;i^XQs86Zt5uMWILrEI-V~I_ZFV;OOa|PE90!~kEu=!|7e9JHyb3!Y#Ch?Tv z%IQm~Drp~3&}~p{ToZxBI3>m|iib23D%;a2Nh9@5(Kn&;b4*5=Iwqr>9g|Vsjmanj z$7Ga?V=~IhF&X9On2fUP3E2Rhn`$hbJ$jRiB+b!EM&F+7E4=etc)fS&S6vnuz$N;% z^a8wx%QT|AjVolHlb}4o6EvU9-uxX`v%gX|fs-h80$O5Fs;BKcPSPGl9wvSt-fzdh z-Z5YM%JBO_et&!ZWXF8%cf;=w`Br=WjgI;H4H>>F(Tuz@-OfJQj`{jM8va1YA8LR8 znU4ATZ5#ej$RBRcpY52h@T iBuh~=J*2jcM>NXN2^sy3+@%ck7*FsFWB4xIx$rNek=+FV literal 0 HcmV?d00001 diff --git a/backend/target/classes/com/rit/portal/entity/NotePyq.class b/backend/target/classes/com/rit/portal/entity/NotePyq.class new file mode 100644 index 0000000000000000000000000000000000000000..16b04ad31b0cd38b5d54caec1c22651a12004435 GIT binary patch literal 4378 zcmb7H3sclq6h484g=|D#qFc1q)>ep*)xK=;(IO~ax(g^Pt@c5~?iHiiWKFU-^jEbr z-O;f#{(%0G{)^!;_Dz4kwC4C?WB)~-ate(iU#b}_FGb;ynJ`9R<1o#XbAhVghG=suQz?ylzyL1bYRJ`+D)4c+ilA-u%SUj zjugs!?Jy8(L$t7`Cc?)4iKf85T!p4$R?0Sf7B1sFF)hKaDU`E~CLW_q+4d!=&~RSb zmSZ#?x|Tv(wAya-QmSs6zjt*!`92m&c}osLuh8)>VY?ns)OL$OMPm`{V&E6&s8n(4 zhP8}<*06$ig-CGQfMkBBZCVZ9%hkF0$~&v%d{`}a0u4aThILT3_Yx{$vSK;S9p`ze zn_;NrmYjyj)0{$=j$%xu3#4mwkuE7TeABc||F%MdbMspWMa8tmTD!R;+!`m3bI)7e zGF+3_A#rF|_+^yyB(`~|phuDGPc<5%Vfg1iHBrT9-yI50GVp3atxX?*46BVnztZR! zjVYu;b~C6YCg0F#lF7$FUhWnab8c%i#hd~wbgS&d0sN@WSpJSi({v(`zZVuA)9-3D z!#HDXp;vCq`c9)_WP(+=*qHvkMzc(xh^YkC#@scH&afeN`C+WkW+T@UN{#g%Xmpl7 zKwEl2^rz+y2cJ_oUKRdRr?FwU=oT~<5`ZR)!h0gF6GoS{REUI8g=1LsVu^?_vm3#g zI7Adc#$d51a0nNJ^upC+2OT*PV@Hk1cH;p#9a>6=$NZK`gQTm}peK1kolf-XF!V{I zU3!Y9+~ZNW{zRdfxpKT*BiB`WMpmAlD|Av~^jp)YNgHSp+j*(b+xYh743A|YjOY<5 zktat~>o;}~sDC3jWU4ovwp$mRDU8f;4qf4`E0jFc@5%#?XB0f_Kab>409VDyCA{s{ z{tMKcR<>~zEm?-=2`tAB&O21Y8peKA@TBqR9IBho36%zTa$uFmY67bfJh}E&K?Tx4 zzzhi41w4=AH~v^kVhSWPFa(kr==Nj=+C5~9<9QrbPkMAJGK7xr=e`$l(f9q_(-9Ya zA95q_f&4xUpt1WI=jbFh{~>(@f%6Ci2j*iuKf!MfH2xd;n=U+hMe~2)eSj|GKT8qf zbVXA5>@CsN1cVYeEIFkAMb{3ik4kkd5TMWKa|kN*1$~(UbUho;*Qr1Y*??}Q0^Q06 z^bLKRvbDu*Kuf6}EoTF|mkP9!4XB(7w3-d5k{Y9GHlTIdND21+Y(Se-!{9jF8w&vE z?ikiDcIeulvJZNlp~}*p2_(YO=B^0_&qMAAoUz2MzePW!!C%h`9}KP#{+NXSF&%y( zD||5iLikAu|0o^)R#y06h=%Y}68}_?qe+s_L)F>`=_uB;_Dez<(Y0fy=n!7h*@%boZ#bNOr;& z{)LSK^s5Orji+XXmL(6(G-=P(~IMSh2y*SF=71adi zw3u_6bgmT`?GBr2IBejEywLEls`7UXT;@0KHr{5Hzepg