From d4cbccd47ee6a89e92c552f77bf2342c15f9d6f4 Mon Sep 17 00:00:00 2001 From: frikky Date: Mon, 22 Jun 2020 14:24:33 +0200 Subject: [PATCH] #63: Added general user editing ability for users --- backend/go-app/main.go | 123 ++++++++++++++++++++++++++++++++++++-- backend/go-app/walkoff.go | 78 ------------------------ frontend/src/Admin.js | 5 +- frontend/src/App.js | 2 +- frontend/src/LoginPage.js | 4 +- 5 files changed, 124 insertions(+), 88 deletions(-) diff --git a/backend/go-app/main.go b/backend/go-app/main.go index e61fd2fa..9774b606 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -838,6 +838,84 @@ func checkPasswordStrength(password string) error { return nil } +func deleteUser(resp http.ResponseWriter, request *http.Request) { + cors := handleCors(resp, request) + if cors { + return + } + + user, userErr := handleApiAuthentication(resp, request) + if userErr != nil { + log.Printf("Api authentication failed in edit workflow: %s", userErr) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + + if user.Role != "admin" { + log.Printf("Wrong user (%s) when deleting - must be admin", user.Username) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Must be admin"}`)) + return + } + + location := strings.Split(request.URL.String(), "/") + var userId string + if location[1] == "api" { + if len(location) <= 4 { + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + + userId = location[4] + } + + if userId == user.Id { + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Can't deactivate yourself"}`)) + return + } + + ctx := context.Background() + q := datastore.NewQuery("Users").Filter("id =", userId) + var users []User + _, err := dbclient.GetAll(ctx, q, &users) + if err != nil { + log.Printf("Error getting users apikey (deleteuser): %s", err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Failed getting users for verification"}`)) + return + } + + if len(users) != 1 { + log.Printf("Found too many users!") + resp.WriteHeader(500) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Backend error: too many or too few users with id %s: %d"}`, userId, len(users)))) + return + } + + // Invert. No user deletion. + if users[0].Active { + users[0].Active = false + } else { + users[0].Active = true + } + + err = setUser(ctx, &users[0]) + if err != nil { + log.Printf("Failed swapping active for user %s (%s)", users[0].Username, users[0].Id) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": true"}`))) + return + } + + log.Printf("Successfully inverted %s", users[0].Username) + + resp.WriteHeader(200) + resp.Write([]byte(`{"success": true}`)) +} + // No more emails :) func checkUsername(Username string) error { // Stupid first check of email loool @@ -1308,8 +1386,9 @@ func handleUpdateUser(resp http.ResponseWriter, request *http.Request) { } type newUserStruct struct { - Role string `json:"role"` - UserId string `json:"user_id"` + Role string `json:"role"` + Username string `json:"username"` + UserId string `json:"user_id"` } ctx := context.Background() @@ -1331,7 +1410,7 @@ func handleUpdateUser(resp http.ResponseWriter, request *http.Request) { foundUser, err := getUser(ctx, t.UserId) if err != nil { - log.Printf("Can't find user %s (apikey gen)", t.UserId, err) + log.Printf("Can't find user %s (update user): %s", t.UserId, err) resp.WriteHeader(401) resp.Write([]byte(fmt.Sprintf(`{"success": false}`))) return @@ -1355,6 +1434,33 @@ func handleUpdateUser(resp http.ResponseWriter, request *http.Request) { foundUser.Roles = []string{t.Role} } + if len(t.Username) > 0 { + q := datastore.NewQuery("Users").Filter("username =", t.Username) + var users []User + _, err = dbclient.GetAll(ctx, q, &users) + if err != nil { + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Failed getting users when updating user"}`)) + return + } + + found := false + for _, item := range users { + if item.Username == t.Username { + found = true + break + } + } + + if found { + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "User with username %s already exists"}`, t.Username))) + return + } + + foundUser.Username = t.Username + } + err = setUser(ctx, foundUser) if err != nil { log.Printf("Error patching user %s: %s", foundUser.Username, err) @@ -1368,6 +1474,7 @@ func handleUpdateUser(resp http.ResponseWriter, request *http.Request) { } func handleApiGeneration(resp http.ResponseWriter, request *http.Request) { + log.Printf("APIGEN!") cors := handleCors(resp, request) if cors { return @@ -1394,6 +1501,7 @@ func handleApiGeneration(resp http.ResponseWriter, request *http.Request) { userInfo = newUserInfo log.Printf("Updated apikey for user %s", userInfo.Username) } else if request.Method == "POST" { + log.Printf("Handling post!") body, err := ioutil.ReadAll(request.Body) if err != nil { log.Println("Failed reading body") @@ -1424,7 +1532,7 @@ func handleApiGeneration(resp http.ResponseWriter, request *http.Request) { foundUser, err := getUser(ctx, t.UserId) if err != nil { - log.Printf("Can't find user %s (apikey gen)", t.UserId, err) + log.Printf("Can't find user %s (apikey gen): %s", t.UserId, err) resp.WriteHeader(401) resp.Write([]byte(fmt.Sprintf(`{"success": false}`))) return @@ -1438,6 +1546,10 @@ func handleApiGeneration(resp http.ResponseWriter, request *http.Request) { return } foundUser = &newUserInfo + + resp.WriteHeader(200) + resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, foundUser.Username, foundUser.Verified, foundUser.ApiKey))) + return } resp.WriteHeader(200) @@ -6232,6 +6344,7 @@ func init() { r.HandleFunc("/functions/outlook/getFolders", handleGetOutlookFolders).Methods("GET", "OPTIONS") // Make user related locations + r.HandleFunc("/api/v1/users/generateapikey", handleApiGeneration).Methods("GET", "POST", "OPTIONS") r.HandleFunc("/api/v1/users/login", handleLogin).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/users/logout", handleLogout).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/users/register", handleRegister).Methods("POST", "OPTIONS") @@ -6239,9 +6352,9 @@ func init() { r.HandleFunc("/api/v1/users/getusers", handleGetUsers).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/users/getinfo", handleInfo).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/users/getsettings", handleSettings).Methods("GET", "OPTIONS") - r.HandleFunc("/api/v1/users/generateapikey", handleApiGeneration).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/users/updateuser", handleUpdateUser).Methods("PUT", "OPTIONS") r.HandleFunc("/api/v1/users/{user}", deleteUser).Methods("DELETE", "OPTIONS") + r.HandleFunc("/api/v1/users", handleGetUsers).Methods("GET", "OPTIONS") // General - duplicates and old. r.HandleFunc("/api/v1/login", handleLogin).Methods("POST", "OPTIONS") diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index 36ab5d2a..b7541c87 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -2929,84 +2929,6 @@ func setWorkflow(ctx context.Context, workflow Workflow, id string) error { return nil } -func deleteUser(resp http.ResponseWriter, request *http.Request) { - cors := handleCors(resp, request) - if cors { - return - } - - user, userErr := handleApiAuthentication(resp, request) - if userErr != nil { - log.Printf("Api authentication failed in edit workflow: %s", userErr) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - if user.Role != "admin" { - log.Printf("Wrong user (%s) when deleting - must be admin", user.Username) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "Must be admin"}`)) - return - } - - location := strings.Split(request.URL.String(), "/") - var userId string - if location[1] == "api" { - if len(location) <= 4 { - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) - return - } - - userId = location[4] - } - - if userId == user.Id { - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "Can't deactivate yourself"}`)) - return - } - - ctx := context.Background() - q := datastore.NewQuery("Users").Filter("id =", userId) - var users []User - _, err := dbclient.GetAll(ctx, q, &users) - if err != nil { - log.Printf("Error getting users apikey (deleteuser): %s", err) - resp.WriteHeader(401) - resp.Write([]byte(`{"success": false, "reason": "Failed getting users for verification"}`)) - return - } - - if len(users) != 1 { - log.Printf("Found too many users!") - resp.WriteHeader(500) - resp.Write([]byte(`{"success": false, "reason": "Backend error: too many users"}`)) - return - } - - // Invert. No user deletion. - if users[0].Active { - users[0].Active = false - } else { - users[0].Active = true - } - - err = setUser(ctx, &users[0]) - if err != nil { - log.Printf("Failed swapping active for user %s (%s)", users[0].Username, users[0].Id) - resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": true"}`))) - return - } - - log.Printf("Successfully inverted %s", users[0].Username) - - resp.WriteHeader(200) - resp.Write([]byte(`{"success": true}`)) -} - func deleteWorkflowApp(resp http.ResponseWriter, request *http.Request) { cors := handleCors(resp, request) if cors { diff --git a/frontend/src/Admin.js b/frontend/src/Admin.js index 902bf3b9..2c76392b 100644 --- a/frontend/src/Admin.js +++ b/frontend/src/Admin.js @@ -72,7 +72,7 @@ const Admin = (props) => { const onPasswordChange = () => { const data = {"username": selectedUser.username, "newpassword": newPassword} - const url = globalUrl+'/api/v1/passwordchange'; + const url = globalUrl+'/api/v1/users/passwordchange'; fetch(url, { mode: 'cors', method: 'POST', @@ -135,7 +135,7 @@ const Admin = (props) => { // Just use this one? var data = {"username": data.Username, "password": data.Password} var baseurl = globalUrl - const url = baseurl+'/api/v1/register'; + const url = baseurl+'/api/v1/users/register'; fetch(url, { method: 'POST', credentials: "include", @@ -296,6 +296,7 @@ const Admin = (props) => { return response.json() }) .then((responseJson) => { + console.log(responseJson) setUsers(responseJson) }) .catch(error => { diff --git a/frontend/src/App.js b/frontend/src/App.js index fd8d20ab..8eb7f108 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -84,7 +84,7 @@ const App = (message, props) => { const checkLogin = () => { var baseurl = globalUrl - fetch(baseurl+"/api/v1/getinfo", { + fetch(baseurl+"/api/v1/users/getinfo", { credentials: "include", headers: { 'Content-Type': 'application/json', diff --git a/frontend/src/LoginPage.js b/frontend/src/LoginPage.js index 7ff22e80..49e22f55 100644 --- a/frontend/src/LoginPage.js +++ b/frontend/src/LoginPage.js @@ -92,7 +92,7 @@ const LoginDialog = props => { var data = {"username": username, "password": password} var baseurl = globalUrl if (register) { - var url = baseurl+'/api/v1/login'; + var url = baseurl+'/api/v1/users/login'; fetch(url, { mode: 'cors', method: 'POST', @@ -123,7 +123,7 @@ const LoginDialog = props => { setLoginInfo("Error in userdata: " + error) }); } else { - url = baseurl+'/api/v1/register'; + url = baseurl+'/api/v1/users/register'; fetch(url, { method: 'POST', body: JSON.stringify(data),