diff --git a/.idea/sqlDataSources.xml b/.idea/sqlDataSources.xml
index f73128a..ef907f0 100644
--- a/.idea/sqlDataSources.xml
+++ b/.idea/sqlDataSources.xml
@@ -27,9 +27,12 @@
+
+
+
-
+
diff --git a/db/nursingHome.db b/db/nursingHome.db
index 0cdc030..b89b146 100644
Binary files a/db/nursingHome.db and b/db/nursingHome.db differ
diff --git a/src/main/java/de/hitec/nhplus/Main.java b/src/main/java/de/hitec/nhplus/Main.java
index 42d99f8..0a72380 100644
--- a/src/main/java/de/hitec/nhplus/Main.java
+++ b/src/main/java/de/hitec/nhplus/Main.java
@@ -1,11 +1,15 @@
package de.hitec.nhplus;
import de.hitec.nhplus.datastorage.ConnectionBuilder;
+import de.hitec.nhplus.login.LoginController;
+import de.hitec.nhplus.login.User;
+import de.hitec.nhplus.main.MainWindowController;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.TabPane;
+import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.IOException;
@@ -33,13 +37,43 @@ public class Main extends Application {
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
- executeMainApplication();
+ User user = executeLogin();
+ if(user != null){
+ executeMainApplication(user);
+ }
+ }
+
+ /**
+ * Executes the login.
+ * @return User The {@link User} object for the logged-in {@link User}.
+ * Is {@code null}, if the login was not successful,
+ */
+ private User executeLogin() {
+ try {
+
+ FXMLLoader loader = new FXMLLoader(Main.class.getResource("/de/hitec/nhplus/login/LoginView.fxml"));
+ BorderPane pane = loader.load();
+ Scene scene = new Scene(pane);
+ Stage loginStage = new Stage();
+ loginStage.setTitle("NHPlus");
+ loginStage.setScene(scene);
+ loginStage.setResizable(false);
+
+ LoginController controller = loader.getController();
+ controller.initialize(loginStage);
+
+ loginStage.showAndWait();
+ return controller.user;
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ return null;
+ }
}
/**
* Executes the main application.
*/
- private void executeMainApplication() {
+ private void executeMainApplication(User user) {
try {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("/de/hitec/nhplus/main/MainWindowView.fxml"));
TabPane pane = loader.load();
@@ -48,6 +82,10 @@ public class Main extends Application {
this.primaryStage.setTitle("NHPlus");
this.primaryStage.setScene(scene);
this.primaryStage.setResizable(true);
+
+ MainWindowController controller = loader.getController();
+ controller.initialize(user);
+
this.primaryStage.show();
this.primaryStage.setOnCloseRequest(event -> {
diff --git a/src/main/java/de/hitec/nhplus/datastorage/DaoFactory.java b/src/main/java/de/hitec/nhplus/datastorage/DaoFactory.java
index 955c88d..067101a 100644
--- a/src/main/java/de/hitec/nhplus/datastorage/DaoFactory.java
+++ b/src/main/java/de/hitec/nhplus/datastorage/DaoFactory.java
@@ -1,5 +1,6 @@
package de.hitec.nhplus.datastorage;
+import de.hitec.nhplus.login.database.UserDao;
import de.hitec.nhplus.medication.database.MedicationDao;
import de.hitec.nhplus.nurse.database.NurseDao;
import de.hitec.nhplus.patient.database.PatientDao;
@@ -63,4 +64,12 @@ public class DaoFactory {
public MedicationDao createMedicationDAO() {
return new MedicationDao(ConnectionBuilder.getConnection());
}
+
+ /**
+ * @return A new {@link UserDao} instance with a database connection.
+ * @see de.hitec.nhplus.login.User User
+ */
+ public UserDao createUserDAO() {
+ return new UserDao(ConnectionBuilder.getConnection());
+ }
}
diff --git a/src/main/java/de/hitec/nhplus/fixtures/Fixtures.java b/src/main/java/de/hitec/nhplus/fixtures/Fixtures.java
index 51719a3..5897378 100644
--- a/src/main/java/de/hitec/nhplus/fixtures/Fixtures.java
+++ b/src/main/java/de/hitec/nhplus/fixtures/Fixtures.java
@@ -46,6 +46,11 @@ public class Fixtures {
medicationFixture.setupTable(connection);
medicationFixture.load();
+ UserFixture userFixture = new UserFixture(nursesByName);
+ userFixture.dropTable(connection);
+ userFixture.setupTable(connection);
+ userFixture.load();
+
} catch (Exception exception) {
System.out.println(exception.getMessage());
}
diff --git a/src/main/java/de/hitec/nhplus/fixtures/NurseFixture.java b/src/main/java/de/hitec/nhplus/fixtures/NurseFixture.java
index c5d0c0f..3da00ed 100644
--- a/src/main/java/de/hitec/nhplus/fixtures/NurseFixture.java
+++ b/src/main/java/de/hitec/nhplus/fixtures/NurseFixture.java
@@ -54,6 +54,12 @@ public class NurseFixture implements Fixture {
true
));
+ nurses.add(new Nurse(
+ "Maria",
+ "Höller",
+ "666"
+ ));
+
NurseDao dao = DaoFactory.getInstance().createNurseDAO();
for (Nurse nurse : nurses) {
dao.create(nurse);
diff --git a/src/main/java/de/hitec/nhplus/fixtures/UserFixture.java b/src/main/java/de/hitec/nhplus/fixtures/UserFixture.java
new file mode 100644
index 0000000..bb75d7d
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/fixtures/UserFixture.java
@@ -0,0 +1,108 @@
+package de.hitec.nhplus.fixtures;
+
+import de.hitec.nhplus.Main;
+import de.hitec.nhplus.datastorage.DaoFactory;
+import de.hitec.nhplus.login.Permissions;
+import de.hitec.nhplus.login.User;
+import de.hitec.nhplus.login.database.UserDao;
+import de.hitec.nhplus.nurse.Nurse;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.*;
+
+/**
+ * {@link Fixture} for {@link User}.
+ *
+ * @author Dominik Säume
+ */
+public class UserFixture implements Fixture {
+ private static final String SCHEMA = "/de/hitec/nhplus/login/database/User.sql";
+ private static final String PERMISSION_SCHEMA = "/de/hitec/nhplus/login/database/UserPermission.sql";
+ private static final String TO_NURSE_SCHEMA = "/de/hitec/nhplus/login/database/UserToNurse.sql";
+
+ private final Map nursesByName;
+
+ public UserFixture(Map nursesByName) {
+ this.nursesByName = nursesByName;
+ }
+
+ @Override
+ public void dropTable(Connection connection) throws SQLException {
+ connection.createStatement().execute("DROP TABLE IF EXISTS user");
+ connection.createStatement().execute("DROP TABLE IF EXISTS user__permissions");
+ connection.createStatement().execute("DROP TABLE IF EXISTS user__nurse");
+ }
+
+ @Override
+ public void setupTable(Connection connection) throws SQLException {
+ final InputStream schema = Main.class.getResourceAsStream(SCHEMA);
+ final InputStream permissionSchema = Main.class.getResourceAsStream(PERMISSION_SCHEMA);
+ final InputStream toNurseSchema = Main.class.getResourceAsStream(TO_NURSE_SCHEMA);
+
+ assert schema != null;
+ assert permissionSchema != null;
+ assert toNurseSchema != null;
+
+ String SQL = new Scanner(schema, StandardCharsets.UTF_8)
+ .useDelimiter("\\A")
+ .next();
+ String permissionSQL = new Scanner(permissionSchema, StandardCharsets.UTF_8)
+ .useDelimiter("\\A")
+ .next();
+ String toNurseSQL = new Scanner(toNurseSchema, StandardCharsets.UTF_8)
+ .useDelimiter("\\A")
+ .next();
+
+ connection.createStatement().execute(SQL);
+ connection.createStatement().execute(permissionSQL);
+ connection.createStatement().execute(toNurseSQL);
+ }
+
+ @Override
+ public Map load() throws SQLException {
+ List users = new ArrayList<>();
+
+ User udo = new User(
+ "udo",
+ Permissions.OWNER,
+ null
+ );
+ udo.setPassword("uD0_187!");
+ users.add(udo);
+
+ User maria = new User(
+ "maria",
+ Permissions.NURSE,
+ nursesByName.get("Maria")
+ );
+ maria.setPassword("H!mm3lf4hrt");
+ users.add(maria);
+
+ User werner = new User(
+ "werner",
+ Permissions.MANAGEMENT,
+ null
+ );
+ werner.setPassword("TurboSchraube42!");
+ users.add(werner);
+
+ User fullPermissionsTestUser = new User(
+ "test",
+ -1,
+ null
+ );
+ fullPermissionsTestUser.setPassword("");
+ users.add(fullPermissionsTestUser);
+
+ UserDao dao = DaoFactory.getInstance().createUserDAO();
+ Map usersByUsername = new HashMap<>();
+ for (User user : users) {
+ dao.create(user);
+ usersByUsername.put(user.getUsername(), user);
+ }
+ return usersByUsername;
+ }
+}
diff --git a/src/main/java/de/hitec/nhplus/login/LoginController.java b/src/main/java/de/hitec/nhplus/login/LoginController.java
new file mode 100644
index 0000000..29cad23
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/login/LoginController.java
@@ -0,0 +1,104 @@
+package de.hitec.nhplus.login;
+
+import de.hitec.nhplus.datastorage.DaoFactory;
+import de.hitec.nhplus.login.database.UserDao;
+import javafx.animation.PauseTransition;
+import javafx.animation.TranslateTransition;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.TextField;
+import javafx.stage.Stage;
+import javafx.util.Duration;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.sql.SQLException;
+import java.util.Arrays;
+
+/**
+ * Controller for handling the login of {@link User}s.
+ *
+ * @author Dominik Säume
+ */
+public class LoginController {
+
+ public User user;
+ @FXML
+ public TextField textFieldUsername;
+ @FXML
+ public PasswordField passwordField;
+ @FXML
+ public Button buttonSubmit;
+ private Stage stage;
+ private int loginTries = 0;
+
+ /**
+ * JavaFX Initialization method that is called after the binding of all the fields.
+ *
+ * @param stage The {@link Stage}, so the modal can close itself, when finished.
+ */
+ public void initialize(Stage stage) {
+ this.stage = stage;
+ }
+
+ /**
+ * Internal method to handle actions on wrong logins, like a shake, timout and total tries.
+ */
+ private void handleWrongPasswordOrUsername() {
+ loginTries++;
+
+ // Shake
+ TranslateTransition ttUsername = new TranslateTransition(Duration.millis(50), textFieldUsername);
+ ttUsername.setByX(10);
+ ttUsername.setAutoReverse(true);
+ ttUsername.setCycleCount(6);
+
+ TranslateTransition ttPassword = new TranslateTransition(Duration.millis(50), passwordField);
+ ttPassword.setByX(10);
+ ttPassword.setAutoReverse(true);
+ ttPassword.setCycleCount(6);
+
+ ttUsername.play();
+ ttPassword.play();
+
+ // Timout
+ PauseTransition pause = new PauseTransition(Duration.seconds(3));
+ pause.setOnFinished(event -> {
+ if (loginTries == 3) {
+ stage.close();
+ }
+ buttonSubmit.setDisable(false);
+ });
+ pause.play();
+
+ }
+
+ @FXML
+ public void handleSubmit() {
+ buttonSubmit.setDisable(true);
+
+ UserDao dao = DaoFactory.getInstance().createUserDAO();
+ try {
+ int id = dao.readUserId(textFieldUsername.getText());
+ if (id == 0) {
+ handleWrongPasswordOrUsername();
+ return;
+ }
+ byte[] salt = dao.readPasswordSalt(id);
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+ md.update(salt);
+ byte[] hash = md.digest(passwordField.getText().getBytes(StandardCharsets.UTF_8));
+ byte[] requiredHash = dao.readPasswordHash(id);
+ if (!Arrays.equals(hash, requiredHash)) {
+ handleWrongPasswordOrUsername();
+ return;
+ }
+ user = dao.read(id);
+ stage.close();
+ } catch (SQLException | NoSuchAlgorithmException exception) {
+ exception.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/de/hitec/nhplus/login/Permissions.java b/src/main/java/de/hitec/nhplus/login/Permissions.java
new file mode 100644
index 0000000..2f53369
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/login/Permissions.java
@@ -0,0 +1,14 @@
+package de.hitec.nhplus.login;
+
+/**
+ * A simple class holding the bitmasks for all permissions.
+ * This is a class instead of an enum, for ease of use.
+ *
+ * @author Dominiok Säume
+ */
+public class Permissions {
+ public final static int EVERYBODY = 0b0;
+ public final static int NURSE = 0b1;
+ public final static int MANAGEMENT = 0b10;
+ public final static int OWNER = 0b100;
+}
diff --git a/src/main/java/de/hitec/nhplus/login/User.java b/src/main/java/de/hitec/nhplus/login/User.java
new file mode 100644
index 0000000..b58e6f2
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/login/User.java
@@ -0,0 +1,120 @@
+package de.hitec.nhplus.login;
+
+import de.hitec.nhplus.nurse.Nurse;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+
+/**
+ * The model for a {@link User}.
+ *
+ * @author Dominik Säume
+ */
+public class User {
+
+ private int id;
+ private String username;
+ private byte[] passwordSalt;
+ private byte[] passwordHash;
+ private int permissions = 0;
+ private Nurse nurse;
+
+
+ /**
+ * This constructor allows instantiating a {@link User} object with all existing fields.
+ */
+ public User(
+ int id,
+ String username,
+ byte[] passwordSalt,
+ byte[] passwordHash,
+ int permissions,
+ Nurse nurse
+ ) {
+ this.id = id;
+ this.username = username;
+ this.passwordSalt = passwordSalt;
+ this.passwordHash = passwordHash;
+ this.permissions = permissions;
+ this.nurse = nurse;
+ }
+
+ /**
+ * This constructor allows instantiating a {@link User} object.
+ */
+ public User(
+ String username,
+ int permissions,
+ Nurse nurse
+ ) {
+ this.username = username;
+ this.permissions = permissions;
+ this.nurse = nurse;
+ }
+
+ /**
+ * Sets the {@link User} password. The {@link User} will need to be manually stored with the
+ * {@link de.hitec.nhplus.login.database.UserDao UserDao}, for changes to persists.
+ * @param password The new Password
+ */
+ public void setPassword(String password) {
+ try {
+ SecureRandom random = new SecureRandom();
+ byte[] salt = new byte[32];
+ random.nextBytes(salt);
+ this.passwordSalt = salt;
+ MessageDigest md = MessageDigest.getInstance("SHA-512");
+ md.update(salt);
+ this.passwordHash = md.digest(password.getBytes(StandardCharsets.UTF_8));
+ }catch (NoSuchAlgorithmException exception){
+ exception.printStackTrace();
+ }
+ }
+
+ public boolean hasNursePermissions(){
+ return (permissions & Permissions.NURSE) != 0;
+ }
+
+ public boolean hasAdminPermissions(){
+ return (permissions & Permissions.MANAGEMENT) != 0;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public byte[] getPasswordSalt() {
+ return passwordSalt;
+ }
+
+ public byte[] getPasswordHash() {
+ return passwordHash;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public int getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(int permissions) {
+ this.permissions = permissions;
+ }
+
+ public Nurse getNurse() {
+ return nurse;
+ }
+
+ public void setNurse(Nurse nurse) {
+ this.nurse = nurse;
+ }
+}
diff --git a/src/main/java/de/hitec/nhplus/login/database/UserDao.java b/src/main/java/de/hitec/nhplus/login/database/UserDao.java
new file mode 100644
index 0000000..221d36a
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/login/database/UserDao.java
@@ -0,0 +1,232 @@
+package de.hitec.nhplus.login.database;
+
+import de.hitec.nhplus.datastorage.Dao;
+import de.hitec.nhplus.datastorage.DaoFactory;
+import de.hitec.nhplus.login.User;
+import de.hitec.nhplus.nurse.Nurse;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The {@link UserDao} is an implementation of the{@link de.hitec.nhplus.datastorage.Dao Dao}
+ * for the {@link User} model.
+ *
+ * @author Dominik Säume
+ */
+public class UserDao implements Dao {
+ protected final Connection connection;
+
+ public UserDao(Connection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Try reading a {@link User#id} by its {@link User#username}.
+ * @param username The {@link User#username username} to try reading the {@link User#id id} of.
+ * @return The {@link User#id}. {@code 0} if the {@link User} doesn't exist.
+ */
+ public int readUserId(String username) throws SQLException {
+ final String SQL = "SELECT id FROM user WHERE username = ?";
+ PreparedStatement statement = this.connection.prepareStatement(SQL);
+ statement.setString(1, username);
+ return statement.executeQuery().getInt(1);
+ }
+
+ /**
+ * Read a {@link User}s {@link User#passwordSalt password salt}.
+ * @param id The {@link User#id} of which the {@link User#passwordSalt password salt} should be read.
+ * @return The {@link User#passwordSalt password salt} as a{@code byte[]}.
+ */
+ public byte[] readPasswordSalt(int id) throws SQLException {
+ final String SQL = "SELECT passwordSalt FROM user WHERE id = ?";
+ PreparedStatement statement = this.connection.prepareStatement(SQL);
+ statement.setInt(1, id);
+ return statement.executeQuery().getBytes(1);
+ }
+
+ /**
+ * Read a {@link User}s {@link User#passwordHash password hash} for authentication purposes.
+ * @param id The {@link User#id} of which the {@link User#passwordHash password hash} should be read.
+ * @return The {@link User#passwordHash password hash} as a{@code byte[]}.
+ */
+ public byte[] readPasswordHash(int id) throws SQLException {
+ final String SQL = "SELECT passwordHash FROM user WHERE id = ?";
+ PreparedStatement statement = this.connection.prepareStatement(SQL);
+ statement.setInt(1, id);
+ return statement.executeQuery().getBytes(1);
+ }
+
+ @Override
+ public User read(int id) throws SQLException {
+ final String SQL = """
+ SELECT
+ user.username,
+ user.passwordSalt,
+ user.passwordHash,
+ user__permissions.permissions,
+ user__nurse.nurseId
+ FROM user
+ LEFT JOIN user__permissions ON user.id = user__permissions.userId
+ LEFT JOIN user__nurse ON user.id = user__nurse.userId
+ WHERE user.id = ?;
+ """;
+ PreparedStatement statement = this.connection.prepareStatement(SQL);
+ statement.setInt(1, id);
+ ResultSet result = statement.executeQuery();
+ int nurseId = result.getInt(5);
+ Nurse nurse = null;
+ if (!result.wasNull()) {
+ nurse = DaoFactory.getInstance().createNurseDAO().read(nurseId);
+ }
+ return new User(
+ id,
+ result.getString(1),
+ result.getBytes(2),
+ result.getBytes(3),
+ result.getInt(4),
+ nurse
+ );
+ }
+
+ @Override
+ public void create(User user) throws SQLException {
+ connection.setAutoCommit(false); //Switch to Manual Commit, to do an SQL Transaction
+ final String userSQL = """
+ INSERT INTO user
+ (username, passwordSalt, passwordHash)
+ VALUES (?, ?, ?);
+ """;
+ PreparedStatement statement = this.connection.prepareStatement(userSQL);
+ statement.setString(1, user.getUsername());
+ statement.setBytes(2, user.getPasswordSalt());
+ statement.setBytes(3, user.getPasswordHash());
+ statement.execute();
+
+ ResultSet generatedKeys = connection.createStatement().executeQuery("SELECT last_insert_rowid()");
+ connection.commit(); //Finish SQL Transaction
+ connection.setAutoCommit(true); //Switch back Mode
+
+ if (!generatedKeys.next()) {
+ return;
+ }
+ int newId = generatedKeys.getInt(1);
+
+ final String permissionSQL = """
+ INSERT INTO user__permissions
+ (userId, permissions)
+ VALUES (?, ?);
+ """;
+ PreparedStatement permissionStatement = this.connection.prepareStatement(permissionSQL);
+ permissionStatement.setInt(1, newId);
+ permissionStatement.setInt(2, user.getPermissions());
+ permissionStatement.execute();
+
+ if (user.getNurse() == null) {
+ return;
+ }
+ final String nurseSQL = """
+ INSERT INTO user__nurse
+ (userId, nurseId)
+ VALUES (?, ?);
+ """;
+ PreparedStatement nurseStatement = this.connection.prepareStatement(nurseSQL);
+ nurseStatement.setInt(1, newId);
+ nurseStatement.setInt(2, user.getNurse().getId());
+ nurseStatement.execute();
+ }
+
+ @Override
+ public void update(User user) throws SQLException {
+ final String userSQL = """
+ UPDATE user SET
+ username = ?,
+ passwordSalt = ?,
+ passwordHash = ?
+ WHERE id = ?
+ """;
+ PreparedStatement statement = this.connection.prepareStatement(userSQL);
+ statement.setString(1, user.getUsername());
+ statement.setBytes(2, user.getPasswordSalt());
+ statement.setBytes(3, user.getPasswordHash());
+ statement.setInt(3, user.getId());
+ statement.executeUpdate();
+
+ final String permissionSQL = """
+ UPDATE user__permissions SET
+ permissions = ?
+ WHERE userId = ?
+ """;
+ PreparedStatement permissionStatement = this.connection.prepareStatement(permissionSQL);
+ permissionStatement.setInt(1, user.getPermissions());
+ permissionStatement.setInt(2, user.getId());
+ permissionStatement.executeUpdate();
+
+ if (user.getNurse() == null) {
+ final String nurseSQL = """
+ DELETE FROM user__nurse WHERE userId = ?
+ """;
+ this.connection.prepareStatement(nurseSQL).executeUpdate();
+ return;
+ }
+
+ final String nurseSQL = """
+ UPDATE user__nurse set
+ nurseId = ?
+ WHERE userId = ?
+ """;
+ PreparedStatement nurseStatement = this.connection.prepareStatement(nurseSQL);
+ nurseStatement.setInt(1, user.getNurse().getId());
+ nurseStatement.setInt(2, user.getId());
+ permissionStatement.executeUpdate();
+ }
+
+ @Override
+ public void delete(int id) throws SQLException {
+ final String SQL = """
+ DELETE FROM user WHERE user.id = ?;
+ """;
+ PreparedStatement preparedStatement = this.connection.prepareStatement(SQL);
+ preparedStatement.setInt(1, id);
+ preparedStatement.executeUpdate();
+ }
+
+ @Override
+ public List readAll() throws SQLException {
+ final String SQL = """
+ SELECT
+ user.id,
+ user.username,
+ user.passwordSalt,
+ user.passwordHash,
+ user__permissions.permissions,
+ user__nurse.nurseId
+ FROM user
+ LEFT JOIN user__permissions ON user.id = user__permissions.userId
+ LEFT JOIN user__nurse ON user.id = user__nurse.userId
+ """;
+ ResultSet result = connection.prepareStatement(SQL).executeQuery();
+
+ List users = new ArrayList<>();
+ while (result.next()) {
+ int nurseId = result.getInt(6);
+ Nurse nurse = null;
+ if (!result.wasNull()) {
+ nurse = DaoFactory.getInstance().createNurseDAO().read(nurseId);
+ }
+ users.add(new User(
+ result.getInt(1),
+ result.getString(2),
+ result.getBytes(3),
+ result.getBytes(4),
+ result.getInt(5),
+ nurse
+ ));
+ }
+ return users;
+ }
+}
diff --git a/src/main/java/de/hitec/nhplus/main/MainWindowController.java b/src/main/java/de/hitec/nhplus/main/MainWindowController.java
index 5b7b4e4..c402020 100644
--- a/src/main/java/de/hitec/nhplus/main/MainWindowController.java
+++ b/src/main/java/de/hitec/nhplus/main/MainWindowController.java
@@ -1,224 +1,98 @@
package de.hitec.nhplus.main;
-import de.hitec.nhplus.Main;
-import de.hitec.nhplus.nurse.Nurse;
+import de.hitec.nhplus.login.Permissions;
+import de.hitec.nhplus.login.User;
+import de.hitec.nhplus.utils.tab.TabManager;
+import de.hitec.nhplus.utils.tab.TabStruct;
+import javafx.event.Event;
import javafx.fxml.FXML;
-import javafx.fxml.FXMLLoader;
-import javafx.scene.control.SelectionModel;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
-import javafx.scene.layout.AnchorPane;
-import javafx.scene.layout.BorderPane;
-import de.hitec.nhplus.treatment.Treatment;
-import de.hitec.nhplus.medication.Medication;
-import de.hitec.nhplus.patient.Patient;
-import java.io.IOException;
-import java.util.Objects;
+import java.util.List;
/**
* Controller for the main window of the application, which holds all tabs.
*
- * @author Bernd Heidemann
* @author Dominik Säume
- * @author Armin Ribic
- * @author Dorian Nemec
*/
public class MainWindowController {
+ private static MainWindowController instace;
@FXML
- private TabPane mainTabPane;
- @FXML
- private AnchorPane patientPage;
- @FXML
- private Tab patientTab;
- @FXML
- private AnchorPane activeTreatmentPage;
- @FXML
- private Tab treatmentTab;
- @FXML
- private TabPane treatmentTabPane;
- @FXML
- private Tab activeTreatmentTab;
- @FXML
- private AnchorPane lockedTreatmentPage;
- @FXML
- private Tab lockedTreatmentTab;
- @FXML
- private Tab nurseTab;
- @FXML
- private TabPane nurseTabPane;
- @FXML
- private AnchorPane activeNursePage;
- @FXML
- private Tab activeNurseTab;
- @FXML
- private AnchorPane lockedNursePage;
- @FXML
- private Tab lockedNurseTab;
- @FXML
- private AnchorPane medicationPage;
- @FXML
- private Tab medicationTab;
-
- /**
- * Initialization method that is called after the binding of all the fields.
- */
- @FXML
- public void initialize() {
- loadPatientPage();
- mainTabPane.getSelectionModel().select(patientTab);
-
- patientTab.setOnSelectionChanged(event -> loadPatientPage());
- medicationTab.setOnSelectionChanged(event -> loadMedicationPage());
-
-
- nurseTab.setOnSelectionChanged(event -> loadNursePage());
- nurseTabPane.getSelectionModel().select(activeNurseTab);
-
- activeNurseTab.setOnSelectionChanged(event -> loadActiveNursePage());
- lockedNurseTab.setOnSelectionChanged(event -> loadLockedNursePage());
-
- treatmentTab.setOnSelectionChanged(event -> loadTreatmentPage());
- treatmentTabPane.getSelectionModel().select(activeTreatmentTab);
-
- activeTreatmentTab.setOnSelectionChanged(event -> loadActiveTreatmentPage());
- lockedTreatmentTab.setOnSelectionChanged(event -> loadLockedTreatmentPage());
+ public TabPane mainTabPane;
+ private User user;
+ private TabManager tabManager;
+ public MainWindowController() {
+ instace = this;
}
/**
- * Loads the {@link Patient} page into its tab.
+ * Method copying the idea of a singleton, to allow getting the current {@link User}.
*/
- private void loadPatientPage() {
- try {
- BorderPane patientsPane = FXMLLoader.load(
- Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/patient/AllPatientView.fxml"))
- );
- patientPage.getChildren().setAll(patientsPane);
- AnchorPane.setTopAnchor(patientsPane, 0d);
- AnchorPane.setBottomAnchor(patientsPane, 0d);
- AnchorPane.setLeftAnchor(patientsPane, 0d);
- AnchorPane.setRightAnchor(patientsPane, 0d);
- } catch (IOException exception) {
- exception.printStackTrace();
- }
+ public static MainWindowController getInstance() {
+ return instace;
}
/**
- * Loads the {@link Treatment } tab.
+ * JavaFX Initialization method that is called after the binding of all the fields.
+ *
+ * @param user The logged in {@link User}.
*/
- private void loadTreatmentPage() {
- SelectionModel selectionModel = treatmentTabPane.getSelectionModel();
- Tab selectedTab = selectionModel.getSelectedItem();
- if (selectedTab == activeTreatmentTab) {
- loadActiveTreatmentPage();
- }
- if (selectedTab == lockedTreatmentTab) {
- loadLockedTreatmentPage();
- }
+ @FXML
+ public void initialize(User user) {
+ instace = this;
+ this.user = user;
+ this.tabManager = new TabManager(user);
+ setupTabs();
}
/**
- * Loads the active {@link Treatment} page into its tab.
+ * Sets up all Tabs Accessible, with help of the {@link TabManager}.
*/
- private void loadActiveTreatmentPage() {
- try {
- BorderPane activeTreatmentPane = FXMLLoader.load(
- Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/treatment/AllTreatmentView.fxml"))
- );
- activeTreatmentPage.getChildren().setAll(activeTreatmentPane);
- AnchorPane.setTopAnchor(activeTreatmentPane, 0d);
- AnchorPane.setBottomAnchor(activeTreatmentPane, 0d);
- AnchorPane.setLeftAnchor(activeTreatmentPane, 0d);
- AnchorPane.setRightAnchor(activeTreatmentPane, 0d);
- } catch (IOException exception) {
- exception.printStackTrace();
- }
+ private void setupTabs() {
+ tabManager.setupTab(mainTabPane, new TabStruct(
+ "Patienten",
+ "/de/hitec/nhplus/patient/AllPatientView.fxml",
+ Permissions.NURSE
+ ));
+ tabManager.setupSubTabPane(mainTabPane, "Behandlungen", Permissions.NURSE, List.of(
+ new TabStruct(
+ "Behandlungen",
+ "/de/hitec/nhplus/treatment/AllTreatmentView.fxml",
+ Permissions.NURSE
+ ),
+ new TabStruct(
+ "Gesperrte Behandlungen",
+ "/de/hitec/nhplus/treatment/LockedTreatmentView.fxml",
+ Permissions.NURSE
+ )
+ ));
+ tabManager.setupSubTabPane(mainTabPane, "Pfleger", Permissions.EVERYBODY, List.of(
+ new TabStruct(
+ "Pfleger",
+ "/de/hitec/nhplus/nurse/AllNurseView.fxml",
+ Permissions.NURSE | Permissions.MANAGEMENT | Permissions.OWNER
+ ),
+ new TabStruct(
+ "Gesperrte Pfleger",
+ "/de/hitec/nhplus/nurse/LockedNurseView.fxml",
+ Permissions.MANAGEMENT | Permissions.OWNER
+ )
+ ));
+ tabManager.setupTab(mainTabPane, new TabStruct(
+ "Medikamente",
+ "/de/hitec/nhplus/medication/AllMedicationView.fxml",
+ Permissions.MANAGEMENT
+ ));
+
+
+ Tab defaultTab = mainTabPane.getTabs().get(0);
+ mainTabPane.getSelectionModel().select(defaultTab);
+ defaultTab.getOnSelectionChanged().handle(new Event(Event.ANY));
}
- /**
- * Loads the locked {@link Treatment} page into its tab.
- */
- private void loadLockedTreatmentPage() {
- try {
- BorderPane treatmentsPane = FXMLLoader.load(
- Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/treatment/LockedTreatmentView.fxml"))
- );
- lockedTreatmentPage.getChildren().setAll(treatmentsPane);
- AnchorPane.setTopAnchor(treatmentsPane, 0d);
- AnchorPane.setBottomAnchor(treatmentsPane, 0d);
- AnchorPane.setLeftAnchor(treatmentsPane, 0d);
- AnchorPane.setRightAnchor(treatmentsPane, 0d);
- } catch (IOException exception) {
- exception.printStackTrace();
- }
- }
-
- /**
- * Loads the {@link Nurse} page into its tab.
- */
- private void loadNursePage() {
- SelectionModel selectionModel = nurseTabPane.getSelectionModel();
- Tab selectedTab = selectionModel.getSelectedItem();
- if (selectedTab == activeNurseTab) {
- loadActiveNursePage();
- }
- if (selectedTab == lockedNurseTab) {
- loadLockedNursePage();
- }
- }
-
- /**
- * Loads the active {@link Nurse} page into its tab.
- */
- private void loadActiveNursePage() {
- try {
- BorderPane activeNursePane = FXMLLoader.load(
- Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/nurse/AllNurseView.fxml"))
- );
- activeNursePage.getChildren().setAll(activeNursePane);
- AnchorPane.setTopAnchor(activeNursePane, 0d);
- AnchorPane.setBottomAnchor(activeNursePane, 0d);
- AnchorPane.setLeftAnchor(activeNursePane, 0d);
- AnchorPane.setRightAnchor(activeNursePane, 0d);
- } catch (IOException exception) {
- exception.printStackTrace();
- }
- }
-
- /**
- * Loads the locked {@link Nurse} page into its tab.
- */
- private void loadLockedNursePage() {
- try {
- BorderPane lockedNursePane = FXMLLoader.load(
- Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/nurse/LockedNurseView.fxml"))
- );
- lockedNursePage.getChildren().setAll(lockedNursePane);
- AnchorPane.setTopAnchor(lockedNursePane, 0d);
- AnchorPane.setBottomAnchor(lockedNursePane, 0d);
- AnchorPane.setLeftAnchor(lockedNursePane, 0d);
- AnchorPane.setRightAnchor(lockedNursePane, 0d);
- } catch (IOException exception) {
- exception.printStackTrace();
- }
- }
-
- /**
- * Loads the {@link Medication} page into its tab.
- */
- private void loadMedicationPage() {
- try {
- BorderPane medicationPane = FXMLLoader.load(
- Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/medication/AllMedicationView.fxml"))
- );
- medicationPage.getChildren().setAll(medicationPane);
- AnchorPane.setTopAnchor(medicationPane, 0d);
- AnchorPane.setBottomAnchor(medicationPane, 0d);
- AnchorPane.setLeftAnchor(medicationPane, 0d);
- AnchorPane.setRightAnchor(medicationPane, 0d);
- } catch (IOException exception) {
- exception.printStackTrace();
- }
+ public User getUser() {
+ return user;
}
}
diff --git a/src/main/java/de/hitec/nhplus/nurse/AllNurseController.java b/src/main/java/de/hitec/nhplus/nurse/AllNurseController.java
index 6f72582..cf9dfa2 100644
--- a/src/main/java/de/hitec/nhplus/nurse/AllNurseController.java
+++ b/src/main/java/de/hitec/nhplus/nurse/AllNurseController.java
@@ -1,8 +1,8 @@
package de.hitec.nhplus.nurse;
-import static de.hitec.nhplus.utils.Validator.*;
-
import de.hitec.nhplus.datastorage.DaoFactory;
+import de.hitec.nhplus.login.Permissions;
+import de.hitec.nhplus.main.MainWindowController;
import de.hitec.nhplus.nurse.database.NurseDao;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
@@ -17,6 +17,8 @@ import javafx.scene.control.cell.TextFieldTableCell;
import java.sql.SQLException;
+import static de.hitec.nhplus.utils.Validator.*;
+
/**
* The controller for viewing all {@link Nurse}s.
*
@@ -49,12 +51,17 @@ public class AllNurseController {
private final ObservableList nurses = FXCollections.observableArrayList();
private NurseDao dao;
+ private boolean hasEditPermissions;
/**
* Initialization method that is called after the binding of all the fields.
*/
@FXML
public void initialize() {
+ int editPermissions = Permissions.MANAGEMENT | Permissions.OWNER;
+ int userPermissions = MainWindowController.getInstance().getUser().getPermissions();
+ hasEditPermissions = (userPermissions & editPermissions) != 0;
+
this.readAllAndShowInTableView();
this.columnId.setCellValueFactory(new PropertyValueFactory<>("id"));
@@ -71,12 +78,18 @@ public class AllNurseController {
this.tableView.setItems(this.nurses);
+
this.buttonAdd.setDisable(true);
- ChangeListener inputNewNurseValidationListener = (observableValue, oldText, newText)->
+ if (!hasEditPermissions) {
+ this.buttonLock.setDisable(true);
+ return;
+ }
+
+ ChangeListener inputNewNurseValidationListener = (observableValue, oldText, newText) ->
{
boolean isValid = isValidFirstName(this.textFieldFirstName.getText())
- && isValidSurName(this.textFieldSurName.getText())
- && isValidPhoneNumber(this.textFieldPhoneNumber.getText());
+ && isValidSurName(this.textFieldSurName.getText())
+ && isValidPhoneNumber(this.textFieldPhoneNumber.getText());
AllNurseController.this.buttonAdd.setDisable(!isValid);
};
@@ -89,12 +102,12 @@ public class AllNurseController {
/**
* Internal method to read all data and set it to the table view.
*/
- private void readAllAndShowInTableView(){
+ private void readAllAndShowInTableView() {
this.nurses.clear();
this.dao = DaoFactory.getInstance().createNurseDAO();
try {
this.nurses.setAll(this.dao.readAllActive());
- }catch (SQLException exception){
+ } catch (SQLException exception) {
exception.printStackTrace();
}
}
@@ -120,14 +133,13 @@ public class AllNurseController {
}
@FXML
- public void handleAdd(){
- String surname=this.textFieldSurName.getText();
- String firstName=this.textFieldFirstName.getText();
- String phoneNumber=this.textFieldPhoneNumber.getText();
+ public void handleAdd() {
+ String surname = this.textFieldSurName.getText();
+ String firstName = this.textFieldFirstName.getText();
+ String phoneNumber = this.textFieldPhoneNumber.getText();
try {
this.dao.create(new Nurse(firstName, surname, phoneNumber));
- }
- catch (SQLException exception){
+ } catch (SQLException exception) {
exception.printStackTrace();
}
readAllAndShowInTableView();
@@ -135,16 +147,16 @@ public class AllNurseController {
}
@FXML
- public void handleLock(){
+ public void handleLock() {
Nurse selectedItem = this.tableView.getSelectionModel().getSelectedItem();
- if (selectedItem == null){
+ if (selectedItem == null) {
return;
}
try {
selectedItem.setLocked(true);
this.dao.update(selectedItem);
- }catch (SQLException exception){
+ } catch (SQLException exception) {
exception.printStackTrace();
}
readAllAndShowInTableView();
@@ -152,6 +164,10 @@ public class AllNurseController {
@FXML
public void handleOnEditSurname(TableColumn.CellEditEvent event) {
+ if(!hasEditPermissions){
+ event.getTableView().refresh();
+ return;
+ }
String newSurName = event.getNewValue();
if (!isValidSurName(newSurName)) {
showValidationError("Nachname");
@@ -164,6 +180,10 @@ public class AllNurseController {
@FXML
public void handleOnEditFirstname(TableColumn.CellEditEvent event) {
+ if(!hasEditPermissions){
+ event.getTableView().refresh();
+ return;
+ }
String newFirstName = event.getNewValue();
if (!isValidFirstName(newFirstName)) {
showValidationError("Vorname");
@@ -176,6 +196,10 @@ public class AllNurseController {
@FXML
public void handleOnEditPhoneNumber(TableColumn.CellEditEvent event) {
+ if(!hasEditPermissions){
+ event.getTableView().refresh();
+ return;
+ }
String newPhoneNumber = event.getNewValue();
if (!isValidPhoneNumber(newPhoneNumber)) {
showValidationError("Telefonnummer");
diff --git a/src/main/java/de/hitec/nhplus/nurse/Nurse.java b/src/main/java/de/hitec/nhplus/nurse/Nurse.java
index 22c4b49..7fa94b9 100644
--- a/src/main/java/de/hitec/nhplus/nurse/Nurse.java
+++ b/src/main/java/de/hitec/nhplus/nurse/Nurse.java
@@ -44,7 +44,7 @@ public class Nurse extends Person {
/**
* This constructor allows instantiating a {@link Nurse} object with
- * specifying if the nurse is locked or not.
+ * specifying whether the {@link Nurse} is locked or not.
*/
public Nurse(
String firstName,
diff --git a/src/main/java/de/hitec/nhplus/utils/tab/TabManager.java b/src/main/java/de/hitec/nhplus/utils/tab/TabManager.java
new file mode 100644
index 0000000..7a872a8
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/utils/tab/TabManager.java
@@ -0,0 +1,114 @@
+package de.hitec.nhplus.utils.tab;
+
+import de.hitec.nhplus.Main;
+import de.hitec.nhplus.login.Permissions;
+import de.hitec.nhplus.login.User;
+import javafx.event.Event;
+import javafx.event.EventHandler;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.BorderPane;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A utility class to construct {@link Tab}s from views. This also supports sub {@link Tab}s.
+ *
+ * @author Dominiok Säume
+ * @see TabManager
+ */
+public class TabManager {
+ private final User user;
+
+ public TabManager(User user) {
+ this.user = user;
+ }
+
+ /**
+ * Internal method to check permissions
+ * @param requiredPermissions The permissions the {@link User} requires.
+ * @param permissions The permissions the {@link User} has.
+ */
+ private boolean hasPermissions(int requiredPermissions, int permissions) {
+ return requiredPermissions == Permissions.EVERYBODY
+ || (permissions & requiredPermissions) != 0;
+ }
+
+ /**
+ * Method to set up a single tab and register it to its {@link TabPane}.
+ * @param tabPane The {@link TabPane} to register to.
+ * @param tabStruct The data needed to construct the new tab.
+ */
+ public void setupTab(TabPane tabPane, TabStruct tabStruct) {
+ if (!hasPermissions(tabStruct.requiredPermissions, user.getPermissions())) {
+ return;
+ }
+ Tab tab = new Tab();
+ tab.setText(tabStruct.title);
+ AnchorPane pane = new AnchorPane();
+ tab.setContent(pane);
+ tab.setOnSelectionChanged(loadTabEventHandler(tabStruct, pane));
+ tabPane.getTabs().add(tab);
+ }
+
+ /**
+ * {@link EventHandler} to handle the loading of a {@link Tab}.
+ * @param tabStruct The {@link TabStruct} holding the path of the view.
+ * @param pane The main pane of the {@link Tab}.
+ */
+ private EventHandler loadTabEventHandler(TabStruct tabStruct, AnchorPane pane) {
+ return event -> {
+ try {
+ BorderPane patientsPane = FXMLLoader.load(
+ Objects.requireNonNull(Main.class.getResource(tabStruct.view))
+ );
+ pane.getChildren().setAll(patientsPane);
+ AnchorPane.setTopAnchor(patientsPane, 0d);
+ AnchorPane.setBottomAnchor(patientsPane, 0d);
+ AnchorPane.setLeftAnchor(patientsPane, 0d);
+ AnchorPane.setRightAnchor(patientsPane, 0d);
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ }
+ };
+ }
+
+ /**
+ * Method to set up a sub tab and register it to its parent {@link TabPane}.
+ * @param parentTabPane The {@link TabPane} to register to.
+ * @param title The title of the {@link Tab}.
+ * @param requiredPermissions The permissions required to see the sub {@link Tab}.
+ * @param subTabs A {@link List} of {@link TabStruct}s to create in the sub {@link Tab}.
+ */
+ public void setupSubTabPane(TabPane parentTabPane, String title, int requiredPermissions, List subTabs) {
+ if (!hasPermissions(requiredPermissions, user.getPermissions())) {
+ return;
+ }
+ Tab tab = new Tab();
+ tab.setText(title);
+ TabPane subTabPane = new TabPane();
+ subTabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
+ tab.setContent(subTabPane);
+ subTabs.forEach(tabStruct -> setupTab(subTabPane, tabStruct));
+ if (subTabPane.getTabs().isEmpty()) {
+ return;
+ }
+ tab.setOnSelectionChanged(loadSubTabPaneEventHandler(subTabPane));
+ parentTabPane.getTabs().add(tab);
+ }
+
+ /**
+ * {@link EventHandler} to handle the loading of a sub {@link TabPane}.
+ * @param tabPane The {@link TabPane} of the sub {@link Tab} to handle loading.
+ */
+ private EventHandler loadSubTabPaneEventHandler(TabPane tabPane) {
+ return event -> {
+ Tab tab = tabPane.getSelectionModel().getSelectedItem();
+ tab.getOnSelectionChanged().handle(new Event(Event.ANY));
+ };
+ }
+}
diff --git a/src/main/java/de/hitec/nhplus/utils/tab/TabStruct.java b/src/main/java/de/hitec/nhplus/utils/tab/TabStruct.java
new file mode 100644
index 0000000..cc2244e
--- /dev/null
+++ b/src/main/java/de/hitec/nhplus/utils/tab/TabStruct.java
@@ -0,0 +1,19 @@
+package de.hitec.nhplus.utils.tab;
+
+/**
+ * A simple class holding the data needed for constructing a {@link javafx.scene.control.Tab Tab}.
+ *
+ * @author Dominiok Säume
+ * @see TabManager
+ */
+public class TabStruct {
+ public String title;
+ public String view;
+ public int requiredPermissions;
+
+ public TabStruct(String title, String view, int requiredPermissions) {
+ this.title = title;
+ this.view = view;
+ this.requiredPermissions = requiredPermissions;
+ }
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 06e67a7..56fcea2 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -10,6 +10,9 @@ module de.hitec.nhplus {
exports de.hitec.nhplus.main;
opens de.hitec.nhplus.main to javafx.base, javafx.fxml;
+ exports de.hitec.nhplus.login;
+ opens de.hitec.nhplus.login to javafx.base, javafx.fxml;
+
exports de.hitec.nhplus.patient;
exports de.hitec.nhplus.patient.database;
opens de.hitec.nhplus.patient.database to javafx.base, javafx.fxml;
diff --git a/src/main/resources/de/hitec/nhplus/login/LoginView.fxml b/src/main/resources/de/hitec/nhplus/login/LoginView.fxml
new file mode 100644
index 0000000..234ff7b
--- /dev/null
+++ b/src/main/resources/de/hitec/nhplus/login/LoginView.fxml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/de/hitec/nhplus/login/database/User.sql b/src/main/resources/de/hitec/nhplus/login/database/User.sql
new file mode 100644
index 0000000..8773d00
--- /dev/null
+++ b/src/main/resources/de/hitec/nhplus/login/database/User.sql
@@ -0,0 +1,7 @@
+CREATE TABLE user
+(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL UNIQUE,
+ passwordSalt BLOB NOT NULL,
+ passwordHash BLOB NOT NULL
+)
\ No newline at end of file
diff --git a/src/main/resources/de/hitec/nhplus/login/database/UserPermission.sql b/src/main/resources/de/hitec/nhplus/login/database/UserPermission.sql
new file mode 100644
index 0000000..4e968f2
--- /dev/null
+++ b/src/main/resources/de/hitec/nhplus/login/database/UserPermission.sql
@@ -0,0 +1,6 @@
+CREATE TABLE user__permissions
+(
+ userId INTEGER NOT NULL UNIQUE,
+ permissions INTEGER NOT NULL, -- Binary Bitmask for Permissions
+ FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
+)
\ No newline at end of file
diff --git a/src/main/resources/de/hitec/nhplus/login/database/UserToNurse.sql b/src/main/resources/de/hitec/nhplus/login/database/UserToNurse.sql
new file mode 100644
index 0000000..b46be11
--- /dev/null
+++ b/src/main/resources/de/hitec/nhplus/login/database/UserToNurse.sql
@@ -0,0 +1,7 @@
+CREATE TABLE user__nurse
+(
+ userId INTEGER NOT NULL UNIQUE,
+ nurseId INTEGER NOT NULL UNIQUE,
+ FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE,
+ FOREIGN KEY (nurseId) REFERENCES nurse (id) ON DELETE CASCADE
+)
\ No newline at end of file
diff --git a/src/main/resources/de/hitec/nhplus/main/MainWindowView.fxml b/src/main/resources/de/hitec/nhplus/main/MainWindowView.fxml
index fdb8bef..033a28e 100644
--- a/src/main/resources/de/hitec/nhplus/main/MainWindowView.fxml
+++ b/src/main/resources/de/hitec/nhplus/main/MainWindowView.fxml
@@ -1,38 +1,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+/>
\ No newline at end of file