From e3b3ab5660856240c84405e6219671f1a68538d0 Mon Sep 17 00:00:00 2001
From: Eilert Tunheim <emtunhei@stud.ntnu.no>
Date: Sun, 8 May 2022 19:33:22 +0200
Subject: [PATCH] Added full functionality for adding an user

---
 .../com/application/DB/Account_handler.java   |  11 ++
 .../GUI/PopUpWindows/LoginPopup.java          | 133 ++++++++++++------
 .../com/application/DB/Account_handler.class  | Bin 2964 -> 3564 bytes
 .../GUI/PopUpWindows/LoginPopup.class         | Bin 7674 -> 10685 bytes
 4 files changed, 99 insertions(+), 45 deletions(-)

diff --git a/src/main/java/com/application/DB/Account_handler.java b/src/main/java/com/application/DB/Account_handler.java
index 2c05fa0..ff63832 100644
--- a/src/main/java/com/application/DB/Account_handler.java
+++ b/src/main/java/com/application/DB/Account_handler.java
@@ -51,4 +51,15 @@ public class Account_handler {
         }
     }
 
+    public static void addUser(String firstName, String lastName, String phoneNo, String username, String password, boolean isAdmin) throws Exception {
+            // Sqlstatement
+            final String sqlStatement =
+                "INSERT INTO " + PROJECT_ID + "." + LOCATION_ID + "." + USERS_TABLE_NAME + "(First_name, Last_name, Phone_no, Username, Password, Admin) " +
+                        "VALUES("+'"'+firstName+'"'+","+'"'+lastName+'"'+","+'"'+phoneNo+'"'+","+'"'+username+'"'+","+'"'+password+'"'+","+ isAdmin+") ";
+
+        System.out.println(sqlStatement);
+
+        HelpingFunctions.createQueryJob(sqlStatement);
+    }
+
 }
diff --git a/src/main/java/com/application/GUI/PopUpWindows/LoginPopup.java b/src/main/java/com/application/GUI/PopUpWindows/LoginPopup.java
index 2e28bb1..d256ef9 100644
--- a/src/main/java/com/application/GUI/PopUpWindows/LoginPopup.java
+++ b/src/main/java/com/application/GUI/PopUpWindows/LoginPopup.java
@@ -1,22 +1,17 @@
 package com.application.GUI.PopUpWindows;
 
-import com.application.GUI.Panes.LogoBar;
+import com.application.DB.Account_handler;
 import javafx.geometry.Pos;
 import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.control.Label;
-import javafx.scene.control.PasswordField;
-import javafx.scene.control.TextField;
+import javafx.scene.control.*;
 import javafx.scene.layout.VBox;
 import javafx.stage.Modality;
 import javafx.stage.Stage;
 
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Arrays;
 
+import static com.application.DB.Account_handler.addUser;
 import static com.application.DB.Account_handler.getAccount;
 import static com.application.DB.Constants.*;
 import static com.application.GUI.Panes.LogoBar.getLogin;
@@ -44,31 +39,14 @@ public class LoginPopup {
         loginButton.setOnAction(event -> {
 
             try {
-                MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
-
-                assert messageDigest != null;
-                messageDigest.update(getPasswordTextField().getText().getBytes(StandardCharsets.UTF_8));
-
-                byte[] hashedPassword = messageDigest.digest();
-
-                StringBuilder hashedPasswordString = new StringBuilder();
-
-                for (byte b: hashedPassword) {
-                    hashedPasswordString.append(String.format("%02x",b));
-                }
-
-                getAccount(userNameTextField.getText(),hashedPasswordString.toString());
-
-                if(!getLogin().getText().equals("Login")){
-                    window.close();
-                }
-
+                getAccount(userNameTextField.getText(), hashPassword(getPasswordTextField().getText()));
             } catch (Exception e) {
                 e.printStackTrace();
             }
 
-
-
+            if(!getLogin().getText().equals("Login")){
+                window.close();
+            }
 
         });
 
@@ -100,16 +78,14 @@ public class LoginPopup {
         Button logout = new Button("Logout");
 
         addUser.setOnAction(event -> {
-            window.close();
             adminAddUser();
         });
         deleteUser.setOnAction(event -> {
-            window.close();
             adminDeleteUser();
         });
         logout.setOnAction(event -> {
-            window.close();
             logout();
+            window.close();
         });
 
 
@@ -132,18 +108,58 @@ public class LoginPopup {
         Label firstNameLabel = new Label("First Name: ");
         Label lastNameLabel = new Label("Last Name: ");
         Label phoneNoLabel = new Label("Phone No: ");
-        Label username = new Label("Username: ");
-        Label passwordFirst = new Label("Password");
+        Label usernameLabel = new Label("Username: ");
+        Label passwordFirstLabel = new Label("Password : ");
+        Label passwordSecondLabel = new Label("Password Repeat: ");
+        Label isAdminLabel = new Label("Is Admin: ");
 
+        TextField firstNameTextField = new TextField();
+        TextField lastNameTextField = new TextField();
+        TextField phoneNoTextField = new TextField();
+        TextField usernameTextField = new TextField();
+        PasswordField passwordFirstField = new PasswordField();
+        PasswordField passwordSecondField = new PasswordField();
+        CheckBox isAdminBox = new CheckBox();
+        isAdminBox.setSelected(false);
 
+        Button close = new Button("Close");
+        Button addUser = new Button("Add User");
 
+        close.setOnAction(event -> window.close());
+        addUser.setOnAction(event -> {
+
+            // If the passwords match each other, add the user, if not display an errormessage
+            if(passwordFirstField.getText().contentEquals(passwordSecondField.getText())){
+
+                // Hashing the password if they match.
+                String hashedPassword = hashPassword(passwordFirstField.getText());
+
+                // Tries to add the user
+                try {
+                    addUser(firstNameTextField.getText(), lastNameTextField.getText(), phoneNoTextField.getText(),
+                            usernameTextField.getText(), hashedPassword, isAdminBox.isSelected());
+                    NotificationPopUp.displayNotificationWindow("Successfully added user!");
+                    window.close();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else {
+                NotificationPopUp.displayNotificationWindow("Passwords does not match!");
+                passwordFirstField.clear();
+                passwordSecondField.clear();
+            }
+
+        });
 
 
         VBox layout = new VBox(10);
         layout.setAlignment(Pos.CENTER);
-        layout.getChildren().addAll();
+        layout.getChildren().addAll(firstNameLabel, firstNameTextField, lastNameLabel, lastNameTextField,
+                                    phoneNoLabel, phoneNoTextField, usernameLabel, usernameTextField,
+                                    passwordFirstLabel, passwordFirstField, passwordSecondLabel, passwordSecondField,
+                                    isAdminLabel, isAdminBox, addUser, close);
 
-        Scene scene = new Scene(layout, 500, 300);
+        Scene scene = new Scene(layout, 500, 600);
         scene.getStylesheets().add(InputPopup.class.getResource("/com.application/CSS/styleSheet.css").toExternalForm());
         window.setScene(scene);
         window.showAndWait();
@@ -155,14 +171,8 @@ public class LoginPopup {
         window.initModality(Modality.APPLICATION_MODAL);
         window.setTitle("Admin window");
 
-        Label firstNameLabel = new Label("First Name: ");
-        Label lastNameLabel = new Label("Last Name: ");
-        Label phoneNoLabel = new Label("Phone No: ");
-        Label username = new Label("Username: ");
-        Label passwordFirst = new Label("Password");
-
-
-
+        Label usernameLabel = new Label("Username: ");
+        TextField usernameTextField = new TextField();
 
 
         VBox layout = new VBox(10);
@@ -197,14 +207,24 @@ public class LoginPopup {
         TextField nameTextfield = new TextField();
         TextField phoneNoTextField = new TextField();
 
+        nameTextfield.setEditable(false);
+        phoneNoTextField.setEditable(false);
+
         nameTextfield.setText(getFirstName() + " " + getLastName());
         phoneNoTextField.setText(getPhoneNo());
 
+
+        Button close = new Button("Close");
         Button logout = new Button("Logout");
+        close.setOnAction(event -> window.close());
+        logout.setOnAction(event -> {
+            logout();
+            window.close();
+        });
 
         VBox layout = new VBox(10);
         layout.setAlignment(Pos.CENTER);
-        layout.getChildren().addAll(nameLabel, nameTextfield, phoneNoLabel, phoneNoTextField, logout);
+        layout.getChildren().addAll(nameLabel, nameTextfield, phoneNoLabel, phoneNoTextField, logout, close);
 
         Scene scene = new Scene(layout, 500, 300);
         scene.getStylesheets().add(InputPopup.class.getResource("/com.application/CSS/styleSheet.css").toExternalForm());
@@ -212,6 +232,29 @@ public class LoginPopup {
         window.showAndWait();
     }
 
+    public static String hashPassword(String password){
+        try {
+            MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
+
+            assert messageDigest != null;
+            messageDigest.update(password.getBytes(StandardCharsets.UTF_8));
+
+            byte[] hashedPassword = messageDigest.digest();
+
+            StringBuilder hashedPasswordString = new StringBuilder();
+
+            for (byte b: hashedPassword) {
+                hashedPasswordString.append(String.format("%02x",b));
+            }
+
+            return hashedPasswordString.toString();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
     public static PasswordField getPasswordTextField() {
         return PASSWORD_TEXT_FIELD;
     }
diff --git a/target/classes/com/application/DB/Account_handler.class b/target/classes/com/application/DB/Account_handler.class
index 8d513275eda4d202e46c120ea5da851ea1fba4e1..6e0dd40dcbbfaca02fad27009793c8cbbaf28c39 100644
GIT binary patch
delta 1198
zcmbOt{zkg~)W2Q(7#J8#7>=+r1aL9vF$A(R1aUDiGX!!l1cT@h5E0735C)>dIT<1t
zBDol%7^1ltVi;n%7~&Y>K|}&KLn1>GH$yT*3W!K$XGr5<Natb@V#wfP$YjU@nVikV
zki(G6#gNC4&&5!{P{_eh#1+Vp$xsYZQ34Vw<zOfS(d8Tr6(G8jgP{r}Sq<XUa4^(z
zG1M{Cb1^h9G;%RCF*I{9v~V!Af*jVy!O+gm(812ox$#g4qk0!RLpM7^4?9B|BLkOf
zMRICENoIatF*`#qBLjP4N=j&PY7rwt+~kd{!jl6Sg^;mPlx7$s17})hQE`c1Vs0uU
z14m9GjLBY*k)N09m(R$+o>}aelAD>w$iNsi*?`G~S)ajRaye6fR3Ae>4?`cr1V#n{
z1xG&@g@DB3;`02W6a`xa9)^hwlh_$1^Ds<dn99yDjfY`6!whzYnLG@$7-q9Gbn`IG
zVVKLqFpptAJHrAVhJ_4^*cp0w7#1@u;bB<HuxxSyvqk-Kh864#D|r}JF)ZU@Sk178
zonb8x!#alb><k-t7&d~8+r-1LnPCPa14jVJt?_yJJPcbvCTwMx#KW)+B*Wzf@?3mg
zVs0uA!*-Aer%z&W2~=PQNPrdWIUa_cAf3Ayb~7?ahZp7NrB4=Tkx<#g!>|`*(>@-C
z{R{`#84mI=9AYqFWGM9X3w8|(QSkH&@t=HwNij?VVUdmk+zK59n9Fn&KoJ3QhYmcP
zbQHi=Ybt~}`h>a$YbY@?FzSFp^e`g>lcoYAgVJO!My1VJEUc`oj0`dwQIi!}rGgn0
z8FU%+7(jrTfssL<!GM90!H|K0L7#z<fsuiMfmLfe1JgzZ1_mYuBL)TrHn1QMgE0dG
z0}q(Z%3#7^%D}+D$zaA{&cMWAxcLw#CnKZL<TG61^&n*?46F=E3@r>643-S63=9lE
z7_1nqK^8LnV6b7ZW?*E{VK~EJ%V5pG#9+a2fWeNzo`IRcfq{WRj)CJJgAY4{BRhi=
zJA?Bd25)u-7fH!q43fVXn3%X2Tp1V`SQr=?+!#0++!;JTmNPIgd}m-{U}s=pXx+_F
z&m6g(fkjAj8v~oxHU>5UrELuCLU5KgrjQP%kS?Z>Bnyg|DC;%`Z6T1>Z48`NY?~Ok
zB-yqxa7(i7sAu2_M}(aa0}BHKg9SqwgAGF+gB?Q)gFQGLJs{3y@Pr0SD}xs}SQr>u
w8N9*40%CyzjTz)EaG-%qYGv?Y@MU0SC}ZFU2Ok?!fG{%nF)%PNGcouB0KOLPM*si-

delta 707
zcmaDOJw?3!)W2Q(7#J8#7`Cu8xN<RQF}SfaxN|WuGq`aucz|e65aGqa;0>aEI2n8y
z{J0qW83MQ%0vUq17=jr>Ktw1vLl{FiH$wzNB#4M&XNcxth~Z)oVu<Bph+~KcnVi7I
zkjRk4#gNR9!o`rvkjBA~&gIMy$B+S1kqHvY;$X-I(K#Fpxga`^gCQRzSpeb`axfHe
zF%&bDa50oJlyNbXGgPoMRI)QvZM+b|C{@kQP{Ynp%gzwZ$iU@Vk(^pkl9``Z%+63Z
z`392<vo?dyWO?TP*m{Nr9)@~`Mn(n!1xG&@g@DB3;`02W6a`xa9)>1{W_E@a9)?zi
zHg<+~9)=EvPIiVa9)@m)9(INr9)@0qJ|2dCh6(Hp6L}aWF-&G>sO4dp!Z4MGVH(49
zMh1<^_UuxV?K!w6FJNS;XJp_AElw@UOUzB>VVJ=%lbvA}55sJR={yW`80NAw%;RC0
z&#-`<VIdF0B9JwUc^H;3bTTq<1Z3prrN-yw^Drz0nY@glnTKIHNQTQTv#7Wv9%A4M
zkO-$wB3xi4NPyKbB{wsVhhY`NR8}5_)eLJUZ)Z^uTg$_+4rIl89)=AJ8`&8)@i1&=
z(Ak{Ns>LeCpva)fpv3?JObm<++6+1jj10Py&vA*V>oG7eurV+)Ffi~i=z~cRo0Y+U
z!H|K0fs?_A!I*)GL3cAZHzy;b-eggp@IsI>69!g>B!(6S69!WTRt5%!9}H#;<{<MK
zelS=tm@_ak=rEjNuw*c2U}CUfIKW`VV9mhHV8g(`AjiP*kHLqX!IquDj-A2&4}&*5
kgM*~xF9yk93`|U142}#83@i+c3{DJ;49*M;3``6z04|M&7ytkO

diff --git a/target/classes/com/application/GUI/PopUpWindows/LoginPopup.class b/target/classes/com/application/GUI/PopUpWindows/LoginPopup.class
index 3f8a75275aab99173bb5eb93f608c03a1989df38..d4a94a6fe190f467c0b42a87ea149c36ce524ac6 100644
GIT binary patch
delta 5845
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
JILn&hD*&s#3I_lH

delta 3310
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

-- 
GitLab