Compare commits

...

15 commits

Author SHA1 Message Date
9663b4c0b5
#8: Implement User Permissions System Base and usage with Tabs
Some checks failed
Quality Check / Linting Check (push) Failing after 12s
Quality Check / Javadoc Check (push) Successful in 21s
Signed-off-by: Dominik Säume <Dominik.Saeume@hmmh.de>
2024-05-21 19:17:48 +02:00
050747d09a
#8: Implement Login Logic
Signed-off-by: Dominik Säume <Dominik.Saeume@hmmh.de>
2024-05-21 19:11:47 +02:00
6f888c140b
#8: Implement Login Logic
Signed-off-by: Dominik Säume <Dominik.Saeume@hmmh.de>
2024-05-21 19:11:47 +02:00
fb6fc923ac
#8: Setup Model, DAO & Fixtures
Signed-off-by: Dominik Säume <Dominik.Saeume@hmmh.de>
2024-05-21 19:11:43 +02:00
03ef4a235a
#8: Setup Schema for User Login 2024-05-21 19:11:05 +02:00
092b436247
#8: Setup Modal Window 2024-05-21 19:11:05 +02:00
fb26756309 README.md aktualisiert
All checks were successful
Quality Check / Linting Check (push) Successful in 18s
Javadoc Deploy / Javadoc (push) Successful in 32s
Quality Check / Javadoc Check (push) Successful in 29s
2024-05-21 17:06:34 +00:00
6e58574909 Merge pull request '#24 Bugfix' (#47) from story/sperren-und-loeschen-von-pflegern-bugfix into main
All checks were successful
Javadoc Deploy / Javadoc (push) Successful in 32s
Quality Check / Linting Check (push) Successful in 12s
Quality Check / Javadoc Check (push) Successful in 21s
Reviewed-on: #47
Reviewed-by: SZUT-Armin <arminribic@web.de>
2024-05-21 08:49:48 +00:00
Dorian Nemec
449f3ade06 #24 Bugfix
All checks were successful
Quality Check / Linting Check (push) Successful in 12s
Quality Check / Javadoc Check (push) Successful in 21s
Quality Check / Linting Check (pull_request) Successful in 12s
Quality Check / Javadoc Check (pull_request) Successful in 21s
2024-05-21 10:38:04 +02:00
970f167bc3
#7 Cleanup
All checks were successful
Quality Check / Linting Check (push) Successful in 19s
Javadoc Deploy / Javadoc (push) Successful in 32s
Quality Check / Javadoc Check (push) Successful in 30s
2024-05-21 09:01:04 +02:00
Dorian Nemec
f77072ab70
#7 Implement Logic 2024-05-21 09:00:59 +02:00
Dorian Nemec
efe10a72a3
#7 Update UI 2024-05-21 09:00:49 +02:00
Dorian Nemec
2856cbd13c
#7 Update model 2024-05-21 09:00:46 +02:00
1cbafa2fe9
#25: Implement Editing of Nurses 2024-05-21 08:56:38 +02:00
30120f3709
#26: Bugfix 2024-05-21 08:56:38 +02:00
36 changed files with 1228 additions and 278 deletions

View file

@ -27,9 +27,12 @@
<option value="file://$PROJECT_DIR$/src/main/resources/de/hitec/nhplus/nurse/database/Nurse.sql" />
<option value="file://$PROJECT_DIR$/src/main/resources/de/hitec/nhplus/medication/database/Medication.sql" />
<option value="file://$PROJECT_DIR$/src/main/resources/de/hitec/nhplus/medication/database/Medication_Ingredient.sql" />
<option value="file://$PROJECT_DIR$/src/main/resources/de/hitec/nhplus/login/database/User.sql" />
<option value="file://$PROJECT_DIR$/src/main/resources/de/hitec/nhplus/login/database/UserPermission.sql" />
<option value="file://$PROJECT_DIR$/src/main/resources/de/hitec/nhplus/login/database/UserToNurse.sql" />
</array>
</option>
<option name="outLayout" value="File per object by schema.groovy" />
<option name="outLayout" value="File per object.groovy" />
</State>
</list>
</option>

View file

@ -1,3 +1,6 @@
[![Static Badge](https://img.shields.io/badge/Wiki-Wiki?style=for-the-badge&logo=wikipedia&color=slategray)](https://git.euph.dev/SZUT/nhplus/wiki)
[![Static Badge](https://img.shields.io/badge/Tests-Tests?style=for-the-badge&logo=textpattern&logoColor=cyan&color=blue)](https://git.euph.dev/SZUT/nhplus/wiki/Tests)
[![Static Badge](https://img.shields.io/badge/Javadoc-Javadoc?style=for-the-badge&logo=readthedocs&logoColor=orange&color=beige)](https://nhplus.euph.dev)
[![Static Badge](https://img.shields.io/badge/Javadoc-Javadoc?style=for-the-badge&logo=readthedocs&logoColor=orange&color=beige)](https://nhplus.euph.dev)
[![Static Badge](https://img.shields.io/badge/Credentails-Credentails?style=for-the-badge&logo=keepassxc&logoColor=lime&color=darkgreen)](https://git.euph.dev/SZUT/nhplus/wiki/Test-Anmelde-Daten)

Binary file not shown.

View file

@ -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,37 @@ public class Main extends Application {
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
executeMainApplication();
executePassword();
}
private void executePassword() {
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();
if(controller.user != null){
executeMainApplication(controller.user);
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
/**
* 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 +76,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 -> {

View file

@ -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());
}
}

View file

@ -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());
}

View file

@ -54,6 +54,12 @@ public class NurseFixture implements Fixture<Nurse> {
true
));
nurses.add(new Nurse(
"Maria",
"Höller",
"666"
));
NurseDao dao = DaoFactory.getInstance().createNurseDAO();
for (Nurse nurse : nurses) {
dao.create(nurse);

View file

@ -58,7 +58,6 @@ public class TreatmentFixture implements Fixture<Treatment> {
Nurse armin = nursesByName.get("Armin");
treatments.add(new Treatment(
1,
seppl,
ole,
convertStringToLocalDate("2023-06-03"),
@ -70,7 +69,6 @@ public class TreatmentFixture implements Fixture<Treatment> {
+ "Patient beruhigt sich erst, als alle Wertsachen im Zimmer gefunden worden sind."
));
treatments.add(new Treatment(
2,
seppl,
armin,
convertStringToLocalDate("2023-06-05"),
@ -82,7 +80,6 @@ public class TreatmentFixture implements Fixture<Treatment> {
+ "Patient wird in seinen Raum zurückbegleitet und erhält Beruhigungsmittel."
));
treatments.add(new Treatment(
3,
martina,
ole,
convertStringToLocalDate("2023-06-04"),
@ -92,80 +89,80 @@ public class TreatmentFixture implements Fixture<Treatment> {
"Patient mit Waschlappen gewaschen und frisch angezogen. Patient gewendet."
));
treatments.add(new Treatment(
4,
seppl,
armin,
convertStringToLocalDate("2023-06-06"),
convertStringToLocalTime("15:10"),
convertStringToLocalTime("16:00"),
"Spaziergang",
"Spaziergang im Park, Patient döst im Rollstuhl ein")
);
"Spaziergang im Park, Patient döst im Rollstuhl ein"
));
treatments.add(new Treatment(
8,
seppl,
ole,
convertStringToLocalDate("2023-06-08"),
convertStringToLocalTime("15:00"),
convertStringToLocalTime("16:00"),
"Spaziergang",
"Parkspaziergang; Patient ist heute lebhafter und hat klare Momente; erzählt von seiner Tochter")
);
"Parkspaziergang; Patient ist heute lebhafter und hat klare Momente; erzählt von seiner Tochter"
));
treatments.add(new Treatment(
9,
martina,
armin,
convertStringToLocalDate("2023-06-07"),
convertStringToLocalTime("11:00"),
convertStringToLocalTime("11:30"),
"Waschen",
"Waschen per Dusche auf einem Stuhl; Patientin gewendet;")
);
"Waschen per Dusche auf einem Stuhl; Patientin gewendet;"
));
treatments.add(new Treatment(
12,
hans,
armin,
convertStringToLocalDate("2023-06-08"),
convertStringToLocalTime("15:00"),
convertStringToLocalTime("15:30"),
"Physiotherapie",
"Übungen zur Stabilisation und Mobilisierung der Rückenmuskulatur")
);
"Übungen zur Stabilisation und Mobilisierung der Rückenmuskulatur"
));
treatments.add(new Treatment(
14,
ahmet,
ole,
convertStringToLocalDate("2023-08-24"),
convertStringToLocalTime("09:30"),
convertStringToLocalTime("10:15"),
"KG",
"Lympfdrainage"));
"Lympfdrainage"
));
treatments.add(new Treatment(
16,
elisabeth,
armin,
convertStringToLocalDate("2023-08-31"),
convertStringToLocalTime("13:30"),
convertStringToLocalTime("13:45"),
"Toilettengang",
"Hilfe beim Toilettengang; Patientin klagt über Schmerzen beim Stuhlgang. Gabe von Iberogast")
);
treatments.add(new Treatment(
17,
"Hilfe beim Toilettengang; Patientin klagt über Schmerzen beim Stuhlgang. Gabe von Iberogast"
));
Treatment lockedTreatment = new Treatment(
elisabeth,
ole,
convertStringToLocalDate("2023-09-01"),
convertStringToLocalTime("16:00"),
convertStringToLocalTime("17:00"),
"KG",
"Massage der Extremitäten zur Verbesserung der Durchblutung")
"Massage der Extremitäten zur Verbesserung der Durchblutung"
);
lockedTreatment.setLocked(true);
treatments.add(lockedTreatment);
TreatmentDao dao = DaoFactory.getInstance().createTreatmentDao();
Map<String, Treatment> treatmentsById = new HashMap<>();
for (Treatment treatment : treatments) {
dao.create(treatment);
}
for (Treatment treatment : dao.readAll()) {
treatmentsById.put(String.valueOf(treatment.getId()), treatment);
}
return treatmentsById;
}

View file

@ -0,0 +1,103 @@
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.*;
public class UserFixture implements Fixture<User>{
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<String, Nurse> nursesByName;
public UserFixture(Map<String, Nurse> 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<String, User> load() throws SQLException {
List<User> 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<String, User> usersByUsername = new HashMap<>();
for (User user : users){
dao.create(user);
usersByUsername.put(user.getUsername(), user);
}
return usersByUsername;
}
}

View file

@ -0,0 +1,92 @@
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;
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;
public void initialize(Stage stage) {
this.stage = stage;
}
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();
}
}
}

View file

@ -0,0 +1,8 @@
package de.hitec.nhplus.login;
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;
}

View file

@ -0,0 +1,101 @@
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;
public class User {
private int id;
private String username;
private byte[] passwordSalt;
private byte[] passwordHash;
private int permissions = 0;
private Nurse nurse;
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;
}
public User(
String username,
int permissions,
Nurse nurse
) {
this.username = username;
this.permissions = permissions;
this.nurse = nurse;
}
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;
}
}

View file

@ -0,0 +1,211 @@
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;
public class UserDao implements Dao<User> {
protected final Connection connection;
public UserDao(Connection connection) {
this.connection = connection;
}
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);
}
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);
}
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<User> 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<User> 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;
}
}

View file

@ -1,17 +1,15 @@
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 java.io.IOException;
import java.util.Objects;
import java.util.List;
/**
* Controller for the main window of the application, which holds all tabs.
@ -23,153 +21,65 @@ import java.util.Objects;
*/
public class MainWindowController {
@FXML
private TabPane mainTabPane;
@FXML
private AnchorPane patientPage;
@FXML
private Tab patientTab;
@FXML
private AnchorPane treatmentPage;
@FXML
private Tab treatmentTab;
@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;
public TabPane mainTabPane;
private User user;
private TabManager tabManager;
/**
* Initialization method that is called after the binding of all the fields.
* JavaFX Initialization method that is called after the binding of all the fields.
*
* @param user The logged in {@link User}.
*/
@FXML
public void initialize() {
loadPatientPage();
mainTabPane.getSelectionModel().select(patientTab);
patientTab.setOnSelectionChanged(event -> loadPatientPage());
treatmentTab.setOnSelectionChanged(event -> loadTreatmentsPage());
nurseTab.setOnSelectionChanged(event -> loadNursePage());
medicationTab.setOnSelectionChanged(event -> loadMedicationPage());
nurseTabPane.getSelectionModel().select(activeNurseTab);
activeNurseTab.setOnSelectionChanged(event -> loadActiveNursePage());
lockedNurseTab.setOnSelectionChanged(event -> loadLockedNursePage());
public void initialize(User user) {
this.user = user;
this.tabManager = new TabManager(user);
setupTabs();
}
/**
* Loads the patient page into its tab.
* Sets up all Tabs Accessible, with help of the {@link TabManager}.
*/
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();
}
}
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
),
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
));
/**
* Loads the {@link } page into its tab.
*/
private void loadTreatmentsPage() {
try {
BorderPane treatmentsPane = FXMLLoader.load(
Objects.requireNonNull(Main.class.getResource("/de/hitec/nhplus/treatment/AllTreatmentView.fxml"))
);
treatmentPage.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 nurse page into its tab.
*/
private void loadNursePage() {
SelectionModel<Tab> 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 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();
}
Tab defaultTab = mainTabPane.getTabs().get(0);
mainTabPane.getSelectionModel().select(defaultTab);
defaultTab.getOnSelectionChanged().handle(new Event(Event.ANY));
}
}

View file

@ -40,7 +40,7 @@ public class IngredientListCell extends ListCell<Ingredient> {
BUTTON_PADDING_Y,
BUTTON_PADDING_X
));
deleteButton.setOnAction(event -> getListView().getItems().remove(this));
deleteButton.setOnAction(event -> getListView().getItems().remove(getItem()));
// Calculate Delete Button Width
Text textNode = new Text(deleteButton.getText());

View file

@ -22,6 +22,8 @@ import java.sql.SQLException;
*
* @author Dominik Säume
* @author Ole Kück
* @author Armin Ribic
* @author Dorian Nemec
*/
public class AllNurseController {
@FXML
@ -106,6 +108,17 @@ public class AllNurseController {
this.textFieldPhoneNumber.clear();
}
/**
* Internal method that stores the changes in the database.
*/
private void doUpdate(TableColumn.CellEditEvent<Nurse, String> event) {
try {
this.dao.update(event.getRowValue());
} catch (SQLException exception) {
exception.printStackTrace();
}
}
@FXML
public void handleAdd(){
String surname=this.textFieldSurName.getText();
@ -137,4 +150,39 @@ public class AllNurseController {
readAllAndShowInTableView();
}
@FXML
public void handleOnEditSurname(TableColumn.CellEditEvent<Nurse, String> event) {
String newSurName = event.getNewValue();
if (!isValidSurName(newSurName)) {
showValidationError("Nachname");
event.getTableView().refresh();
return;
}
event.getRowValue().setSurName(newSurName);
this.doUpdate(event);
}
@FXML
public void handleOnEditFirstname(TableColumn.CellEditEvent<Nurse, String> event) {
String newFirstName = event.getNewValue();
if (!isValidFirstName(newFirstName)) {
showValidationError("Vorname");
event.getTableView().refresh();
return;
}
event.getRowValue().setFirstName(newFirstName);
this.doUpdate(event);
}
@FXML
public void handleOnEditPhoneNumber(TableColumn.CellEditEvent<Nurse, String> event) {
String newPhoneNumber = event.getNewValue();
if (!isValidPhoneNumber(newPhoneNumber)) {
showValidationError("Telefonnummer");
event.getTableView().refresh();
return;
}
event.getRowValue().setPhoneNumber(newPhoneNumber);
this.doUpdate(event);
}
}

View file

@ -113,6 +113,11 @@ public class LockedNurseController {
@FXML
public void handleMouseClick() {
Nurse nurse = tableView.getSelectionModel().getSelectedItem();
if(nurse == null)
{
return;
}
boolean canBeDeleted = nurse.calculateDeleteDate().isBefore(LocalDate.now());
buttonDelete.setDisable(!canBeDeleted);
}

View file

@ -74,7 +74,7 @@ public class NurseDao extends DaoImp<Nurse> {
* Read all database entries of active {@link Nurse}s into a {@link List} of model instances.
*/
public List<Nurse> readAllActive() throws SQLException {
final String SQL = "SELECT * FROM nurse WHERE isLocked=false";
final String SQL = "SELECT * FROM nurse WHERE isLocked = false";
return getListFromResultSet(this.connection.prepareStatement(SQL).executeQuery());
}
@ -82,7 +82,7 @@ public class NurseDao extends DaoImp<Nurse> {
* Read all database entries of locked {@link Nurse}s into a {@link List} of model instances.
*/
public List<Nurse> readAllLocked() throws SQLException {
final String SQL = "SELECT * FROM nurse WHERE isLocked=true";
final String SQL = "SELECT * FROM nurse WHERE isLocked = true";
return getListFromResultSet(this.connection.prepareStatement(SQL).executeQuery());
}

View file

@ -154,7 +154,7 @@ public class AllPatientController {
public void handleOnEditFirstname(TableColumn.CellEditEvent<Patient, String> event) {
String newFirstName = event.getNewValue();
if (!isValidFirstName(newFirstName)) {
showValidationError("First Name");
showValidationError("Vorname");
event.getTableView().refresh();
return;
}
@ -166,7 +166,7 @@ public class AllPatientController {
public void handleOnEditSurname(TableColumn.CellEditEvent<Patient, String> event) {
String newSurName = event.getNewValue();
if (!isValidSurName(newSurName)) {
showValidationError("Sur Name");
showValidationError("Nachname");
event.getTableView().refresh();
return;
}
@ -178,7 +178,7 @@ public class AllPatientController {
public void handleOnEditDateOfBirth(TableColumn.CellEditEvent<Patient, String> event) {
String newDateString = event.getNewValue();
if (!isValidDate(newDateString)) {
showValidationError("Date");
showValidationError("Geburtstag");
event.getTableView().refresh();
return;
}
@ -190,7 +190,7 @@ public class AllPatientController {
public void handleOnEditCareLevel(TableColumn.CellEditEvent<Patient, String> event) {
String newCareLevel = event.getNewValue();
if (!isValidCareLevel(newCareLevel)) {
showValidationError("Care Level");
showValidationError("Pflegegrad");
event.getTableView().refresh();
return;
}
@ -202,7 +202,7 @@ public class AllPatientController {
public void handleOnEditRoomNumber(TableColumn.CellEditEvent<Patient, String> event) {
String newRoomNumber = event.getNewValue();
if (!isValidRoomNumber(newRoomNumber)) {
showValidationError("Room Number");
showValidationError("Raum");
event.getTableView().refresh();
return;
}

View file

@ -20,6 +20,7 @@ import javafx.stage.Stage;
import java.io.IOException;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
/**
@ -27,6 +28,8 @@ import java.util.ArrayList;
*
* @author Bernd Heidemann
* @author Dominik Säume
* @author Armin Ribic
* @author Dorian Nemec
*/
public class AllTreatmentController {
@ -61,7 +64,7 @@ public class AllTreatmentController {
public ComboBox<String> comboBoxNurseSelection;
@FXML
private Button buttonDelete;
private Button buttonLock;
private final ObservableList<Treatment> treatments = FXCollections.observableArrayList();
private TreatmentDao dao;
@ -100,15 +103,16 @@ public class AllTreatmentController {
this.columnDescription.setCellValueFactory(new PropertyValueFactory<>("description"));
this.tableView.setItems(this.treatments);
this.buttonDelete.setDisable(true);
this.buttonLock.setDisable(true);
this.tableView
.getSelectionModel()
.selectedItemProperty()
.addListener((observableValue, oldTreatment, newTreatment) ->
AllTreatmentController.this.buttonDelete.setDisable(newTreatment == null)
AllTreatmentController.this.buttonLock.setDisable(newTreatment == null)
);
this.createComboBoxData();
}
/**
@ -117,7 +121,7 @@ public class AllTreatmentController {
public void readAllAndShowInTableView() {
this.dao = DaoFactory.getInstance().createTreatmentDao();
try {
this.treatments.setAll(dao.readAll());
this.treatments.setAll(dao.readAllActive());
} catch (SQLException exception) {
exception.printStackTrace();
}
@ -136,7 +140,7 @@ public class AllTreatmentController {
this.patientSelection.add(patient.getSurName());
}
nurseList = (ArrayList<Nurse>) nurseDao.readAll();
nurseList = (ArrayList<Nurse>) nurseDao.readAllActive();
for (Nurse nurse : nurseList) {
this.nurseSelection.add(nurse.getSurName());
}
@ -258,18 +262,6 @@ public class AllTreatmentController {
}
}
@FXML
public void handleDelete() {
int index = this.tableView.getSelectionModel().getSelectedIndex();
Treatment t = this.treatments.remove(index);
TreatmentDao dao = DaoFactory.getInstance().createTreatmentDao();
try {
dao.delete(t.getId());
} catch (SQLException exception) {
exception.printStackTrace();
}
}
@FXML
public void handleNewTreatment() {
String selectedPatient = this.comboBoxPatientSelection.getSelectionModel().getSelectedItem();
@ -316,4 +308,22 @@ public class AllTreatmentController {
});
}
@FXML
public void handleLock(){
Treatment selectedItem = this.tableView.getSelectionModel().getSelectedItem();
if (selectedItem == null){
return;
}
try {
selectedItem.setLocked(true);
this.dao.update(selectedItem);
}catch (SQLException exception){
exception.printStackTrace();
}
readAllAndShowInTableView();
}
}

View file

@ -0,0 +1,124 @@
package de.hitec.nhplus.treatment;
import de.hitec.nhplus.datastorage.DaoFactory;
import de.hitec.nhplus.nurse.Nurse;
import de.hitec.nhplus.patient.Patient;
import de.hitec.nhplus.treatment.database.TreatmentDao;
import de.hitec.nhplus.utils.DateConverter;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
/**
* Controller for all locked treatments.
*
* @author Armin Ribic
* @author Dorian Nemec
*/
public class LockedTreatmentController {
@FXML
public Button buttonUnlock;
@FXML
public TableView<Treatment> tableView;
@FXML
public TableColumn<Treatment, Long> columnId;
@FXML
private TableColumn<Treatment, String> columnPatient;
@FXML
private TableColumn<Treatment, String> columnNurse;
@FXML
private TableColumn<Treatment, String> columnDeleteDate;
private final ObservableList<Treatment> treatments = FXCollections.observableArrayList();
private TreatmentDao treatmentDao;
/**
* This method allows initializing a {@link LockedTreatmentController} object
* that is called after the binding of all the fields.
*/
public void initialize() {
this.readAllAndShowInTableView();
this.columnId.setCellValueFactory(new PropertyValueFactory<>("id"));
this.columnPatient.setCellValueFactory(
cellData -> {
Patient patient = cellData.getValue().getPatient();
return new SimpleStringProperty(patient.getSurName() + ", " + patient.getFirstName());
}
);
this.columnNurse.setCellValueFactory(
cellData -> {
Nurse nurse = cellData.getValue().getNurse();
return new SimpleStringProperty(nurse.getSurName() + ", " + nurse.getFirstName());
}
);
this.columnDeleteDate.setCellValueFactory(cellData -> new SimpleStringProperty(
DateConverter.convertLocalDateToString(cellData.getValue().calculateDeleteDate())));
this.tableView.setItems(this.treatments);
}
/**
* Reads all locked {@link Treatment} data and shows it in the table.
*/
private void readAllAndShowInTableView() {
this.treatments.clear();
this.treatmentDao = DaoFactory.getInstance().createTreatmentDao();
try {
this.treatments.addAll(this.treatmentDao.readAllLocked());
deleteOldTreatments();
} catch (SQLException exception) {
exception.printStackTrace();
}
}
/**
* Deletes all {@link Treatment}s which are older than allowed.
*/
private void deleteOldTreatments() {
LocalDate today = LocalDate.now();
for (Treatment treatment : treatments) {
LocalDate deleteDate = treatment.calculateDeleteDate();
if (today.isEqual(deleteDate) || today.isAfter(deleteDate)) {
try {
treatmentDao.delete(treatment.getId());
} catch (SQLException exception) {
exception.printStackTrace();
}
}
}
}
@FXML
private void unlockTreatment() {
Treatment selectedItem = this.tableView.getSelectionModel().getSelectedItem();
if (selectedItem == null) {
return;
}
try {
selectedItem.setLocked(false);
this.treatmentDao.update(selectedItem);
} catch (SQLException exception) {
exception.printStackTrace();
}
readAllAndShowInTableView();
}
}

View file

@ -3,6 +3,7 @@ package de.hitec.nhplus.treatment;
import de.hitec.nhplus.nurse.Nurse;
import de.hitec.nhplus.patient.Patient;
import de.hitec.nhplus.utils.DateConverter;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
@ -16,6 +17,8 @@ import java.util.StringJoiner;
*
* @author Bernd Heidemann
* @author Dominik Säume
* @author Armin Ribic
* @author Dorian Nemec
*/
public class Treatment {
private SimpleIntegerProperty id;
@ -26,6 +29,8 @@ public class Treatment {
private final SimpleObjectProperty<LocalTime> end;
private final SimpleStringProperty description;
private final SimpleStringProperty remarks;
private final SimpleBooleanProperty locked;
private final static int BLOCKED_YEARS = 10;
/**
* This constructor allows instantiating a {@link Treatment} object,
@ -50,6 +55,7 @@ public class Treatment {
this.end = new SimpleObjectProperty<>(end);
this.description = new SimpleStringProperty(description);
this.remarks = new SimpleStringProperty(remarks);
this.locked = new SimpleBooleanProperty(false);
}
/**
@ -63,7 +69,8 @@ public class Treatment {
LocalTime begin,
LocalTime end,
String description,
String remarks
String remarks,
Boolean isLocked
) {
this.id = new SimpleIntegerProperty(id);
this.patient = new SimpleObjectProperty<>(patient);
@ -73,6 +80,26 @@ public class Treatment {
this.end = new SimpleObjectProperty<>(end);
this.description = new SimpleStringProperty(description);
this.remarks = new SimpleStringProperty(remarks);
this.locked = new SimpleBooleanProperty(isLocked);
}
/**
* Calculates delete date of treatment.
*/
public LocalDate calculateDeleteDate() {
return DateConverter.convertStringToLocalDate(getDate()).plusYears(BLOCKED_YEARS);
}
public boolean isLocked() {
return locked.get();
}
public SimpleBooleanProperty lockedProperty() {
return locked;
}
public void setLocked(boolean locked) {
this.locked.set(locked);
}
public int getId() {
@ -166,6 +193,8 @@ public class Treatment {
.add("End: " + this.getEnd())
.add("Description: " + this.getDescription())
.add("Remarks: " + this.getRemarks())
.add("isLocked: " + this.isLocked())
.toString();
}
}

View file

@ -11,6 +11,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@ -20,6 +21,8 @@ import java.util.List;
*
* @author Bernd Heidemannn
* @author Dominik Säume
* @author Armin Ribic
* @author Dorian Nemec
*/
public class TreatmentDao extends DaoImp<Treatment> {
@ -27,60 +30,22 @@ public class TreatmentDao extends DaoImp<Treatment> {
super(connection);
}
@Override
protected PreparedStatement getCreateStatement(Treatment treatment) throws SQLException {
final String SQL = """
INSERT INTO treatment
(patientId, nurseId, date, begin, end, description, remark)
VALUES (?, ?, ?, ?, ?, ?, ?)
""";
PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setInt(1, treatment.getPatient().getId());
statement.setInt(2, treatment.getNurse().getId());
statement.setString(3, treatment.getDate());
statement.setString(4, treatment.getBegin());
statement.setString(5, treatment.getEnd());
statement.setString(6, treatment.getDescription());
statement.setString(7, treatment.getRemarks());
return statement;
/**
* Read all database entries of active {@link Treatment}s into a {@link List} of model instances.
*/
public List<Treatment> readAllActive() throws SQLException {
final String SQL = "SELECT * FROM treatment WHERE isLocked = false";
return getListFromResultSet(this.connection.prepareStatement(SQL).executeQuery());
}
@Override
protected PreparedStatement getReadByIDStatement(int id) throws SQLException {
final String SQL = "SELECT * FROM treatment WHERE id = ?";
PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setInt(1, id);
return statement;
/**
* Read all database entries of locked {@link Treatment}s into a {@link Treatment} of model instances.
*/
public List<Treatment> readAllLocked() throws SQLException {
final String SQL = "SELECT * FROM treatment WHERE isLocked = true";
return getListFromResultSet(this.connection.prepareStatement(SQL).executeQuery());
}
@Override
protected Treatment getInstanceFromResultSet(ResultSet result) throws SQLException {
return new Treatment(
result.getInt(1),
DaoFactory.getInstance().createPatientDAO().read(result.getInt(2)),
DaoFactory.getInstance().createNurseDAO().read(result.getInt(3)),
DateConverter.convertStringToLocalDate(result.getString(4)),
DateConverter.convertStringToLocalTime(result.getString(5)),
DateConverter.convertStringToLocalTime(result.getString(6)),
result.getString(7),
result.getString(8)
);
}
@Override
protected PreparedStatement getReadAllStatement() throws SQLException {
final String SQL = "SELECT * FROM treatment";
return this.connection.prepareStatement(SQL);
}
@Override
protected List<Treatment> getListFromResultSet(ResultSet result) throws SQLException {
ArrayList<Treatment> list = new ArrayList<>();
while (result.next()) {
list.add(getInstanceFromResultSet(result));
}
return list;
}
/**
* Retrieves a list of {@link Treatment}s associated with a specific
@ -112,6 +77,63 @@ public class TreatmentDao extends DaoImp<Treatment> {
return getListFromResultSet(result);
}
@Override
protected PreparedStatement getCreateStatement(Treatment treatment) throws SQLException {
final String SQL = """
INSERT INTO treatment
(patientId, nurseId, date, begin, end, description, remark, isLocked)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""";
PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setInt(1, treatment.getPatient().getId());
statement.setInt(2, treatment.getNurse().getId());
statement.setString(3, treatment.getDate());
statement.setString(4, treatment.getBegin());
statement.setString(5, treatment.getEnd());
statement.setString(6, treatment.getDescription());
statement.setString(7, treatment.getRemarks());
statement.setBoolean(8, treatment.isLocked());
return statement;
}
@Override
protected PreparedStatement getReadByIDStatement(int id) throws SQLException {
final String SQL = "SELECT * FROM treatment WHERE id = ?";
PreparedStatement statement = this.connection.prepareStatement(SQL);
statement.setInt(1, id);
return statement;
}
@Override
protected Treatment getInstanceFromResultSet(ResultSet result) throws SQLException {
return new Treatment(
result.getInt(1),
DaoFactory.getInstance().createPatientDAO().read(result.getInt(2)),
DaoFactory.getInstance().createNurseDAO().read(result.getInt(3)),
DateConverter.convertStringToLocalDate(result.getString(4)),
DateConverter.convertStringToLocalTime(result.getString(5)),
DateConverter.convertStringToLocalTime(result.getString(6)),
result.getString(7),
result.getString(8),
result.getBoolean(9)
);
}
@Override
protected PreparedStatement getReadAllStatement() throws SQLException {
final String SQL = "SELECT * FROM treatment";
return this.connection.prepareStatement(SQL);
}
@Override
protected List<Treatment> getListFromResultSet(ResultSet result) throws SQLException {
ArrayList<Treatment> list = new ArrayList<>();
while (result.next()) {
list.add(getInstanceFromResultSet(result));
}
return list;
}
@Override
protected PreparedStatement getUpdateStatement(Treatment treatment) throws SQLException {
final String SQL = """
@ -120,7 +142,8 @@ public class TreatmentDao extends DaoImp<Treatment> {
begin = ?,
end = ?,
description = ?,
remark = ?
remark = ?,
isLocked = ?
WHERE id = ?
""";
PreparedStatement statement = this.connection.prepareStatement(SQL);
@ -129,7 +152,8 @@ public class TreatmentDao extends DaoImp<Treatment> {
statement.setString(3, treatment.getEnd());
statement.setString(4, treatment.getDescription());
statement.setString(5, treatment.getRemarks());
statement.setInt(6, treatment.getId());
statement.setBoolean(6, treatment.isLocked());
statement.setInt(7, treatment.getId());
return statement;
}
@ -141,4 +165,5 @@ public class TreatmentDao extends DaoImp<Treatment> {
statement.setInt(1, id);
return statement;
}
}

View file

@ -0,0 +1,82 @@
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;
public class TabManager {
private final User user;
public TabManager(User user) {
this.user = user;
}
private boolean hasPermissions(int requiredPermissions, int permissions) {
return requiredPermissions == Permissions.EVERYBODY
|| (permissions & requiredPermissions) != 0;
}
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);
}
private EventHandler<Event> 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();
}
};
}
public void setupSubTabPane(TabPane parentTabPane, String title, int requiredPermissions, List<TabStruct> 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);
}
private EventHandler<Event> loadSubTabPaneEventHandler(TabPane tabPane) {
return event -> {
Tab tab = tabPane.getSelectionModel().getSelectedItem();
tab.getOnSelectionChanged().handle(new Event(Event.ANY));
};
}
}

View file

@ -0,0 +1,13 @@
package de.hitec.nhplus.utils.tab;
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;
}
}

View file

@ -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;

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.*?>
<BorderPane
xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="de.hitec.nhplus.login.LoginController"
minWidth="240"
maxWidth="240"
>
<padding>
<Insets bottom="8" left="8" right="8" top="8"/>
</padding>
<top>
<Label text="Anmeldung" BorderPane.alignment="CENTER"/>
</top>
<center>
<VBox spacing="8">
<BorderPane.margin>
<Insets bottom="8.0" top="8.0"/>
</BorderPane.margin>
<TextField
fx:id="textFieldUsername"
promptText="nutzername"
VBox.vgrow="ALWAYS"
/>
<PasswordField
fx:id="passwordField"
promptText="password"
VBox.vgrow="ALWAYS"
/>
</VBox>
</center>
<bottom>
<Button
fx:id="buttonSubmit"
text="Bestätigen"
BorderPane.alignment="CENTER"
onAction="#handleSubmit"
/>
</bottom>
</BorderPane>

View file

@ -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
)

View file

@ -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
)

View file

@ -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
)

View file

@ -1,31 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.AnchorPane?>
<TabPane
fx:id="mainTabPane"
tabClosingPolicy="UNAVAILABLE"
xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="de.hitec.nhplus.main.MainWindowController"
>
<Tab fx:id="patientTab" text="Patienten">
<AnchorPane fx:id="patientPage"/>
</Tab>
<Tab fx:id="treatmentTab" text="Behandlungen">
<AnchorPane fx:id="treatmentPage"/>
</Tab>
<Tab fx:id="nurseTab" text="Pfleger">
<TabPane fx:id="nurseTabPane" tabClosingPolicy="UNAVAILABLE">
<Tab fx:id="activeNurseTab" text="Pfleger">
<AnchorPane fx:id="activeNursePage"/>
</Tab>
<Tab fx:id="lockedNurseTab" text="Gesperrte Pfleger">
<AnchorPane fx:id="lockedNursePage"/>
</Tab>
</TabPane>
</Tab>
<Tab fx:id="medicationTab" text="Medikamente">
<AnchorPane fx:id="medicationPage"/>
</Tab>
</TabPane>
/>

View file

@ -22,16 +22,19 @@
<TableColumn
fx:id="columnSurName"
minWidth="140.0"
onEditCommit="#handleOnEditSurname"
text="Nachname"
/>
<TableColumn
fx:id="columnFirstName"
minWidth="140.0"
onEditCommit="#handleOnEditFirstname"
text="Vorname"
/>
<TableColumn
fx:id="columnPhoneNumber"
minWidth="140.0"
onEditCommit="#handleOnEditPhoneNumber"
text="Telefonnummer"
/>
</columns>

View file

@ -12,7 +12,11 @@
<Insets top="8" left="8" right="8" bottom="8"/>
</padding>
<center>
<TableView fx:id="tableView" layoutX="31.0" layoutY="40" onMouseClicked="#handleMouseClick" >
<TableView
fx:id="tableView"
layoutX="31.0"
layoutY="40"
onMouseClicked="#handleMouseClick" >
<columns>
<TableColumn
fx:id="columnId"

View file

@ -88,11 +88,11 @@
</center>
<right>
<Button
fx:id="buttonDelete"
fx:id="buttonLock"
mnemonicParsing="false"
onAction="#handleDelete"
onAction="#handleLock"
prefWidth="200.0"
text="Löschen"
text="Sperren"
GridPane.columnIndex="2"
/>
</right>

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane prefHeight="400.0"
prefWidth="600.0"
xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="de.hitec.nhplus.treatment.LockedTreatmentController">
<padding>
<Insets bottom="8" left="8" right="8" top="8" />
</padding>
<center>
<TableView
fx:id="tableView"
layoutX="31.0"
layoutY="40">
<columns>
<TableColumn
fx:id="columnId"
minWidth="40.0"
prefWidth="102.0"
text="ID"
/>
<TableColumn
fx:id="columnPatient"
minWidth="40.0"
prefWidth="102.0"
text="Patient"
/>
<TableColumn
fx:id="columnNurse"
minWidth="40.0"
prefWidth="102.0"
text="Pflegekraft"
/>
<TableColumn
fx:id="columnDeleteDate"
minWidth="40.0"
prefWidth="102.0"
text="Löschung am"
/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</center>
<bottom>
<BorderPane>
<BorderPane.margin>
<Insets top="8.0"/>
</BorderPane.margin>
<center>
<HBox spacing="8.0">
<padding>
<Insets right="8.0"/>
</padding>
</HBox>
</center>
<right>
<HBox>
<spacing>8.0</spacing>
<Button
fx:id="buttonUnlock"
mnemonicParsing="false"
onAction="#unlockTreatment"
prefWidth="90.0"
text="Entsperren"
/>
</HBox>
</right>
</BorderPane>
</bottom>
</BorderPane>

View file

@ -8,6 +8,7 @@ CREATE TABLE treatment
end TEXT NOT NULL,
description TEXT NOT NULL,
remark TEXT NOT NULL,
isLocked BOOLEAN NOT NULL DEFAULT false,
FOREIGN KEY (patientId) REFERENCES patient (id) ON DELETE CASCADE,
FOREIGN KEY (nurseId) REFERENCES nurse (id) ON DELETE SET NULL
FOREIGN KEY (nurseId) REFERENCES nurse (id) ON DELETE CASCADE
)