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
117 changed files with 211780 additions and 18363 deletions
Vendored
BIN
View File
Binary file not shown.
View File
@@ -3,7 +3,6 @@
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
+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>
+1 -1
View File
@@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/projekt.iml" filepath="$PROJECT_DIR$/.idea/projekt.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/anwendungsprojekt.iml" filepath="$PROJECT_DIR$/.idea/anwendungsprojekt.iml" />
</modules>
</component>
</project>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<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)
+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>
);
}
@@ -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
}
}
@@ -1,9 +0,0 @@
export class CalenderEntry
{
constructor(start_point, end_point)
{
this.start_point = start_point;
this.end_point = end_point;
this.colorID = 0;
}
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
//export const baseURL = "http://185.245.96.48:8080"
export const baseURL = "http://localhost:8080"
+6 -10
View File
@@ -4,20 +4,16 @@ function addDays(date, days) {
return result;
}
export default function DateElement(props){
let startDate;
let endDate;
const currDate = new Date();
export default function DateElement(p){
startDate = addDays(currDate, (currDate.getDay()-1)*-1); //berechnet den Montag der aktuellen Woche
startDate = addDays(startDate, props.week*7); //erhöht das Datum um 7 Tage für jede Woche, die weiter geklickt wurde.
endDate = addDays(startDate, 6);
let startDate = new Date(p.year, 0, p.startday);
let endDate = new Date(p.year, 0, p.startday + 5);
const startDateString = `${startDate.getDate()}.${startDate.getMonth()+1}.${startDate.getFullYear()}`;
const endDateString = `${endDate.getDate()}.${endDate.getMonth()+1}.${endDate.getFullYear()}`;
let startDateString = `${startDate.getDate()}.${startDate.getMonth()+1}.${startDate.getFullYear()}`;
let endDateString = `${endDate.getDate()}.${endDate.getMonth()+1}.${endDate.getFullYear()}`;
return (
<>
<div className="dateElement round-border">
<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>
)
}
+12
View File
@@ -5,3 +5,15 @@ export const arrowLeft = `<svg xmlns="http://www.w3.org/2000/svg" fill="white" c
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>
)
}
+6 -26
View File
@@ -3,41 +3,21 @@ import {useState} from "react";
let shown = false;
export default function PopUp() {
const [displayState, setDisplayState] = useState("none");
export default function PopUp(p) {
function toggleModal() {
shown = !shown;
if (shown)
{
setDisplayState("block");
}
else
{
setDisplayState("none");
}
console.log("test");
}
function on_abgeben_pressed()
{
}
return (
<>
<Button text={"Abgeben"} onClick={toggleModal}/>
<div style={{
display: displayState
display: p.displayState
}}>
<div className={"modal-container"}>
<div className={"modal"}>
<p className={"font-middle"}>Kalender wirklich abgeben?</p>
<div className={"modal box-shadow"}>
<p className={"font-middle"}>{p.hint}</p>
<div>
<Button text={"Abbrechen"} color={"#363636"} onClick={toggleModal}/>
<Button text={"Abgeben"} color={"#7a7a7a"} onClick={on_abgeben_pressed}/>
<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>
+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>
)
}
+3 -3
View File
@@ -12,9 +12,9 @@ export default function StatusBar(p)
return (
<div className={"step-container"}>
<div className={"steps"}>
<span className={"step " + classNames[index] + " " + actives[0]}>1</span>
<span className={"step " + classNames[index] + " " + actives[1]}>2</span>
<span className={"step " + classNames[index] + " " + actives[2]}>3</span>
<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 + "%"
+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;
+5 -5
View File
@@ -6,14 +6,14 @@ import { useState } from 'react'
export default function WeekSelector(){
const [weeks, setWeeks] = useState(0)
export default function WeekSelector(p){
return (
<>
<div className="weekSelector">
<Button icon={arrowLeft} onClick={() => setWeeks(weeks-1)} />
<DateElement week={weeks}/>
<Button icon={arrowRight} onClick={() => setWeeks(weeks+1)}/>
<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

+2
View File
@@ -1,4 +1,6 @@
import '@/styles/globals.css'
import '@/styles/calendarSideBar.css'
import '@/styles/helppage.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
@@ -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>
)
}
+27 -13
View File
@@ -1,27 +1,41 @@
import {Inter} from 'next/font/google'
import React, {useState} from "react";
import StatusBar from "@/components/StatusBar";
import Button from "@/components/Button";
import {arrowLeft, arrowRight} from "@/components/Icons";
import WeekSelector from "@/components/WeekSelector";
import PopUp from "@/components/PopUp";
import CalenderView from "@/components/CalenderView";
import DateElement from "@/components/DateElement";
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 style={{height: 50}}></div>
<CalenderView/>
</>
<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;
}
}
+461 -228
View File
@@ -3,298 +3,531 @@
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 255, 255, 255;
--background-end-rgb: 255, 255, 255;
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 255, 255, 255;
--background-end-rgb: 255, 255, 255;
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
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: 5px;
border-width: 0;
.round-border {
border-radius: 10px;
border-width: 0;
}
.font-small
{
font-size: 12px;
.font-small {
font-size: 12px;
}
.font-middle
{
font-size: 16px ;
.font-middle {
font-size: 16px;
}
.font-big
{
font-size: 22px;
.font-big {
font-size: 22px;
}
.button
{
background-color: #363636;
padding: 5px;
color: white;
.button {
background-color: #363636;
padding: 5px;
color: white;
}
.button:hover
{
background-color: #585858;
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;
.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;
.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;
.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);
.steps .not-started {
/*background-image: linear-gradient(#b42121, #b44821);*/
background-color: #77932b;
}
.steps .started
{
background-image: linear-gradient(#c75c0c, #c77c0c);
}
.steps .finished
{
background-image: linear-gradient(#43C20BFF, #0bc27c);
}
.steps .active
{
border-width: 3px;
border-color: #1e2428;
}
.progress-bar
{
position: absolute;
height: 8px;
background-color: #5d606e;
z-index: -1;
.steps .started {
/*background-image: linear-gradient(#c75c0c, #c77c0c);*/
background-color: #77932b;
}
.dateElement{
display: flex;
margin-left: 20px;
margin-right: 20px;
height: 50px;
width: 200px;
align-items: center;
justify-content: center;
background-color: #0d52ce;
.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 {
display: flex;
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.3);
.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
{
width: 300px;
height: 100px;
border-radius: 10px;
background-color: rgb(255, 255, 255);
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 5px;
.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;
}
.modal p
{
text-align: center;
@keyframes modalgrow {
from
{
height: 90px;
width: 150px;
}
to
{
height: 180px;
width: 300px;
}
}
.modal div
{
display: flex;
flex-direction: row;
width: 100%;
justify-content: end;
gap: 5px;
.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
*/
.calender-container
{
max-height: 600px;
overflow-y: scroll;
display: grid;
@media (max-width: 1300px) {
.error-bar
{
display: none;
}
}
.calender-container::-webkit-scrollbar
{
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;
}
}
.content
.calender-direction-wrapper
{
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;
background-color: #363636;
}
.calender-view
{
width: 1000px;
height: 2400px;
background-color: #363636;
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: stretch;
gap: 5px;
user-select: none;
padding: 2px 0 0 0;
}
.calender-view .spalte
{
border-radius: 10px;
width: 400px;
background-color: white;
display: grid;
padding: 0 3px;
grid-template-columns: 100%;
}
.wochen-tag-container .wochen-tag
{
text-align: center;
background-color: #f80000;
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: 5px;
cursor: ns-resize;
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.entry p
.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
{
color: white;
font-size: 16px;
cursor: default;
pointer-events: none;
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;
}
-1
View File
@@ -14,5 +14,4 @@ module.exports = {
},
},
},
plugins: [],
}
+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()
{
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "TIF22A_AnwProjekt_B",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/feiertagejs": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/feiertagejs/-/feiertagejs-1.3.9.tgz",
"integrity": "sha512-tUP+WBv2OWBhPwe3NfqwCtjMq+ym598a42tfqmL0FySswEb9xs96p2iKwqqx+lxKieu1njJBRZKsFm92bJhxZw==",
"engines": {
"node": ">=8.0.0"
}
}
}
}
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Simon Fakir
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+93
View File
@@ -0,0 +1,93 @@
# Feiertage.js
[![npm version](https://badge.fury.io/js/feiertagejs.svg)](https://badge.fury.io/js/feiertagejs)
[![Build Status](https://travis-ci.org/sfakir/feiertagejs.svg?branch=master)](https://travis-ci.org/sfakir/feiertagejs)
Feiertage.js is a small *typescript* npm module without dependencies to calculate German holidays for each Bundesland.
## Installation
- [yarn](https://yarnpkg.com/en/): `yarn add feiertagejs`
- [npm](https://www.npmjs.com/): `npm install feiertagejs`
- [bower](https://bower.io/): `bower install feiertagejs` *outdated!*
- [Plain Javascript](http://extern.fakir.it/feiertagejs/feiertagejs.zip) *outdated!*
## Quick Examples
### ES Modules (Typescript/Javasript)
The prefered whay is to directly import the typescript module. However, you can also use .js.
Please find here some examples and full api [here](docs.md).
```javascript
import { getHolidays, isHoliday, isSpecificHoliday } from 'feiertagejs';
const today = new Date();
console.log(isHoliday(today, 'BW'));
// probably false, because you are working ;)
// check if a day is a specific holiday:
console.log(isSpecificHoliday(today, 'CHRISTIHIMMELFAHRT','ALL'));
// get all holiday for a single year: getHolidays()
// returns an array of "Holiday" Objects. Please see the docs.md for all properties.
const holidays2023 = getHolidays('2023','BUND');
console.log('date', holidays2023[0].date); // = Date("2023-01-01");
console.log('name', holidays2023[0].name); // 'NEUJAHRSTAG' (constant)
console.log('translation', holidays2023[0].trans('de')); // German translation: Neujahrstag
console.log('equals?', holidays2023[0].equals(date)); // Compare days only (ignore time)
```
### Usage in Node.js
```javascript
var feiertagejs = require('feiertagejs');
var today = new Date();
console.log(feiertagejs.isHoliday(today, 'BW'));
// probably false, because you are working ;)
// check if a day is a specific holiday:
console.log(feiertagejs.isSpecificHoliday(today, 'CHRISTIHIMMELFAHRT'));
// get all holiday for a single year: getHolidays()
// returns an array of "Holiday" Objects. Please see the docs.md for all properties.
var holidays2023 = feiertagejs.getHolidays('2023', 'BUND');
console.log('date', holidays2023[0].date); // = Date("2023-01-01");
console.log('name', holidays2023[0].name); // 'NEUJAHRSTAG' (constant)
console.log('translation', holidays2023[0].translate()); // German translation: Neujahrstag
console.log('equals?', holidays2023[0].equals(date)); // Compare days only (ignore time)
```
## API doc
The full API doc can be found [here](docs.md).
## Feedback and Questions
You have two options two give feedback or ask questions:
* Comment the official release [post](https://fakir.tech/de/feiertage-js-deutsche-feiertage-fuer-node-js-und-browser-javascript/)
* Open issues or pullrequests on [github](https://github.com/sfakir/feiertagejs)
## Contributors
Thank you for contributing:
* thetric
* SteveOswald
## Feedback
If you have any questions, feel free to open an issue.
+476
View File
@@ -0,0 +1,476 @@
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
export { addTranslation, getHolidayByDate, getHolidays, getLanguage, isHoliday, isSpecificHoliday, isSunOrHoliday, setLanguage };
//# sourceMappingURL=feiertage.esm.js.map
File diff suppressed because one or more lines are too long
+476
View File
@@ -0,0 +1,476 @@
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
export { addTranslation, getHolidayByDate, getHolidays, getLanguage, isHoliday, isSpecificHoliday, isSunOrHoliday, setLanguage };
//# sourceMappingURL=feiertage.js.map
File diff suppressed because one or more lines are too long
+496
View File
@@ -0,0 +1,496 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () {
var current = global.feiertagejs;
var exports = global.feiertagejs = {};
factory(exports);
exports.noConflict = function () { global.feiertagejs = current; return exports; };
})());
})(this, (function (exports) { 'use strict';
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
exports.addTranslation = addTranslation;
exports.getHolidayByDate = getHolidayByDate;
exports.getHolidays = getHolidays;
exports.getLanguage = getLanguage;
exports.isHoliday = isHoliday;
exports.isSpecificHoliday = isSpecificHoliday;
exports.isSunOrHoliday = isSunOrHoliday;
exports.setLanguage = setLanguage;
}));
//# sourceMappingURL=feiertage.umd.cjs.map
File diff suppressed because one or more lines are too long
+496
View File
@@ -0,0 +1,496 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, (function () {
var current = global.feiertagejs;
var exports = global.feiertagejs = {};
factory(exports);
exports.noConflict = function () { global.feiertagejs = current; return exports; };
})());
})(this, (function (exports) { 'use strict';
const germanTranslations = {
NEUJAHRSTAG: 'Neujahrstag',
HEILIGEDREIKOENIGE: 'Heilige Drei Könige',
KARFREITAG: 'Karfreitag',
OSTERSONNTAG: 'Ostersonntag',
OSTERMONTAG: 'Ostermontag',
TAG_DER_ARBEIT: 'Tag der Arbeit',
CHRISTIHIMMELFAHRT: 'Christi Himmelfahrt',
PFINGSTSONNTAG: 'Pfingstsonntag',
PFINGSTMONTAG: 'Pfingstmontag',
FRONLEICHNAM: 'Fronleichnam',
MARIAHIMMELFAHRT: 'Mariä Himmelfahrt',
DEUTSCHEEINHEIT: 'Tag der Deutschen Einheit',
REFORMATIONSTAG: 'Reformationstag',
ALLERHEILIGEN: 'Allerheiligen',
BUBETAG: 'Buß- und Bettag',
ERSTERWEIHNACHTSFEIERTAG: '1. Weihnachtstag',
ZWEITERWEIHNACHTSFEIERTAG: '2. Weihnachtstag',
WELTKINDERTAG: 'Weltkindertag',
WELTFRAUENTAG: 'Weltfrauentag',
AUGSBURGER_FRIEDENSFEST: 'Augsburger Friedensfest',
};
const allHolidays = [
'NEUJAHRSTAG',
'HEILIGEDREIKOENIGE',
'KARFREITAG',
'OSTERSONNTAG',
'OSTERMONTAG',
'TAG_DER_ARBEIT',
'CHRISTIHIMMELFAHRT',
'MARIAHIMMELFAHRT',
'PFINGSTSONNTAG',
'PFINGSTMONTAG',
'FRONLEICHNAM',
'DEUTSCHEEINHEIT',
'REFORMATIONSTAG',
'ALLERHEILIGEN',
'BUBETAG',
'ERSTERWEIHNACHTSFEIERTAG',
'ZWEITERWEIHNACHTSFEIERTAG',
'WELTKINDERTAG',
'WELTFRAUENTAG',
'AUGSBURGER_FRIEDENSFEST',
];
const allRegions = [
'BW',
'BY',
'BE',
'BB',
'HB',
'HE',
'HH',
'MV',
'NI',
'NW',
'RP',
'SL',
'SN',
'ST',
'SH',
'TH',
'BUND',
'AUGSBURG',
'ALL',
];
/*!
* feiertage.js
* @repository https://github.com/sfakir/feiertagejs
* @docs https://github.com/sfakir/feiertagejs/blob/master/docs.md
*
* Copyright 2015-2021 Simon Fakir
* Released under the MIT license
*/
// translations
const defaultLanguage = 'de';
let currentLanguage = defaultLanguage;
const translations = {
de: germanTranslations,
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
function addTranslation(isoCode, newTranslation) {
const code = isoCode.toLowerCase();
const defaultTranslation = translations[defaultLanguage];
let missingFields = false;
// fill new Translation with default Language
for (const holiday of allHolidays) {
if (!newTranslation[holiday]) {
missingFields = true;
newTranslation[holiday] = defaultTranslation[holiday];
}
}
if (missingFields) {
console.warn('[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback');
}
translations[code] = newTranslation;
}
/**
* Set a language to default language
* @param {string} isoCode
*/
function setLanguage(isoCode) {
const code = isoCode.toLowerCase();
if (!translations[code]) {
throw new TypeError(`[feiertagejs] tried to set language to ${code} but the translation is missing. Please use addTranslation(isoCode,object) first`);
}
currentLanguage = isoCode;
}
/**
* Get currently set language
* @returns {string}
*/
function getLanguage() {
return currentLanguage;
}
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
function isSunOrHoliday(date, region) {
checkRegion(region);
return date.getDay() === 0 || isHoliday(date, region);
}
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
function isHoliday(date, region) {
checkRegion(region);
const year = date.getFullYear();
const internalDate = toUtcTimestamp(date);
const holidays = getHolidaysAsUtcTimestamps(year, region);
return holidays.indexOf(internalDate) !== -1;
}
function getHolidayByDate(date, region = 'ALL') {
checkRegion(region);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
return holidays.find((holiday) => holiday.equals(date));
}
// additional runtime checks
/**
* Checks if the given region is a valid {@link Region}.
*
* @param region {@link Region} to check
* @throws {Error}
* @private
*/
function checkRegion(region) {
if (region === null || region === undefined) {
throw new Error(`Region must not be undefined or null`);
}
if (allRegions.indexOf(region) === -1) {
throw new Error(`Invalid region: ${region}! Must be one of ${allRegions.toString()}`);
}
}
/**
* Checks if the given holidayName is a valid {@link HolidayType}.
* @param holidayName {@link HolidayType} to check
* @throws {Error}
* @private
*/
function checkHolidayType(holidayName) {
if (holidayName === null || holidayName === undefined) {
throw new TypeError('holidayName must not be null or undefined');
}
if (allHolidays.indexOf(holidayName) === -1) {
throw new Error(`feiertage.js: invalid holiday type "${holidayName}"! Must be one of ${allHolidays.toString()}`);
}
}
function isSpecificHoliday(date, holidayName, region = 'ALL') {
checkRegion(region);
checkHolidayType(holidayName);
const holidays = getHolidaysOfYear(date.getFullYear(), region);
const foundHoliday = holidays.find((holiday) => holiday.equals(date));
if (!foundHoliday) {
return false;
}
return foundHoliday.name === holidayName;
}
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
function getHolidays(year, region) {
let y;
if (typeof year === 'string') {
y = parseInt(year, 10);
}
else {
y = year;
}
checkRegion(region);
return getHolidaysOfYear(y, region);
}
/**
*
* @param {number} year
* @param region
* @returns {number[]}
* @private
*/
function getHolidaysAsUtcTimestamps(year, region) {
const holidays = getHolidaysOfYear(year, region);
return holidays.map((holiday) => toUtcTimestamp(holiday.date));
}
/**
*
* @param {number} year
* @param region
* @returns {{objects: Array.<Holiday>, integers}}
* @private
*/
function getHolidaysOfYear(year, region) {
const easterDate = getEasterDate(year);
const karfreitag = addDays(new Date(easterDate.getTime()), -2);
const ostermontag = addDays(new Date(easterDate.getTime()), 1);
const christiHimmelfahrt = addDays(new Date(easterDate.getTime()), 39);
const pfingstsonntag = addDays(new Date(easterDate.getTime()), 49);
const pfingstmontag = addDays(new Date(easterDate.getTime()), 50);
const holidays = [
...getCommonHolidays(year),
newHoliday('KARFREITAG', karfreitag),
newHoliday('OSTERMONTAG', ostermontag),
newHoliday('CHRISTIHIMMELFAHRT', christiHimmelfahrt),
newHoliday('PFINGSTMONTAG', pfingstmontag),
];
addHeiligeDreiKoenige(year, region, holidays);
addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, holidays);
addFronleichnam(region, easterDate, holidays);
addMariaeHimmelfahrt(year, region, holidays);
addReformationstag(year, region, holidays);
addAllerheiligen(year, region, holidays);
addBussUndBetttag(year, region, holidays);
addWeltkindertag(year, region, holidays);
addWeltfrauenTag(year, region, holidays);
addRegionalHolidays(year, region, holidays);
return holidays.sort((a, b) => a.date.getTime() - b.date.getTime());
}
function getCommonHolidays(year) {
return [
newHoliday('NEUJAHRSTAG', makeDate(year, 1, 1)),
newHoliday('TAG_DER_ARBEIT', makeDate(year, 5, 1)),
newHoliday('DEUTSCHEEINHEIT', makeDate(year, 10, 3)),
newHoliday('ERSTERWEIHNACHTSFEIERTAG', makeDate(year, 12, 25)),
newHoliday('ZWEITERWEIHNACHTSFEIERTAG', makeDate(year, 12, 26)),
];
}
function addRegionalHolidays(year, region, feiertageObjects) {
if (region === 'AUGSBURG') {
feiertageObjects.push(newHoliday('AUGSBURGER_FRIEDENSFEST', makeDate(year, 8, 8)));
}
}
function addHeiligeDreiKoenige(year, region, feiertageObjects) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ST' ||
region === 'ALL') {
feiertageObjects.push(newHoliday('HEILIGEDREIKOENIGE', makeDate(year, 1, 6)));
}
}
function addEasterAndPfingsten(year, region, easterDate, pfingstsonntag, feiertageObjects) {
if (region === 'BB' || region === 'ALL') {
feiertageObjects.push(newHoliday('OSTERSONNTAG', easterDate), newHoliday('PFINGSTSONNTAG', pfingstsonntag));
}
}
function addFronleichnam(region, easterDate, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'HE' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
const fronleichnam = addDays(new Date(easterDate.getTime()), 60);
holidays.push(newHoliday('FRONLEICHNAM', fronleichnam));
}
}
function addMariaeHimmelfahrt(year, region, holidays) {
if (region === 'SL' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'ALL') {
holidays.push(newHoliday('MARIAHIMMELFAHRT', makeDate(year, 8, 15)));
}
}
function addReformationstag(year, region, holidays) {
if (year === 2017 ||
region === 'NI' ||
region === 'BB' ||
region === 'HB' ||
region === 'HH' ||
region === 'MV' ||
region === 'SN' ||
region === 'ST' ||
region === 'TH' ||
region === 'SH' ||
region === 'ALL') {
holidays.push(newHoliday('REFORMATIONSTAG', makeDate(year, 10, 31)));
}
}
function addAllerheiligen(year, region, holidays) {
if (region === 'BW' ||
region === 'BY' ||
region === 'AUGSBURG' ||
region === 'NW' ||
region === 'RP' ||
region === 'SL' ||
region === 'ALL') {
holidays.push(newHoliday('ALLERHEILIGEN', makeDate(year, 11, 1)));
}
}
function addBussUndBetttag(year, region, holidays) {
if (region === 'SN' || region === 'ALL') {
// @todo write test
const bussbettag = getBussBettag(year);
holidays.push(newHoliday('BUBETAG', makeDate(bussbettag.getUTCFullYear(), bussbettag.getUTCMonth() + 1, bussbettag.getUTCDate())));
}
}
function addWeltkindertag(year, region, holidays) {
if (year >= 2019 && (region === 'TH' || region === 'ALL')) {
holidays.push(newHoliday('WELTKINDERTAG', makeDate(year, 9, 20)));
}
}
function addWeltfrauenTag(year, region, feiertageObjects) {
if (year <= 2018) {
return;
}
if (region === 'BE' || region === 'ALL') {
// in Berlin ist der Weltfrauentag ein Feiertag seit 2018
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
if (region === 'MV' && year >= 2023) {
// in MV wird der Weltfrauentag erst ab 2023 eingeführt
feiertageObjects.push(newHoliday('WELTFRAUENTAG', makeDate(year, 3, 8)));
}
}
/**
* Calculates the Easter date of a given year.
* @param year {number}
* @returns {Date} Easter date
* @private
*/
function getEasterDate(year) {
const C = Math.floor(year / 100);
// tslint:disable:binary-expression-operand-order
// tslint generates false positives in the following blocks
const N = year - 19 * Math.floor(year / 19);
const K = Math.floor((C - 17) / 25);
let I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
I -= 30 * Math.floor(I / 30);
I -=
Math.floor(I / 28) *
(1 -
Math.floor(I / 28) *
Math.floor(29 / (I + 1)) *
Math.floor((21 - N) / 11));
let J = year + Math.floor(year / 4) + I + 2 - C + Math.floor(C / 4);
J -= 7 * Math.floor(J / 7);
const L = I - J;
const M = 3 + Math.floor((L + 40) / 44);
const D = L + 28 - 31 * Math.floor(M / 4);
// tslint:enable:binary-expression-operand-order
return new Date(year, M - 1, D);
}
/**
* Computes the "Buss- und Bettag"'s date.
* @param jahr {number}
* @returns {Date} the year's "Buss- und Bettag" date
* @private
*/
function getBussBettag(jahr) {
const weihnachten = new Date(jahr, 11, 25, 12, 0, 0);
const ersterAdventOffset = 32;
let wochenTagOffset = weihnachten.getDay() % 7;
if (wochenTagOffset === 0) {
wochenTagOffset = 7;
}
const tageVorWeihnachten = wochenTagOffset + ersterAdventOffset;
let bbtag = new Date(weihnachten.getTime());
bbtag = addDays(bbtag, -tageVorWeihnachten);
return bbtag;
}
/**
* Adds {@code days} days to the given {@link Date}.
* @param date
* @param days
* @returns {Date}
* @private
*/
function addDays(date, days) {
const changedDate = new Date(date);
changedDate.setDate(date.getDate() + days);
return changedDate;
}
/**
* Creates a new {@link Date}.
* @param year
* @param naturalMonth month (1-12)
* @param day
* @returns {Date}
* @private
*/
function makeDate(year, naturalMonth, day) {
return new Date(year, naturalMonth - 1, day);
}
/**
*
* @param name
* @param date
* @returns {Holiday}
* @private
*/
function newHoliday(name, date) {
return {
name,
date,
dateString: localeDateObjectToDateString(date),
trans(lang = currentLanguage) {
console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"');
return this.translate(lang);
},
translate(lang = currentLanguage) {
return lang === undefined || lang === null
? undefined
: translations[lang][this.name];
},
getNormalizedDate() {
return toUtcTimestamp(this.date);
},
equals(otherDate) {
const dateString = localeDateObjectToDateString(otherDate);
return this.dateString === dateString;
},
};
}
/**
*
* @param date
* @returns {string}
* @private
*/
function localeDateObjectToDateString(date) {
const normalizedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
normalizedDate.setUTCHours(0, 0, 0, 0);
return normalizedDate.toISOString().slice(0, 10);
}
/**
* Returns the UTC timestamp of the given date with hours, minutes, seconds, and milliseconds set to zero.
* @param date
* @returns {number} UTC timestamp
*/
function toUtcTimestamp(date) {
const internalDate = new Date(date);
internalDate.setHours(0, 0, 0, 0);
return internalDate.getTime();
}
exports.addTranslation = addTranslation;
exports.getHolidayByDate = getHolidayByDate;
exports.getHolidays = getHolidays;
exports.getLanguage = getLanguage;
exports.isHoliday = isHoliday;
exports.isSpecificHoliday = isSpecificHoliday;
exports.isSunOrHoliday = isSunOrHoliday;
exports.setLanguage = setLanguage;
}));
//# sourceMappingURL=feiertage.umd.js.map
File diff suppressed because one or more lines are too long
+144
View File
@@ -0,0 +1,144 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
### Table of Contents
*Types*
- [HolidayType](#holidaytype)
- [Region](#region)
- [Holiday](#holiday)
- [allHolidays](#allholidays)
- [allRegions](#allregions)
- [TranslationTable](#translationtable)
*API*
- [isHoliday(date, region)](#isholiday)
- [getHolidayByDate(date, region)](#getholidaybydate)
- [getHolidays(year, region)](#getholidays)
- [isSunOrHoliday(date, region)](#issunorholiday)
- [isSpecificHoliday(date, name, region)](#isspecificholiday)
- [addTranslation(isoCode, translation)](#addtranslation)
- [setLanguage(lng)](#setlanguage)
- [getLanguage()](#getlanguage)
## Types
### HolidayType
Type: (`"NEUJAHRSTAG"` \| `"HEILIGEDREIKOENIGE"` \| `"KARFREITAG"` \| `"OSTERSONNTAG"` \| `"OSTERMONTAG"` \| `"TAG_DER_ARBEIT"` \| `"CHRISTIHIMMELFAHRT"` \| `"MARIAHIMMELFAHRT"` \| `"PFINGSTSONNTAG"` \| `"PFINGSTMONTAG"` \| `"FRONLEICHNAM"` \| `"DEUTSCHEEINHEIT"` \| `"REFORMATIONSTAG"` \| `"ALLERHEILIGEN"` \| `"BUBETAG"` \| `"ERSTERWEIHNACHTSFEIERTAG"` \| `"ZWEITERWEIHNACHTSFEIERTAG"` \| `"WELTKINDERTAG"` \| `"WELTFRAUENTAG"` \| `"AUGSBURGER_FRIEDENSFEST"`)
### Region
Type: (`"BW"` \| `"BY"` \| `"BE"` \| `"BB"` \| `"HB"` \| `"HE"` \| `"HH"` \| `"MV"` \| `"NI"` \| `"NW"` \| `"RP"` \| `"SL"` \| `"SN"` \| `"ST"` \| `"SH"` \| `"TH"` \| `"BUND"` \| `"ALL"`)
As defined here: https://de.wikipedia.org/wiki/Land_(Deutschland)#Amtliche_bzw._Eigenbezeichnungen
The difference between BUND and ALL is defined as follows:
* "ALL" refers to every holiday which is valid in **at least** one region. So a holiday that only applies to one state will be included.
* "BUND" refers to holidays that are valid in every region ("bundesweit"). So a holiday that only applies to one state will not be included.
### Holiday
Type: {name: [HolidayType](#holidaytype), date: [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date), trans: function (lang: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?): [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), dateString: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), equals: function (date: [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)): [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)}
**Properties**
- `name` **[HolidayType](#holidaytype)**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `trans` **function (lang: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?): [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `dateString` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
- `equals` **function (date: [Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)): [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### allHolidays
Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[HolidayType](#holidaytype)>
### allRegions
Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[Region](#region)>
### TranslationTable
Map of [HolidayType](#holidaytype) to translation string.
Type: {}
## API
### addTranslation()
Adds a translation for the holidays (e.g. English).
This also allows overriding the German names.
Hint: Interpolates German for missing translations
**Parameters**
- `isoCode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** of the new language
- `newTranslation` **[TranslationTable](#translationtable)** map of {HolidayType} to translation stringg
### setLanguage()
Set a language to default language
**Parameters**
- `isoCode` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
### getLanguage()
Get currently set language
Returns **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
### isSunOrHoliday()
Checks if a specific date is sunday or holiday.
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `region` **[Region](#region)**
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### isHoliday()
Check is specific date is holiday.
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `region` **[Region](#region)** two character [Region](#region) code
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### getHolidayByDate()
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `region` **[Region](#region)** (optional, default `'ALL'`)
Returns **([Holiday](#holiday) | void)**
### isSpecificHoliday()
**Parameters**
- `date` **[Date](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date)**
- `holidayName` **[HolidayType](#holidaytype)**
- `region` **[Region](#region)** (optional, default `'ALL'`)
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
### getHolidays()
Returns all holidays of a year in a [Region](#region).
**Parameters**
- `year` **([number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))**
- `region` **[Region](#region)**
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[Holiday](#holiday)>**
+113
View File
@@ -0,0 +1,113 @@
declare type Region =
| 'BW' // Baden-Württemberg
| 'BY' // Bayern
| 'BE' // Berlin
| 'BB' // Brandenburg
| 'HB' // Bremen
| 'HE' // Hessen
| 'HH' // Hamburg
| 'MV' // Mecklenburg-Vorpommern
| 'NI' // Niedersachsen
| 'NW' // Nordrhein-Westfalen
| 'RP' // Rheinland-Pfalz
| 'SL' // Saarland
| 'SN' // Sachsen
| 'ST' // Sachsen-Anhalt
| 'SH' // Schleswig-Holstein
| 'TH' // Thüringen
| 'BUND' // Gesamt-Deutschland
| 'AUGSBURG'
| 'ALL';
declare type Holiday = {
name: HolidayType;
date: Date;
trans?: (lang: string | undefined) => string; // deprecated;
translate: (lang?: string | undefined) => string;
dateString: string;
equals: (date: Date) => boolean;
};
declare type HolidayType =
| 'NEUJAHRSTAG'
| 'HEILIGEDREIKOENIGE'
| 'KARFREITAG'
| 'OSTERSONNTAG'
| 'OSTERMONTAG'
| 'TAG_DER_ARBEIT'
| 'CHRISTIHIMMELFAHRT'
| 'MARIAHIMMELFAHRT'
| 'PFINGSTSONNTAG'
| 'PFINGSTMONTAG'
| 'FRONLEICHNAM'
| 'DEUTSCHEEINHEIT'
| 'REFORMATIONSTAG'
| 'ALLERHEILIGEN'
| 'BUBETAG'
| 'ERSTERWEIHNACHTSFEIERTAG'
| 'ZWEITERWEIHNACHTSFEIERTAG';
/**
* Map of {@link HolidayType} to translation string.
*/
export type TranslationTable = {
[key: string]: string;
};
/**
* adds a translation for the holidays (e.g. english).
* This also allows to override the German names.
* Hint: Interpolates German for missing translations
* @param {string} isoCode of the new language
* @param {TranslationTable} newTranslation map of {HolidayType} to translation stringg
*/
declare function addTranslation(
isoCode: string,
newTranslation: TranslationTable,
): void;
/**
* Set a language to default language
* @param {string} isoCode
*/
declare function setLanguage(isoCode: string): void;
/**
* Get currently set language
* @returns {string}
*/
declare function getLanguage(): string;
// holidays api
/**
* Checks if a specific date is sunday or holiday.
* @param date
* @param region
* @returns {boolean}
*/
declare function isSunOrHoliday(date: Date, region: Region): boolean;
/**
* Check is specific date is holiday.
* @param date
* @param {Region} region two character {@link Region} code
* @returns {boolean}
*/
declare function isHoliday(date: Date, region: Region): boolean;
declare function getHolidayByDate(date: Date, region: Region): Holiday | void;
declare function isSpecificHoliday(
date: Date,
holidayName: HolidayType,
region: Region,
): boolean;
/**
* Returns all holidays of a year in a {@link Region}.
* @param year
* @param region
* @returns {Array.<Holiday>}
*/
declare function getHolidays(year: number | string, region: Region): Holiday[];
+53
View File
@@ -0,0 +1,53 @@
{
"name": "feiertagejs",
"version": "1.3.9",
"description": "A module to calculate German holidays made for node.js",
"type": "module",
"main": "build/feiertage.umd.cjs",
"module": "build/feiertage.js",
"types": "index.d.ts",
"scripts": {
"test": "vitest run --coverage",
"test:w": "vitest watch",
"format": "prettier --write \"{**/*,*}.{ts,json}\" \"!coverage/**\" \"!build/**\" \"!package.json\" \"!package-lock.json\" --cache",
"lint": "eslint \"src\" \"spec\"",
"build": "rollup -c"
},
"repository": {
"type": "git",
"url": "https://github.com/sfakir/feiertagejs"
},
"keywords": [
"node",
"holidays",
"feiertage",
"javascript"
],
"engines": {
"node": ">=8.0.0"
},
"author": "Simon Fakir",
"license": "MIT",
"bugs": {
"url": "https://github.com/sfakir/feiertagejs/issues"
},
"homepage": "https://github.com/sfakir/feiertagejs",
"devDependencies": {
"@vitest/coverage-c8": "^0.26.2",
"prettier": "^2.8.1",
"rollup": "^3.9.0",
"@rollup/plugin-typescript": "^10.0.1",
"typescript": "^4.9.4",
"vitest": "^0.26.2",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.5.0"
},
"files": [
"build",
"docs.md",
"Readme.md",
"index.d.ts"
]
}
+20
View File
@@ -0,0 +1,20 @@
{
"name": "TIF22A_AnwProjekt_B",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"feiertagejs": "^1.3.9"
}
},
"node_modules/feiertagejs": {
"version": "1.3.9",
"resolved": "https://registry.npmjs.org/feiertagejs/-/feiertagejs-1.3.9.tgz",
"integrity": "sha512-tUP+WBv2OWBhPwe3NfqwCtjMq+ym598a42tfqmL0FySswEb9xs96p2iKwqqx+lxKieu1njJBRZKsFm92bJhxZw==",
"engines": {
"node": ">=8.0.0"
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"dependencies": {
"feiertagejs": "^1.3.9"
}
}

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