Author SHA1 Message Date
brausjonas e526b6c804 Bug Fixed 2023-06-16 09:01:11 +02:00
brausjonas 3e381687c2 Only Errors Shown In Side Bar (No Okay Days) 2023-06-16 08:59:40 +02:00
brausjonas 38ce89c295 Clicking On ALl Tiles Bug Fixed 2023-06-16 08:55:27 +02:00
brausjonas 79c1c93bd2 Database with Module ID for entries 2023-06-15 22:07:21 +02:00
brausjonas 5eba3a6733 Multiselected For Lectures / Modules Implemented
Der Multiselect funktioniert auf seitens des Frontends und des Backends. Allerdings haben Termine noch nicht die Spalte moduleID, weswegen entries für zwei modules eines Dozenten innerhalb eines Semesters gleich angezeigt werden.
2023-06-15 22:04: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
135 changed files with 213640 additions and 17646 deletions
Vendored
BIN
View File
Binary file not shown.
View File
@@ -3,7 +3,6 @@
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" /> <excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/temp" /> <excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" /> <excludeFolder url="file://$MODULE_DIR$/tmp" />
</content> </content>
+16
View File
@@ -0,0 +1,16 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="CssUnknownProperty" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myCustomPropertiesEnabled" value="true" />
<option name="myIgnoreVendorSpecificProperties" value="false" />
<option name="myCustomPropertiesList">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="font-color" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="Node.js Core" />
</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/anwendungsprojekt.iml" filepath="$PROJECT_DIR$/.idea/anwendungsprojekt.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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
# TIF22A_AnwProjekt_B
Team B im Anwendungsprojekt (TIF22A)
Website can be accessed under: http://lectureplanner.de/ (caution no https, only http)
+16 -4
View File
@@ -8,16 +8,28 @@
# testing # testing
/coverage /coverage
# next.js
/.next/
/out/
# production # production
/build /build
# misc # misc
.DS_Store .DS_Store
.env.local *.pem
.env.development.local
.env.test.local
.env.production.local
# debug
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
+5
View File
@@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>
+1 -1
View File
@@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <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> </modules>
</component> </component>
</project> </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
+1378
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
{
"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",
"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>
)
}
+33
View File
@@ -0,0 +1,33 @@
import React from "react";
export default function Background()
{
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
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)
{
let date = new Date(parseInt(startParts[2]), parseInt(startParts[1]) + monthIndex - 1, 1)
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)
let endDate = new Date(p.endyear, 0 , p.endday)
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) => (
<div className={"A box-shadow"} onClick={() => p.onMonthClick(
(parseInt(startParts[1]) + index),
startParts
)} >
<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={{
pointerEvents: "none"
}}>{weekday}</p>
))}
{freeSpaces(index)}
{monthResult.map((date) => (
<p key={date} style={{
pointerEvents: "none"
}}>{date}</p>
))}
</div>
</div>
))}
</div>
</div>
)
}
function getMonthName(monthIndex) {
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])
{
for (let i = startParts[1] - 1; i <= 11; i++)
{
let monthResult = [];
for (let j = 1; j <= days[i]; j++)
{
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)
)
{
monthResult.push(j);
calculateDay(startParts[2], i, j)
}
}
result.push(monthResult);
if (i == 11)
{
for (let h = 0; h <= endParts[1] - 1; h++)
{
let monthResultNewYear = [];
for (let g = 1; g <= days[h]; g++)
{
if (new Date(endParts[2], h, g) <= new Date(endParts[2], endParts[1] - 1, endParts[0]))
{
monthResultNewYear.push(g);
calculateDay(endParts[2], h, g)
}
}
result.push(monthResultNewYear);
}
}
}
} else
{
for (let i = startParts[1] - 1; i <= endParts[1] - 1; i++)
{
let monthResult = [];
for (let j = 1; j <= days[i]; j++)
{
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])
)
{
monthResult.push(j)
calculateDay(startParts[2], i, j)
}
}
result.push(monthResult);
}
}
}
function calculateDay(x, i, j){
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)
{
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
}
}
+815
View File
@@ -0,0 +1,815 @@
import {useEffect, useRef, useState} from "react";
import Button from "@/components/Button";
import {list} from "postcss";
import Background from "@/components/Background";
import WeekSelector from "@/components/WeekSelector";
import {baseURL} from "@/components/Constants";
import {ErrorType} from "@/components/ErrorType";
import BasicDateCalendar from "@/components/CalendarSideBar";
import feiertagejs from "feiertagejs";
let cellHeight = 20;
let colors = ["#f80000", "#414141"]
let semesterStart;
let semesterEnd;
let currentWeekStartDay;
let currentYear;
let semesterStartYear;
let semesterEndYear;
let selectedElement;
let grabbedDown;
let isDayOkay = [true, true, true, true, true, true]
let errorState = [ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay]
let grayedOut = [false, false, false, false, false, false]
export default function CalenderView(p) {
const [entries, setEntries] = useState([[], [], [], [], [], []])
const [update, setUpdate] = useState(false)
const scrollRef = useRef(null);
const [startDayCalenderSideBar, setStartDayCalenderSideBar] = useState(0)
const [startYearCalenderSideBar, setStartYearCalenderSideBar] = useState(2000)
const [endDayCalenderSideBar, setEndDayCalenderSideBar] = useState(0)
const [endYearCalenderSideBar, setEndYearCalenderSideBar] = useState(2000)
const [highlightMonth, setHighlightMonth] = useState(0)
const [highlightYear, setHighlightYear] = useState(2000)
function readEntries() {
let url = baseURL + "/entries?semesterid=" + localStorage.getItem("currentsid") +
"&daynumber=" + currentWeekStartDay + "&yearnumber=" + currentYear + "&sessionid=" + localStorage.getItem("sessionid");
let currentsid = localStorage.getItem("currentsid")
let userid = localStorage.getItem("userid")
try {
fetch(url).then(r => r.json()).then(en => {
for (let i = 0; i < en.length; i++) {
isDayOkay[i] = true
let maxLunchBreak = 0
let daySum = 0
for (let j = 0; j < en[i].length; j++) {
if (en[i][j] != null && currentsid == (en[i][j]).semesterid) {
let elem = en[i][j]
if ((elem.timestart - 1) / 4 < 8) {
errorState[i] = ErrorType.TooEarly
isDayOkay[i] = false
break
} else if ((elem.timeend - 1) / 4 > 17) {
errorState[i] = ErrorType.TooLate
isDayOkay[i] = false
break
}
else if(new Date(currentYear, 0, elem.daynumber).getUTCDay() === 5) {
errorState[i] = ErrorType.Saturday
isDayOkay[i] = false
}
else {
if ((elem.timestart - 1) / 4 <= 11 && (elem.timeend - 1) / 4 >= 14) {
errorState[i] = ErrorType.NotEnoughLunchTime
isDayOkay[i] = false
break
} else if ((elem.timeend - 1) / 4 >= 11 && (elem.timeend - 1) / 4 <= 14) {
let min = 24 * 3
for (let j2 = 0; j2 < en[i].length; j2++) {
if (en[i][j2] != null && (en[i][j2].timestart - 1) / 4 >= 11 && (en[i][j2].timestart - 1) / 4 <= 14 && currentsid == (en[i][j2]).semesterid) {
if (en[i][j2].timestart < min && en[i][j2].timestart >= elem.timeend) {
min = en[i][j2].timestart
}
}
}
if (min - elem.timeend < 3) {
errorState[i] = ErrorType.NotEnoughLunchTime
isDayOkay[i] = false
break
}
}
errorState[i] = ErrorType.Okay
}
daySum += elem.timeend - elem.timestart
}
}
if (daySum / 4 > 8) {
errorState[i] = ErrorType.TooLong
isDayOkay[i] = false
}
}
for (let i = 0; i < 6; i++) {
for (let k = 0; k < 20; k++) {
if (en[i][k] != null){
if (en[i][k].semesterid != currentsid)
{
for (let l = 0; l < 20; l++) {
if (en[i][l] != null && en[i][l].usercreatedbyid != userid) {
if (en[i][l].timestart <= en[i][k].timestart && en[i][l].timeend >= en[i][k].timeend) {
en[i][k] = null;
break
}
if (en[i][k].timestart <= en[i][l].timeend && en[i][k].timestart >= en[i][l].timestart) {
en[i][k].timestart = en[i][l].timeend
}
if (en[i][k].timeend >= en[i][l].timestart && en[i][k].timeend <= en[i][l].timeend) {
en[i][k].timeend = en[i][l].timestart
}
}
}
}
if (en[i][k] != null && en[i][k].usercreatedbyid != userid) {
for (let l = 0; l < 20; l++) {
if (en[i][l] != null && en[i][l].semesterid != currentsid) {
if (en[i][l].timestart <= en[i][k].timestart && en[i][l].timeend >= en[i][k].timeend) {
en[i][k] = null;
break
}
}
}
}
}
}
}
let j = 0;
for(let i = Math.round(((new Date(currentYear, 0, currentWeekStartDay) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))); i <= Math.round(((new Date(currentYear, 0, currentWeekStartDay + 5) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))); i++)
{
grayedOut[j] = i % Math.round(((new Date(currentYear, 11, 31) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))) < semesterStart && semesterEnd && new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() == semesterStartYear || i % Math.round(((new Date(currentYear, 11, 31) - new Date(currentYear, 0, 0)) / (1000 * 60 * 60 * 24))) > semesterEnd && new Date(currentYear, 0, currentWeekStartDay + j).getFullYear() == semesterEndYear
j++
}
for (let i = 0; i < 6; i++) {
let date = new Date(currentYear, 0, currentWeekStartDay+i)
grayedOut[i] = holiday(currentYear, date.getMonth(), date.getDate()) ? holiday(currentYear, date.getMonth(), date.getDate()) : grayedOut[i]
}
setEntries(en)
})
} catch (e) {
}
}
function pushEntry(currentColumnID, row) {
let url = baseURL + "/entries" + "?sessionid=" + localStorage.getItem("sessionid")
let json = {
"id": 0,
"daynumber": currentWeekStartDay + currentColumnID,
"yearnumber": currentYear,
"semesterid": localStorage.getItem("currentsid"),
"usercreatedbyid": localStorage.getItem("userid"),
"timestart": row,
"timeend": row + 3,
"info": localStorage.getItem("currentmodulename")
}
fetch(url, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(json)
}).then(r => {
readEntries()
})
}
function deleteEntry(id) {
let url = baseURL + "/entries?id=" + id + "&sessionid=" + localStorage.getItem("sessionid");
fetch(url, {
method: "DELETE"
}).then(r => readEntries())
}
function holiday(year, month, day){
var feiertagejs = require('feiertagejs');
let today = new Date(year, month, day)
return feiertagejs.isHoliday(today, 'BW')
}
function checkForElementAtRow(row, column) {
let currentList = entries[column];
for (let i = 0; i < currentList.length; i++) {
if (currentList[i] != null) {
if (row >= currentList[i].timestart && row <= currentList[i].timeend) {
return true;
}
}
}
return false;
}
function getElementInColumn(id, column) {
let currentList = entries[column];
for (let i = 0; i < currentList.length; i++) {
if (currentList[i] != null) {
if (currentList[i].id === id) {
return currentList[i];
}
}
}
return null;
}
function onMouseUp(e) {
if (selectedElement != null) {
let id = selectedElement.id;
if ((selectedElement.timestart - 1) / 4 >= 7 && (selectedElement.timeend - 1) / 4 <= 18) {
let url = baseURL + "/entries?sessionid=" + localStorage.getItem("sessionid");
let json = {
"id": id,
"daynumber": 0,
"yearnumber": 0,
"semesterid": 0,
"usercreatedbyid": 0,
"timestart": selectedElement.timestart,
"timeend": selectedElement.timeend,
"info": ""
}
fetch(url, {
method: "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(json)
}).then(r => {
readEntries()
})
}
selectedElement = null;
}
}
function onMouseMove(e) {
if (selectedElement != null) {
let y_window = e.clientY;
let y_target_offset = e.currentTarget.getBoundingClientRect().top;
let row = Math.floor((y_window - y_target_offset) / cellHeight) + 1;
let currentColumnID = parseInt(e.currentTarget.id)
if (grabbedDown) {
if (row - 1 > selectedElement.timestart) {
let free = true;
for (let i = 0; i < entries[currentColumnID].length; i++) {
if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) {
if (row <= entries[currentColumnID][i].timeend &&
row >= entries[currentColumnID][i].timestart ||
row > entries[currentColumnID][i].timeend &&
selectedElement.timestart < entries[currentColumnID][i].timestart) {
free = false;
break;
}
}
}
if (free) {
selectedElement.timeend = row + 1;
}
}
} else if (row + 2 < selectedElement.timeend) {
let free = true;
for (let i = 0; i < entries[currentColumnID].length; i++) {
if (entries[currentColumnID][i] != null && selectedElement !== entries[currentColumnID][i]) {
if (row < entries[currentColumnID][i].timeend &&
row >= entries[currentColumnID][i].timestart ||
row < entries[currentColumnID][i].timestart &&
selectedElement.timeend > entries[currentColumnID][i].timestart) {
free = false;
break;
}
}
}
if (free) {
selectedElement.timestart = row;
}
}
setUpdate(!update);
}
}
function onMouseDown(e) {
let y_window = e.clientY;
let y_target_offset = e.currentTarget.getBoundingClientRect().top;
let row = Math.floor((y_window - y_target_offset) / cellHeight) + 1;
let currentColumnID = parseInt(e.currentTarget.id)
let currentId = e.target.id;
let currentUserID = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid")
if (e.button === 0) {
if (!currentId.includes("e")) {
if (!currentId.includes("grab")) {
if (!checkForElementAtRow(row + 2, currentColumnID) && !checkForElementAtRow(row+1, currentColumnID)) {
if ((row - 1) / 4 >= 7 && (row + 2) / 4 <= 18) {
if(!grayedOut[currentColumnID]) {
pushEntry(currentColumnID, row)
}
}
}
} else {
let parentID = parseInt(e.target.parentElement.id.replace("e", ""));
if (currentUserID == getElementInColumn(parentID, currentColumnID).usercreatedbyid && getElementInColumn(parentID, currentColumnID).semesterid == currentsid) {
grabbedDown = currentId.includes("down")
selectedElement = getElementInColumn(parentID, currentColumnID);
}
}
}
} else if (e.button === 2) {
let parentID = parseInt(e.target.id.replace("e", ""));
if (currentUserID == getElementInColumn(parentID, currentColumnID).usercreatedbyid && currentId.includes("e") && getElementInColumn(parentID, currentColumnID).semesterid == currentsid) {
let id = parseInt(currentId.replace("e", ""))
errorState[currentColumnID] = ErrorType.Okay
deleteEntry(id)
}
}
}
function onWeekLeft() {
currentWeekStartDay -= 7;
let date = new Date(currentYear, 0, currentWeekStartDay + 5)
setHighlightMonth(date.getMonth())
setHighlightYear(date.getFullYear())
for(let i = 0; i < errorState.length; i++)
{
errorState[i] = ErrorType.Okay
}
readEntries()
}
function onWeekRight() {
currentWeekStartDay += 7;
let date = new Date(currentYear, 0, currentWeekStartDay + 5)
setHighlightMonth(date.getMonth())
setHighlightYear(date.getFullYear())
for(let i = 0; i < errorState.length; i++)
{
errorState[i] = ErrorType.Okay
}
readEntries()
}
function getEntryColor(userCreatedByID, columnID, semesterid) {
let id = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid")
if (id == userCreatedByID) {
if (isDayOkay[columnID] && semesterid == currentsid) {
return "#77932b";
}else if(semesterid != currentsid){
return "#346991";
}else {
return "#e5a10e";
}
} else {
return "#a2a2a2";
}
}
function getResizeBarColor(userCreatedByID, columnID, semesterid) {
let id = localStorage.getItem("userid");
let currentsid = localStorage.getItem("currentsid")
if (id == userCreatedByID) {
if (isDayOkay[columnID] && currentsid == semesterid) {
return "#5a6c20";
} else if(currentsid != semesterid)
{
return "#346991"
}
else {
return "#c08809";
}
} else {
return "#a2a2a2";
}
}
useEffect(() => {
semesterStart = 0;
semesterEnd = 0;
semesterStartYear = 0;
semesterEndYear = 0;
currentWeekStartDay = 0;
currentYear = 2000;
selectedElement = null;
grabbedDown = false;
errorState = [ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay, ErrorType.Okay]
let url = baseURL + "/semester/id?sessionid=" + localStorage.getItem("sessionid") +
"&id=" + localStorage.getItem("currentsid");
fetch(url).then(r => r.json()).then(s => {
currentWeekStartDay = s.startday - new Date(s.startyear, 0, s.startday).getUTCDay();
currentYear = s.startyear;
setStartYearCalenderSideBar(currentYear)
setEndYearCalenderSideBar(s.endyear)
setHighlightMonth(new Date(s.startyear, 0, s.startday).getMonth())
setHighlightYear(currentYear)
semesterStart = s.startday;
semesterEnd = s.endday;
semesterStartYear = s.startyear;
semesterEndYear = s.endyear;
setStartDayCalenderSideBar(semesterStart)
setEndDayCalenderSideBar(s.endday)
}).then(readEntries)
scrollRef.current.scrollTop = 600;
window.addEventListener("contextmenu", (e) => (e.preventDefault()))
window.addEventListener("keypress", (e) => {
try {
if (e.key === "+") {
cellHeight += 2
} else if (e.key === "-") {
if (cellHeight - 2 >= 8) {
cellHeight -= 2
}
}
} catch (e) {
}
})
setInterval(function () {
if (selectedElement == null) {
readEntries()
}
}, 500);
}, [])
//returns internal format (0 - 96) to a string
function internal_to_time(internal) {
internal -= 1
internal /= 4
let integer = Math.floor(internal)
let decimal = internal.toFixed(2);
let minutes = Math.floor((decimal - integer) * 60);
let minutes_string = minutes.toString().length === 1 ? "0" + minutes : minutes
return integer + ":" + minutes_string;
}
let temp = []
for (let i = 2; i <= 96; i += 2) {
temp.push(i);
}
function onMonthClick(monthIndex, startParts) {
monthIndex--
let date = new Date(parseInt(startParts[2]), monthIndex, 1)
let start = new Date(date.getFullYear(), 0, 0)
currentWeekStartDay = Math.round((date - start) / (1000 * 60 * 60 * 24))
currentWeekStartDay = currentWeekStartDay - new Date(date.getFullYear(), 0, currentWeekStartDay).getUTCDay()
currentYear = date.getFullYear()
setHighlightMonth(date.getMonth())
setHighlightYear(currentYear)
for(let i = 0; i < errorState.length; i++)
{
errorState[i] = ErrorType.Okay
}
readEntries()
}
return (
<div className={"calender-direction-wrapper"}>
<div>
<BasicDateCalendar startyear={startYearCalenderSideBar} startday={startDayCalenderSideBar}
endyear={endYearCalenderSideBar} endday={endDayCalenderSideBar}
highlightYear={highlightYear} highlightMonth={highlightMonth}
onMonthClick={onMonthClick}/>
</div>
<div style={{
display: "flex",
height: "73vh",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}} id={update}>
<WeekSelector year={currentYear} startday={currentWeekStartDay} onFunctionLeft={() => onWeekLeft()}
onFunctionRight={() => onWeekRight()}/>
<div style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
backgroundColor: "white",
gap: 5,
}}>
<div style={{borderRadius: 10, padding: 10, backgroundColor: "#f1f1f1"}} className={"box-shadow"}>
<div>
<div className={"wochen-tag-container"}>
<div
className={"wochen-tag font-big"}>Montag {new Date(currentYear, 0, currentWeekStartDay).getDate()}.
</div>
<div
className={"wochen-tag font-big"}>Dienstag {new Date(currentYear, 0, currentWeekStartDay + 1).getDate()}.
</div>
<div
className={"wochen-tag font-big"}>Mittwoch {new Date(currentYear, 0, currentWeekStartDay + 2).getDate()}.
</div>
<div
className={"wochen-tag font-big"}>Donnerstag {new Date(currentYear, 0, currentWeekStartDay + 3).getDate()}.
</div>
<div
className={"wochen-tag font-big"}>Freitag {new Date(currentYear, 0, currentWeekStartDay + 4).getDate()}.
</div>
<div
className={"wochen-tag font-big"}>Samstag {new Date(currentYear, 0, currentWeekStartDay + 5).getDate()}.
</div>
</div>
</div>
<div className={"calender-container"} ref={scrollRef}>
<div className={"calender-view content"} style={{height: cellHeight * 96 + 10}}>
<div className={"spalte"}
id={"0"} style={{gridTemplateRows: `repeat(96, ${cellHeight}px)`, backgroundColor: grayedOut[0] ? "#aaaaaa" : "#ffffff"}}
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}>
{entries[0].map(d => (d != null && <div className={"entry"} style={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 0, d.semesterid)
}} id={d.id + "e"}>
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid)
}}></div>
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
</div>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 0, d.semesterid)
}}></div>
</div>))}
</div>
<div className={"spalte"}
id={"1"} style={{gridTemplateRows: `repeat(96, ${cellHeight}px)`, backgroundColor: grayedOut[1] ? "#aaaaaa" : "#ffffff"}}
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}>
{entries[1].map(d => (d != null && <div className={"entry"} style={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 1, d.semesterid)
}} id={d.id + "e"}>
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 1, d.semesterid)
}}></div>
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
</div>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 1, d.semesterid)
}}></div>
</div>))}
</div>
<div className={"spalte"}
id={"2"} style={{gridTemplateRows: `repeat(96, ${cellHeight}px)`, backgroundColor: grayedOut[2] ? "#aaaaaa" : "#ffffff"}}
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}>
{entries[2].map(d => (d != null && <div className={"entry"} style={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 2, d.semesterid)
}} id={d.id + "e"}>
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 2, d.semesterid)
}}></div>
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
</div>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 2, d.semesterid)
}}></div>
</div>))}
</div>
<div className={"spalte"}
id={"3"} style={{gridTemplateRows: `repeat(96, ${cellHeight}px)`, backgroundColor: grayedOut[3] ? "#aaaaaa" : "#ffffff"}}
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}>
{entries[3].map(d => (d != null && <div className={"entry"} style={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 3, d.semesterid)
}} id={d.id + "e"}>
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 3, d.semesterid)
}}></div>
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
</div>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 3, d.semesterid)
}}></div>
</div>))}
</div>
<div className={"spalte"}
id={"4"} style={{gridTemplateRows: `repeat(96, ${cellHeight}px)`, backgroundColor: grayedOut[4] ? "#aaaaaa" : "#ffffff"}}
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}>
{entries[4].map(d => (d != null && <div className={"entry"} style={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 4, d.semesterid)
}} id={d.id + "e"}>
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 4, d.semesterid)
}}></div>
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
</div>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 4, d.semesterid)
}}></div>
</div>))}
</div>
<div className={"spalte"}
id={"5"} style={{gridTemplateRows: `repeat(96, ${cellHeight}px)`, backgroundColor: grayedOut[5] ? "#aaaaaa" : "#ffffff"}}
onMouseDown={e => onMouseDown(e)}
onMouseMove={e => onMouseMove(e)}
onMouseUp={e => onMouseUp(e)}>
{entries[5].map(d => (d != null && <div className={"entry"} style={{
width: "100%",
gridRowStart: d.timestart,
gridRowEnd: d.timeend,
backgroundColor: getEntryColor(d.usercreatedbyid, 5, d.semesterid)
}} id={d.id + "e"}>
<div className={"resize-grab"} id={"grabup"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 5, d.semesterid)
}}></div>
<div style={{maxHeight: "60%"}} className={"no-pointer-events"}>
<p>{internal_to_time(d.timestart) + " - " + internal_to_time(d.timeend)}</p>
<p>{d.info}</p>
</div>
<div className={"resize-grab"} id={"grabdown"} style={{
backgroundColor: getResizeBarColor(d.usercreatedbyid, 5, d.semesterid)
}}></div>
</div>))}
</div>
</div>
<div className={"overlay"} style={{backgroundColor: "rgba(0, 0, 0, 0)"}}>
{/*maps a list of internal time stamps to lines and time stamps*/}
{temp.map(i => (<div style={{
width: "100%",
height: cellHeight * 2,
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "center",
}} className={"no-pointer-events"}>
<div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{
color: "gray",
marginTop: cellHeight - 3,
marginRight: 120,
fontSize: 12,
textAlign: "center"
}}>{internal_to_time(i + 1)}</p></div>
<div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{
color: "gray",
marginTop: cellHeight - 3,
marginRight: 120,
fontSize: 12,
textAlign: "center"
}}>{internal_to_time(i + 1)}</p></div>
<div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{
color: "gray",
marginTop: cellHeight - 3,
marginRight: 120,
fontSize: 12,
textAlign: "center"
}}>{internal_to_time(i + 1)}</p></div>
<div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{
color: "gray",
marginTop: cellHeight - 3,
marginRight: 120,
fontSize: 12,
textAlign: "center"
}}>{internal_to_time(i + 1)}</p></div>
<div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{
color: "gray",
marginTop: cellHeight - 3,
marginRight: 120,
fontSize: 12,
textAlign: "center"
}}>{internal_to_time(i + 1)}</p></div>
<div style={{
borderBottom: (i / 4 === 7 || i / 4 === 18 ? "3px solid #fc3d03" : "1px solid #363636"),
}}><p style={{
color: "gray",
marginTop: cellHeight - 3,
marginRight: 120,
fontSize: 12,
textAlign: "center"
}}>{internal_to_time(i + 1)}</p></div>
</div>))}
</div>
</div>
</div>
</div>
</div>
<div className={"error-bar"}>
{errorState.map((e, index) => (
<div style={{
display: e === ErrorType.Okay ? "none" : "flex",
width: "90%",
backgroundColor: e === ErrorType.Okay ? "white" : "#e5a10e",
borderRadius: 15,
flexDirection: "column",
justifyContent: "center",
gap: 10,
alignItems: "center",
minHeight: 120,
maxHeight: 120,
padding: 10
}} className={"box-shadow"}>
<p style={{
borderRadius: 15,
backgroundColor: "#346991",
width: "90%",
paddingTop: 1,
paddingBottom: 1,
color: "white",
textAlign: "center"
}}>{new Date(currentYear, 0, currentWeekStartDay + index).toLocaleDateString()}</p>
<p style={{
textAlign: "center"
}}>{e}</p>
</div>))}
</div>
</div>
)
}
+2
View File
@@ -0,0 +1,2 @@
//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()}`;
let endDateString = `${endDate.getDate()}.${endDate.getMonth()+1}.${endDate.getFullYear()}`;
return (
<>
<div className="dateElement round-border box-shadow">
<p>{startDateString} - {endDateString}</p>
</div>
</>
);
}
+8
View File
@@ -0,0 +1,8 @@
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>
)
}
+19
View File
@@ -0,0 +1,19 @@
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>`
+361
View File
@@ -0,0 +1,361 @@
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";
let modulesDummy = [
["Analysis", "Theo Inf 1"],
["Lineare Algebra", "Anwendungsprojekt"],
["Theo Inf 3", "Software Eng"],
["Security", "BWL"],
["Software Eng", "Security"],
["Studienarbeit", "Bachelor"]
]
let tempSemesterNumber = 0
let update = false
let baseMapping = []
export default function InputForm(p) {
const [startDate, setStartDate] = useState("0000-00-00")
const [endDate, setEndDate] = useState("0000-00-00")
const [courseName, setCourseName] = useState("")
const [semesterNumber, setSemesterNumber] = useState(0)
const [users, setUsers] = useState([])
const [modulesSelectorValues, setModulesSelectorValues] = useState(["nothing", "nothing"])
const [userModulesMapping, setUserModulesMapping] = useState({})
const [isChecked, setIsChecked] = useState([])
const [isActivated, setIsActivated] = useState([])
const router = useRouter()
useEffect(() => {
let base = baseURL + "/semester/id?sessionid=" + localStorage.getItem("sessionid") + "&id=" + localStorage.getItem("currentsid")
fetch(base).then(r => r.json()).then(j => {
setCourseName(j.name)
let tempStartDate = new Date(parseInt(j.startyear), 0, parseInt(j.startday))
let tempEndDate = new Date(parseInt(j.endyear), 0, parseInt(j.endday))
setStartDate(tempStartDate.getFullYear() + "-" + ((tempStartDate.getMonth() + 1).toString().padStart(2, "0")) + "-" + tempStartDate.getDate().toString().padStart(2, "0"))
setEndDate(tempEndDate.getFullYear() + "-" + ((tempEndDate.getMonth() + 1).toString().padStart(2, "0")) + "-" + tempEndDate.getDate().toString().padStart(2, "0"))
setSemesterNumber(j.number)
tempSemesterNumber = j.number
}).then(() => {
readModules()
update = true
}).catch(() => readModules())
}, [])
function readModules() {
let usersTemp = []
let userURL = baseURL + "/users/all?sessionid=" + localStorage.getItem("sessionid")
fetch(userURL).then(r => r.json()).then(j => {
setUsers(j)
usersTemp = j
let temp = [false, false, false]
let temp2 = []
for (let i = 0; i < j.length; i++) {
temp.push(false)
temp2.push(false)
}
setIsChecked(temp)
setIsActivated(temp2)
}).then(() => {
let modulesURL = baseURL + "/module/bysemesterid?sessionid=" + localStorage.getItem("sessionid") + "&semesterid=" + localStorage.getItem("currentsid");
fetch(modulesURL).then(r => r.json()).then(j => {
setUserModulesMapping(j)
baseMapping = j
let temp = isChecked.slice()
let temp2 = isActivated.slice()
for (let i = 0; i < usersTemp.length; i++) {
let currentUser = usersTemp[i]
let found = false
let foundModuleLast = null
for (let f = 0; f < j.length; f++) {
let currentModule = j[f]
if (currentModule.userid === currentUser.id) {
found = true
foundModuleLast = currentModule
}
}
if (found) {
temp[i] = true
temp2[i] = foundModuleLast.activated === 1
}
}
setIsChecked(temp)
setIsActivated(temp2)
})
}).then(() => {
setModulesSelectorValues(modulesDummy[tempSemesterNumber])
})
}
function onCourseNameChange(e) {
setCourseName(e.target.value)
}
function onStartDateChange(e) {
setStartDate(e.target.value)
}
function onEndDateChange(e) {
setEndDate(e.target.value)
}
function onSemesterNumberChange(e) {
setSemesterNumber(e.target.value)
setModulesSelectorValues(modulesDummy[e.target.value])
}
function isOptionSelected(e, userid) {
let found = false;
for (let i = 0; i < userModulesMapping.length; i++) {
let current = userModulesMapping[i]
if (current.name === e && current.userid === userid) {
found = true;
}
}
return found;
}
function onCheckedChange(e, index) {
let temp = isChecked.slice()
temp[index] = e.target.checked
setIsChecked(temp)
if (!e.target.checked) {
let temp = []
let currentUser = users[index]
for (let j = 0; j < userModulesMapping.length; j++) {
if (userModulesMapping[j].userid !== currentUser.id) {
temp.push(userModulesMapping[j])
}
}
setUserModulesMapping(temp)
}
}
function onActivatedChange(e, index) {
let temp = isActivated.slice()
temp[index] = e.target.checked
setIsActivated(temp)
let userid = users[index].id
for (let j = 0; j < userModulesMapping.length; j++) {
if (userModulesMapping[j].userid === userid) {
userModulesMapping[j].activated = e.target.checked ? 1 : 0
}
}
}
function onModuleSelectionChange(e, index) {
let userid = users[index].id
let newMapping = []
let oldNamesIds = new Map()
for (let j = 0; j < userModulesMapping.length; j++) {
let currentModuleMapping = userModulesMapping[j]
if (currentModuleMapping.userid != userid) {
newMapping.push(currentModuleMapping)
} else {
oldNamesIds.set(currentModuleMapping.name, currentModuleMapping.id)
}
}
let found = false
for (let i = 0; i < e.target.options.length; i++) {
let currentOption = e.target.options[i]
if (currentOption.selected) {
found = true
newMapping.push({
"id": oldNamesIds.has(currentOption.value) ? oldNamesIds.get(currentOption.value) : -1,
"userid": userid,
"semesterid": -1,
"name": currentOption.value,
"activated": isActivated[index] ? 1 : 0
})
}
}
let temp = isChecked.slice()
temp[index] = found
setIsChecked(temp)
setUserModulesMapping(newMapping)
}
function onButtonAbort() {
router.back()
}
function onButtonSave() {
let tempDateStart = new Date(parseInt(startDate.split("-")[0]), parseInt(startDate.split("-")[1]) - 1, parseInt(startDate.split("-")[2]))
let tempDateEnd = new Date(parseInt(endDate.split("-")[0]), parseInt(endDate.split("-")[1]) - 1, parseInt(endDate.split("-")[2]))
let startDayInYear = Math.round((tempDateStart - new Date(tempDateStart.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24))
let endDayInYear = Math.round((tempDateEnd - new Date(tempDateEnd.getFullYear(), 0, 0)) / (1000 * 60 * 60 * 24))
let semesterJson = {
"id": update ? localStorage.getItem("currentsid") : 0,
"startday": startDayInYear,
"endday": endDayInYear,
"name": courseName,
"startyear": tempDateStart.getFullYear(),
"endyear": tempDateEnd.getFullYear(),
"number": semesterNumber
}
fetch(baseURL + "/semester?sessionid=" + localStorage.getItem("sessionid"), {
method: update ? "PUT" : "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(semesterJson)
}).then(r => r.json()).then(async sem => {
let semesterID = sem.id
for (let i = 0; i < baseMapping.length; i++) {
let found = false
for (let j = 0; j < userModulesMapping.length; j++) {
if (baseMapping[i].name === userModulesMapping[j].name) {
found = true
}
}
if (!found) {
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid") + "&id=" + baseMapping[i].id, {
method: "DELETE"
})
}
}
for (let i = 0; i < userModulesMapping.length; i++) {
userModulesMapping[i].semesterid = semesterID
setTimeout(() => {
console.log(userModulesMapping[i])
fetch(baseURL + "/module?sessionid=" + localStorage.getItem("sessionid"), {
method: userModulesMapping[i].id === -1 ? "POST" : "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(userModulesMapping[i])
})
}, i * 100)
}
})
router.back()
}
return (
<>
<Background/>
<div className={"box-shadow input-form round-border"}>
<p>Kursname</p>
<input type={"text"} className={"box-shadow round-border"} style={{padding: 8, width: "100%"}}
onChange={e => onCourseNameChange(e)} 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}}
onChange={e => onStartDateChange(e)} value={startDate}/>
<input type={"date"} className={"box-shadow round-border"} style={{padding: 8}}
onChange={e => onEndDateChange(e)} value={endDate}/>
</div>
<p>Semester Wählen</p>
<select className={"round-border box-shadow"} style={{padding: 5, width: "100%"}} value={semesterNumber}
onChange={e => onSemesterNumberChange(e)}>
<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>
<div className={"table-wrapper"}>
<table>
<tbody>
<tr>
<th>Wählen</th>
<th>Freischalten</th>
<th>Dozent</th>
<th>Modul</th>
</tr>
{
users.map((user, index) => (
<tr>
<td>
<input type={"checkbox"} checked={isChecked[index]}
onChange={e => onCheckedChange(e, index)}/>
</td>
<td>
<input type={"checkbox"} checked={isActivated[index]}
onChange={e => onActivatedChange(e, index)}/>
</td>
<td>
{user.firstName + " " + user.lastName}
</td>
<td>
<select multiple={true} className={"box-shadow round-border"}
style={{padding: 5}}
onChange={e => onModuleSelectionChange(e, index)}>
{modulesSelectorValues.map(msv => (
<option value={msv}
selected={isOptionSelected(msv, user.id)}>{msv}</option>
))}
</select>
</td>
</tr>
))
}
</tbody>
</table>
</div>
<div style={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center",
width: "100%",
gap: 10
}}>
<Button text={"Abbrechen"} onClick={onButtonAbort}/>
<Button text={"Speichern"} color={"#77932b"} onClick={onButtonSave}/>
</div>
</div>
</>
)
}
+75
View File
@@ -0,0 +1,75 @@
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"
async function on_login_click() {
url += "?mail=" + inputUserName + "&password=" + inputPassword;
let response = await fetch(url, {
method: "GET",
});
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})
localStorage.setItem("admin", admin)
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("")
const [hint, setHint] = useState("type here")
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"}>
<br/>
<p className={"font-kinda-big"}>Username</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"}>Password</p>
<input type="password" value={inputPassword} onChange={e => setInputPassword(e.target.value)}
placeholder={hint} 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>
)
}
+28
View File
@@ -0,0 +1,28 @@
import Button from "@/components/Button";
import {useState} from "react";
let shown = false;
export default function PopUp(p) {
return (
<>
<div style={{
display: p.displayState
}}>
<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>
</>
)
}
+49
View File
@@ -0,0 +1,49 @@
import StatusBar from "@/components/StatusBar";
import React, {useEffect} from "react";
import Button from "@/components/Button";
import {deleteItem, editItem} from "@/components/Icons";
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>
)
}
+26
View File
@@ -0,0 +1,26 @@
import React from "react"
export default function StatusBar(p)
{
if(p.progress > 100) p.progress = 100;
let classNames = ["not-started", "started", "finished"];
let index = p.progress / 50;
let actives = ["", "", ""]
actives[index] = "active";
return (
<div className={"step-container"}>
<div className={"steps"}>
<span className={"step " + classNames[0] + " " + actives[0]}>1</span>
<span className={"step " + classNames[1] + " " + actives[1]}>2</span>
<span className={"step " + classNames[2] + " " + actives[2]}>3</span>
<div className={"progress-bar " + classNames[index]}
style={{
width: p.progress + "%"
}}
></div>
</div>
</div>
)
}
+21
View File
@@ -0,0 +1,21 @@
import Button from "@/components/Button";
import { baseURL } from "@/components/Constants";
import {useRouter} from "next/router";
export default function SubmitButton() {
const router = useRouter();
return (
<div
style={{
position: "absolute",
right: 70,
bottom: 20,
borderBottomRightRadius: 10,
}}
>
<Button onClick={() => router.push("/submit")} text={"Abgeben"} color={"#77932b"} width={100} height={40} />
</div>
);
}
@@ -0,0 +1,56 @@
import {baseURL} from "@/components/Constants";
import Button from "@/components/Button";
export default function SubmitWarning(p){
async function submit() {
let url = baseURL + "/module?sessionid=" + localStorage.getItem("sessionid");
let json1 = {
"id": 0,
"userid": localStorage.getItem("userid"),
"semesterid": localStorage.getItem("currentsid"),
"name": localStorage.getItem("currentmodulename"),
"activated": 0
}
await fetch(url, {
method: "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(json1)
})
p.onClick();
p.onClick();
}
return (
<div className="box-shadow" style={{
position: "absolute",
top: 300,
left: 0,
right: 0,
borderRadius: 5,
textAlign: "center",
fontSize: 20,
margin: "auto",
width: 600
}}>
<p style={{paddingTop: 20, paddingBottom: 5}}>Möchten Sie wirklich abgeben?</p>
<p>Danach können Sie keine Änderungen mehr vornehmen!</p>
<div style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
paddingTop: 40,
paddingBottom: 20
}}>
<Button onClick={() => submit()} text={"Bestätigen"} color={"#77932b"} width={100} height={40} />
<div style={{width: 20}}></div>
<Button onClick={() => p.onClick()} text={"Abbrechen"} color={"red"} width={100} height={40} />
</div>
</div>
)
}
+19
View File
@@ -0,0 +1,19 @@
export default function Test(p)
{
// let datum = new Date(2023, 1, 10);
// let start = new Date(datum.getFullYear(), 0, 0);
//
// let difference = (datum - start) / (1000 * 60 * 60 * 24)
let day = 41
let datum = new Date(2023, 0, 30)
return (
<div>
<p>{datum.getMonth()}</p>
</div>
);
}
+67
View File
@@ -0,0 +1,67 @@
import React from 'react';
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;
+20
View File
@@ -0,0 +1,20 @@
import Button from "@/components/Button";
import DateElement from "@/components/DateElement";
import { arrowLeft } from "./Icons"
import { arrowRight } from "./Icons"
import { useState } from 'react'
export default function WeekSelector(p){
return (
<>
<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: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 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>
<div className={"help-line"}>
<img src={screen1.src}/>
<div className={"text-form"}>
<h1>Die Monats-Seiten-Leiste</h1>
<p>- Hier kannst du sehen in welchem Monat du dich aktuell befindest (blau hinterlegt).</p>
<p>- Durch einen Links-Klick auf eine Monatskacheln kannst du direkt an den Anfang dieses Monats springen</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen2.src}/>
<div className={"text-form"}>
<h1>Die Planungs-Ansicht</h1>
<p>- Hier siehst du alle deine Termine in grün (bzw. gelb bei Warnungen) und von anderen 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 kannst du die Zeiten des Termins anpassen</p>
<p>- Durch Rechts-Klick kannst du eine Vorlesung löschen</p>
<p>- Durch Klicken auf die Pfeiltasten oben kannst du die Woche wechseln</p>
<p>- Bitte beachte, dass du Vorlesungen nur zwischen den beiden Roten linien erstellen kannst</p>
<p>- Ausgegraute Tage liegen nicht im Semester, hier kannst du nicht planen</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 aber müssen nicht zwangshaft beachtet werden</p>
<p>- Sollte hier "Okay" für einen Tag stehen ist alles perfekt</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen5.src}/>
<div className={"text-form"}>
<h1>Der Login</h1>
<p>- Hier kannst du dich mit deiner Email und deinem Passwort einloggen</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</h1>
<h2>Für Admins:</h2>
<p>- Über den "+" Knopf kannst du ein neues Semester erstellen</p>
<p>- Über den Stift kannst du ein bestehendes Semester editieren</p>
<p>- Über den Mülleimer kannst du ein bestehndes Semester löschen</p>
<h2>Für Dozenten (und Admins):</h2>
<p>- Hier siehst du deine Semester mit den jeweiligen Modulen</p>
<p>- Sollte ein Semester bei dir Ausgegraut sein, wurdest du für dieses schon gewählt aber noch nicht freigeschalten</p>
<p>- Duch einen Links-Klick auf ein weises Semester kann in die Planungsübersicht gewechselt werden</p>
</div>
</div>
<div className={"help-line"}>
<img src={screen7.src}/>
<div className={"text-form"}>
<h1>Semester erstellen / bearbeiten</h1>
<p>- Hier kannst du alle daten wie Name, Start- und Endzeitpunkt eines Semesters eintragen</p>
<p>- Du kannst einen Dozenten "wählen" d.h. er soll in diesem Semester dozieren</p>
<p>- Jedem Dozenten kannst du ein Modul zuordnen, welches er dozieren soll</p>
<p>- Sobald du die Schaltfläche "Freischalten" aktiviert hast, 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>
)
}
+41
View File
@@ -0,0 +1,41 @@
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()
useEffect(() => {
let isEdge = window.navigator.userAgent.indexOf("Edg") > -1
let isChrome = window.navigator.userAgent.indexOf("Chrome") > -1
if(!(isEdge || isChrome))
{
router.push("/browserNotSupported")
}
})
return (
<div className={"normal-centered"}>
<Background/>
<HelpButton/>
<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/>
</div>
)
}
+25
View File
@@ -0,0 +1,25 @@
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";
import SubmitButton from "@/components/SubmitButton";
export default function planning(p)
{
let router = useRouter()
return (
<div className={"normal-centered"}>
<Logout/>
<Back onClick={() => router.back()}/>
<HelpButton/>
<Background/>
<CalenderView/>
<SubmitButton />
</div>
)
}
+141
View File
@@ -0,0 +1,141 @@
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) {
async function getSemesters() {
let urlTest = baseURL + "/semester/all?sessionid=" + localStorage.getItem("sessionid");
await fetch(urlTest).then(response => response.json()).then(s => {
setEntries(s)
})
}
function onClickSemester(e, m) {
if (m.target === m.currentTarget) {
localStorage.setItem("currentsid", e.id)
router.push("/planning")
}
}
function onClickNewSemester() {
localStorage.setItem("currentsid", 0);
router.push("/createSemester");
}
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;
await fetch(url, {
method: "DELETE"
});
togglePopup();
getSemesters();
}
async function funcButtonEdit(e, m) {
localStorage.setItem("currentsid", e.id);
let semester = e;
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);
await router.push({
pathname: "/createSemester",
query: {
courseName: semester.name,
startDate: startDate.toISOString().slice(0, 10),
endDate: endDate.toISOString().slice(0, 10)
},
});
getSemesters();
}
useEffect(() => {
getSemesters();
}, [])
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 => (
<div className={"semester-tile box-shadow"} onClick={(f) => onClickSemester(e, f)}>
<SemesterTile text={e.name} onClick={(f) => onClickSemester(e, f)} onButtonDeleteClick={() => {
localStorage.setItem("currentsid", e.id)
setModalHint(e.name + " Löschen?");
togglePopup();
}} onButtonEditClick={(m) => {
localStorage.setItem("currentsid", e.id)
funcButtonEdit(e, m);
}}/>
<StatusBar progress={0}/>
<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()}/>
<PopUp hint={modalHint} text1={"Abbrechen"} text2={"Löschen"} displayState={modalDisplay}
function1={funcButtonAbort} function2={funcButtonDelete}/>
</div>
)
}
@@ -0,0 +1,75 @@
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) {
function getModules() {
let urlTest = baseURL + "/module/id?sessionid=" + localStorage.getItem("sessionid");
fetch(urlTest).then(response => response.json()).then(m => {
setEntries(m);
let args = "";
for (let i = 0; i < m.length; i++) {
args += m[i].semesterid;
if (i < m.length - 1) {
args += "a";
}
}
let temp = []
let semesterURL = baseURL + "/semester/id/all?ids=" + args + "&sessionid=" + localStorage.getItem("sessionid");
fetch(semesterURL).then(r => r.json()).then(sem => {
sem.map(e => {
temp.push(e.name)
})
}).then(() => setSemesterNames(temp))
})
}
function onClickSemester(e, m) {
if (e.activated == 1) {
if (m.target === m.currentTarget) {
localStorage.setItem("currentsid", e.semesterid)
localStorage.setItem("currentmodulename", e.name)
localStorage.setItem("moduleid", e.id)
router.push("/planning")
}
}
}
useEffect(() => {
getModules();
}, [])
const [entries, setEntries] = useState([]);
const [semesterNames, setSemesterNames] = useState([]);
const router = useRouter();
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)}>
<SemesterTile
editable={false} text={semesterNames[index]} text2={e.name}
onClick={(f) => onClickSemester(e, f)}
/>
<StatusBar progress={0}/>
</div>
))}
</div>
);
}
+19
View File
@@ -0,0 +1,19 @@
import Logout from "@/components/Logout";
import SubmitWarning from "@/components/SubmitWarning";
import Back from "@/components/Back";
import {useRouter} from "next/router";
import Background from "@/components/Background";
export default function Submit(){
const router = useRouter();
return(
<div>
<Background />
<Logout />
<SubmitWarning onClick={() => router.back()}/>
<Back onClick={() => router.back()}/>
</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;
}
}
+533
View File
@@ -0,0 +1,533 @@
@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;
}
.steps .not-started {
/*background-image: linear-gradient(#b42121, #b44821);*/
background-color: #77932b;
}
.steps .started {
/*background-image: linear-gradient(#c75c0c, #c77c0c);*/
background-color: #77932b;
}
.steps .finished {
/*background-image: linear-gradient(#43C20BFF, #0bc27c);*/
background-color: #77932b;
}
.steps .active {
/*border-width: 2px;*/
/*border-color: #1e2428;*/
background-color: #346991;
}
.progress-bar {
position: absolute;
height: 8px;
background-color: #5d606e;
z-index: -1;
}
/*
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;
/*gap: 10px;*/
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))',
},
},
},
}
+33
View File
@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
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,517 @@
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;
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, info) values (" +
entry.getDaynumber() + ", " + entry.getYearnumber() + ", " + entry.getSemesterid() + ", " +
entry.getUsercreatedbyid() + ", " + entry.getTimestart() + ", " + entry.getTimeend() + ", '" + entry.getInfo() + "')"
);
} 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);
}
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[][] getAllEntrys(int semesterid, int daynumber, int yearnumber, int userid) {
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(int semesterid, int userid) {
try {
ResultSet rs = st.executeQuery("select * from entries where " +
"semesterid=" + semesterid +
" and usercreatedbyid=" + userid);
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) {
return null;
}
}
public void deleteEntry(int id) {
try {
st.executeUpdate("delete from entries where id=" + id);
} catch (Exception e) {
}
}
public void updateEntry(Entry entry) {
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.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) {
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;
}
}
public void deleteSemester(int id) {
try {
st.executeUpdate("DELETE FROM modules WHERE semesterid=" + id);
st.executeUpdate("delete from semester where id=" + id);
} catch (Exception e) {
}
}
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;
}
}
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;
}
}
//get module objects by its semester and its lecturer
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;
}
}
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;
}
}
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;
}
}
public Module updateModule(Module m) {
try {
st.executeUpdate("update modules set activated=" + m.getActivated() + ", semesterid=" + m.getsemesterid() + ", name='" + m.getName() + "' where id=" + m.getid());
return null;
} catch (SQLException ex) {
ex.printStackTrace();
return null;
}
}
public boolean deleteModule(int id) {
try {
st.executeUpdate("delete from modules where id=" + id);
return true;
} catch (Exception ex) {
return false;
}
}
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
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;
}
public User getUser(int id) {
try {
ResultSet rs = st.executeQuery("select * from users where id=" + id);
return resultSetToUser(rs);
} catch (Exception e) {
return null;
}
}
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;
}
}
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;
}
}
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;
}
}
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,66 @@
package com.example.backend.anwprj.Entries;
//entry data class
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 String info;
public Entry(int id, int daynumber, int yearnumber, int usercreatedbyid, int timestart, int timeend, int semesterid, String info)
{
this.id = id;
this.daynumber = daynumber;
this.yearnumber = yearnumber;
this.usercreatedbyid = usercreatedbyid;
this.timestart = timestart;
this.timeend = timeend;
this.semesterid = semesterid;
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 String getInfo()
{
return info;
}
}
@@ -0,0 +1,31 @@
package com.example.backend.anwprj.Module;
//module data class
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;
//semester data class
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;
//user data class
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;
//mapping of the integer rights to enum
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,68 @@
package com.example.backend.anwprj.Users;
import com.example.backend.anwprj.Database.DataBaseHandler;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
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,139 @@
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/planned")
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,168 @@
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);
}
/**
DELETE
Delete A Module
*/
@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,156 @@
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);
}
@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);
}
@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);
}
@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);
}
@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);
}
@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,185 @@
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.*;
@RestController
public class UserController {
//reference to the database handler
private DataBaseHandler db;
{
db = DataBaseHandler.getInstance();
}
@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);
}
@CrossOrigin
@GetMapping("/users/logout")
public ResponseEntity<Boolean> logout(@RequestParam(name = "sessionid") String sessionID) {
boolean success = UserSessionIDHandler.removeUser(sessionID);
return new ResponseEntity<>(success, HttpStatus.OK);
}
@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);
}
@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,60 @@
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.*;
@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,32 @@
package com.example.backend.discard.Days;
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,58 @@
package com.example.backend.discard.Encryption;
import javax.crypto.Cipher;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
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,124 @@
/**
* 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,26 @@
package com.example.backend.discard.Week;
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,59 @@
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;
@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);
// }
}
@@ -0,0 +1 @@
@@ -0,0 +1,15 @@
package com.example.backend;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class BackendApplicationTests
{
@Test
void contextLoads()
{
}
}

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