Added ability for admin to control user passwords, active and API
This commit is contained in:
+85
-60
@@ -70,7 +70,7 @@ var baseDockerName = "frikky/shuffle"
|
|||||||
var dbclient *datastore.Client
|
var dbclient *datastore.Client
|
||||||
|
|
||||||
type Userapi struct {
|
type Userapi struct {
|
||||||
Username string `datastore:"Username"`
|
Username string `datastore:"username"`
|
||||||
ApiKey string `datastore:"apikey"`
|
ApiKey string `datastore:"apikey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ type session struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type loginStruct struct {
|
type loginStruct struct {
|
||||||
Username string `json:"Username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,9 +810,9 @@ func parseLoginParameters(resp http.ResponseWriter, request *http.Request) (logi
|
|||||||
// Removed for localhost
|
// Removed for localhost
|
||||||
func checkPasswordStrength(password string) error {
|
func checkPasswordStrength(password string) error {
|
||||||
// Check password strength here
|
// Check password strength here
|
||||||
//if len(password) < 10 {
|
if len(password) < 10 {
|
||||||
// return errors.New("Minimum password length is 10.")
|
return errors.New("Minimum password length is 10.")
|
||||||
//}
|
}
|
||||||
|
|
||||||
//if len(password) > 128 {
|
//if len(password) > 128 {
|
||||||
// return errors.New("Maximum password length is 128.")
|
// return errors.New("Maximum password length is 128.")
|
||||||
@@ -1334,7 +1334,7 @@ func handleApiGeneration(resp http.ResponseWriter, request *http.Request) {
|
|||||||
|
|
||||||
log.Printf("Updated apikey for user %s", userInfo.Username)
|
log.Printf("Updated apikey for user %s", userInfo.Username)
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "Username": "%s", "verified": %t, "apikey": "%s"}`, userInfo.Username, userInfo.Verified, userInfo.ApiKey)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, userInfo.Username, userInfo.Verified, userInfo.ApiKey)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSettings(resp http.ResponseWriter, request *http.Request) {
|
func handleSettings(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -1380,7 +1380,7 @@ func handleSettings(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteHeader(200)
|
resp.WriteHeader(200)
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": true, "Username": "%s", "verified": %t, "apikey": "%s"}`, UserInfo.Username, UserInfo.Verified, UserInfo.ApiKey)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": true, "username": "%s", "verified": %t, "apikey": "%s"}`, UserInfo.Username, UserInfo.Verified, UserInfo.ApiKey)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -1402,9 +1402,10 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
sessionToken := c.Value
|
sessionToken := c.Value
|
||||||
|
log.Printf("Found session %s", sessionToken)
|
||||||
session, err := getSession(ctx, sessionToken)
|
session, err := getSession(ctx, sessionToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//log.Printf("Session %#v doesn't exist: %s", session, err)
|
log.Printf("Session %#v doesn't exist: %s", session, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "No session"}`))
|
resp.Write([]byte(`{"success": false, "reason": "No session"}`))
|
||||||
return
|
return
|
||||||
@@ -1501,9 +1502,10 @@ type passwordReset struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type passwordChange struct {
|
type passwordChange struct {
|
||||||
Password1 string `json:"newpassword"`
|
Username string `json:"username"`
|
||||||
Password2 string `json:"newpassword2"`
|
Newpassword string `json:"newpassword"`
|
||||||
Password3 string `json:"currentpassword"`
|
Newpassword2 string `json:"newpassword2"`
|
||||||
|
Currentpassword string `json:"currentpassword"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePasswordResetMail(resp http.ResponseWriter, request *http.Request) {
|
func handlePasswordResetMail(resp http.ResponseWriter, request *http.Request) {
|
||||||
@@ -1524,7 +1526,7 @@ func handlePasswordResetMail(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type passwordReset struct {
|
type passwordReset struct {
|
||||||
Username string `json:"Username"`
|
Username string `json:"username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var t passwordReset
|
var t passwordReset
|
||||||
@@ -1679,13 +1681,12 @@ func handlePasswordReset(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handlePasswordChange(resp http.ResponseWriter, request *http.Request) {
|
func handlePasswordChange(resp http.ResponseWriter, request *http.Request) {
|
||||||
log.Println("Handling password change")
|
|
||||||
|
|
||||||
cors := handleCors(resp, request)
|
cors := handleCors(resp, request)
|
||||||
if cors {
|
if cors {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("Handling password change")
|
||||||
body, err := ioutil.ReadAll(request.Body)
|
body, err := ioutil.ReadAll(request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed reading body")
|
log.Println("Failed reading body")
|
||||||
@@ -1694,6 +1695,7 @@ func handlePasswordChange(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the current user - check if they're admin or the "username" user.
|
||||||
var t passwordChange
|
var t passwordChange
|
||||||
err = json.Unmarshal(body, &t)
|
err = json.Unmarshal(body, &t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1703,21 +1705,41 @@ func handlePasswordChange(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Password1 != t.Password2 {
|
user, err := handleApiAuthentication(resp, request)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Api authentication failed in set new workflowhandler: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
curUserFound := false
|
||||||
|
if t.Username != user.Username && user.Role != "admin" {
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Admin required to change others' passwords"}`))
|
||||||
|
return
|
||||||
|
} else if t.Username == user.Username {
|
||||||
|
curUserFound = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.Role != "admin" {
|
||||||
|
if t.Newpassword != t.Newpassword2 {
|
||||||
err := "Passwords don't match"
|
err := "Passwords don't match"
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t.Password1) < 10 || len(t.Password2) < 10 {
|
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
err := "Passwords don't match - 2"
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = checkPasswordStrength(t.Password3)
|
if len(t.Newpassword) < 10 || len(t.Newpassword2) < 10 {
|
||||||
|
err := "Passwords too short - 2"
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current password
|
||||||
|
err = checkPasswordStrength(t.Newpassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Bad password strength: %s", err)
|
log.Printf("Bad password strength: %s", err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
@@ -1725,56 +1747,52 @@ func handlePasswordChange(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cookie
|
|
||||||
c, err := request.Cookie("session_token")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("User doesn't have sessiontoken on pw change: %s", err)
|
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "You're not logged in."}`)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// Validate with User
|
if !curUserFound {
|
||||||
sessionToken := c.Value
|
log.Printf("Have to find a different user")
|
||||||
session, err := getSession(ctx, sessionToken)
|
q := datastore.NewQuery("Users").Filter("Username =", strings.ToLower(t.Username))
|
||||||
|
var users []User
|
||||||
|
_, err = dbclient.GetAll(ctx, q, &users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Session %s doesn't exist (password change): %s", session.Session, err)
|
log.Printf("Failed getting user %s", t.Username)
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": "You're not logged in"}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get session first
|
|
||||||
// Should basically never happen
|
|
||||||
Userdata, err := getUser(ctx, session.Id)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Username %s doesn't exist (pw change): %s", session.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(Userdata.Password), []byte(t.Password1))
|
if len(users) != 1 {
|
||||||
|
log.Printf(`Found multiple users with the same username: %s: %d`, t.Username, len(users))
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Found multiple users with the same username: %s"}`, t.Username)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user = users[0]
|
||||||
|
} else {
|
||||||
|
// Admins can re-generate others' passwords as well.
|
||||||
|
if user.Role != "admin" {
|
||||||
|
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(t.Newpassword))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Bad password for %s: %s", session.Username, err)
|
log.Printf("Bad password for %s: %s", user.Username, err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(t.Newpassword), 8)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("New password failure for %s: %s", user.Username, err)
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(t.Password3), 8)
|
user.Password = string(hashedPassword)
|
||||||
|
err = setUser(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Wrong password for %s: %s", Userdata.Username, err)
|
log.Printf("Error fixing password for user %s: %s", user.Username, err)
|
||||||
resp.WriteHeader(401)
|
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Userdata.Password = string(hashedPassword)
|
|
||||||
err = setUser(ctx, Userdata)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error adding User %s: %s", Userdata.Username, err)
|
|
||||||
resp.WriteHeader(401)
|
resp.WriteHeader(401)
|
||||||
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
resp.Write([]byte(`{"success": false, "reason": "Username and/or password is incorrect"}`))
|
||||||
return
|
return
|
||||||
@@ -2057,6 +2075,7 @@ func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Userdata := users[0]
|
Userdata := users[0]
|
||||||
|
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(Userdata.Password), []byte(data.Password))
|
err = bcrypt.CompareHashAndPassword([]byte(Userdata.Password), []byte(data.Password))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Password for %s is incorrect: %s", data.Username, err)
|
log.Printf("Password for %s is incorrect: %s", data.Username, err)
|
||||||
@@ -2065,7 +2084,14 @@ func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("%s SUCCESSFULLY LOGGED IN", data.Username)
|
if !Userdata.Active {
|
||||||
|
log.Printf("%s is not active, but tried to login", data.Username, err)
|
||||||
|
resp.WriteHeader(401)
|
||||||
|
resp.Write([]byte(`{"success": false, "reason": "This user is deactivated"}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("%s SUCCESSFULLY LOGGED IN with session %s", data.Username, Userdata.Session)
|
||||||
//if !Userdata.Verified {
|
//if !Userdata.Verified {
|
||||||
// log.Printf("User %s is not verified", data.Username)
|
// log.Printf("User %s is not verified", data.Username)
|
||||||
// resp.WriteHeader(403)
|
// resp.WriteHeader(403)
|
||||||
@@ -2100,7 +2126,6 @@ func handleLogin(resp http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sessionToken := uuid.NewV4()
|
sessionToken := uuid.NewV4()
|
||||||
|
|
||||||
http.SetCookie(resp, &http.Cookie{
|
http.SetCookie(resp, &http.Cookie{
|
||||||
Name: "session_token",
|
Name: "session_token",
|
||||||
Value: sessionToken.String(),
|
Value: sessionToken.String(),
|
||||||
|
|||||||
+119
-15
@@ -1,5 +1,6 @@
|
|||||||
import React, { useEffect} from 'react';
|
import React, { useEffect} from 'react';
|
||||||
|
|
||||||
|
import {Link} from 'react-router-dom';
|
||||||
import Paper from '@material-ui/core/Paper';
|
import Paper from '@material-ui/core/Paper';
|
||||||
import List from '@material-ui/core/List';
|
import List from '@material-ui/core/List';
|
||||||
import Divider from '@material-ui/core/Divider';
|
import Divider from '@material-ui/core/Divider';
|
||||||
@@ -32,6 +33,8 @@ const Admin = (props) => {
|
|||||||
const [environments, setEnvironments] = React.useState([]);
|
const [environments, setEnvironments] = React.useState([]);
|
||||||
const [schedules, setSchedules] = React.useState([])
|
const [schedules, setSchedules] = React.useState([])
|
||||||
const [selectedUser, setSelectedUser] = React.useState({})
|
const [selectedUser, setSelectedUser] = React.useState({})
|
||||||
|
const [newPassword, setNewPassword] = React.useState("");
|
||||||
|
const [selectedUserModalOpen, setSelectedUserModalOpen] = React.useState(false)
|
||||||
|
|
||||||
const alert = useAlert()
|
const alert = useAlert()
|
||||||
|
|
||||||
@@ -64,6 +67,34 @@ const Admin = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onPasswordChange = () => {
|
||||||
|
const data = {"username": selectedUser.username, "newpassword": newPassword}
|
||||||
|
const url = globalUrl+'/api/v1/passwordchange';
|
||||||
|
fetch(url, {
|
||||||
|
mode: 'cors',
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: 'include',
|
||||||
|
crossDomain: true,
|
||||||
|
withCredentials: true,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=utf-8',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response =>
|
||||||
|
response.json().then(responseJson => {
|
||||||
|
if (responseJson["success"] === false) {
|
||||||
|
alert.error("Failed setting new password")
|
||||||
|
} else {
|
||||||
|
alert.success("Changed password!")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
alert.error("Err: ", error.toString())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const deleteUser = (data) => {
|
const deleteUser = (data) => {
|
||||||
// Just use this one?
|
// Just use this one?
|
||||||
const url = globalUrl+'/api/v1/users/'+data.id
|
const url = globalUrl+'/api/v1/users/'+data.id
|
||||||
@@ -85,7 +116,7 @@ const Admin = (props) => {
|
|||||||
if (!responseJson.success && responseJson.reason !== undefined) {
|
if (!responseJson.success && responseJson.reason !== undefined) {
|
||||||
alert.error("Failed to deactivate user: "+responseJson.reason)
|
alert.error("Failed to deactivate user: "+responseJson.reason)
|
||||||
} else {
|
} else {
|
||||||
alert.success("Deleted user "+data.id)
|
alert.success("Deactivated user "+data.id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -287,10 +318,41 @@ const Admin = (props) => {
|
|||||||
modalUser[field] = value
|
modalUser[field] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const generateApikey = () => {
|
||||||
|
fetch(globalUrl+"/api/v1/generateapikey", {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
credentials: "include",
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log("Status not 200 for WORKFLOW EXECUTION :O!")
|
||||||
|
} else {
|
||||||
|
getUsers()
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then((responseJson) => {
|
||||||
|
console.log("RESP: ", responseJson)
|
||||||
|
if (!responseJson.success && responseJson.reason !== undefined) {
|
||||||
|
alert.error("Failed getting new: "+responseJson.reason)
|
||||||
|
} else {
|
||||||
|
alert.success("Got new API key")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const editUserModal =
|
const editUserModal =
|
||||||
<Dialog modal
|
<Dialog modal
|
||||||
open={modalOpen}
|
open={selectedUserModalOpen}
|
||||||
onClose={() => {setModalOpen(false)}}
|
onClose={() => {setSelectedUserModalOpen(false)}}
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: surfaceColor,
|
backgroundColor: surfaceColor,
|
||||||
@@ -300,7 +362,55 @@ const Admin = (props) => {
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle><span style={{color: "white"}}>Add user</span></DialogTitle>
|
<DialogTitle><span style={{color: "white"}}>Edit user</span></DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<div style={{display: "flex"}}>
|
||||||
|
<TextField
|
||||||
|
style={{backgroundColor: inputColor, flex: 3}}
|
||||||
|
InputProps={{
|
||||||
|
style:{
|
||||||
|
height: 50,
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color="primary"
|
||||||
|
required
|
||||||
|
fullWidth={true}
|
||||||
|
placeholder="New password"
|
||||||
|
type="password"
|
||||||
|
id="standard-required"
|
||||||
|
autoComplete="password"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
onChange={e => setNewPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
style={{maxHeight: 50, flex: 1}}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => onPasswordChange()}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Divider style={{marginTop: 20, marginBottom: 20, backgroundColor: inputColor}}/>
|
||||||
|
<Button
|
||||||
|
style={{}}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => deleteUser(selectedUser)}
|
||||||
|
>
|
||||||
|
{selectedUser.active ? "Deactivate" : "Activate"}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={{}}
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => generateApikey(selectedUser)}
|
||||||
|
>
|
||||||
|
Get new API key
|
||||||
|
</Button>
|
||||||
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
const modalView =
|
const modalView =
|
||||||
@@ -447,7 +557,6 @@ const Admin = (props) => {
|
|||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{users === undefined ? null : users.map(data => {
|
{users === undefined ? null : users.map(data => {
|
||||||
console.log("USER: ", data)
|
|
||||||
return (
|
return (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
@@ -475,17 +584,12 @@ const Admin = (props) => {
|
|||||||
style={{}}
|
style={{}}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => deleteUser(data)}
|
onClick={() => {
|
||||||
|
setSelectedUserModalOpen(true)
|
||||||
|
setSelectedUser(data)
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{data.active ? "Deactivate" : "Activate"}
|
Edit user
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
style={{}}
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={() => deleteUser(data)}
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</Button>
|
</Button>
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Divider from '@material-ui/core/Divider';
|
|||||||
import {Link} from 'react-router-dom';
|
import {Link} from 'react-router-dom';
|
||||||
|
|
||||||
import TextField from '@material-ui/core/TextField';
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
import { useAlert } from "react-alert";
|
||||||
|
|
||||||
|
|
||||||
//const tmpdata = {
|
//const tmpdata = {
|
||||||
@@ -23,6 +24,7 @@ import TextField from '@material-ui/core/TextField';
|
|||||||
// FIXME: Use isLoggedIn :)
|
// FIXME: Use isLoggedIn :)
|
||||||
const Settings = (props) => {
|
const Settings = (props) => {
|
||||||
const { globalUrl, isLoaded, userdata, surfaceColor, inputColor } = props;
|
const { globalUrl, isLoaded, userdata, surfaceColor, inputColor } = props;
|
||||||
|
const alert = useAlert()
|
||||||
|
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [firstname, setFirstname] = useState("");
|
const [firstname, setFirstname] = useState("");
|
||||||
@@ -65,7 +67,7 @@ const Settings = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onPasswordChange = () => {
|
const onPasswordChange = () => {
|
||||||
const data = {"currentpassword": currentPassword, "newpassword": newPassword, "newpassword2": newPassword2}
|
const data = {"username": userSettings.username, "currentpassword": currentPassword, "newpassword": newPassword, "newpassword2": newPassword2}
|
||||||
const url = globalUrl+'/api/v1/passwordchange';
|
const url = globalUrl+'/api/v1/passwordchange';
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
@@ -82,6 +84,9 @@ const Settings = (props) => {
|
|||||||
response.json().then(responseJson => {
|
response.json().then(responseJson => {
|
||||||
if (responseJson["success"] === false) {
|
if (responseJson["success"] === false) {
|
||||||
setPasswordFormMessage(responseJson["reason"])
|
setPasswordFormMessage(responseJson["reason"])
|
||||||
|
} else {
|
||||||
|
alert.success("Changed password!")
|
||||||
|
setPasswordFormMessage("")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user