Create Users api
Former-commit-id: d2eb78f0f491d32239c5f5c8865408198f914235 [formerly 27ba4eb9f58ea6b31ba17514fb3ce1404059e26e] [formerly 1e8be28be7b9a3b2fcc90d197b4fded2fa0eb07f [formerly 9b0ca01aa5]]
Former-commit-id: b1b2aa6ea47c8c91bc4e641eb374229160c14abb [formerly fb8324f8241b5c7bbb7ffa732b90029cf1184406]
Former-commit-id: c4e4aeb77d1b5dff14980655295faf1998b94df1
			
			
				pull/726/head
			
			
		
							parent
							
								
									eb6335f0ca
								
							
						
					
					
						commit
						c95378632e
					
				
							
								
								
									
										252
									
								
								api.go
								
								
								
								
							
							
						
						
									
										252
									
								
								api.go
								
								
								
								
							| 
						 | 
				
			
			@ -2,12 +2,17 @@ package filemanager
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/asdine/storm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func cleanURL(path string) (string, string) {
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +59,8 @@ func serveAPI(c *requestContext, w http.ResponseWriter, r *http.Request) (int, e
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println(c.us)
 | 
			
		||||
 | 
			
		||||
	switch router {
 | 
			
		||||
	case "download":
 | 
			
		||||
		return downloadHandler(c, w, r)
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +72,12 @@ func serveAPI(c *requestContext, w http.ResponseWriter, r *http.Request) (int, e
 | 
			
		|||
		return search(c, w, r)
 | 
			
		||||
	case "resource":
 | 
			
		||||
		return resourceHandler(c, w, r)
 | 
			
		||||
	case "users":
 | 
			
		||||
		if !c.us.Admin && !(r.URL.Path == "/self" && r.Method == http.MethodPut) {
 | 
			
		||||
			return http.StatusForbidden, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return usersHandler(c, w, r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return http.StatusNotFound, nil
 | 
			
		||||
| 
						 | 
				
			
			@ -319,3 +332,242 @@ func handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (sort
 | 
			
		|||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func usersHandler(c *requestContext, w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
	switch r.Method {
 | 
			
		||||
	case http.MethodGet:
 | 
			
		||||
		return usersGetHandler(c, w, r)
 | 
			
		||||
	case http.MethodPost:
 | 
			
		||||
		return usersPostHandler(c, w, r)
 | 
			
		||||
	case http.MethodDelete:
 | 
			
		||||
		return usersDeleteHandler(c, w, r)
 | 
			
		||||
	case http.MethodPut:
 | 
			
		||||
		return usersPutHandler(c, w, r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return http.StatusNotImplemented, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// usersGetHandler is used to handle the GET requests for /api/users. It can print a list
 | 
			
		||||
// of users or a specific user. The password hash is always removed before being sent to the
 | 
			
		||||
// client.
 | 
			
		||||
func usersGetHandler(c *requestContext, w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
	// If the request is a list of users.
 | 
			
		||||
	if r.URL.Path == "/" {
 | 
			
		||||
		users := []User{}
 | 
			
		||||
 | 
			
		||||
		for _, user := range c.fm.Users {
 | 
			
		||||
			// Copies the user and removes the password.
 | 
			
		||||
			u := *user
 | 
			
		||||
			u.Password = ""
 | 
			
		||||
			users = append(users, u)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return renderJSON(w, users)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise we just want one, specific, user.
 | 
			
		||||
	sid := strings.TrimPrefix(r.URL.Path, "/")
 | 
			
		||||
	sid = strings.TrimSuffix(sid, "/")
 | 
			
		||||
 | 
			
		||||
	id, err := strconv.Atoi(sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusNotFound, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Searches for the user and prints the one who matches.
 | 
			
		||||
	for _, user := range c.fm.Users {
 | 
			
		||||
		if user.ID != id {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		u := *user
 | 
			
		||||
		u.Password = ""
 | 
			
		||||
		return renderJSON(w, u)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If there aren't any matches, return Not Found.
 | 
			
		||||
	return http.StatusNotFound, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func usersPostHandler(c *requestContext, w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
	// New users should be created on /api/users.
 | 
			
		||||
	if r.URL.Path != "/" {
 | 
			
		||||
		return http.StatusMethodNotAllowed, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the request body is empty, send a Bad Request status.
 | 
			
		||||
	if r.Body == nil {
 | 
			
		||||
		return http.StatusBadRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var u User
 | 
			
		||||
 | 
			
		||||
	// Parses the user and checks for error.
 | 
			
		||||
	err := json.NewDecoder(r.Body).Decode(&u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusBadRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The username and the password cannot be empty.
 | 
			
		||||
	if u.Username == "" || u.Password == "" || u.FileSystem == "" {
 | 
			
		||||
		return http.StatusBadRequest, errors.New("Username, password or scope are empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize rules if they're not initialized.
 | 
			
		||||
	if u.Rules == nil {
 | 
			
		||||
		u.Rules = []*Rule{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize commands if not initialized.
 | 
			
		||||
	if u.Commands == nil {
 | 
			
		||||
		u.Commands = []string{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// It's a new user so the ID will be auto created.
 | 
			
		||||
	if u.ID != 0 {
 | 
			
		||||
		u.ID = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Hashes the password.
 | 
			
		||||
	pw, err := hashPassword(u.Password)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u.Password = pw
 | 
			
		||||
 | 
			
		||||
	// Saves the user to the database.
 | 
			
		||||
	err = c.fm.db.Save(&u)
 | 
			
		||||
	if err == storm.ErrAlreadyExists {
 | 
			
		||||
		return http.StatusConflict, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Saves the user to the memory.
 | 
			
		||||
	c.fm.Users[u.Username] = &u
 | 
			
		||||
 | 
			
		||||
	// Set the Location header and return.
 | 
			
		||||
	w.WriteHeader(http.StatusCreated)
 | 
			
		||||
	w.Header().Set("Location", c.fm.RootURL()+"/api/users/"+strconv.Itoa(u.ID))
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func usersDeleteHandler(c *requestContext, w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
	// New users should be created on /api/users.
 | 
			
		||||
	if r.URL.Path == "/" {
 | 
			
		||||
		return http.StatusMethodNotAllowed, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise we just want one, specific, user.
 | 
			
		||||
	sid := strings.TrimPrefix(r.URL.Path, "/")
 | 
			
		||||
	sid = strings.TrimSuffix(sid, "/")
 | 
			
		||||
 | 
			
		||||
	id, err := strconv.Atoi(sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusNotFound, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = c.fm.db.DeleteStruct(&User{ID: id})
 | 
			
		||||
	if err == storm.ErrNotFound {
 | 
			
		||||
		return http.StatusNotFound, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, user := range c.fm.Users {
 | 
			
		||||
		if user.ID == id {
 | 
			
		||||
			delete(c.fm.Users, user.Username)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return http.StatusOK, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func usersPutHandler(c *requestContext, w http.ResponseWriter, r *http.Request) (int, error) {
 | 
			
		||||
	// New users should be created on /api/users.
 | 
			
		||||
	if r.URL.Path == "/" {
 | 
			
		||||
		return http.StatusMethodNotAllowed, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise we just want one, specific, user.
 | 
			
		||||
	sid := strings.TrimPrefix(r.URL.Path, "/")
 | 
			
		||||
	sid = strings.TrimSuffix(sid, "/")
 | 
			
		||||
 | 
			
		||||
	id, err := strconv.Atoi(sid)
 | 
			
		||||
	if err != nil && sid != "self" {
 | 
			
		||||
		return http.StatusNotFound, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the request body is empty, send a Bad Request status.
 | 
			
		||||
	if r.Body == nil {
 | 
			
		||||
		return http.StatusBadRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var u User
 | 
			
		||||
 | 
			
		||||
	// Parses the user and checks for error.
 | 
			
		||||
	err = json.NewDecoder(r.Body).Decode(&u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusBadRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sid == "self" {
 | 
			
		||||
		if u.Password == "" {
 | 
			
		||||
			return http.StatusBadRequest, errors.New("Password missing")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pw, err := hashPassword(u.Password)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println(err)
 | 
			
		||||
			return http.StatusInternalServerError, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.us.Password = pw
 | 
			
		||||
		err = c.fm.db.UpdateField(&User{ID: c.us.ID}, "Password", pw)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println(err)
 | 
			
		||||
			return http.StatusInternalServerError, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return http.StatusOK, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The username and the filesystem cannot be empty.
 | 
			
		||||
	if u.Username == "" || u.FileSystem == "" {
 | 
			
		||||
		return http.StatusBadRequest, errors.New("Username, password or scope are empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize rules if they're not initialized.
 | 
			
		||||
	if u.Rules == nil {
 | 
			
		||||
		u.Rules = []*Rule{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize commands if not initialized.
 | 
			
		||||
	if u.Commands == nil {
 | 
			
		||||
		u.Commands = []string{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ouser, ok := c.fm.Users[u.Username]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return http.StatusNotFound, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u.ID = id
 | 
			
		||||
	u.Password = ouser.Password
 | 
			
		||||
 | 
			
		||||
	// Updates the whole User struct because we always are supposed
 | 
			
		||||
	// to send a new entire object.
 | 
			
		||||
	err = c.fm.db.Save(&u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.fm.Users[u.Username] = &u
 | 
			
		||||
	return http.StatusOK, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue