192 Commits
Author SHA1 Message Date
brausjonas cb2ddc7bcf Hinweis zu Online Backend URL 2023-07-09 00:49:57 +02:00
brausjonas 68e2d553f9 Weitere backend kommentare 2023-07-09 00:42:44 +02:00
brausjonas 86f9e559b5 Weitere Kommentare im Frontend 2023-07-09 00:22:52 +02:00
AliGitGut 65a399693e Comments
Alle, von mir zu bearbeitenden, komplizierten und relevanten Codeteile wurden ausführlich beschrieben
2023-07-08 14:54:50 +02:00
AlexE030 3382d732a9 Improved Calender Side Bar jump Feature
Wenn man jetzt in der Kalender-Sidebar auf einen Monat klickt, dann springt er nicht mehr immer zum Ersten des Monats.
2023-06-30 00:58:11 +02:00
brausjonas 7b6a82c073 Update README.md 2023-06-28 09:31:07 +02:00
brausjonas d80abcaf8c Create LICENSE 2023-06-28 09:29:11 +02:00
brausjonas 17a3ad0b33 Fixed Logout Bug 2023-06-22 00:16:30 +02:00
brausjonas be9ace5238 Fixed User Loading Bug
Manchmal wurden User im Input Form nicht richtig geladen. Dieser Bug ist hiermit behoben
2023-06-22 00:01:48 +02:00
Amira24523 fcdf8492a6 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-06-21 23:34:58 +02:00
Amira24523 d4d01c730a Login Module in deutsch 2023-06-21 23:33:33 +02:00
brausjonas a4c600301e Bessere Erkennbarkeit von nicht Zuordnung von Dozenten zu Modulen 2023-06-21 23:22:25 +02:00
Amira24523 4ec1cb0749 Fixed SideBar 2023-06-21 23:10:02 +02:00
AliGitGut 20e2351ba9 Bugfix Pausen
Pausen werden nicht mehr angerecht aber dem Dozenten mitgeteilt
2023-06-21 22:49:47 +02:00
Amira24523 4f45d48061 InputForm Semester Width change 2023-06-21 22:36:33 +02:00
Amira24523 ee5805434d StatusBar Color update 2023-06-21 22:32:57 +02:00
AliGitGut 024d22711f Firefox
Firefox ist jetzt freigeschalten, wird aber nicht empfohlen
2023-06-21 21:04:27 +02:00
AliGitGut 9315f5b18d Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-06-21 20:38:39 +02:00
AliGitGut 34c2786840 Pausen Updates
Pausenskalierung angepasst, Pausen werden nun in den Modulen angezeigt
2023-06-21 20:38:36 +02:00
brausjonas ca23f7f993 More Dummy Data For Modules 2023-06-21 20:21:22 +02:00
AliGitGut d81922d188 Pausenvalidierung
Alle 4h muss ein Dozent eine Pause von 15 min einlegen // alle 8h eine von 30 min
2023-06-21 20:00:17 +02:00
brausjonas c979c3a801 Multiselect Fixed by Changing Columns 2023-06-21 17:04:26 +02:00
Amira24523 0a3a390bb8 Warning message 2023-06-21 15:55:40 +02:00
AliGitGut 09f288532e names changed 2023-06-20 18:21:50 +02:00
AliGitGut 137684f5be Help Page Angepasst
Help Page nochmal angepasst
2023-06-20 10:53:27 +02:00
AliGitGut a0841f4b2b Help Page Aktualisiert
Die Hilfe Seite wurde auf den neusten Stand gebracht, auf der Login Page entfernt und hat einen Back button bekommen
2023-06-19 15:29:56 +02:00
brausjonas 571e6e72c0 Grayed Out Bug Fixed 2023-06-19 15:02:09 +02:00
brausjonas ac4b62f32c Design Dateien Wiederhergestellt 2023-06-18 14:27:18 +02:00
brausjonas 8dc16c5b2c Bug Fix 2023-06-18 14:10:29 +02:00
brausjonas dd6f08880a Function Status Bar and Time Validation 2023-06-18 11:29:06 +02:00
AlexE030 b3fb3b1b8f Added Status Bar for Admins
There are still some minor Bugs to fix, but it works
2023-06-16 22:38:19 +02:00
AlexE030 dc20f35fb8 Finished Status Bar
Submit-Validation not yet implemented
2023-06-16 16:49:21 +02:00
AlexE030 9024dbc26e Bugfix localStorage is not defined 2023-06-16 12:35:37 +02:00
AlexE030 05a6a3ee23 Zwischenpush 2023-06-16 12:13:20 +02:00
brausjonas c9f3efd7f9 Merge branch 'AlexUndMikeBranch' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B into AlexUndMikeBranch 2023-06-16 11:59:09 +02:00
brausjonas 7983e23815 Calender View Module and Semester names and Numbers are shown
Also in the Dashboard for Lecturers
2023-06-16 11:59:06 +02:00
AliGitGut 5446b2d1cb Input Form Bugfix
Kursname, Theorieanfang und Ende müssen nun gesetzt werden sonst kann kein Kurs angelegt werden
2023-06-16 11:48:34 +02:00
brausjonas 8205b7d9d9 Calender View Angepasst auf die Module ID eines Entries 2023-06-16 11:33:36 +02:00
brausjonas 53ac8ff0bf Merge Of Branches Multiselect 2023-06-16 10:33:04 +02:00
AlexE030 e436e61041 Added Status Check 2023-06-16 10:02:57 +02:00
AliGitGut cff384f5b4 Bugfix Inputform
Bugfix for the start and enddate
2023-06-14 12:24:20 +02:00
AliGitGut eb69b97b9d Datum Validierung
Start eines Theorie Semester kann nicht hinter dem Ende des Theorie Semesters liegen
2023-06-14 11:29:31 +02:00
AlexE030 c02a0592ed Added Submitbutton 2023-06-13 19:28:32 +02:00
brausjonas e65ae7b90e Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-06-13 15:08:59 +02:00
brausjonas ac97e1937f Fixed Feiertage 2023-06-13 15:08:50 +02:00
AliGitGut 65325046c7 Bugfixing
Inputform bugfix
2023-06-13 15:03:06 +02:00
brausjonas fd6af0cdf4 Gray out logic restored 2023-06-13 14:58:29 +02:00
AliGitGut acf4b7d89a Feiertage Implementiert
Feiertage werden nun ausgegraut ^^
2023-06-13 14:28:19 +02:00
brausjonas 5c0de04f29 Database Corrected (not corrupt anymore, No server problem)) 2023-06-13 14:11:13 +02:00
brausjonas 7009a48735 New Database from Website 2023-06-13 13:44:26 +02:00
brausjonas 04df42b67a Push From Amira 2023-06-13 13:37:23 +02:00
brausjonas b89a1fd2fe Revert "Font size change"
This reverts commit a57e2b589a.
2023-06-13 13:35:16 +02:00
Amira24523 a57e2b589a Font size change 2023-06-13 13:29:40 +02:00
AliGitGut 0392c45eea Vorbereitung Progessbar
Semester Tiles angepasst für Progessbar implementierung
2023-06-10 01:18:46 +02:00
AliGitGut e9de6c41af Backend Statusbar Update
Backend Statusbar Funktionen hinzugefügt
2023-06-10 00:56:54 +02:00
AliGitGut 43165d7756 Overlap Bugfix
If any entries overlaps with the Users entries from other Semesters, the users entries will be cut of
2023-06-10 00:01:53 +02:00
brausjonas 092f7d3a8a Added Help Page 2023-06-09 22:49:56 +02:00
AliGitGut 394b920a4e All Entrys Shown for Lecturer
A lecturer can now see all his entries in his lecture view. Entries from other semester are blue colored, cant be configured from the from lecture view and are not of relevance for the rule semester, since they don´t apply for the students, only for the lecturer him- or herself
2023-06-09 21:35:02 +02:00
brausjonas b4020d0756 Final Bug Fix For Validation 2023-06-09 17:10:29 +02:00
brausjonas b1da16aed5 Bug In Validation Fixed 2023-06-09 16:44:53 +02:00
brausjonas 7b2602172e Valditions Displayed 2023-06-09 16:29:36 +02:00
brausjonas 74fbf38ecd Days Grayed Out 2023-06-09 14:22:18 +02:00
brausjonas b93c05b874 Calender Side Bar Autoscroll behaviour 2023-06-09 00:30:51 +02:00
brausjonas 9368ea423d Bug Finally Fixed 2023-06-09 00:10:22 +02:00
brausjonas 2280ff64a4 Bug Fixed 2023-06-09 00:07:02 +02:00
AliGitGut 2be842abea Highlight Added
Bugs
2023-06-08 23:58:12 +02:00
brausjonas dc5815d73d Calender Sidebar Get Months from Semester 2023-06-08 23:06:37 +02:00
brausjonas 8eed2746e9 Calender Side Bar on Click 2023-06-08 22:50:33 +02:00
AliGitGut 2abef513fe Calendar Sidebar Fixed
@AlexE030 and me
the days start at the right weekday now
2.30 am coding sessions are the best
2023-06-08 02:36:36 +02:00
brausjonas 964934690b Calender Validation Not Shown Explicit Error message
Die Fehlermeldung wird bereits in einem Feld gespeichert, jedoch noch nicht abgespeichert
PUUUUSH
2023-06-08 02:29:00 +02:00
AliGitGut 76ff99a365 Calendar Sidebar Added
Calendar Sidebar edited and added to the CalendarView
2023-06-08 00:27:20 +02:00
AliGitGut 62902d1b47 Performance Update
Dozenten Freigabe/Blockade möglich
Zurück Button Implementiert
PUUUUSH (insider für Jonas)
2023-06-07 23:06:08 +02:00
brausjonas 3b788cdd6b Semester Tile Takes Color Property 2023-06-07 22:28:54 +02:00
brausjonas 530047ac68 Connected SemesterOverviewLecturer and Calenderview 2023-06-07 21:58:54 +02:00
brausjonas 7446fca94d Lower Case Bug Fixed on Backend 2023-06-07 21:27:34 +02:00
AlexE030 88947e36f0 Username Bugfix 2023-05-30 15:50:54 +02:00
brausjonas b298fe0bdf Create README.md 2023-05-30 15:11:20 +02:00
brausjonas e33301f02e Prevent AutoScroll On Resize 2023-05-30 04:00:17 +02:00
brausjonas dac59d4a23 Use URL as Constant 2023-05-30 02:28:51 +02:00
AliGitGut a0d6d15099 Lecturer Dashboard Finished Version 2023-05-29 23:32:29 +02:00
AliGitGut dc708392c8 Dashboard Test 1
Lecturer Dashboard
2023-05-29 21:50:45 +02:00
brausjonas d90303f5c5 Revert "Init"
This reverts commit aa790a20d6.
2023-05-29 21:30:15 +02:00
brausjonas aa790a20d6 Init 2023-05-29 21:28:48 +02:00
brausjonas 866dfe9e2b Zoom Again Added to Calender View with + and - key 2023-05-26 16:27:20 +02:00
brausjonas d5443c87d0 Auto Scroll CalenderView to Middle 2023-05-26 15:43:41 +02:00
brausjonas aada7872da Datum neben dem Wochentg 2023-05-26 15:30:43 +02:00
AliGitGut 594c82ce23 Starttime edited
Starttime can be changed now
2023-05-26 14:50:04 +02:00
brausjonas edaba10719 New Calender View Design 2023-05-26 14:24:38 +02:00
brausjonas cf7201bc80 Backend Aufgeräumt 2023-05-26 13:36:28 +02:00
Amira24523 a8aa28e245 Calender Sync
Kalenderansicht synchronisieren sich automatisch
2023-05-26 12:00:04 +02:00
brausjonas 76243295cc Add files via upload 2023-05-26 10:28:09 +02:00
brausjonas b4c71af857 Calender View Sync Prototype Working Correctly 2023-05-26 02:10:15 +02:00
brausjonas f52d4275ba New Calender View Logic Concept 2023-05-26 00:46:50 +02:00
brausjonas 0c42a5820a Merge branch 'JonasTestBranch' into main 2023-05-25 23:01:50 +02:00
brausjonas 09d46a9faf Edit Logic Finished 2023-05-25 13:36:38 +02:00
brausjonas ac9fa44b99 Edit Function Finished (Semester and Modules)
Man kann bis jetzt eine dozenten noch nicht "abwählen"
2023-05-25 13:22:22 +02:00
brausjonas 00d57da32d Test Input Form reload data 2023-05-25 02:06:30 +02:00
brausjonas 15d325815d Bug Fix 2023-05-24 17:36:38 +02:00
brausjonas 7703b0676d Modules On Push 2023-05-24 17:30:16 +02:00
brausjonas f42f2df078 FrontEnd Bug Fix 2023-05-24 16:05:21 +02:00
brausjonas 337aea6a65 Merge branch 'DesignIdea' into main 2023-05-24 12:47:35 +02:00
brausjonas 6c13caca85 Input Form new Design 2023-05-24 12:47:15 +02:00
brausjonas 9255fb8e9b Updated Maven File for Build 2023-05-24 09:31:43 +02:00
brausjonas 2fba6b4354 Popup Animated 2023-05-24 01:21:19 +02:00
brausjonas 12f5773930 Design Extended to button 2023-05-24 01:05:04 +02:00
brausjonas 702e3e8e4d Design idea 2023-05-24 00:49:59 +02:00
brausjonas aadd9f5f94 Module Controller Fixed 2023-05-23 18:40:49 +02:00
brausjonas ed13b80a23 Revert "Added modules to Database"
This reverts commit 1da2f5be41.
2023-05-23 18:18:37 +02:00
brausjonas d46e125ff1 Added Modules Table To DataBase 2023-05-23 17:59:04 +02:00
AlexE030 1da2f5be41 Added modules to Database
+ small changes in backend
2023-05-23 17:44:35 +02:00
AliGitGut 2a87d54102 Kalender Side Bar Bugfix
Noch etwas Bugfix + neue Funktionalität hinzugefügt :)
2023-05-22 23:49:01 +02:00
AliGitGut 4741ba6911 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-05-22 22:58:44 +02:00
brausjonas d8cc85713c In Semester Edit and Create there are real users to select now
And dummy data of modules to select from a list
2023-05-22 22:58:35 +02:00
AliGitGut 09188005f6 Kalender Side Bar Bugfix
Monatsnamen werden nun Jahresübergreifend richtig angezeigt
2023-05-22 22:51:50 +02:00
brausjonas 7d6d48d09e Fixed "React UseState useEffect" Loop on Semester overview 2023-05-22 19:43:26 +02:00
brausjonas aa408b27d1 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-05-22 19:31:23 +02:00
brausjonas f8d36fcd8a Update Logic For Semester 2023-05-22 19:31:19 +02:00
AliGitGut 10d7dbf1df Update GruppenAufteilungEtc.pdf 2023-05-22 15:21:42 +02:00
AliGitGut 59fa7185cc Calendar Side Bar added
Calendar Side Bar and CSS File added
Don´t touch it, CSS makes problems
2023-05-21 14:50:39 +02:00
AlexE030 313df3e343 Added automatic module delete
+ small Changes
2023-05-20 22:33:53 +02:00
AlexE030 e92712d1d6 Added Modules to DBHandler
Datenbankeinträge fehlen noch.
2023-05-20 00:45:58 +02:00
brausjonas 8a1f0854a6 Delete Button For Semester Tile 2023-05-16 23:39:36 +02:00
brausjonas 99f22c77e3 Can Delete Semester on Right click menu 2023-05-16 23:23:51 +02:00
brausjonas ce38765fe1 Input Form Connected with Backend 2023-05-16 22:47:45 +02:00
brausjonas b1ede8005d Had To Move Some code because states wont work otherwise 2023-05-16 22:17:55 +02:00
brausjonas f6af4be682 First Prototype Frontend (Not Finished) 2023-05-16 22:03:02 +02:00
brausjonas ef1358baa4 OnLoginClick Logic
Fetch data from the backend and save the session id to the local storage
2023-05-16 19:52:58 +02:00
brausjonas bd6ec7b21f Login Function added 2023-05-16 19:22:54 +02:00
brausjonas 2da3e62c15 Database structure (Temp) 2023-05-16 11:49:29 +02:00
AliGitGut 34a6ca5aea Day Controller umgebogen
Day Controller wurde angepasst (wie Jonas sagen würde: umgebogen)
2023-05-16 11:38:08 +02:00
brausjonas 3a5768f51e Semester Fixed in databasehandler 2023-05-16 11:14:01 +02:00
brausjonas 0e4bee203d Semester Structure Changed 2023-05-16 11:10:05 +02:00
brausjonas 574ecaf305 Test Day In Year 2023-05-16 10:46:26 +02:00
AlexE030 8ef1540ff5 added Module Prototype 2023-05-16 00:32:55 +02:00
MikeBaier5 824e612140 WeekController finished 2023-05-14 22:10:54 +02:00
brausjonas ad025c07fb Database Handler Error Message on Connection Failed 2023-05-14 16:39:46 +02:00
brausjonas 301f976cb9 Add files via upload 2023-05-14 15:46:02 +02:00
brausjonas 8f68ff16a5 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-05-14 15:41:52 +02:00
brausjonas 9daff98b9e Backend Frontend Merge 2023-05-14 15:41:49 +02:00
brausjonas 076263e89b Delete projekt directory 2023-05-14 15:39:58 +02:00
Amira24523 83a426d86e Final Login Design 2023-05-14 15:27:32 +02:00
Amira24523 371c9c7997 Login design update 2023-05-11 21:40:54 +02:00
AlexE030 22635bb6e5 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-05-10 18:22:30 +02:00
AlexE030 7db358248d Added static Input-Form Prototype 2023-05-10 18:19:34 +02:00
Amira24523 a24ba0fb3b Added Login 2023-05-08 11:52:46 +02:00
MikeBaier5 646c64c7d9 Hovering tile finished 2023-05-08 01:46:31 +02:00
brausjonas 57ebdf002d Calender View move bug fix 2023-05-07 18:06:21 +02:00
brausjonas 67563b798d Calender View Block Elements Overlapping 2023-05-07 17:02:22 +02:00
brausjonas 49a53f3d05 Calender View documentation 2023-05-06 15:15:18 +02:00
brausjonas af5849affc Calender Resize
Der Kalender kann mittels eines "+" und "-" buttons vergrößert und verkleinert werden. D.h. Zeilen werden enger zusammengerückt oder auseinander gezogen
2023-05-06 00:12:20 +02:00
brausjonas 4a4601d175 Calender Correct Scaling XD 2023-05-05 21:26:12 +02:00
brausjonas bd6d279919 Scrollbar for entire Website shown again 2023-05-05 20:26:37 +02:00
brausjonas fd43a158dd Calender View Bug Fix 2023-05-05 20:04:07 +02:00
brausjonas 33ba88abef Calender View Clean Graphics 2023-05-05 19:47:08 +02:00
brausjonas c9c8222c8c Calender View Timeline
Lines with time stamps are shown on the columns
2023-05-05 19:45:17 +02:00
brausjonas 9d05046106 Calender View Einheitliche Ränder 2023-05-05 18:49:02 +02:00
brausjonas 54394cc726 Calender View Delete Elements
Calender View Delete Elements with Right click
2023-05-05 18:08:45 +02:00
brausjonas 4f981e37a1 CalenderView Tage Always on top
Tage in der Kalender werden nicht mit gescrolled
2023-05-05 17:47:46 +02:00
brausjonas b96ce074b3 Draggable Objects 2023-05-05 15:01:20 +02:00
brausjonas 1ebcecf640 Simple Resize System
Man kann erstellte Termine nach oben und unter resizen
2023-05-05 14:00:36 +02:00
brausjonas bf8e8700b7 Only Right Scroll bar in calender view 2023-05-05 13:09:05 +02:00
brausjonas bc88f54dc1 Calender View 15 Minuten Takt
Beim Setzen neuer Termine wird die Überschneidung mit einem bereits vorhandenem termin durch das verhindern des setzens blockiert
2023-05-05 12:47:44 +02:00
brausjonas 88fe8b84e3 Calender Prototype 2023-05-04 16:41:21 +02:00
AlexE030 87e34e7a2e Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-05-04 12:40:41 +02:00
AlexE030 1614bdc04d added WeekSelector 2023-05-04 12:33:20 +02:00
brausjonas cd11c3f7a9 Button new Options
Options for Font Color
2023-05-04 12:14:38 +02:00
brausjonas 0e7b9b176b Popup Doubleclick bug fixed 2023-05-04 12:04:59 +02:00
brausjonas 5394e7fc3c Modal (Popup) Component
A Component that contains a button to open a modal. Containing A message and a button to abort and send
2023-05-04 11:55:28 +02:00
brausjonas cc39ce4e90 Status Bar Active Design 2023-05-04 10:47:44 +02:00
brausjonas ec1c4a9a6f Status Bar Bug Fix 2023-05-02 23:22:00 +02:00
brausjonas d9dd4c6cb9 Status Bar Active Element Highlighted 2023-05-02 23:08:41 +02:00
brausjonas 05e3916952 Progressbar extended
Better Color sheme and indexes on the progress points
2023-05-02 23:04:03 +02:00
brausjonas 124ad09c37 StatusBar Component
Implemented a basic status bar with 3 dots, that is able to show 3 states. The length of the status line can be controlled by a paramter called "progress". Every value between 0 and 100 is valid. The Progress bar will change its color depending on the value of "progress"
2023-05-02 22:49:05 +02:00
brausjonas 104c30553b Moved CSS Code from App to Global 2023-05-02 16:03:02 +02:00
brausjonas dccefaa3ea Button Documentation 2023-05-02 15:50:46 +02:00
brausjonas 1f172ea4d2 App.css 2023-05-02 15:41:58 +02:00
AlexE030 3e485945f3 Merge branch 'main' of https://github.com/DHBWLoerrach/TIF22A_AnwProjekt_B 2023-05-02 15:36:39 +02:00
AlexE030 59b4f93930 added DateElement 2023-05-02 15:36:03 +02:00
brausjonas 5104ce93b7 Button Component Finished 2023-05-02 15:31:18 +02:00
brausjonas 04ca2319c2 Empty White Page 2023-05-02 15:17:14 +02:00
brausjonas 2b8b5259b9 next js configure correctly 2023-05-02 14:58:32 +02:00
brausjonas 975b0fca96 Created Next Js Project 2023-05-02 14:47:34 +02:00
brausjonas a67e293cdc Deleted Because Not Valid 2023-05-02 14:24:13 +02:00
Mike Baier 86a2068f83 Created next.js project 2023-05-02 14:22:01 +02:00
brausjonas 27da0c3152 Button fix 2023-04-27 22:07:21 +02:00
brausjonas d6d2e23bf4 Merge branch 'JonasTestBranch' into main 2023-04-27 22:07:06 +02:00
brausjonas 612bf4539f Merge branch 'main' into JonasTestBranch 2023-04-27 21:59:18 +02:00
brausjonas 659b6f9112 Button with onhover and function paramter
Man kann eine Funktion als Parameter dem button übergeben, sodass er diese ausführt, sobald auf ihn geklickt wird
2023-04-27 21:59:12 +02:00
brausjonas 96f4778d77 Merge branch 'main' into JonasTestBranch 2023-04-27 19:26:20 +02:00
brausjonas eb91703cc9 Merge branch 'JonasTestBranch' into main 2023-04-27 18:59:13 +02:00
brausjonas 09e0e006ec Variable Buttons
Padding, width, height, text are optional, if not set there are default values (no css)
2023-04-27 18:58:41 +02:00
brausjonas 1d087d7996 Button (Not ready) 2023-04-27 16:58:50 +02:00
167 changed files with 880785 additions and 17646 deletions
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JpaBuddyIdeaProjectConfig">
<option name="renamerInitialized" value="true" />
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="16" project-jdk-type="JavaSDK" />
<component name="ProjectType">
<option name="id" value="jpab" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/TIF22A_AnwProjekt_B.iml" filepath="$PROJECT_DIR$/.idea/TIF22A_AnwProjekt_B.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+170
View File
@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="744e9299-0ce3-415c-8733-c935bf920887" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/components/CalendarSideBar.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/components/CalendarSideBar.jsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/components/DateElement.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/components/DateElement.jsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/components/WeekSelector.jsx" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/components/WeekSelector.jsx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/pages/semesteroverview.js" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/pages/semesteroverview.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/anwendung/src/pages/semesteroverviewLecturer.js" beforeDir="false" afterPath="$PROJECT_DIR$/anwendung/src/pages/semesteroverviewLecturer.js" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="CSS File" />
<option value="JavaScript File" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2PV5k9t8lC9xvqgtEIMZ2TApWUu" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;ignore.virus.scanning.warn.message&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;C:/Users/afist/WebstormProjects/SideBarCalendarTest&quot;,
&quot;list.type.of.created.stylesheet&quot;: &quot;CSS&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;ts.external.directory.path&quot;: &quot;C:\\Users\\afist\\AppData\\Local\\JetBrains\\Toolbox\\apps\\WebStorm\\ch-0\\231.8770.64\\plugins\\javascript-impl\\jsLanguageServicesImpl\\external&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\TIF22A_AnwProjekt_B\anwendung\src\images" />
</key>
</component>
<component name="RunManager" selected="npm.dev">
<configuration name="index.js" type="NodeJSConfigurationType" temporary="true" nameIsGenerated="true" path-to-js-file="index.js" working-dir="$PROJECT_DIR$/anwendung/src/pages">
<method v="2" />
</configuration>
<configuration name="build" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/anwendung/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="node" />
<envs />
<method v="2" />
</configuration>
<configuration name="dev" type="js.build_tools.npm" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/anwendung/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<node-interpreter value="node" />
<package-manager value="npm" />
<envs />
<method v="2">
<option name="NpmBeforeRunTask" enabled="true">
<package-json value="$PROJECT_DIR$/anwendung/package.json" />
<command value="run" />
<scripts>
<script value="build" />
</scripts>
<node-interpreter value="node" />
<package-manager value="npm" />
<envs />
</option>
</method>
</configuration>
<list>
<item itemvalue="Node.js.index.js" />
<item itemvalue="npm.build" />
<item itemvalue="npm.dev" />
</list>
<recent_temporary>
<list>
<item itemvalue="Node.js.index.js" />
</list>
</recent_temporary>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="744e9299-0ce3-415c-8733-c935bf920887" name="Changes" comment="" />
<created>1683529551159</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1683529551159</updated>
<workItem from="1683529552463" duration="1756000" />
<workItem from="1683830457997" duration="1285000" />
<workItem from="1684223646646" duration="1195000" />
<workItem from="1684228236564" duration="1017000" />
<workItem from="1684257831013" duration="1011000" />
<workItem from="1684267194850" duration="890000" />
<workItem from="1684672228161" duration="1603000" />
<workItem from="1684788345629" duration="1507000" />
<workItem from="1684856925307" duration="3000" />
<workItem from="1684856964097" duration="5995000" />
<workItem from="1684915449317" duration="9318000" />
<workItem from="1685011281036" duration="2214000" />
<workItem from="1685055429281" duration="634000" />
<workItem from="1685103879210" duration="2066000" />
<workItem from="1685142372079" duration="5289000" />
<workItem from="1685311018550" duration="2063000" />
<workItem from="1685356323722" duration="4005000" />
<workItem from="1685389394962" duration="4465000" />
<workItem from="1685439319096" duration="492000" />
<workItem from="1686165563810" duration="18166000" />
<workItem from="1686259026223" duration="2970000" />
<workItem from="1686313568230" duration="1725000" />
<workItem from="1686331195896" duration="7520000" />
<workItem from="1686345244271" duration="7553000" />
<workItem from="1686572559048" duration="4289000" />
<workItem from="1686655739777" duration="3725000" />
<workItem from="1686659590430" duration="2344000" />
<workItem from="1686690018802" duration="32000" />
<workItem from="1686690072078" duration="307000" />
<workItem from="1686727178400" duration="9281000" />
<workItem from="1686825740350" duration="2964000" />
<workItem from="1686831091729" duration="595000" />
<workItem from="1686906198799" duration="2151000" />
<workItem from="1686910129813" duration="1653000" />
<workItem from="1686923077769" duration="3441000" />
<workItem from="1687173723149" duration="7011000" />
<workItem from="1687240431966" duration="47000" />
<workItem from="1687245202053" duration="3425000" />
<workItem from="1687249039012" duration="3407000" />
<workItem from="1687349584578" duration="477000" />
<workItem from="1687354510081" duration="453000" />
<workItem from="1687354999964" duration="291000" />
<workItem from="1687431213516" duration="596000" />
<workItem from="1688661149524" duration="602000" />
<workItem from="1688661766941" duration="1680000" />
<workItem from="1688812359996" duration="6843000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
</project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Ali Fistik, Jonas Braus, Amira Michels, Alexander Ebner, Mike Baier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+64
View File
@@ -0,0 +1,64 @@
# TIF22A_AnwProjekt_B
Team B im Anwendungsprojekt (TIF22A)
Website can be accessed under: http://lectureplanner.de/ (caution no https, only http)
Hinweise für Lokale Installation:
Hinweis: Alles ist auf Windows getestet, sollte aber auch auf Mac und Linux funktionieren
1. es sollte java in einer der neusten Versionen installiert sein. (Empfehlung Java 20)
Downloadlink: https://www.oracle.com/de/java/technologies/downloads/
Eventuell müssen Sie nach der Installation den PC neu Starten.
Im Terminal können Sie mit "java -version" Ihre aktuelle Java version überprüfen.
2. Für das Frontend muss zusätzlich npm auf dem Computer installiert sein. (Weiteres siehe z.B. hier: https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)
3. Es sollte feiertagejs installiert sein "npm install feiertagejs" (weiters: https://github.com/sfakir/feiertagejs)
Ausführen des Backends (nicht im "backend" ordner):
1. Öffnen Sie ein Terminal, dort wo die datei "backend.jar" liegt. Achten Sie darauf, dass die Dateien "database.mv.db" und "database.trace.db" im gleichen Ordner
wie die ".jar" Datei liegen.
2. Geben sie im Terminal ein: "java -jar backend.jar"
Ausführen des Frontends:
1. Gehen Sie in den Ordner "anwendung"
2. Öffnen Sie hier ein Terminal und führen den Command "npm run build" aus. (Bitte beachten, dass Feiertagejs vorher hier installiert sein sollte)
3. Führen Sie nun im gleichen Terminal den Command "npm run start" aus.
4. Gehen Sie im Browser auf "http://localhost:3000" oder einem davon abeweichenden Link der im Terminal angezeigt wird.
5. Einloggen können Sie sich mit folgenden User-Daten:
Sollte das ausführen lokal nicht funktionieren, können Sie das Projekt immer noch über die website http://www.lectureplanner.de betrachten.
Admins:
Email -------------------- Passwort
braus@gmail.com 123
fistik@gmail.com 123
Dozenten:
Email -------------------- Passwort
gloessner@gmail.com 123
birn@mail.com 123
behrends@gmx.de 123
+16 -4
View File
@@ -8,16 +8,28 @@
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
@@ -3,7 +3,6 @@
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
+1 -1
View File
@@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/projekt.iml" filepath="$PROJECT_DIR$/.idea/projekt.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/anwendung.iml" filepath="$PROJECT_DIR$/.idea/anwendung.iml" />
</modules>
</component>
</project>
View File
+38
View File
@@ -0,0 +1,38 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
+7
View File
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
+6
View File
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfig
+1387
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
{
"name": "anwendung",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"autoprefixer": "10.4.14",
"feiertagejs": "^1.3.9",
"next": "13.3.4",
"postcss": "8.4.23",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.2"
}
}
+6
View File
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>

After

Width:  |  Height:  |  Size: 629 B

+21
View File
@@ -0,0 +1,21 @@
import Button from "@/components/Button";
import {useRouter} from "next/router";
import {baseURL} from "@/components/Constants";
import {arrowLeft} from "@/components/Icons";
export default function Back(p)
{
return(
<div style={{
position : "absolute",
left : 20,
top : 20,
width : 60,
height : 60
}}>
<Button onClick={() => p.onClick()} icon={arrowLeft} color={"#77932b"} width={75} height={40}/>
</div>
)
}
+34
View File
@@ -0,0 +1,34 @@
import React from "react";
export default function Background()
{
//diese komponente generiert über css properties und geschickte rotationen von div element im raum das hintergrundbild
return (
<div style={{
position: "absolute",
width: "100%",
height: "100%",
overflow: "clip",
pointerEvents: "none"
}}>
<div style={{
position: "absolute",
transform: "skew(20deg)",
width: "100%",
height: "100%",
zIndex: -10,
backgroundColor: "#f2f2f2",
borderTopLeftRadius: 400,
borderBottomRightRadius: 800,
}}></div>
<div style={{
position: "absolute",
width: "100%",
height: "100%",
zIndex: -11,
backgroundColor: "#346991",
}}></div>
</div>
);
}
+65
View File
@@ -0,0 +1,65 @@
/**
* Function Takes in Paramter for:
* text: text to be shown on the button
* width, height: width and height of the button
* icon: an icon that should be shown on the button (HTML <svg> tag) (see Icons.js for example)
* iconWidth, iconHeight: width and height of the icon
* onClick: a function that should be run if the button is clicked
* Example for onClick:
* <Button onClick={onClick={() => {console.log("do something")}}
* Example for icon:
*/
export default function Button(p) {
//default parameters for the button
let text = p.text;
let width = p.width, height = p.height;
let iconHTML = p.icon;
let iconWidth = p.iconWidth, iconHeight = p.iconHeight;
let onClick = p.onClick;
let color = p.color;
let fontColor = p.fontColor;
let font_size = p.fontSize;
//if parameters are not set, they are set to default values
if (height == null) height = 0;
if (width == null) width = 0;
if (iconWidth == null) iconWidth = width-10;
if (iconHeight == null) iconHeight = height-10;
if (onClick == null) onClick = () => {};
if (color == null) color = "#363636";
if (fontColor == null) fontColor = "white";
if (font_size == null) font_size = 16;
//build in the icon width and height to the svg tag (svg tag should not contain any size information by default)
if (iconHTML != null) {
let split = iconHTML.split("fill=");
split[1] = "fill=" + split[1];
split[0] += " width=" + iconWidth + " height=" + iconHeight + " ";
iconHTML = split[0] + split[1]
} else {
iconHTML = "";
}
//return the button html
return (
<>
<button className={"round-border button font font-small"}
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: color,
color: fontColor,
fontSize: font_size,
minWidth: width,
minHeight: height,
textAlign: "center",
}}
onClick={onClick}>
{text}
<div dangerouslySetInnerHTML={{__html: iconHTML}}/>
</button>
</>
);
}
@@ -0,0 +1,184 @@
import {useEffect, useRef} from "react";
let startParts = []
let endParts = []
const months = [["Januar", 31], ["Februar", 28], ["März", 31], ["April", 30], ["Mai", 31], ["Juni", 30], ["Juli", 31], ["August", 31], ["September", 30], ["Oktober", 31], ["November", 30], ["Dezember", 31]]
const days = months.map((month => month[1]))
let result = []
let startDate
let calculatedDay = []
const weekdays = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
let lastMonth = 0
export default function BasicDateCalendar(p) {
const ref = useRef(null)
function getBackMonthColor(monthIndex) //Farbliche Kennzeichnung des Monats in dem man aktuell Plant
{
let date = new Date(parseInt(startParts[2]), parseInt(startParts[1]) + monthIndex - 1, 1) //Datums Objekt des Monats in dem man sich aktuell befindet
if (date.getFullYear() === p.highlightYear && date.getMonth() === p.highlightMonth)
{
if(lastMonth !== p.highlightMonth)
{
ref.current.scrollTo({top: 290 * monthIndex - 270, behavior: "smooth"})
}
lastMonth = p.highlightMonth
return true
}else
return false
}
useEffect(() => {
startParts = []
endParts = []
result = []
calculatedDay = []
startDate = new Date(p.startyear, 0 ,p.startday) //Startdatum des Theoriesemesters
let endDate = new Date(p.endyear, 0 , p.endday) //Enddatum des Theoriesemesters
let startString = startDate.getDate() + "." + (startDate.getMonth() + 1) + "." + p.startyear
let endString = endDate.getDate() + "." + (endDate.getMonth() + 1) + "." + p.endyear
generateCalendar(startString, endString)
})
return (
<div className={"Allround"} ref={ref}>
<div className={"Down"}>
{result.map((monthResult, index) => ( //map durch alle Monate aus dem Array monthResult
<div className={"A box-shadow"} onClick={() => p.onMonthClick(
(parseInt(startParts[1]) + index),
startParts //gibt zurück auf welchen Monat geklickt wurde, wodurch direkt in den jeweiligen Monat gewechselt werden kann
)} >
<p style={{
textAlign : "center",
marginBottom : 10,
fontSize: 19,
pointerEvents: "none",
backgroundColor: getBackMonthColor(index) ? "#346991":"rgba(0,0,0,0)",
color : getBackMonthColor(index) ? "white":"black",
borderRadius : 10
}}>{getMonthName(index) + " " + new Date(parseInt(startParts[2]), parseInt(startParts[1]) + index - 1, 1).getFullYear()}</p>
<div className={"Days"} style={{
pointerEvents: "none"
}}>
{weekdays.map((weekday) => (
<p key={weekday} style={{ //generiere einmal alle Wochentage (Montag,...,Sonntag)
pointerEvents: "none"
}}>{weekday}</p>
))}
{freeSpaces(index)}
{monthResult.map((date) => (
<p key={date} style={{
pointerEvents: "none"
}}>{date}</p>
))}
</div>
</div>
))}
</div>
</div>
)
}
function getMonthName(monthIndex) { //holt die relevanten Monatsnamen aus dem 2D Array
if (startParts[1] - 1 + monthIndex < 12) {
return months[startParts[1] - 1 + monthIndex][0];
} else {
return months[startParts[1] - 1 + monthIndex - 12][0];
}
}
function generateCalendar(start, ende)
{
splitter(start, ende)
if (startParts[2] < endParts[2]) //Abfrage für den Fall, dass ein Theoriesemester Jahresübergreifend ist
{
for (let i = startParts[1] - 1; i <= 11; i++) //Durchlaufe alle Monate bis zum Jahresende
{
let monthResult = [];
for (let j = 1; j <= days[i]; j++) //durchlaufe alle Tage des Monats in dem wir uns befinden
{
if (
new Date(startParts[2], i, j) >= new Date(startParts[2], startParts[1] - 1, startParts[0]) &&
new Date(startParts[2], i, j) <= new Date(startParts[2], 11, 31)
) //überprüft ob der Tag noch in der angegebenen Zeitspanne des Theoriesemsters liegt
{
monthResult.push(j);
calculateDay(startParts[2], i, j)
}
}
result.push(monthResult);
if (i == 11) //erstes Jahr ist fertig abgebildet
{
for (let h = 0; h <= endParts[1] - 1; h++) //laufe vom Anfang des Jahres bis zum angegebenen Ende des Theoriesemesters
{
let monthResultNewYear = [];
for (let g = 1; g <= days[h]; g++) //durchlaufe alle Tage des Monats in dem wir uns befinden
{
if (new Date(endParts[2], h, g) <= new Date(endParts[2], endParts[1] - 1, endParts[0])) //überprüft ob der Tag noch in der angegebenen Zeitspanne des Theoriesemsters liegt
{
monthResultNewYear.push(g);
calculateDay(endParts[2], h, g)
}
}
result.push(monthResultNewYear);
}
}
}
} else //Normalfall das ein Anfang und Ende eines Theoriesemester im gleichen Jahr liegt
{
for (let i = startParts[1] - 1; i <= endParts[1] - 1; i++) //durchlaufe alle Monate in der angegebenen Zeitspanne
{
let monthResult = [];
for (let j = 1; j <= days[i]; j++) //durchlaufe alle Tage des Monats in dem wir uns befinden
{
if (
new Date(startParts[2], i, j) >= new Date(startParts[2], startParts[1] - 1, startParts[0]) &&
new Date(startParts[2], i, j) <= new Date(startParts[2], endParts[1] - 1, endParts[0])
) //überprüft ob der Tag noch in der angegebenen Zeitspanne des Theoriesemsters liegt
{
monthResult.push(j)
calculateDay(startParts[2], i, j)
}
}
result.push(monthResult);
}
}
}
function calculateDay(x, i, j)//berechnet den Wochentag eines Datums (Montag,...,Sonntag)
{
if (j == startDate.getDate() && i == startDate.getMonth() || j == 1){
let monthStart = new Date(x, i, j)
if (monthStart.getDay() == 0)
calculatedDay.push(6)
else calculatedDay.push(monthStart.getDay() - 1)
}
}
function freeSpaces(index)//generiert Leerzeichen damit Tage genau unter ihrem jeweiligen Wochentag stehen
{
let arrayTest = []
for (let i = 0; i < calculatedDay[index]; i++) {
arrayTest.push(<p style={{
pointerEvents: "none"
}}></p>)
}
return arrayTest
}
function splitter(startDate, endDate)
{
startParts = startDate.split(".")
if (startParts[1][0] === 0) //prüft ob die erste Stelle des Monats eine 0 vorne stehen hat
{
startParts[1] = startParts[1][1] //überschreibt den Monat ohne die 0
}
endParts = endDate.split(".") //prüft ob die erste Stelle des Monats eine 0 vorne stehen hat
if (endParts[1][0] === 0)
{
endParts[1] = endParts[1][1] //überschreibt den Monat ohne die 0
}
}
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
//Achtung!!! hier kann die URL für das Backend auf das Online Backend geändert werden. Verwendung des Online Backends
//auf eigene Gefahr. Aktuellster Stand der Software kann hier in Kombination mit einem Lokalen Frontend nicht gewährleistet werden.
//export const baseURL = "http://185.245.96.48:8080"
export const baseURL = "http://localhost:8080"
+21
View File
@@ -0,0 +1,21 @@
function addDays(date, days) {
let result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}
export default function DateElement(p){
let startDate = new Date(p.year, 0, p.startday);
let endDate = new Date(p.year, 0, p.startday + 5);
let startDateString = `${startDate.getDate()}.${startDate.getMonth()+1}.${startDate.getFullYear()}`; //Anfang der Woche in der man sich befindet wird in startDateString geladen
let endDateString = `${endDate.getDate()}.${endDate.getMonth()+1}.${endDate.getFullYear()}`; //Ende der Woche in der man sich befindet wird in endDateString geladen
return /*Anzeige des Beginns und Endes der Woche in der man sich befindet*/(
<>
<div className="dateElement round-border box-shadow">
<p>{startDateString} - {endDateString}</p>
</div>
</>
);
}
+9
View File
@@ -0,0 +1,9 @@
//hier werden fehlertypen mit ihrem anzeigetext für die CalenderView hinterlegt
export const ErrorType = {
Okay: "Okay",
TooLong: "Zu lang, maximal 8h pro Tag!",
TooEarly: "Wenn möglich nicht vor 8:00",
TooLate: "Wenn möglich nicht nach 17:00",
NotEnoughLunchTime: "Mind. 45min Pause zwischen 11:00 - 14:00",
Saturday: "Wenn möglich nicht am Samstag"
}
+19
View File
@@ -0,0 +1,19 @@
import Button from "@/components/Button";
import {helpButton} from "@/components/Icons";
import {useRouter} from "next/router";
export default function HelpButton(p)
{
const router = useRouter()
return (
<div style={{
position: "absolute",
bottom: 20,
right: 20,
borderRadius: 15
}} className={"box-shadow"}>
<Button width={40} height={40} color={"white"} icon={helpButton} onClick={() => router.push("/help")}/>
</div>
)
}
+22
View File
@@ -0,0 +1,22 @@
//hier sind wichtige svg images zur späteren verwendung auf buttons usw. hinterlegt. In diese können später evtl. per stringmanipulation weitere infos
//wie breite und höhe eingearbeitet werden.
export const arrowLeft = `<svg xmlns="http://www.w3.org/2000/svg" fill="white" class="bi bi-arrow-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
</svg>`
export const arrowRight = `<svg xmlns="http://www.w3.org/2000/svg" fill="white" class="bi bi-arrow-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z"/>
</svg>`
export const deleteItem = `<svg xmlns="http://www.w3.org/2000/svg" fill="black" class="bi bi-trash-fill" viewBox="0 0 16 16">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"/>
</svg>`
export const editItem = `<svg xmlns="http://www.w3.org/2000/svg" fill="black" class="bi bi-pencil-fill" viewBox="0 0 16 16">
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
</svg>`
export const helpButton = `<svg xmlns="http://www.w3.org/2000/svg" fill="black" class="bi bi-question" viewBox="0 0 16 16">
<path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z"/>
</svg>`
+346
View File
@@ -0,0 +1,346 @@
import Button from "@/components/Button";
import {useRouter} from "next/router";
import {useEffect, useState} from "react";
import Background from "@/components/Background";
import {baseURL} from "@/components/Constants";
import Back from "@/components/Back";
//dummy daten für die vorlesungsfächer
let modulesDummy = [
["Grundlagen u. Logik", "Programmieren 1", "Programmieren 2", "Digitaltechnik", "Web. Eng.", "Analysis"],
["Lineare Algebra", "Anwendungsprojekt", "BWL", "Projektmanagement", "Algo. Kompl.", "Python", "Prolog"],
["Software Eng. 1", "Netztechnik", "Betriebssysteme", "Rechnerarchitektur", "Systemnahe Progra.", "Algorithmen 2", "Stochastik", "Angewandte Mathe."],
["Software Eng. 2", "Datenbanken", "Compilerbau", "Automaten", "Formale Sprachen", "IT-Sicherheit", "IOT"],
["Software Eng. 3", "Datenbanken 2", ],
["Bachelor"]
]
//speichert ab, ob die nummer des semesters in der bearbeitung geändert wurde.
//wichtig umd daten (aus alten semester nummern) korrekt löschen zu können
let hasSemesterNumberChanged = false
export default function InputForm(p) {
const [courseName, setCourseName] = useState("")
const [startDate, setStartDate] = useState("")
const [endDate, setEndDate] = useState("")
const [semesterNumber, setSemesterNumber] = useState(0)
const [users, setUsers] = useState([])
const [moduleUserMapping, setModuleUserMapping] = useState([])
const router = useRouter()
useEffect(() => {
hasSemesterNumberChanged = false
//lädt zu beginn alle dummy daten des ersten semesters
let arr = []
modulesDummy[0].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
})
setModuleUserMapping(arr)
let url = baseURL + "/users/all?sessionid=" + localStorage.getItem("sessionid")
//holt alle dozenten, die für das dozieren in fragen kommen.
fetch(url).then(r => r.json()).then(u => {
setUsers(u)
}).then(() => {
let tempSemesterNumber = 0
//hier kann ausgemacht werden, ob ein semester neu erstellt werden soll oder bearbeitet, wenn 0 dann wird neu erstellt
//also hier wird bearbeitet
if(localStorage.getItem("currentsid") != 0)
{
//holen alle daten, die bis jetzt in diesem semester vorhanden sind (noch keine zuweisungen von dozenten zu vorlesungen)
fetch(baseURL + "/semester/id?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid")).then(r => r.json()).then(semester => {
setCourseName(semester.name)
let startYear = semester.startyear
let endYear = semester.endyear
let start = new Date(startYear, 0, semester.startday)
let end = new Date(endYear, 0, semester.endday)
setStartDate(startYear + "-" + ((start.getMonth() + 1) < 10 ? "0" + (start.getMonth() + 1) : (start.getMonth() + 1)) + "-" + (start.getDate() < 10 ? "0" + start.getDate() : start.getDate()))
setEndDate(endYear + "-" + ((end.getMonth() + 1) < 10 ? "0" + (end.getMonth() + 1) : (end.getMonth() + 1)) + "-" + (end.getDate() < 10 ? "0" + end.getDate() : end.getDate()))
tempSemesterNumber = semester.number
setSemesterNumber(semester.number)
arr = []
modulesDummy[semester.number].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
})
}).then(() => {
//hole alle zuweisungen von dozenten zu vorlesungen / fächern innerhalb dieses semesters.
fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&semesterid=" + localStorage.getItem("currentsid")).then(r => r.json()).then(modules => {
console.log(modules)
for(let i = 0; i < modules.length; i++)
{
for(let j = 0; j < modulesDummy[tempSemesterNumber].length; j++)
{
if(modulesDummy[tempSemesterNumber][j] == modules[i].name)
{
arr[j].userid = modules[i].userid
arr[j].moduleid = modules[i].id
arr[j].activated = modules[i].activated
break
}
}
}
setModuleUserMapping(arr)
})
})
}
})
}, [])
//sollte auf abbrechen geklickt worden sein...
function onButtonAbort(e) {
router.back()
}
//sollte auf speichern geklickt worden sein... hier werden nur daten des semesters übermittelt, noch nicht die
//zweisungen von dozenten und vorlesungen / modulen
function onButtonSave(e) {
//bereite alle relevanten daten des input form auf
let semesterid = localStorage.getItem("currentsid")
let startYear = parseInt(startDate.split("-")[0])
let endYear = parseInt(endDate.split("-")[0])
let start = new Date(startYear, parseInt(startDate.split("-")[1]) - 1, parseInt(startDate.split("-")[2]))
let end = new Date(endYear, parseInt(endDate.split("-")[1]) - 1, parseInt(endDate.split("-")[2]))
let startDayInYear = Math.round((start - new Date(startYear, 0, 0)) / (1000 * 60 * 60 * 24))
let endDayInYear = Math.round((end - new Date(endYear, 0, 0)) / (1000 * 60 * 60 * 24))
//wenn das semester neu erstellt werden soll, sende eine post anfrage and das backend.
if(semesterid == 0)
{
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": 0,
"startday": startDayInYear,
"endday": endDayInYear,
"name": courseName,
"startyear": startYear,
"endyear": endYear,
"number": semesterNumber
})
}).then(r => r.json()).then(semester => {semesterid = semester.id}).then(() => modulesInBackend(semesterid))
}
//wenn das semester nur editiert wurde, stelle eine put anfrage an das backend.
else
{
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
method: "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": semesterid,
"startday": startDayInYear,
"endday": endDayInYear,
"name": courseName,
"startyear": startYear,
"endyear": endYear,
"number": semesterNumber
})
}).then(() => modulesInBackend(semesterid))
}
}
function modulesInBackend(semesterid)
{
//sollte sich die nummer des semesters geändert haben, lösche alle alten zuweisungen von dozenten und modulen aus dem backend.
if (hasSemesterNumberChanged) {
fetch(baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid"), {
method: "DELETE"
}).then(() => {
for (let i = 0; i < moduleUserMapping.length; i++) {
let current = moduleUserMapping[i]
if (current.userid != -1) {
if (current.moduleid == -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": 0,
"userid": current.userid,
"semesterid": semesterid,
"name": modulesDummy[semesterNumber][i],
"activated": current.activated
})
})
}
}
}
})
} else {
//hier werden modulzuweisungen zu dozenten am backend aktualisiert
for (let i = 0; i < moduleUserMapping.length; i++) {
let current = moduleUserMapping[i]
//solte die zuweisung des modules zum dozenten noch aktiv sein...
if (current.userid != -1) {
//im fall, dass das die zuweisung nocht nie existiert hat, stelle eine post anfrage
if (current.moduleid == -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": 0,
"userid": current.userid,
"semesterid": semesterid,
"name": modulesDummy[semesterNumber][i],
"activated": current.activated
})
})
} else {
//im fall, dass die zuweisung schon existiert hat aber nur geändert wurde, stelle eine PUT anfrage
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
"id": current.moduleid,
"userid": current.userid,
"semesterid": 0,
"name": "",
"activated": current.activated
})
})
}
//.. ist diese zuweisung nicht mehr aktiv, lösche die zuweisung aus dem backend.
} else {
if (current.moduleid != -1) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid") + "&id=" + current.moduleid, {
method: "DELETE"
})
}
}
}
}
//gehe nach dem speichern zurück auf das dashboard
router.back()
}
return (
<>
{/*das hintergrundbild*/}
<Background/>
<div className={"box-shadow input-form round-border"}>
{/*grundlegende input forms für namen... semesternummer usw.*/}
<p>Kursname</p>
<input type={"text"} className={"box-shadow round-border"}
style={{padding: 8, width: "100%", backgroundColor: (courseName == "") ? "#E44747" : "white"}}
onChange={(e) => {
setCourseName(e.target.value)
}} value={courseName}/>
<div style={{display: "flex", justifyContent: "flex-start", gap: 40}}>
<p>Theorie Anfang</p>
<p>Theorie Ende</p>
</div>
<div style={{display: "flex", justifyContent: "flex-start", gap: 20}}>
<input type={"date"} className={"box-shadow round-border"} style={{
padding: 8, backgroundColor: (startDate == "" || startDate >= endDate) ? "#E44747" : "white"
}} value={startDate} onChange={e => {
setStartDate(e.target.value)
}}/>
<input type={"date"} className={"box-shadow round-border"} style={{
padding: 8, backgroundColor: (endDate == "" || startDate >= endDate) ? "#E44747" : "white"
}} value={endDate} onChange={e => {
setEndDate(e.target.value)
}}/>
</div>
<p>Semester Wählen</p>
<select className={"round-border box-shadow"} style={{padding: 5, width: "27%"}} value={semesterNumber}
onChange={e => {
setSemesterNumber(e.target.value)
let arr = []
modulesDummy[e.target.value].map(e => {
arr.push({"moduleid": -1, "userid": -1, "activated": 0})
})
setModuleUserMapping(arr)
hasSemesterNumberChanged = true
}}>
<option value={0}>1. Semester</option>
<option value={1}>2. Semester</option>
<option value={2}>3. Semester</option>
<option value={3}>4. Semester</option>
<option value={4}>5. Semester</option>
<option value={5}>6. Semester</option>
</select>
{/*hier die tabelle, die alle zuweisungen von dozenten und modulen / vorlesungen anzeigt*/}
<div className={"table-wrapper"}>
<table>
<tbody>
<tr>
<th>Freischalten</th>
<th>Modul</th>
<th>Dozent</th>
</tr>
{
modulesDummy[semesterNumber].map((module, index) => (
<tr style={{height: 50}}>
<td>
<input type={"checkbox"}
checked={index < moduleUserMapping.length && moduleUserMapping[index].activated == 1}
onChange={e => {
let arr = moduleUserMapping.slice()
arr[index].activated = e.target.checked ? 1 : 0
setModuleUserMapping(arr)
}
}></input>
</td>
<td>
<p style={{fontWeight: "normal"}}>{module}</p>
</td>
<td>
<select className={"box-shadow round-border"} style={{padding: 5}}
onChange={e => {
let arr = moduleUserMapping.slice()
arr[index].userid = e.target.value
setModuleUserMapping(arr)
console.log(moduleUserMapping)
}}
value={index < moduleUserMapping.length && moduleUserMapping[index].userid}>
<option value={-1}>-</option>
{users.map(user => (
<option value={user.id}>{user.firstName} {user.lastName}</option>
))}
</select>
</td>
</tr>
))
}
</tbody>
</table>
</div>
<div style={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
width: "100%",
gap: 10
}}>
{/*hier die knöpfe abbrechen und speichern mit einer kleinen validierung, ob die grundlegen semesterdaten angegeben wurden*/}
<Button text={"Abbrechen"} onClick={onButtonAbort}/>
<Button text={"Speichern"} color={"#77932b"} onClick={() => {
(startDate == "" || endDate == "" || startDate >= endDate || courseName == "") ? () => {
} : onButtonSave()
}}/>
</div>
</div>
</>
)
}
+87
View File
@@ -0,0 +1,87 @@
import React, {useState} from "react";
import Button from "@/components/Button";
import {NextResponse} from "next/server";
import Link from "next/link";
import {useRouter} from "next/router";
import {baseURL} from "@/components/Constants";
export default function Login() {
let url = baseURL + "/users"
//sollte auf den login knopf geklickt worden sein...
async function on_login_click() {
//füge der url die mail und das passwort an, sicherheitsfeatures werden die hier vorläufig nicht berücktsichtigt
url += "?mail=" + inputUserName + "&password=" + inputPassword;
let response = await fetch(url, {
method: "GET",
});
//lese die antwort vom backend, und versuche die sessionid (für weitere anfragen am backend wird diese übergeben) auszulesen.
//ist der status nicht "failed" wurden die einloggdaten gefunden und im fall, dass kein fehler aufgetreten ist
//eine sessionid zurückgegeben.
let reader = response.body.getReader();
let value = String.fromCharCode.apply(null, ((await reader.read()).value))
if (value != "failed") {
localStorage.setItem("sessionid", value);
url = baseURL + "/users/check?sessionid=" + value;
fetch(url).then(r => r.json()).then(u => localStorage.setItem("userid", u.id))
let admin = 0
await fetch(url).then(o => o.json()).then(user => {
admin = user.permissions})
//setze für die spätere verwendung im localstorage, ob es sich bei dem aktuellen nutzer um einen admin handelt.
//selbst wenn diese informationen vom nutzer im browser manuell editiert werden, blockt das backend
//über sämtliche anfrage mit einer sessionid die dozenten bezogen ist ab. => diese information ist nur für die anzeige.
//diese könnte allerdings nicht ordnungsgemäß funktionieren sollte ein nutzer versuchen das tool "auszutricksen"
localStorage.setItem("admin", admin)
//leite den nutzer je nach seinem status auf die admin oder dozenten ansicht weiter.
if(admin === 1) {
await router.push("/semesteroverview")
}else await router.push("/semesteroverviewLecturer")
} else {
setInputPassword("");
setInputUserName("");
setHint("wrong login credentials")
}
}
const [inputUserName, setInputUserName] = useState("")
const [inputPassword, setInputPassword] = useState("")
//hier states für die hinweise in den loginfeldern für späteres anzeigen von evtl. fehlgeschlagen login versuchen.
const [hint, setHint] = useState("Benutzername")
const [hint2, setHint2] = useState("Passwort")
const [backgroundColor, setBackgroundColor] = useState("rgb(255, 255, 255)")
const router = useRouter()
return (
// <div className="border">
<login className={"login-container box-shadow"}>
<p className={"font-big-fat placement"}>Login</p>
<div className={"placement"}>
<p className={"font-kinda-big"}>Benutzername:</p>
<input type="text" value={inputUserName} onChange={e => setInputUserName(e.target.value.toLowerCase())}
placeholder={hint} className="input input-bordered input-sm w-full max-w-xs box-shadow"
style={{
backgroundColor: backgroundColor
}}/>
<br/>
<p className={"font-kinda-big"}>Passwort:</p>
<input type="password" value={inputPassword} onChange={e => setInputPassword(e.target.value)}
placeholder={hint2} className="input input-bordered input-sm w-full max-w-xs box-shadow"
style={{
backgroundColor: backgroundColor
}}/>
</div>
<Button text={"Login"} color={"#77932b"} width={100} height={40} onClick={() => on_login_click()}/>
</login>
// </div>
);
}
+29
View File
@@ -0,0 +1,29 @@
import Button from "@/components/Button";
import {useRouter} from "next/router";
import {baseURL} from "@/components/Constants";
export default function Logout()
{
const router = useRouter()
async function logout()
{
let url = baseURL + "/users/logout?sessionid=" + localStorage.getItem("sessionid");
await fetch(url)
await router.push("/")
}
return (
<div style={{
position: "absolute",
right: 20,
top: 20,
width: 130,
height: 60,
borderBottomRightRadius: 10,
}}>
<Button onClick={() => logout()} text={"Logout"} color={"#77932b"} width={100} height={40}/>
</div>
)
}
+29
View File
@@ -0,0 +1,29 @@
import Button from "@/components/Button";
import {useState} from "react";
let shown = false;
export default function PopUp(p) {
return (
<>
<div style={{
display: p.displayState,
zIndex: 1000
}}>
<div className={"modal-container"}>
<div className={"modal box-shadow"}>
<p className={"font-middle"}>{p.hint}</p>
<div>
<Button text={p.text1} color={"rgba(54,54,54,0.64)"} onClick={p.function1}/>
<Button text={p.text2} color={"#77932b"} onClick={p.function2}/>
</div>
</div>
</div>
</div>
</>
)
}
+45
View File
@@ -0,0 +1,45 @@
import React, {useEffect} from "react";
export default function SemesterTile(p)
{
let editable = true;
let color = "#ffffff"
if (p.color != null)
{
color = p.color;
}
if (p.editable != null)
{
editable = p.editable
}
useEffect(() =>
{
window.addEventListener("contextmenu", (e) => (e.preventDefault()))
})
return (
<div
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0,0,0,0)"
}}
onClick={(e) => p.onClick(e)}>
<p className={"semester-tile-p"} style={{
}}>{p.text}</p>
<p className={"semester-tile-p"} style={{
color: "gray"
}}>{p.text2}</p>
<div style={{
display: editable ? "flex" : "none",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
gap: 5
}}>
</div>
</div>
)
}
+40
View File
@@ -0,0 +1,40 @@
import React, {useState} from "react"
import {baseURL} from "@/components/Constants";
import {console} from "next/dist/compiled/@edge-runtime/primitives/console";
export default function StatusBar(p)
{
if(p.progress > 100) p.progress = 100;
let classNames = ["not-started"];
let index = p.progress / 50;
let index2 = p.progress / 100;
let index3 = p.progress - 100;
let index4 = p.progress - 50;
let actives = ["", "", ""];
actives[index] = "active";
let actives2 = ["", "", ""];
actives2[index2] = "active";
let actives3 = ["", "", ""];
actives3[index3] = "active";
let actives4 = ["", "", ""];
actives4[index4] = "active";
return (
<div className={"step-container"}>
<div className={"steps"}>
<span className={"step " + classNames[0] + " " + actives[0] + actives2[1] + actives3[1] + actives4[0]}>1</span>
<span className={"step " + classNames[0] + " " + actives[1] + actives2[1] + actives3[1] + actives4[1]}>2</span>
<span className={"step " + classNames[0] + " " + actives[2] + actives2[2] + actives3[2] + actives4[2]}>3</span>
<div className={"progress-bar " + classNames[index]}
style={{
width: p.progress + "%"
}}
></div>
</div>
</div>
)
}
+14
View File
@@ -0,0 +1,14 @@
//hier ein test für die umrechnung zwischen internen und externen datumsformaten. Kann zur nachvollziehbarkeit der rechnung evtl. nützlich sein.
export default function Test(p)
{
let day = 41
let datum = new Date(2023, 0, day)
datum.getMonth()
let datum2 = new Date(2023, 5, 12);
let start = new Date(datum2.getFullYear(), 0, 0);
let dayInYear = (datum2 - start) / (1000 * 60 * 60 * 24)
}
+69
View File
@@ -0,0 +1,69 @@
import React from 'react';
//hier eine verworfene version der SemesterTile, welche einen hübschen hover effekt ansetzt. Könnte evtl.
//wieder eingepflegt werden.
const Tile = () => {
const [isHovered, setIsHovered] = React.useState(false);
const [cursorPosition, setCursorPosition] = React.useState({ x: 0, y: 0 });
const tileRef = React.useRef(null);
const handleMouseEnter = () => {
setIsHovered(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
};
const handleMouseMove = (event) => {
if (tileRef.current) {
const rect = tileRef.current.getBoundingClientRect();
setCursorPosition({
x: event.clientX - rect.left,
y: event.clientY - rect.top,
});
}
};
return (
<div
ref={tileRef}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onMouseMove={handleMouseMove}
style={{
backgroundColor: 'rgba(255,0,0,0.89)',
width: '250px',
height: '150px',
margin: '10px',
transition: 'transform 0.2s',
transform: isHovered ? 'translateY(-5px)' : 'none',
position: 'relative',
borderRadius: '10px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<span style = {{ color: 'white', fontWeight: 'bold'}}>Kalender</span>
{isHovered && (
<div
style={{
position: 'absolute',
top: cursorPosition.y - 10,
left: cursorPosition.x - 10,
width: '20px',
height: '20px',
borderRadius: '50%',
background:
'radial-gradient(circle at center, rgba(255, 255, 255) 0%, rgba(255,255,255,0) 70%)',
}}
/>
)}
</div>
);
};
export default Tile;
+19
View File
@@ -0,0 +1,19 @@
import Button from "@/components/Button";
import DateElement from "@/components/DateElement";
import { arrowLeft } from "./Icons"
import { arrowRight } from "./Icons"
export default function WeekSelector(p){
return /*Aufruf des DateElements mit aktuellem Starttag im Jahr und dem Jahr, sowie Buttons zum hin und her Wechsel der Wochen*/(
<>
<div className="weekSelector">
<Button icon={arrowLeft} onClick={() => p.onFunctionLeft()} width={50} color={"#346991"}/>
<DateElement year={p.year} startday={p.startday}/>
<Button icon={arrowRight} onClick={() => p.onFunctionRight()} width={50} color={"#346991"}/>
</div>
</>
)
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

+7
View File
@@ -0,0 +1,7 @@
import '@/styles/globals.css'
import '@/styles/calendarSideBar.css'
import '@/styles/helppage.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}
+5
View File
@@ -0,0 +1,5 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
@@ -0,0 +1,20 @@
export default function BrowserNotSupported(p)
{
return (
<div style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
height: "100vh",
}} >
<p style={{
fontSize: 40,
color: "red"
}}>Sorry but your browser is not supported right now</p>
<p style={{
fontSize: 30
}}>We recommend using Microsoft Edge or Google Chrome</p>
</div>
)
}
+17
View File
@@ -0,0 +1,17 @@
import InputForm from "@/components/InputForm";
import {useRouter} from "next/router";
import Logout from "@/components/Logout";
export default function CreateSemester()
{
const router = useRouter();
let {courseName, startDate, endDate} = router.query;
return (
<div className={"normal-centered"}>
<Logout/>
<InputForm startDate={startDate} endDate={endDate} courseName={courseName}/>
</div>
)
}
+97
View File
@@ -0,0 +1,97 @@
import Background from "@/components/Background";
import Back from "@/components/Back";
import {useRouter} from "next/router";
import screen1 from "@/images/screen1.png"
import screen2 from "@/images/screen2.png"
import screen3 from "@/images/screen3.png"
import screen4 from "@/images/screen4.png"
import screen5 from "@/images/screen5.png"
import screen6 from "@/images/screen6.png"
import screen7 from "@/images/screen7.png"
export default function Help(p)
{
const router = useRouter()
return (
<div>
<Back onClick={() => router.back()}/>
<div className={"help-line"}>
<img src={screen1.src}/>
<div className={"text-form"}>
<h1>Die Monats-Leiste</h1>
<p>- Hier siehst du in welchem Monat Sie sich aktuell befinden (blau hinterlegt)</p>
<p>- Durch einen Links-Klick auf eine Monatskacheln springst du direkt an den Anfang des jeweiligen Monats</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen2.src} width={1000}/>
<div className={"text-form"}>
<h1>Die Planungs-Ansicht</h1>
<p>- Hier siehst du deine eingetragenen Vorlesungen in diesem Kurs in Grün, deine eigenen Vorlesungen aus anderen Kursen in Blau und die geplanten Vorlesungen anderer Dozenten in Grau</p>
<p>- Durch einen Links-Klick kannst du eine neue Vorlesung an einem Tag erstellen</p>
<p>- Durch Halten der dunkleren Leisten ist es möglich die Zeiten deiner Termine anzupassen</p>
<p>- Durch einen Rechts-Klick können eigene Termine gelöscht werden</p>
<p>- Mithilfe der Navigationsleiste ist es möglich die Wochen zur Planung zu wechseln</p>
<p>- Ausgegraute Tage liegen entweder nicht im Semester oder sind Feiertage, hier kann nicht geplant werden</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen3.src}/>
<div className={"text-form"}>
<h1>Die Warnungs-Ansicht</h1>
<p>- Sollte ein Termin gelb erscheinen kannst du hier sehen woran das liegt</p>
<p>- Warnung sind empfohlene Verbesserungsverschläge, müssen aber nicht zwangshaft beachtet werden</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen4.src}/>
<div className={"text-form"}>
<h1>Der Logout</h1>
<p>- Über diesen Button kannst du dich ausloggen</p>
<p>- Loggst du dich nicht selbst aus, wirst du nach 2 Stunden automatisch ausgeloggt</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen6.src}/>
<div className={"text-form"}>
<h1>Das Dashboard für Admins</h1>
<p>- Hier werden alle bestehenden Semester gelistet</p>
<p>- Über den "+" Button ist es möglich ein neues Semester zu erstellen</p>
<p>- Über das Stift-Symbol kann ein bestehends Semester editiert werden</p>
<p>- Über das Mülleimer-Symbol kann ein bestehndes Semester gelöscht werden</p>
<p>- Die Fortschrittsanzeige bleibt auf der (1) bis ein Dozent seinen Plan abgegeben hat, sobald das geschieht wechselt sie auf die (2) und wenn alle Dozenten ihre Pläne abgegeben haben, springt die Anzeige auf die (3)</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen5.src}/>
<div className={"text-form"}>
<h2>Das Dashboard für Dozenten</h2>
<p>- Hier werden alle Semester angzeigt in welchem der eingeloggte Dozent Vorlesungen planen soll</p>
<p>- Sollte ein Semester ausgegraut sein, wurden Sie für dieses schon gewählt aber noch nicht freigeschalten</p>
<p>- Durch einen Links-Klick auf ein weißes Semester kann in die Planungsübersicht gewechselt werden</p>
<p>- Die Fortschrittsanzeige bleibt auf der (1) bis eine Vorlesung geplant wird, sobald das geschieht wechselt sie auf die (2) und wenn der Dozent seinen Plan abgibt, springt die Anzeige auf die (3)</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen7.src}/>
<div className={"text-form"}>
<h1>Semester erstellen / bearbeiten</h1>
<p>- Hier müssen die folgenden Daten eingetragen werden: Kursname sowie Start- und Endzeitpunkt einer Vorlesungsphase</p>
<p>- Der Start muss vor dem Endzeitpunkt liegen</p>
<p>- Einen Dozenten zu wählen bedeutet ihn dem Kurs hinzuzufügen, sollte ihm kein Modul zugewiesen werden, wird er automatisch abgewählt</p>
<p>- Ein Dozent muss mindestens ein, kann aber auch mehrere Module zugewiesen bekommen</p>
<p>- Um einem Dozenten mehrere Module zuzuweisen, halte die "STRG"-Taste gedrückt während du per Links klick die Module auswählst</p>
<p>- Sobald die Schaltfläche "Freischalten" aktiviert wurde, kann der Dozent mit der eigenständigen Planung beginnen</p>
<p>- Jeder genannte Schritt, insbesondere der Letzte kann auch nachträglich im Bearbeitungsmodus ausgeführt werden</p>
</div>
</div>
</div>
)
}
+53
View File
@@ -0,0 +1,53 @@
import {Inter} from 'next/font/google'
import React, {useEffect, useState} from "react";
import Login from "@/components/Login";
import Background from "@/components/Background";
import {useRouter} from "next/router";
import HelpButton from "@/components/HelpButton";
const inter = Inter({subsets: ['latin']})
export default function Home(p) {
const router = useRouter()
//hier wird im login fenster überpüft ob der aktuelle browser mit dem tool kompatibel ist.
//evtl. sind auch browser, die nicht chrome basiert sind kompatibel, diese konnten aber nicht ausführlich genug getest werden.
useEffect(() => {
let isEdge = window.navigator.userAgent.indexOf("Edg") > -1
let isChrome = window.navigator.userAgent.indexOf("Chrome") > -1
let isFireFox = window.navigator.userAgent.indexOf("firefox") > -1
//ist der browser nicht unterstützt so wird der nutzer auf die browser nicht unterstützt seite weitergeleitet.
if(!(isEdge || isChrome || isFireFox))
{
router.push("/browserNotSupported")
}
})
return (
<div className={"normal-centered"}>
<Background/>
<h1 style={{
fontSize: 40,
fontWeight: "bold",
color: "#77932b",
marginBottom: "5%",
textShadow: "2px 2px 2px rgba(0, 0, 0, 0.2)",
textAlign: "center"
}}>Willkommen in deinem Vorlesungsplaner</h1>
<Login/>
<p1 style={{
fontSize: 18,
fontWeight: "bold",
color: "red",
marginTop: "5%",
textAlign: "center",
maxWidth: 450,
justifyContent: "start"
}}>Es handelt sich hierbei um eine BETA-VERSION! Keine Gewähr auf Korrekte oder vollständige Informationen</p1>
</div>
)
}
+30
View File
@@ -0,0 +1,30 @@
import CalenderView from "@/components/CalenderView";
import Background from "@/components/Background";
import Logout from "@/components/Logout";
import Back from "@/components/Back";
import BasicDateCalendar from "@/components/CalendarSideBar";
import {useRouter} from "next/router";
import HelpButton from "@/components/HelpButton";
export default function planning(p)
{
let router = useRouter()
let semesterName;
if (typeof window !== 'undefined'){
semesterName = localStorage.getItem("semestername") + " " + (localStorage.getItem("admin") == 1 ? "" : localStorage.getItem("currentmodulename"))
}
return (
<div className={"normal-centered"}>
<Logout/>
<Back onClick={() => router.back()}/>
<HelpButton/>
<Background/>
<CalenderView semesterName={semesterName}/>
</div>
)
}
+222
View File
@@ -0,0 +1,222 @@
import Button from "@/components/Button";
import React, {useEffect, useState} from "react";
import SemesterTile from "@/components/SemesterTile";
import InputForm from "@/components/InputForm";
import {useRouter} from "next/router";
import PopUp from "@/components/PopUp";
import Background from "@/components/Background";
import Logout from "@/components/Logout";
import {baseURL} from "@/components/Constants";
import HelpButton from "@/components/HelpButton";
import StatusBar from "@/components/StatusBar";
import {deleteItem, editItem} from "@/components/Icons";
export default function SemesterOverview(p) {
const [progresses, setProgresses] = useState([])
async function getSemesters(set) {
let urlTest = baseURL + "/semester/all?sessionid=" + localStorage.getItem("sessionid");
let allSemesters
let allModules
let allEntries
//Datenanfrage an das Backend für alle existierenden Semester
await fetch(urlTest).then(response => response.json()).then(s => {
allSemesters = s
if (set) {
setEntries(s)
}
}).then(() => {
if(!set)
{
//Datenanfrage an das Backend um alle Module zu erhalten
fetch(baseURL + "/module/all?sessionid=" + localStorage.getItem("sessionid")).then(r => r.json()).then(mod => {
allModules = mod
}).then(() => {
//Datenanfrage an das Backend um alle gesetzten Entries zu erhalten
fetch(baseURL + "/entries/all?sessionid=" + localStorage.getItem("sessionid")).then(r => r.json()).then(en => {
allEntries = en
}).then(() => {
let modulesCountInSemester = []
for (let i = 0; i < allSemesters.length; i++) //durchlaufe die Anzahl der Semester welche von dem Backend zurück gegeben wurden
{
let count = 0
for (let j = 0; j < allModules.length; j++) { //durchlaufe die Anzahl der Module welche von dem Backend zurück gegeben wurden
if (allSemesters[i].id === allModules[j].semesterid) //Prüfe ob das Modul zu dem jeweiligen Semester gehört und erhöhe count
{
count++;
}
}
modulesCountInSemester.push(count)
}
let temp = []
for (let s = 0; s < allSemesters.length; s++) //durchlaufe die Anzahl der Semester welche von dem Backend zurück gegeben wurden
{
let count = 0;
for (let i = 0; i < allModules.length; i++) //durchlaufe die Anzahl der Module welche von dem Backend zurück gegeben wurden
{
if (allModules[i].semesterid === allSemesters[s].id) //Prüfe ob das Modul zu dem jeweiligen Semester gehört
{
let sum = 0
let ent = allEntries.filter(e => e.moduleid === allModules[i].id) //lade alle Entries die zu dem Modul gehören in dem wir uns befinden in die Variable
for (let j = 0; j < ent.length; j++) //durchlaufe die Anzahl der Entries aus ent
{
sum += ent[j].timeend - ent[j].timestart //summiere die Dauer aller Entries in dem Semester
}
sum /= 3
if (sum >= 20 && allModules[i].activated === 0) //Überprüfung ob alle 20 Schulstunden eines Moduls gesetzt worden sind und der Vorlesungsplan des Moduls abgegeben worden ist
{
count++;
}
}
}
if (count === 0) {
temp.push(0)
} else if (count >= 1 && count !== modulesCountInSemester[s]) {
temp.push(50)
} else {
temp.push(100)
}
setProgresses(temp) //setze die Fortschrittsleiste entsprechend der Einträge im Semester
}
})
})
}
})
}
function onClickSemester(e, m) {
if (m.target === m.currentTarget) {
localStorage.setItem("currentsid", e.id)
router.push("/planning") //leite weiter auf die Planungsseite
localStorage.setItem("semestername", e.name + " Sem. " + (e.number + 1))
}
}
function onClickNewSemester() {
localStorage.setItem("currentsid", 0);
router.push("/createSemester"); //leite weiter auf die Seite für das Inputform zur Erstellung eines neuen Semesters
}
function togglePopup() {
if (modalDisplay === "block") {
setModalDisplay("none");
} else {
setModalDisplay("block");
}
}
function funcButtonAbort() {
togglePopup();
}
async function funcButtonDelete() {
let id = localStorage.getItem("currentsid");
let url = baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid") + "&id=" + id; //Anfrage an das Backend auf spezifisches Semesters auf das geklickt worden ist
await fetch(url, {
method: "DELETE" //lösche das spezifisch angeklickte Semester
});
togglePopup();
getSemesters(true);
}
async function funcButtonEdit(e, m) {
localStorage.setItem("currentsid", e.id);
let semester = e;
//setze die Einträge des Semesters auf die aktuell gespeicherten Einträge
let startYear = semester.startyear;
let endYear = semester.endyear;
let startDay = semester.startday;
let endDay = semester.endday;
//+1 because input field shows date in another way then the date object does
let startDate = new Date(startYear, 0, startDay + 1);
let endDate = new Date(endYear, 0, endDay + 1);
//speichere die abgeänderten Daten des Semesters
await router.push({
pathname: "/createSemester",
query: {
courseName: semester.name,
startDate: startDate.toISOString().slice(0, 10),
endDate: endDate.toISOString().slice(0, 10)
},
});
}
useEffect(() => {
getSemesters(true);
setTimeout(() => {
getSemesters(false)
}, 2000)
}, [])
const [entries, setEntries] = useState([])
const [modalDisplay, setModalDisplay] = useState("none");
const [modalHint, setModalHint] = useState("");
const router = useRouter()
return (
<div className={"semester-overview"}>
<Logout/>
<HelpButton/>
<Background/>
{
entries.map((e, index) => (
<div className={"semester-tile box-shadow"} onClick={(f) => onClickSemester(e, f)}>
<SemesterTile text={e.name + " Sem. " + (e.number + 1)} onClick={(f) => onClickSemester(e, f) /*Darstellung der Semester mit ihren Namen und der Semesternummer in welcher der Kurs sich befindet*/}
onButtonDeleteClick={() => {
localStorage.setItem("currentsid", e.id)
setModalHint(e.name + " Löschen?");
togglePopup();
}} onButtonEditClick={(m) => {
localStorage.setItem("currentsid", e.id)
funcButtonEdit(e, m) /*Aufruf der Editierfunktion für das Angeklickte Semester*/;
}}/>
<StatusBar progress={progresses[index] /*Fortschrittsleiste wird gesetzt*/}/>
<div style={
{
display: "flex",
justifyContent: "center",
alignItems: "center"
}
}>
<Button icon={deleteItem} width={30} height={30} color={"#ffffff"}
onClick={(m) => {
localStorage.setItem("currentsid", e.id)
setModalHint(e.name + " Löschen?");
togglePopup()
}}/>
<Button icon={editItem} width={30} height={30} color={"#ffffff"}
onClick={(m) => {
localStorage.setItem("currentsid", e.id)
funcButtonEdit(e, m)
}}/>
</div>
</div>))
}
<Button color={"#dcdcdc"} text={"+"} width={240} height={160} fontColor={"black"} fontSize={50}
onClick={() => onClickNewSemester() /*Zuweisung der Funktion für den Button zu Erstellung eines neuen Semesters*/}/>
<PopUp hint={modalHint} text1={"Abbrechen"} text2={"Löschen"} displayState={modalDisplay}
function1={funcButtonAbort} function2={funcButtonDelete}/>
</div>
)
}
@@ -0,0 +1,127 @@
import React, {useEffect, useState} from "react";
import SemesterTile from "@/components/SemesterTile";
import {useRouter} from "next/router";
import Background from "@/components/Background";
import Logout from "@/components/Logout";
import {baseURL} from "@/components/Constants"
import HelpButton from "@/components/HelpButton";
import StatusBar from "@/components/StatusBar";
export default function SemesteroverviewLecturer(p) {
const [timeStamps, setTimeStamps] = useState([])
function getModules() {
let urlTest = baseURL + "/module/id?sessionid=" + localStorage.getItem("sessionid");
//Datenanfrage an das Backend für alle Module welche dem User zugewiesen worden sind
fetch(urlTest).then(response => response.json()).then(m => {
setEntries(m);
let args = "";
for (let i = 0; i < m.length; i++) //durchlaufe die Anzahl der Module
{
args += m[i].semesterid; //füge dem String "args" die Einträge hinzu
if (i < m.length - 1) {
args += "a"; //trenne die Einträge durch ein "a" voneinander ab
}
}
let temp = []
let semesterURL = baseURL + "/semester/id/all?ids=" + args + "&sessionid=" + localStorage.getItem("sessionid");
//Datenanfrage an das Backend für alle Semester welche dem User für die Planung zugewiesen sind
fetch(semesterURL).then(r => r.json()).then(sem => {
sem.map(e => {
temp.push(e.name + " Sem. " + (e.number + 1)) //lade das Semester in welchem der Kurs sich befindet in das Array "temp"
})
}).then(() => setSemesterNames(temp)).then(() => {
let entriesURL = baseURL + "/entries/all?sessionid=" + localStorage.getItem("sessionid")
//Datenanfrage an das Backend aller Entries eines Moduls eines Semesters (automatisch nur die Entries die durch den User erstellt worden sind)
fetch(entriesURL).then(r => r.json()).then(en => {
let tempTimeStamps = []
for(let j = 0; j < m.length; j++) //durchlaufe die Anzahl an Modulen die von dem Backend zurückgegeben worden sind
{
let sum = 0
let currentModule = m[j]
for (let i = 0; i < en.length; i++) //durchlaufe die Anzahl der Entries die von dem Backend zurückgegeben worden sind
{
if(currentModule.id === en[i].moduleid)
{
sum += en[i].timeend - en[i].timestart //summiere die Dauer all dieser Entries
}
}
sum /= 3
tempTimeStamps.push(sum) //lade die Summe aller Entries eines Moduls in das Array "tempTimeStamps"
}
setTimeStamps(tempTimeStamps)
})
})
})
}
function onClickSemester(e, m, name) {
if (e.activated == 1) {
if (m.target === m.currentTarget) {
localStorage.setItem("currentsid", e.semesterid)
localStorage.setItem("currentmodulename", e.name)
localStorage.setItem("moduleid", e.id)
localStorage.setItem("semestername", name)
router.push("/planning")
}
}
}
useEffect(() => {
setTimeout(() => {
getModules();
}, 1000)
}, [])
const [entries, setEntries] = useState([]);
const [semesterNames, setSemesterNames] = useState([]);
const router = useRouter();
function getProgressForTime(time, activated)//überprüfe welchen Status die Fortschrittsanzeige haben muss und gib diesen zurück
{
if(time === 0)
{
return 0
}
else if( 20 >= time > 0 && activated === 1)
{
return 50
}
else if(time >= 20 && activated === 0)
{
return 100
}
}
return (
<div className={"semester-overview"}>
<Logout/>
<Background/>
<HelpButton/>
{entries.map((e, index) => (
<div className={"semester-tile box-shadow"} style={{
backgroundColor: e.activated == 1 ? "#ffffff" : "#aaaaaa"
}} onClick={(f) => onClickSemester(e, f, semesterNames[index])}>
<SemesterTile
editable={false} text={semesterNames[index]} text2={e.name}
onClick={(f) => onClickSemester(e, f, semesterNames[index])}
/>
<StatusBar progress={getProgressForTime(timeStamps[index], e.activated)/*beladenes Array "timeStamps" an der Stelle "index" => relevante Summe der Einträge eines Moduls in einem Semester/Kurs*/} module={e}/>
</div>
))}
</div>
);
}
+63
View File
@@ -0,0 +1,63 @@
.A
{
border: 0px solid;
border-radius: 20px;
margin: 10px;
background-color: white;
padding: 15px;
height: 270px;
}
.A P
{
text-align: center;
}
.Days
{
display: inline-grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(5, 1fr);
height: 200px;
width: 250px;
}
.Down
{
border-radius: 20px;
display: inline-grid;
grid-column: auto;
height: 200%;
width: 20%;
}
@media only screen and (min-width: 1650px)
{
.Allround
{
position: relative;
max-height : 73vh;
overflow-y: scroll;
overflow-anchor: none;
}
.Allround::-webkit-scrollbar
{
background-color: rgba(0, 0, 0, 0);
width: 12px;
}
.Allround::-webkit-scrollbar-thumb
{
background-color: gray;
border-radius: 15px;
}
}
@media only screen and (max-width: 1650px)
{
.Allround
{
display: none;
}
}
+521
View File
@@ -0,0 +1,521 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 255, 255, 255;
--background-end-rgb: 255, 255, 255;
}
body {
background-color: #f2f2f2;
}
::-webkit-scrollbar
{
background-color: rgba(0, 0, 0, 0);
width: 12px;
}
::-webkit-scrollbar-thumb
{
background-color: gray;
border-radius: 15px;
}
.splash {
position: absolute;
border-radius: 70px;
background-color: #c77c0c;
z-index: -5;
}
/**
Page Layouts
*/
.normal-centered {
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.semester-overview {
height: 100vh;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
align-content: center;
gap: 10px;
}
body {
height: 100vh;
}
.box-shadow
{
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.box-shadow-heavy
{
box-shadow: 0 0 10px rgba(0, 0, 0,1);
}
/*
Input Form
*/
.input-form
{
width: 600px;
background-color: white;
padding: 30px;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: flex-start;
gap: 20px;
}
table
{
width: 550px;
}
.table-wrapper
{
max-height: 40%;
overflow-y: scroll;
}
td
{
text-align: center;
}
.input-form p, .input-form th
{
font-size: 18px;
font-weight: bold;
color: #5e5e5e;
}
/*
Button
*/
.round-border {
border-radius: 10px;
border-width: 0;
}
.font-small {
font-size: 12px;
}
.font-middle {
font-size: 16px;
}
.font-big {
font-size: 22px;
}
.button {
background-color: #363636;
padding: 5px;
color: white;
}
.button:hover
{
filter: brightness(0.65);
}
.button:hover {
background-color: #585858;
}
/*
Step Progress Bar
*/
.step-container {
display: flex;
flex-direction: column;
align-items: center;
max-width: 400px;
pointer-events: none;
}
.steps {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 20px;
width: 100%;
position: relative;
pointer-events: none;
}
.step {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
pointer-events: none;
z-index: 101;
}
.steps .not-started {
/*background-image: linear-gradient(#b42121, #b44821);*/
background-color: grey;
}
.steps .active {
/*border-width: 2px;*/
/*border-color: #1e2428;*/
background-color: #77932b;
}
.progress-bar {
position: absolute;
height: 8px;
background-color: #77932b;
z-index: 100;
}
/*
weekSelector
*/
.dateElement {
display: flex;
max-width: 900px;
width: 900px;
margin-left: 20px;
margin-right: 20px;
align-items: center;
justify-content: center;
font-weight: bold;
color: black;
font-size: 20px;
}
.weekSelector {
height: 13vh;
display: flex;
padding: 5px 5px;
background-color: rgba(0, 0, 0, 0);
border-radius: 10px;
}
/*
Popup
*/
.modal-container {
z-index: 1;
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
}
.modal {
height: 180px;
width: 300px;
border-radius: 10px;
background-color: rgb(255, 255, 255);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 20px;
animation-name: modalgrow;
animation-duration: 0.2s;
animation-play-state: running;
}
@keyframes modalgrow {
from
{
height: 90px;
width: 150px;
}
to
{
height: 180px;
width: 300px;
}
}
.modal p {
text-align: center;
pointer-events: none;
font-weight: bold;
font-size: 20px;
}
.modal div {
display: flex;
flex-direction: row;
width: 100%;
justify-content: flex-end;
gap: 5px;
}
/*
Calender View
*/
@media (max-width: 1300px) {
.error-bar
{
display: none;
}
}
@media (min-width: 1300px) {
.error-bar
{
width: 250px;
border-radius: 15px;
height: 73vh;
max-height: 73vh;
overflow-y: scroll;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
gap: 10px;
}
}
.calender-direction-wrapper
{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.calender-container {
position: relative;
max-height: 60vh;
overflow-y: scroll;
overflow-anchor: none;
display: grid;
}
.content {
grid-area: 1 / 1;
}
.overlay {
padding: 2px 0 0 0;
grid-area: 1 / 1;
pointer-events: none;
}
.no-pointer-events {
pointer-events: none;
}
.wochen-tag-container {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 60px;
width: 1000px;
gap: 5px;
padding: 0 0 5px 0;
}
.calender-view {
width: 1000px;
height: 2400px;
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: stretch;
gap: 5px;
user-select: none;
padding: 0;
}
.calender-view .spalte {
border-radius: 10px;
width: 400px;
/*background-color: #ffffff;*/
display: grid;
padding: 0 3px;
grid-template-columns: 100%;
background-color: white;
}
.wochen-tag-container .wochen-tag {
text-align: center;
background-color: #346991;
width: 400px;
color: white;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
grid-row-start: 1;
grid-row-end: 4;
}
.entry {
border-radius: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 0 2px;
align-items: center;
/*cursor: move;*/
z-index: 10;
overflow: hidden;
margin-top: 1px;
margin-bottom: 1px;
}
.entry .resize-grab {
height: 6px;
cursor: ns-resize;
width: 100%;
}
.entry p {
color: white;
font-size: 16px;
cursor: default;
pointer-events: none;
text-align: center;
}
/*
Login
*/
.login-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.5);
width: 375px;
height: 350px;
}
.input-bordered {
border: none;
border-radius: 5px;
}
.input {
padding: 5px;
border: none;
background-color: white;
border-radius: 5px;
font-size: 16px;
}
.input:focus
{
outline: none;
}
.placement {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: left;
}
.font-kinda-big {
font-size: 18px;
color: #777777;
font-weight: 500;
}
.font-big-fat {
font-size: 22px;
font-weight: bold;
}
.input-sm {
height: 2rem /* 32px */;
padding-left: 0.75rem /* 12px */;
padding-right: 0.75rem /* 12px */;
font-size: 0.875rem /* 14px */;
line-height: 2rem /* 32px */;
}
/**
SemesterTile
*/
.semester-tile {
width: 240px;
height: 160px;
color: black;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 20px;
gap: 10px;
background-color: white;
}
.semester-tile:hover {
background-color: #e1e1e1;
}
.semester-tile-p {
pointer-events: none;
font-weight: bold;
font-size: 23px;
}
.Error
{
}
+31
View File
@@ -0,0 +1,31 @@
.help-line
{
padding: 30px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 50px;
}
.text-form
{
display: flex;
flex-direction: column;
justify-content: flex-start;
height: 100%;
}
.text-form h1
{
font-size: 30px;
}
.text-form p
{
font-size: 20px;
}
.text-form h2
{
font-size: 26px;
}
+17
View File
@@ -0,0 +1,17 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
}
+8
View File
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="backend" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="backend" options="-parameters" />
</option>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="h2-2.1.214">
<CLASSES>
<root url="jar://$PROJECT_DIR$/H2JDBCDriver/h2-2.1.214.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="20" project-jdk-type="JavaSDK" />
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
Binary file not shown.
+18
View File
@@ -0,0 +1,18 @@
# 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
#
# https://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.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
#!/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
#
# https://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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
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"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
+188
View File
@@ -0,0 +1,188 @@
@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 https://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 Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%
+68
View File
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>backend</name>
<description>backend</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>install-file</goal>
</goals>
<configuration>
<groupId>com.example</groupId>
<artifactId>example</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<file>${basedir}/H2JDBCDriver/h2-2.1.214.jar</file>
<generatePom>true</generatePom>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,15 @@
package com.example.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);
}
}
@@ -0,0 +1,609 @@
package com.example.backend.anwprj.Database;
import com.example.backend.discard.Encryption.RSA;
import com.example.backend.anwprj.Entries.Entry;
import com.example.backend.anwprj.Semesters.Semester;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Module.Module;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//kleiner hinweis zur Datenbank:
//die datenkbank H2 benötigt die beiden dateien database.mv.db und database.trace.db
//um die datenbank verwenden zu können muss der jdbc driver in das projekt eingebunden sein.
//dieser driver liegt im ordner als h2jdbcdriver als .jar datei
//der nutzername für die datenbank ist: adm
//das passwort für die datenbank ist: 73bgjfdsfJ!934
//die datenbank als einzelnes kann entweder über die h2console (windows) oder jetbrains datagrip (alle systeme) editiert werden.
//oder über jedes weitere tool welches h2 datenbanken unterstützt.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public class DataBaseHandler {
//singleton instance of database handler
private static DataBaseHandler instance = null;
public static DataBaseHandler getInstance() {
if (instance == null) {
instance = new DataBaseHandler();
}
return instance;
}
//connection to the database
private Connection connection;
//sql statement
private Statement st;
private boolean encrypted = false;
public DataBaseHandler() {
try {
//connect to the local database
connection = DriverManager.getConnection("jdbc:h2:./database", "adm", "73bgjfdsfJ!934");
st = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* ENTRIES
*/
public void addEntry(Entry entry)
{
try
{
st.executeUpdate("insert into entries (daynumber, yearnumber, semesterid, usercreatedbyid, timestart, timeend, moduleid, info) values (" +
entry.getDaynumber() + ", " + entry.getYearnumber() + ", " + entry.getSemesterid() + ", " +
entry.getUsercreatedbyid() + ", " + entry.getTimestart() + ", " + entry.getTimeend() + ", " + entry.getModuleid() + " ,'" + entry.getInfo() + "')"
); //Datenbank Eintrag eines neu erstellten Entry mit allen nötigen Informationen
}
catch(Exception e)
{
e.printStackTrace();
}
}
public Entry[][] getEntries(int semesterid, int daynumber, int yearnumber) {
try {
ResultSet rs = st.executeQuery("select * from entries where " +
"semesterid=" + semesterid +
" and yearnumber=" + yearnumber +
" and daynumber between " + daynumber + " and " + daynumber + 6);
List<Entry> entryList = new ArrayList<>();
Entry current = null;
while ((current = resultSetToEntry(rs)) != null) {
entryList.add(current);
} //Datenbankanfrage für alle Entries bei denen die Semesterid, das Jahr und der Tag mit den übergebenen Paramtern übereinstimmt
Entry[][] entries = new Entry[6][20];
for (int i = 0; i < 6; i++) //durchlaufe die Anzahl der Tage einer Vorlesungswoche (Montag,...,Samstag)
{
int f = 0;
for (int j = 0; j < entryList.size(); j++)
{
if (entryList.get(j).getDaynumber() == i + daynumber) {
entries[i][f] = entryList.get(j); //belade das Array "entries" mit dem entries einer woche
f++;
}
}
}
return entries; //gib das Array "entries" zurück
} catch (Exception e) {
return null;
}
}
public Entry[][] getAllEntrys(int semesterid, int daynumber, int yearnumber, int userid) //Datenbankanfrage für alle Entries eines Users in einem Semester
{
try {
ResultSet rs = st.executeQuery("select * from entries where " +
"semesterid<>" + semesterid +
" and yearnumber=" + yearnumber +
" and usercreatedbyid=" + userid +
" and daynumber between " + daynumber + " and " + daynumber + 6);
List<Entry> entryList = new ArrayList<>();
Entry current = null;
while ((current = resultSetToEntry(rs)) != null) {
entryList.add(current);
}
Entry[][] entries = new Entry[6][20];
for (int i = 0; i < 6; i++) {
int f = 0;
for (int j = 0; j < entryList.size(); j++) {
if (entryList.get(j).getDaynumber() == i + daynumber) {
entries[i][f] = entryList.get(j);
f++;
}
}
}
return entries;
} catch (Exception e) {
return null;
}
}
public Entry[] getAllEntries() //Datenbankanfrage für alle Entries
{
try {
ResultSet rs = st.executeQuery("select * from entries");
List<Entry> entriestate = new ArrayList<>();
Entry current = null;
while((current = resultSetToEntry(rs)) != null)
{
entriestate.add(current);
}
return entriestate.toArray(new Entry[0]);
}catch (Exception e){
System.out.println(e.getMessage());
return null;
}
}
public Entry[] getAllEntriesModule(int moduleid) //Datenbankanfrage für alle Entries eines spezifischen Moduls
{
try {
ResultSet rs = st.executeQuery("select * from entries where moduleid=" + moduleid);
List<Entry> result = new ArrayList<>();
Entry current = null;
while((current = resultSetToEntry(rs)) != null)
{
result.add(current);
}
return result.toArray(new Entry[0]);
}
catch(Exception e)
{
return new Entry[]{};
}
}
public void deleteEntry(int id) //Löschung eines spezifischen entries
{
try {
st.executeUpdate("delete from entries where id=" + id);
} catch (Exception e) {
}
}
public void updateEntry(Entry entry) //Aktualisiere Einträge eines Entry falls es verändert wurde
{
try {
st.executeUpdate("update entries set timeend=" + entry.getTimeend() + ", timestart=" + entry.getTimestart() + " where id=" + entry.getId());
} catch (Exception e) {
}
}
public Entry resultSetToEntry(ResultSet rs)
{
try
{
rs.next();
return new Entry(
rs.getInt("id"),
rs.getInt("daynumber"),
rs.getInt("yearnumber"),
rs.getInt("usercreatedbyid"),
rs.getInt("timestart"),
rs.getInt("timeend"),
rs.getInt("semesterid"),
rs.getInt("moduleid"),
rs.getString("info")
);
}
catch(Exception e)
{
return null;
}
}
/**
* SEMESTER
*/
//get a semester object by its name
public Semester getSemester(String name) {
try {
ResultSet rs = st.executeQuery("select * from SEMESTER where name = '" + name + "'");
return resultSetToSemester(rs);
} catch (Exception e) {
return null;
}
}
public Semester getSemester(int id)
{
try {
ResultSet rs = st.executeQuery("select * from semester where id=" + id);
return resultSetToSemester(rs);
} catch (Exception e) {
return null;
}
}
//write a new semester to the database returns if process was successful
public Semester addSemester(Semester s) {
try {
st.executeUpdate("insert into SEMESTER (startday, endday, name, startyear, endyear, number) values (" + s.getStartday() + ", " + s.getEndday() + ", '" + s.getName() + "', " + s.getStartyear() + ", " + s.getEndyear() + ", " + s.getNumber() + ")");
return getSemester(s.getName());
} catch (Exception e) {
return null;
}
}
public Semester[] getAllSemesters() {
try {
ResultSet rs = st.executeQuery("select * from semester");
List<Semester> semestersList = new ArrayList<>();
Semester s = null;
while ((s = resultSetToSemester(rs)) != null) {
semestersList.add(s);
}
return semestersList.toArray(new Semester[0]);
} catch (Exception e) {
return null;
}
}
public Semester updateSemester(Semester semester) //Aktualisiere die Einträge eines Semesters bei Veränderungen durch editier Funktion
{
try {
st.executeUpdate("update semester set startday=" + semester.getStartday() + ", " +
"endday=" + semester.getEndday() + ", " +
"name='" + semester.getName() + "', " +
"startyear=" + semester.getStartyear() + ", " +
"number=" + semester.getNumber() + ", " +
"endyear=" + semester.getEndyear() + " where id=" + semester.getId());
return getSemester(semester.getId());
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
//ist dafür da, um ein semester anhand seiner id aus der datenbank zu löschen
public void deleteSemester(int id) {
try {
st.executeUpdate("DELETE FROM modules WHERE semesterid=" + id);
st.executeUpdate("delete from semester where id=" + id);
st.executeUpdate("delete from entries where semesterid=" + id);
} catch (Exception e) {
}
}
//kann ein resultset der datenbank in ein internes semester objekt umwandeln.
public Semester resultSetToSemester(ResultSet rs) {
try {
rs.next();
return new Semester(
rs.getInt("id"),
rs.getInt("startday"),
rs.getInt("endday"),
rs.getString("name"),
rs.getInt("startyear"),
rs.getInt("endyear"),
rs.getInt("number")
);
} catch (Exception e) {
return null;
}
}
/**
* MODULE
*/
//get a module object by its id
public Module getModule(int id) {
try {
ResultSet rs = st.executeQuery("SELECT * FROM modules WHERE id=" + id);
return resultSetToModule(rs);
} catch (Exception ex) {
return null;
}
}
//ein modul anhand der zuweisung von dozent und semester bekommen.
public Module getModule(int userid, int semesterid) {
try {
ResultSet rs = st.executeQuery("select * from modules where userid=" + userid + " and semesterid=" + semesterid);
return resultSetToModule(rs);
} catch (Exception e) {
return null;
}
}
//bekomme alle modulzuweisungen, die zu einem dozenten gehören.
public Module[] getModules(int userid) {
try {
ResultSet rs = st.executeQuery("SELECT * FROM modules WHERE userid = " + userid);
List<Module> moduleList = new ArrayList<>();
Module m = null;
while ((m = resultSetToModule(rs)) != null) {
moduleList.add(m);
}
return moduleList.toArray(new Module[0]);
} catch (Exception ex) {
return null;
}
}
//füge eine neue modulzuweisung zwischen dozenten und fächern hinzu
public Module addModule(Module m) {
try {
st.executeUpdate("insert into modules (userid, semesterid, name, activated) " +
"Values (" + m.getUserid() + ", " + m.getsemesterid() + ", '" + m.getName() + "', " + m.getActivated() + ")");
return getModule(m.getUserid(), m.getsemesterid());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//gibt alle zuweisungen zurück.
public Module[] getAllModules() {
try {
ResultSet rs = st.executeQuery("SELECT * FROM modules");
List<Module> moduleList = new ArrayList<>();
Module m = null;
while ((m = resultSetToModule(rs)) != null) {
moduleList.add(m);
}
return moduleList.toArray(new Module[0]);
} catch (Exception e) {
return null;
}
}
//updatet eine zuweisung anhand ihrer id
public Module updateModule(Module m) {
try {
st.executeUpdate("update modules set activated=" + m.getActivated() + ", userid=" + m.getUserid() + " where id=" + m.getid());
return getModule(m.getid());
} catch (SQLException ex) {
ex.printStackTrace();
return null;
}
}
//setzt die aktivierung einer modulzuweisung zurück.
public void submitModule(int id)
{
try
{
st.executeUpdate("update modules set activated=0 where id=" + id);
}
catch(Exception e)
{
}
}
//kann alle modulzuweisungen innerhalb eines semesters löschen.
//hierbei werden auch alle termine mit gelöscht.
public boolean deleteModuleBySemesterID(int id) {
try {
st.executeUpdate("delete from modules where semesterid=" + id);
st.executeUpdate("delete from entries where semesterid=" + id);
return true;
} catch (Exception ex) {
return false;
}
}
//kann eine einzelne modulzuweisung anhand ihrer id löschen.
//hierbei werden auch alle zu dieser zuweisung gehörigen termine gelöscht
public boolean deleteModule(int id) {
try {
st.executeUpdate("delete from modules where id=" + id);
st.executeUpdate("delete from entries where moduleid=" + id);
return true;
} catch (Exception ex) {
return false;
}
}
//kann ein result set der datenbank in ein internes modul objekt umwandeln.
public Module resultSetToModule(ResultSet rs) {
try {
rs.next();
return new Module(
rs.getInt("id"),
rs.getInt("userid"),
rs.getInt("semesterid"),
rs.getString("name"),
rs.getInt("activated"));
} catch (Exception ex) {
return null;
}
}
/**
* USER
*/
//Alle User, die nicht admin sind
public User[] getAllUsers() {
try {
ResultSet rs = st.executeQuery("select * from users where permission=0");
User u = null;
List<User> output = new ArrayList<>();
while ((u = resultSetToUser(rs)) != null) {
u.clearOutPassword();
output.add(u);
}
return output.toArray(new User[0]);
} catch (Exception e) {
return null;
}
}
//einen User anhand seiner email und passwort zurückgeben.
public User getUser(String mail, String password) {
try {
ResultSet rs = st.executeQuery("select * from users where mail = '" + mail + "' and password = '" + password + "'");
return resultSetToUser(rs);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//einen nutzer andhand seiner id zurückgeben.
//diese funktion sollte nur für admins verfügbar sein.
public User getUser(int id) {
try {
ResultSet rs = st.executeQuery("select * from users where id=" + id);
return resultSetToUser(rs);
} catch (Exception e) {
return null;
}
}
//ein nutzer anhand seiner mail zurückgeben. diese funktion sollte nur für admins erreichbar sein.
public User getUser(String mail) {
try {
ResultSet rs = st.executeQuery("select * from users where mail='" + mail + "'");
User u = resultSetToUser(rs);
if (u != null) u.clearOutPassword();
return u;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
//kann ein result set der datenbank in ein internes nutzer objekt umwandeln.
public User resultSetToUser(ResultSet rs) {
try {
rs.next();
return new User(
rs.getInt("id"),
rs.getString("firstname"),
rs.getString("lastname"),
rs.getString("mail"),
rs.getString("password"),
rs.getInt("permission")
);
} catch (Exception e) {
return null;
}
}
//add a new user object to the database returns if process was successful
public User addUser(User user) {
//check if mail and passwort (key user information) is given
if (user.getMail() == null || user.getPassword() == null) {
return null;
}
try {
String password = user.getPassword();
if (encrypted) {
RSA rsa = RSA.getInstance();
byte[] psw = rsa.loadByteArray(password);
try {
password = rsa.decrypt(psw);
} catch (Exception e) {
e.printStackTrace();
}
}
st.executeUpdate("insert into users (firstname, lastname, mail, password, permission) values (" + "'" + user.getFirstName() + "', '" + user.getLastName() + "', '" + user.getMail() + "', '" + password + "', " + 0 + ")");
return getUser(user.getMail(), user.getPassword());
} catch (Exception e) {
return null;
}
}
//kann einen nutzer updaten, aber auch dessen rechte verändern, hierbei werden die rechte nur angepasst,
//wenn der boolean elevationRequestByAdmin true ist
public User updateUser(User user, int id, boolean elevationRequestByAdmin) {
try {
String password = user.getPassword();
if (encrypted) {
RSA rsa = RSA.getInstance();
byte[] psw = rsa.loadByteArray(password);
try {
password = rsa.decrypt(psw);
} catch (Exception e) {
e.printStackTrace();
}
}
if (!elevationRequestByAdmin) {
st.executeUpdate("update users set " +
"firstname='" + user.getFirstName() + "', " +
"lastname='" + user.getLastName() + "', " +
"mail='" + user.getMail() + "', " +
"password='" + password + "' " +
"where id=" + id);
} else {
st.executeUpdate("update users set " +
"firstname='" + user.getFirstName() + "', " +
"lastname='" + user.getLastName() + "', " +
"mail='" + user.getMail() + "', " +
"password='" + password + "'," +
"permission=" + user.getPermissions() +
"where id=" + id);
}
return getUser(id);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
//hier kann ein nutzer anhand seiner email addresse gelöscht werden.
//diese funktion sollte nur für den eigenen nutzer oder für admins verfügbar sein.
public boolean deleteUser(String mail) {
try {
ResultSet rs = st.executeQuery("SELECT id FROM user WHERE mail='" + mail + "'");
rs.next();
int id = rs.getInt("id");
st.executeUpdate("DELETE FROM modules WHERE lecturerId = " + id);
st.executeUpdate("delete from users where mail='" + mail + "'");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
@@ -0,0 +1,70 @@
package com.example.backend.anwprj.Entries;
//interne klasse für die darstellung von terminen
public class Entry
{
private int id;
private int daynumber;
private int yearnumber;
private int usercreatedbyid;
private int timestart;
private int timeend;
private int semesterid;
private int moduleid;
private String info;
public Entry(int id, int daynumber, int yearnumber, int usercreatedbyid, int timestart, int timeend, int semesterid, int moduleid, String info)
{
this.id = id;
this.daynumber = daynumber;
this.yearnumber = yearnumber;
this.usercreatedbyid = usercreatedbyid;
this.timestart = timestart;
this.timeend = timeend;
this.semesterid = semesterid;
this.moduleid = moduleid;
this.info = info;
}
public int getId()
{
return id;
}
public int getDaynumber()
{
return daynumber;
}
public int getYearnumber()
{
return yearnumber;
}
public int getUsercreatedbyid()
{
return usercreatedbyid;
}
public int getTimestart()
{
return timestart;
}
public int getTimeend()
{
return timeend;
}
public int getSemesterid()
{
return semesterid;
}
public int getModuleid() {return moduleid;}
public String getInfo()
{
return info;
}
}
@@ -0,0 +1,31 @@
package com.example.backend.anwprj.Module;
//klasse für die interne darstellungen für die zuweisungen zwischen dozenten und fächern.
public class Module {
private int id;
private int userid;
private int semesterid;
private String name;
private int activated;
public Module(int id, int userid, int semesterid, String name, int activated)
{
this.id = id;
this.userid = userid;
this.semesterid = semesterid;
this.name = name;
this.activated = activated;
}
public int getid() { return id; }
public int getUserid() { return userid; }
public int getsemesterid() { return semesterid; }
public String getName() { return name; }
public int getActivated() { return activated; }
}
@@ -0,0 +1,49 @@
package com.example.backend.anwprj.Semesters;
//klasse für die interne darstellung von semestern.
public class Semester
{
private int id;
private int startday;
private int endday;
private String name;
private int startyear;
private int endyear;
private int number;
public Semester(int id, int startday, int endday, String name, int startyear, int endyear, int number) {
this.id = id;
this.startday = startday;
this.endday = endday;
this.name = name;
this.startyear = startyear;
this.endyear = endyear;
this.number = number;
}
public int getId() {
return id;
}
public int getStartday() {
return startday;
}
public int getEndday() {
return endday;
}
public String getName() {
return name;
}
public int getStartyear() {
return startyear;
}
public int getEndyear() {
return endyear;
}
public int getNumber(){return number; }
}
@@ -0,0 +1,57 @@
package com.example.backend.anwprj.Users;
//klasse für die darstellung von benutzerobjekten.
public class User
{
private int id;
private String firstName;
private String lastName;
private String mail;
private String password;
private int permissions;
public User(int id, String firstName, String lastName, String mail, String password, int permissions)
{
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.mail = mail;
this.password = password;
this.permissions = permissions;
}
public int getId()
{
return id;
}
public String getFirstName()
{
return firstName;
}
public String getLastName()
{
return lastName;
}
public String getMail()
{
return mail;
}
public String getPassword()
{
return password;
}
public int getPermissions()
{
return permissions;
}
public void clearOutPassword()
{
password = "****";
}
}
@@ -0,0 +1,20 @@
package com.example.backend.anwprj.Users;
// zuweisung der zahlen 0 für normaler user / dozenten und 1 für admin.
public enum UserPermissions
{
self(0),
admin(1);
private final int value;
public int getValue()
{
return value;
}
private UserPermissions(int value)
{
this.value = value;
}
}
@@ -0,0 +1,71 @@
package com.example.backend.anwprj.Users;
import com.example.backend.anwprj.Database.DataBaseHandler;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
//diese klasse kümmert sich um die zuweisungen von nutzern und deren sessionids.
//wird für alle möglichen anfragen der nutzer an das backend verwendet um eine sessionid
//in ein benutzerobjekt aufzulösen.
public class UserSessionIDHandler
{
//stores mapping of session ids to users
public static HashMap<String, User> mapping = new HashMap<>();
//returns a user object by its session id (ONLY FOR SERVER INTERNAL USE!)
public static User getUserBySessionID(String sessionID)
{
return mapping.get(sessionID);
}
public static boolean removeUser(String sessionID)
{
try
{
mapping.remove(sessionID);
return true;
}
catch(Exception e)
{
return false;
}
}
public static String addUser(String mail, String password)
{
//try to get user from database
User user = DataBaseHandler.getInstance().getUser(mail, password);
//if user exists
if(user != null)
{
//generate random session id based on ascii table
byte[] id = new byte[100];
for(int i = 0; i < id.length; i++)
{
id[i] = (byte) (Math.random() * 26 + 64);
}
String generatedString = new String(id, StandardCharsets.US_ASCII);
mapping.put(generatedString, user);
//makes user session expire after ca. 2h
new java.util.Timer().schedule(new java.util.TimerTask(){
@Override
public void run()
{
mapping.remove(generatedString);
return;
}
}, 7500000);
return generatedString;
}
return "failed";
}
}
@@ -0,0 +1,165 @@
package com.example.backend.anwprj.controller;
import com.example.backend.anwprj.Database.DataBaseHandler;
import com.example.backend.anwprj.Entries.Entry;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Users.UserPermissions;
import com.example.backend.anwprj.Users.UserSessionIDHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class EntriesController
{
private DataBaseHandler db;
{
db = DataBaseHandler.getInstance();
}
/**
GET
a set of entries for a week, based on the semester, the startdaynumber of the week and the year
Every user is allowed
*/
@CrossOrigin
@GetMapping("/entries")
public ResponseEntity<Entry[][]> getEntries(@RequestParam(name = "semesterid") int semesterid,
@RequestParam(name = "daynumber") int daynumber,
@RequestParam(name = "yearnumber") int yearnumber,
@RequestParam(name = "sessionid") String sessionid)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
if (sessionUser != null)
{
var lonelyEntry = db.getEntries(semesterid, daynumber, yearnumber);
var happyEntry = db.getAllEntrys(semesterid, daynumber, yearnumber, sessionUser.getId());
var combinedEntry = new Entry[6][20];
for (int i = 0; i < 6; i++) {
var idx = 0;
for (int j = 0; j < 20; j++) {
if (lonelyEntry != null && lonelyEntry[i][j] != null){
combinedEntry[i][idx] = lonelyEntry[i][j];
idx++;
}
if (happyEntry != null && happyEntry[i][j] != null){
combinedEntry[i][idx] = happyEntry[i][j];
idx++;
}
}
}
return new ResponseEntity<>(combinedEntry, HttpStatus.OK);
}
return new ResponseEntity<>(null, HttpStatus.FORBIDDEN);
}
@CrossOrigin
@GetMapping("/entries/all")
public ResponseEntity<Entry[]> getAllEntries(@RequestParam(name = "sessionid") String sessionid)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
if (sessionUser != null)
{
var entries = db.getAllEntries();
return new ResponseEntity<>(entries, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
@CrossOrigin
@GetMapping("/entries/all/module")
public ResponseEntity<Entry[]> getAllEntriesModule(@RequestParam(name="sessionid") String sessionid, @RequestParam(name="moduleid") int moduleid)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
if (sessionUser != null)
{
return new ResponseEntity<>(db.getAllEntriesModule(moduleid), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
// @CrossOrigin
// @GetMapping("/entries")
// public ResponseEntity<Integer[]> getEntries(@RequestParam(name = "semesterid") int semesterid,
// @RequestParam(name = "sessionid") String sessionid)
// {
// User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
// if (sessionUser != null)
// {
// var entries = db.getAllEntries(semesterid, sessionUser.getId());
// var count = 0;
// for (int i = 0; i < entries.length; i++) {
// count += entries[i].getTimeend()-entries[i].getTimestart();
// }
// return new ResponseEntity<>(new Integer[]{count}, HttpStatus.OK);
// }
// return new ResponseEntity<>(HttpStatus.FORBIDDEN);
// }
/**
POST
A new entry to the database. Every user except of admins is allowed
*/
@CrossOrigin
@PostMapping("/entries")
public ResponseEntity<Boolean> postEntry(@RequestBody Entry entry, @RequestParam(name = "sessionid") String sessionid)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
if (sessionUser != null && sessionUser.getPermissions() == UserPermissions.self.getValue())
{
db.addEntry(entry);
return new ResponseEntity<>(true, HttpStatus.OK);
}
return new ResponseEntity<>(false, HttpStatus.FORBIDDEN);
}
/**
PUT
Update the endTime of an existing entry in the database. Every user except of admins is allowed
*/
@CrossOrigin
@PutMapping("/entries")
public ResponseEntity<Boolean> updateEntry(@RequestParam(name="sessionid") String sessionid, @RequestBody Entry entry)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
if (sessionUser != null)
{
db.updateEntry(entry);
return new ResponseEntity<>(true, HttpStatus.OK);
}
return new ResponseEntity<>(false, HttpStatus.FORBIDDEN);
}
/**
Delete
an existing entry from the database
*/
@CrossOrigin
@DeleteMapping("/entries")
public ResponseEntity<Boolean> deleteEntry(@RequestParam(name = "id") int id, @RequestParam(name = "sessionid") String sessionid)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionid);
if (sessionUser != null)
{
db.deleteEntry(id);
return new ResponseEntity<>(true, HttpStatus.OK);
}
return new ResponseEntity<>(false, HttpStatus.FORBIDDEN);
}
}
@@ -0,0 +1,195 @@
package com.example.backend.anwprj.controller;
import com.example.backend.anwprj.Database.DataBaseHandler;
import com.example.backend.anwprj.Module.Module;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Users.UserPermissions;
import com.example.backend.anwprj.Users.UserSessionIDHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* Ein Modul hier entspricht nicht z.b. Analysis im Allgemeinen.
* Es beschreibt die Verbindung zwischen einem Dozenten und Analysis in einem Speziellen Semester.
*/
@RestController
public class ModuleController
{
private final DataBaseHandler db;
{
db = DataBaseHandler.getInstance();
}
/**
GET
A Module by its id
*/
@CrossOrigin
@GetMapping("/module/id")
public ResponseEntity<Module[]> getModules(
@RequestParam(name = "sessionid") String sessionID)
{
User user = UserSessionIDHandler.getUserBySessionID(sessionID);
if (user != null)
{
Module[] modules = db.getModules(user.getId());
if (modules != null)
{
return new ResponseEntity<>(modules, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
@CrossOrigin
@GetMapping("/module/bysemesterid")
public ResponseEntity<Module[]> getModulesBySemesterID(@RequestParam(name="sessionid") String sessionID, @RequestParam(name="semesterid") int semesterid)
{
User user = UserSessionIDHandler.getUserBySessionID(sessionID);
if(user != null && user.getPermissions() == UserPermissions.admin.getValue())
{
Module[] tempModuleArray = db.getAllModules();
List<Module> result = new ArrayList<>();
for(int i = 0; i < tempModuleArray.length; i++)
{
if(tempModuleArray[i].getsemesterid() == semesterid)
{
result.add(tempModuleArray[i]);
}
}
return new ResponseEntity<>(result.toArray(new Module[0]), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
/**
GET
all modules from the database. (Not used now)
*/
@CrossOrigin
@GetMapping("/module/all")
public ResponseEntity<Module[]> getModule(@RequestParam(name = "sessionid") String sessionid)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if (u != null)
{
if (u.getPermissions() == UserPermissions.admin.getValue())
{
return new ResponseEntity<>(db.getAllModules(), HttpStatus.OK);
}
}
return null;
}
/**
POST
a new module entry. (When a user is selected in a semester.)
*/
@CrossOrigin
@PostMapping("/module")
public ResponseEntity<Module> addModule(@RequestBody Module module, @RequestParam(name = "sessionid") String sessionID)
{
User user = UserSessionIDHandler.getUserBySessionID(sessionID);
if (user.getPermissions() == UserPermissions.admin.getValue())
{
Module m = db.addModule(module);
if (m != null)
{
return new ResponseEntity<>(m, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
/**
PUT
Update a Module
*/
@CrossOrigin
@PutMapping("/module")
public ResponseEntity<Module> updateModule(@RequestBody Module module, @RequestParam(name = "sessionid") String sessionID)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionID);
if (u != null)
{
Module m = db.updateModule(module);
if (m != null)
{
return new ResponseEntity<>(m, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
@CrossOrigin
@PutMapping("/module/submit")
public ResponseEntity<Module> submitModule(@RequestParam(name="sessionid") String sessionID, @RequestParam(name="id") int id)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionID);
if (u != null)
{
db.submitModule(id);
return new ResponseEntity<>(null, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
/**
DELETE
Delete A Module
*/
@CrossOrigin
@DeleteMapping("/module/bysemesterid")
public void deleteModuleBySemesterID(@RequestParam(name = "sessionid") String sessionid, @RequestParam(name="id") int id)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if (u != null && u.getPermissions() == UserPermissions.admin.getValue())
{
db.deleteModuleBySemesterID(id);
}
}
@CrossOrigin
@DeleteMapping("/module")
public void deleteModule(@RequestParam(name = "sessionid") String sessionid, @RequestParam(name="id") int id)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if (u != null && u.getPermissions() == UserPermissions.admin.getValue())
{
db.deleteModule(id);
}
}
}
@@ -0,0 +1,161 @@
package com.example.backend.anwprj.controller;
import com.example.backend.anwprj.Database.DataBaseHandler;
import com.example.backend.anwprj.Semesters.Semester;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Users.UserPermissions;
import com.example.backend.anwprj.Users.UserSessionIDHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
public class SemesterController
{
//reference to the database handler
private DataBaseHandler db;
{
db = DataBaseHandler.getInstance();
}
//get a semester object by its name
@CrossOrigin
@GetMapping("/semester")
public ResponseEntity<Semester> getSemester(@RequestParam(name="name") String name, @RequestParam(name="sessionid") String sessionID)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionID);
if(u != null)
{
Semester s = db.getSemester(name);
if (s != null)
{
return new ResponseEntity<>(s, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//get a semester object by its id
@CrossOrigin
@GetMapping("/semester/id")
public ResponseEntity<Semester> getSemester(@RequestParam(name="id") int id, @RequestParam(name="sessionid") String sessionID)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionID);
if(u != null)
{
Semester s = db.getSemester(id);
if(s != null)
{
return new ResponseEntity<>(s, HttpStatus.OK);
}
return new ResponseEntity<>(null, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//takes in a list of semester ids seperatet by an a as list seperator
@CrossOrigin
@GetMapping("/semester/id/all")
public ResponseEntity<Semester[]> getSemestersAll(@RequestParam(name="ids") String ids, @RequestParam(name="sessionid") String sessionid)
{
String[] idsSplit = ids.split("a");
List<Semester> resultList = new ArrayList<>();
for(int i = 0; i < idsSplit.length; i++)
{
int currentID = Integer.parseInt(idsSplit[i]);
resultList.add(db.getSemester(currentID));
}
return new ResponseEntity<>(resultList.toArray(new Semester[0]), HttpStatus.OK);
}
//gibt alle semester zurück
@CrossOrigin
@GetMapping("/semester/all")
public ResponseEntity<Semester[]> getSemester(@RequestParam(name="sessionid") String sessionid)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if(u != null)
{
if(u.getPermissions() == UserPermissions.admin.getValue())
{
return new ResponseEntity<>(db.getAllSemesters(), HttpStatus.OK);
}
}
return null;
}
//a new semester add is requested (only allowed for admin users)
@CrossOrigin
@PostMapping("/semester")
public ResponseEntity<Semester> addSemester(@RequestBody Semester semester, @RequestParam(name="sessionid") String sessionID)
{
User user = UserSessionIDHandler.getUserBySessionID(sessionID);
if(user.getPermissions() == UserPermissions.admin.getValue())
{
Semester s = db.addSemester(semester);
if(s != null)
{
return new ResponseEntity<>(s, HttpStatus.OK);
}
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//updatet ein semester
@CrossOrigin
@PutMapping("/semester")
public ResponseEntity<Semester> updateSemester(@RequestBody Semester semester, @RequestParam(name="sessionid") String sessionID)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionID);
if(u != null && u.getPermissions() == UserPermissions.admin.getValue())
{
Semester s = db.updateSemester(semester);
if(s != null)
{
return new ResponseEntity<>(s, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//löscht ein semester anhand seiner id
@CrossOrigin
@DeleteMapping("/semester")
public void deleteSemester(@RequestParam(name="sessionid") String sessionid, @RequestParam(name="id") int id)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if(u != null && u.getPermissions() == UserPermissions.admin.getValue())
{
db.deleteSemester(id);
}
}
}
@@ -0,0 +1,194 @@
package com.example.backend.anwprj.controller;
import com.example.backend.discard.Encryption.RSA;
import com.example.backend.anwprj.Database.DataBaseHandler;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Users.UserPermissions;
import com.example.backend.anwprj.Users.UserSessionIDHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/*
Hier sind einige nutzer funktionen mehr, als für das tool benötigt werden. Diese dienen nur testzwecken
zum verwalten von nutzer z.b. über postman.
*/
@RestController
public class UserController {
//reference to the database handler
private DataBaseHandler db;
{
db = DataBaseHandler.getInstance();
}
//hole alle user, nur erlaubt für admins
@CrossOrigin
@GetMapping("/users/all")
public ResponseEntity<User[]> getAllUsers(@RequestParam(name = "sessionid") String sessionid)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if(u != null && u.getPermissions() == UserPermissions.admin.getValue())
{
User[] output = db.getAllUsers();
return new ResponseEntity<>(output, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
//a user wants to login
@CrossOrigin
@GetMapping("/users")
public ResponseEntity<String> login(@RequestParam(name = "mail") String mail, @RequestParam(name = "password") String password) {
//generate a session id for the user trying to login
boolean isEncrypted = false;
if(isEncrypted)
{
RSA rsa = RSA.getInstance();
byte[] psw = rsa.loadByteArray(password);
try {
password = rsa.decrypt(psw);
} catch (Exception e) {
e.printStackTrace();
}
}
mail = mail.toLowerCase();
String sessionID = UserSessionIDHandler.addUser(mail, password);
return new ResponseEntity<>(sessionID, HttpStatus.OK);
}
//ein nutzer möchte sich ausloggen, damit sollte seinen sessionid entfernt werden.
@CrossOrigin
@GetMapping("/users/logout")
public ResponseEntity<Boolean> logout(@RequestParam(name = "sessionid") String sessionID) {
boolean success = UserSessionIDHandler.removeUser(sessionID);
return new ResponseEntity<>(success, HttpStatus.OK);
}
//admins können hier die daten eiens nutzer anfordern.
@CrossOrigin
@GetMapping("/users/data")
public ResponseEntity<User> getUserData(
@RequestParam(name = "sessionid") String sessionID,
@RequestParam(name = "mail") String mail) {
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionID);
if (sessionUser != null) {
System.out.println(sessionUser.getMail() + " " + mail);
if (sessionUser.getMail().equals(mail) || sessionUser.getPermissions() == UserPermissions.admin.getValue()) {
User searchedUser = db.getUser(mail);
return new ResponseEntity<>(searchedUser, HttpStatus.OK);
}
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
@CrossOrigin
@GetMapping("/users/check")
public ResponseEntity<User> checkLogin(@RequestParam(name="sessionid") String sessionid)
{
User u = UserSessionIDHandler.getUserBySessionID(sessionid);
if(u != null)
{
return new ResponseEntity<>(db.getUser(u.getId()), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
//adds a new user to the database (cannot create an admin user)
@CrossOrigin
@PostMapping("/users")
public ResponseEntity<String> addUser(@RequestBody User user) {
User checkUser = db.getUser(user.getMail());
if (checkUser != null) {
return new ResponseEntity<>("mail", HttpStatus.FORBIDDEN);
}
//if user was successfully added to database
User u = db.addUser(user);
if (u != null) {
//generate a session id
return new ResponseEntity<String>(UserSessionIDHandler.addUser(user.getMail(), user.getPassword()), HttpStatus.OK);
}
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
}
@CrossOrigin
@PutMapping("/users")
public ResponseEntity<Boolean> updateUser(@RequestParam(name = "sessionid") String sessionID, @RequestBody User u, @RequestParam(name = "mail") String mail) {
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionID);
if (sessionUser != null) {
if (sessionUser.getMail().equals(mail) || sessionUser.getPermissions() == UserPermissions.admin.getValue()) {
System.out.println(sessionUser.getId());
User resultingUser = db.updateUser(u, sessionUser.getId(), false);
if (resultingUser != null) {
UserSessionIDHandler.removeUser(sessionID);
return new ResponseEntity<>(true, HttpStatus.OK);
}
return new ResponseEntity<>(false, HttpStatus.NOT_FOUND);
}
}
return new ResponseEntity<>(false, HttpStatus.FORBIDDEN);
}
//rechte eines nutzers erhöhen, kann nur von admins ausgeführt werden.
@CrossOrigin
@PutMapping("/users/elevate")
public ResponseEntity<Boolean> elevateUser(
@RequestParam(name = "sessionid") String sessionID,
@RequestParam(name = "mail") String mail,
@RequestParam(name = "permission") int permission)
{
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionID);
if(sessionUser != null && sessionUser.getPermissions() == UserPermissions.admin.getValue())
{
System.out.println("test");
User userToUpdateTemplate = db.getUser(mail);
User userToUpdate = new User(userToUpdateTemplate.getId(), userToUpdateTemplate.getFirstName(), userToUpdateTemplate.getLastName(),
userToUpdateTemplate.getMail(), userToUpdateTemplate.getPassword(), permission);
User resultingUser = db.updateUser(userToUpdate, userToUpdate.getId(), true);
if(resultingUser == null)
{
return new ResponseEntity<>(false, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(true, HttpStatus.OK);
}
return new ResponseEntity<>(false, HttpStatus.FORBIDDEN);
}
@CrossOrigin
@DeleteMapping("/users")
public ResponseEntity<Boolean> deleteUser(@RequestParam(name = "sessionid") String sessionID, @RequestParam(name = "mail") String mail) {
User sessionUser = UserSessionIDHandler.getUserBySessionID(sessionID);
if (sessionUser != null && sessionUser.getPermissions() == UserPermissions.admin.getValue()) {
return new ResponseEntity<>(db.deleteUser(mail), HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
@@ -0,0 +1,61 @@
package com.example.backend.discard;
import com.example.backend.anwprj.Database.DataBaseHandler;
import com.example.backend.discard.Days.Day;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Users.UserPermissions;
import com.example.backend.anwprj.Users.UserSessionIDHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
//alte verworfenen klasse für die funktionalität nicht wichtig
@RestController
public class DayController
{
// private DataBaseHandler db;
//
// {
// db = DataBaseHandler.getInstance();
// }
//
// @CrossOrigin
// @GetMapping("/days")
// public ResponseEntity<Day> getDay(
// @RequestParam(name="sessionid") String sessionID,
// @RequestParam(name="dayinyear") int dayinyear,
// @RequestParam(name="yearnumber") int yearnumber,
// @RequestParam(name="semesterid") int semesterID)
// {
// User u = UserSessionIDHandler.getUserBySessionID(sessionID);
//
// if(u != null)
// {
// Day d = db.getDay(dayinyear, yearnumber, semesterID);
//
// if (d != null)
// {
// return new ResponseEntity<>(d, HttpStatus.OK);
// }
//
// return new ResponseEntity<>(HttpStatus.NOT_FOUND);
// }
//
// return new ResponseEntity<>(HttpStatus.FORBIDDEN);
// }
//
// @CrossOrigin
// @PostMapping("/days")
// public ResponseEntity<Day> addDay(@RequestBody Day day, @RequestParam(name="sessionid") String sessionID)
// {
// User u = UserSessionIDHandler.getUserBySessionID(sessionID);
//
// if(u != null && u.getPermissions() == UserPermissions.admin.getValue())
// {
// return new ResponseEntity<>(db.addDay(day), HttpStatus.OK);
// }
//
// return new ResponseEntity<>(null, HttpStatus.FORBIDDEN);
// }
}
@@ -0,0 +1,33 @@
package com.example.backend.discard.Days;
//alte verworfene klasse nicht wichtig für die funktionalität
public class Day
{
private int id;
private int dayinyear;
private int yearnumber;
private int semesterid;
public Day(int id, int dayinyear, int yearnumber, int semesterid) {
this.id = id;
this.dayinyear = dayinyear;
this.yearnumber = yearnumber;
this.semesterid = semesterid;
}
public int getId() {
return id;
}
public int getDayinyear() {
return dayinyear;
}
public int getYearnumber() {
return yearnumber;
}
public int getSemesterid() {
return semesterid;
}
}
@@ -0,0 +1,60 @@
package com.example.backend.discard.Encryption;
import javax.crypto.Cipher;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
//hier ein versuch für die übertragung von vertraulichen daten wie nutzername und passwörtern RSA verschlüsselung anzuwenden.
//finde aktuell keine anwendung im projekt.
public class RSA {
private PublicKey publicKey;
private PrivateKey privateKey;
private static RSA instance = null;
public static RSA getInstance()
{
if(instance == null)
{
instance = new RSA();
}
return instance;
}
private RSA(){}
public String decrypt(byte[] text) throws Exception
{
readKeyPairs();
var cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
var plainText = cipher.doFinal(text);
return new String(plainText, StandardCharsets.US_ASCII);
}
private void readKeyPairs() throws Exception
{
var publicInput = new ObjectInputStream(new FileInputStream(new File("./public.kfs")));
publicKey = (PublicKey) publicInput.readObject();
publicInput.close();
var privateInput = new ObjectInputStream(new FileInputStream(new File("./private.kfs")));
privateKey = (PrivateKey) privateInput.readObject();
privateInput.close();
}
public byte[] loadByteArray(String text)
{
String[] split = text.split(",");
byte[] output = new byte[split.length];
for(int i = 0; i < split.length; i++)
{
output[i] = Byte.parseByte(split[i]);
}
return output;
}
}
@@ -0,0 +1,140 @@
!!!!!!!!!
!!!!!!!!!
hier sieht man eine sammlung alter databasehandler funktionen,
welche nicht benötigt wurden. Von deren Verwendung ist abzuraten,
die Funkionalität dieser bei erneutem einfügen in den Databasehandler
kann nicht gewährleistet werden
!!!!!!!!
!!!!!!!!
!!!!!!!!
/**
* WEEKS
*/
public Week addWeek(Week week)
{
try
{
st.executeUpdate("insert into weeks (semesterid, weeknumber) values (" + week.getSemesterid() + ", " + week.getWeeknumber() + ")");
return getWeek(week.getSemesterid(), week.getWeeknumber());
} catch (SQLException e)
{
return null;
}
}
public Week getWeek(int id)
{
ResultSet rs = null;
try
{
rs = st.executeQuery("select * from weeks where id=" + id);
return resultSetToWeek(rs);
} catch (SQLException e)
{
return null;
}
}
public Week getWeek(int semesterid, int weeknumber)
{
try
{
ResultSet rs = st.executeQuery("select * from weeks where semesterid =" + semesterid + " and weeknumber=" + weeknumber);
return resultSetToWeek(rs);
}
catch (SQLException e)
{
return null;
}
}
private Week resultSetToWeek(ResultSet rs) {
try {
rs.next();
return new Week(
rs.getInt("id"),
rs.getInt("semesterid"),
rs.getInt("weeknumber")
);
} catch (SQLException e) {
return null;
}
}
/**
DAYS
*/
public Day addDay(Day day)
{
try
{
st.executeUpdate("insert into days (dayinyear, yearnumber, semesterid) values (" + day.getDayinyear() + ", " + day.getYearnumber() + ", " + day.getSemesterid() + ")");
return getDay(day.getDayinyear(), day.getYearnumber(), day.getSemesterid());
} catch (SQLException e)
{
return null;
}
}
public Day getDay(int id)
{
try
{
ResultSet rs = st.executeQuery("select * from days where id=" + id);
return resultSetToDay(rs);
}
catch(Exception e)
{
return null;
}
}
public Day getDay(int dayinyear, int yearnumber, int semesterid)
{
try
{
ResultSet rs = st.executeQuery("select * from days where dayinyear =" + dayinyear + " and yearnumber =" + yearnumber + " and semesterid =" + semesterid);
return resultSetToDay(rs);
}
catch(Exception e)
{
return null;
}
}
private Day resultSetToDay(ResultSet rs)
{
try
{
rs.next();
return new Day(
rs.getInt("id"),
rs.getInt("dayinyear"),
rs.getInt("yearnumber"),
rs.getInt("semesterid")
);
} catch (SQLException e)
{
return null;
}
}
@@ -0,0 +1,27 @@
package com.example.backend.discard.Week;
//alte verworfene klasse, nicht wichtig für die funktionalität
public class Week {
private int id;
private int semesterid;
private int weeknumber;
public Week(int id, int semesterid, int weeknumber) {
this.id = id;
this.semesterid = semesterid;
this.weeknumber = weeknumber;
}
public int getId() {
return id;
}
public int getSemesterid() {
return semesterid;
}
public int getWeeknumber() {
return weeknumber;
}
}
@@ -0,0 +1,60 @@
package com.example.backend.discard;
import com.example.backend.anwprj.Database.DataBaseHandler;
import com.example.backend.anwprj.Users.User;
import com.example.backend.anwprj.Users.UserPermissions;
import com.example.backend.anwprj.Users.UserSessionIDHandler;
import org.springframework.http.HttpStatus;
import com.example.backend.discard.Week.Week;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLException;
//alte verworfene klassen, für die funktionalität des tools nicht wichtig
@RestController
public class WeekController
{
// private DataBaseHandler db;
//
// {
// db = DataBaseHandler.getInstance();
// }
//
// @CrossOrigin
// @GetMapping("/weeks")
// public ResponseEntity<Week> getWeek(
// @RequestParam(name="sessionid") String sessionID,
// @RequestParam(name="semesterid") int semesterID,
// @RequestParam(name="weeknumber") int weekNumber) throws SQLException {
// User u = UserSessionIDHandler.getUserBySessionID(sessionID);
//
// if(u != null)
// {
// Week w = db.getWeek(semesterID,weekNumber);
//
// if(w != null)
// {
// return new ResponseEntity<>(w, HttpStatus.OK);
// }
// return new ResponseEntity<>(HttpStatus.NOT_FOUND);
// }
// return new ResponseEntity<>(HttpStatus.FORBIDDEN);
// }
//
// @CrossOrigin
// @PostMapping("/weeks")
// public ResponseEntity<Week> addWeek(@RequestBody Week week, @RequestParam(name="sessionid") String sessionID)
// {
// User u = UserSessionIDHandler.getUserBySessionID(sessionID);
//
// if(u !=null && u.getPermissions() == UserPermissions.admin.getValue())
// {
// return new ResponseEntity<>(db.addWeek(week), HttpStatus.OK);
// }
//
// return new ResponseEntity<>(null, HttpStatus.FORBIDDEN);
// }
}

Some files were not shown because too many files have changed in this diff Show More