oktopus/backend/services/controller/internal/api/user.go
2024-04-30 17:56:46 -03:00

266 lines
6.0 KiB
Go

package api
import (
"encoding/json"
"log"
"net/http"
"net/mail"
"github.com/gorilla/mux"
"github.com/leandrofars/oktopus/internal/api/auth"
"github.com/leandrofars/oktopus/internal/db"
"github.com/leandrofars/oktopus/internal/utils"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func (a *Api) retrieveUsers(w http.ResponseWriter, r *http.Request) {
users, err := a.db.FindAllUsers()
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
for _, x := range users {
objectID, ok := x["_id"].(primitive.ObjectID)
if ok {
creationTime := objectID.Timestamp()
x["createdAt"] = creationTime.Format("02/01/2006")
}
delete(x, "password")
}
err = json.NewEncoder(w).Encode(users)
if err != nil {
log.Println(err)
}
}
func (a *Api) registerUser(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
if tokenString == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
email, err := auth.ValidateToken(tokenString)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
//Check if user which is requesting creation has the necessary privileges
rUser, err := a.db.FindUser(email)
if rUser.Level != AdminUser {
w.WriteHeader(http.StatusForbidden)
return
}
var user db.User
err = json.NewDecoder(r.Body).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
user.Level = NormalUser
if err := user.HashPassword(user.Password); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if user.Email == "" || user.Password == "" || !valid(user.Email) {
w.WriteHeader(http.StatusBadRequest)
return
}
if err := a.db.RegisterUser(user); err != nil {
if err == db.ErrorUserExists {
w.WriteHeader(http.StatusConflict)
w.Write([]byte("User with this email already exists"))
return
}
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func valid(email string) bool {
_, err := mail.ParseAddress(email)
return err == nil
}
func (a *Api) deleteUser(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
if tokenString == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
email, err := auth.ValidateToken(tokenString)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
//Check if user which is requesting deletion has the necessary privileges
rUser, err := a.db.FindUser(email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
userEmail := mux.Vars(r)["user"]
if rUser.Email == userEmail || (rUser.Level == AdminUser && rUser.Email != userEmail) { //Admin can delete any account, but admin account can never be deleted
if err := a.db.DeleteUser(userEmail); err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(err)
return
}
} else {
w.WriteHeader(http.StatusForbidden)
}
}
func (a *Api) changePassword(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
if tokenString == "" {
w.WriteHeader(http.StatusUnauthorized)
return
}
email, err := auth.ValidateToken(tokenString)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
userToChangePasswd := mux.Vars(r)["user"]
if userToChangePasswd != "" && userToChangePasswd != email {
rUser, _ := a.db.FindUser(email)
if rUser.Level != AdminUser {
w.WriteHeader(http.StatusForbidden)
return
}
email = userToChangePasswd
}
var user db.User
err = json.NewDecoder(r.Body).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
utils.MarshallEncoder(err, w)
return
}
user.Email = email
if err := user.HashPassword(user.Password); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := a.db.UpdatePassword(user); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func (a *Api) registerAdminUser(w http.ResponseWriter, r *http.Request) {
var user db.User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
users, err := a.db.FindAllUsers()
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
adminExists := adminUserExists(users)
if adminExists {
log.Println("There might exist only one admin")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode("There might exist only one admin")
return
}
user.Level = AdminUser
if err := user.HashPassword(user.Password); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := a.db.RegisterUser(user); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func adminUserExists(users []map[string]interface{}) bool {
for _, x := range users {
if x["level"].(int32) == AdminUser {
log.Println("Admin exists")
return true
}
}
return false
}
func (a *Api) adminUserExists(w http.ResponseWriter, r *http.Request) {
users, err := a.db.FindAllUsers()
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
adminExits := adminUserExists(users)
json.NewEncoder(w).Encode(adminExits)
return
}
type TokenRequest struct {
Email string `json:"email"`
Password string `json:"password"`
}
func (a *Api) generateToken(w http.ResponseWriter, r *http.Request) {
var tokenReq TokenRequest
err := json.NewDecoder(r.Body).Decode(&tokenReq)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
user, err := a.db.FindUser(tokenReq.Email)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode("Invalid Credentials")
return
}
credentialError := user.CheckPassword(tokenReq.Password)
if credentialError != nil {
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode("Invalid Credentials")
return
}
token, err := auth.GenerateJWT(user.Email, user.Name)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(token)
return
}