diff options
Diffstat (limited to 'user')
| -rw-r--r-- | user/controller.go | 116 | ||||
| -rw-r--r-- | user/router.go | 2 | ||||
| -rw-r--r-- | user/service.go | 35 | ||||
| -rw-r--r-- | user/user.go | 55 | ||||
| -rw-r--r-- | user/validators.go | 60 | 
5 files changed, 62 insertions, 206 deletions
diff --git a/user/controller.go b/user/controller.go index 1dc85da..7dd519a 100644 --- a/user/controller.go +++ b/user/controller.go @@ -1,5 +1,5 @@  /* openbills - Server for web based Libre Billing Software - * Copyright (C) 2023-2024  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * Copyright (C) 2023-2025  Vidhu Kant Sharma <vidhukant@vidhukant.com>   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -20,8 +20,6 @@ package user  import (    e "vidhukant.com/openbills/errors"  	"github.com/gin-gonic/gin" -	"github.com/google/uuid" -	"github.com/spf13/viper"  	"net/http"  ) @@ -37,7 +35,7 @@ func handleGetUser (ctx *gin.Context) {    userId := uId.(uint) -  err := GetUser(&user, userId) +  err := GetUserById(&user, userId)  	if err != nil {  		ctx.Error(err)  		ctx.Abort() @@ -48,116 +46,6 @@ func handleGetUser (ctx *gin.Context) {    user.Password = ""  	ctx.JSON(http.StatusOK, gin.H{ -		"message": "success",  		"data": user,  	})  } - -func handleUploadLogo(ctx *gin.Context) { -	var user User - -  uId, ok := ctx.Get("UserID") -  if !ok { -    ctx.Error(e.ErrUnauthorized) -    ctx.Abort() -    return -  } - -  userId := uId.(uint) -	user.ID = userId - -	// TODO: handle potential errors -	file, err := ctx.FormFile("logo") -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	dest := uuid.New().String() - -	// TODO: handle potential errors -	err = ctx.SaveUploadedFile(file, viper.GetString("data.upload_dir") + dest) -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	// TODO: delete old file (if any) -	err = user.update(map[string]interface{}{"logo_file": dest}) -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	ctx.JSON(http.StatusOK, gin.H{ -		"message": "success", -	}) -} - -func handleUploadSignature(ctx *gin.Context) { -	var user User - -  uId, ok := ctx.Get("UserID") -  if !ok { -    ctx.Error(e.ErrUnauthorized) -    ctx.Abort() -    return -  } - -  userId := uId.(uint) -	user.ID = userId - -	// TODO: handle potential errors -	file, err := ctx.FormFile("signature") -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	dest := uuid.New().String() - -	// TODO: handle potential errors -	err = ctx.SaveUploadedFile(file, viper.GetString("data.upload_dir") + dest) -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	// TODO: delete old file (if any) -	err = user.update(map[string]interface{}{"signature_file": dest}) -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	ctx.JSON(http.StatusOK, gin.H{ -		"message": "success", -	}) -} - -// TODO: fix this stuff -// also add some kind of 2 factor verification -func handleDelUser (ctx *gin.Context) { -	id := uint(1) // get from JWT - -	var user User -	user.ID = id - -	// TODO: add a verification mechanism -	err := user.del() -	if err != nil { -		ctx.Error(err) -		ctx.Abort() -		return -	} - -	ctx.JSON(http.StatusOK, gin.H{ -		"message": "success", -	}) -} diff --git a/user/router.go b/user/router.go index d9fa7e0..eb7270a 100644 --- a/user/router.go +++ b/user/router.go @@ -25,7 +25,5 @@ func Routes(route *gin.RouterGroup) {  	g := route.Group("/user")  	{  		g.GET("/", handleGetUser) -		g.POST("/logo", handleUploadLogo) -		g.POST("/signature", handleUploadSignature)  	}  } diff --git a/user/service.go b/user/service.go index 222df4a..4dec8bc 100644 --- a/user/service.go +++ b/user/service.go @@ -1,5 +1,5 @@  /* openbills - Server for web based Libre Billing Software - * Copyright (C) 2023-2024  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * Copyright (C) 2023-2025  Vidhu Kant Sharma <vidhukant@vidhukant.com>   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -27,14 +27,12 @@ func (u *User) Create() error {  	return res.Error  } -func GetUserWithAccountName(user *User, accountName, method string) error { +func GetUserByAccountName(user *User, accountName, method string) error {  	if method != "username" && method != "email" {  		return e.ErrInvalidLoginMethod  	} -	res := db.Where(method + " = ?", accountName).Find(&user) - -	// TODO: handle potential errors +	res := db.Where(method + " = ?", accountName).Preload("Roles").Find(&user)  	if res.Error != nil {  		return res.Error  	} @@ -46,10 +44,8 @@ func GetUserWithAccountName(user *User, accountName, method string) error {  	return nil  } -func GetUser(user *User, id uint) error { -	res := db.Find(&user, id) - -	// TODO: handle potential errors +func GetUserById(user *User, id uint) error { +	res := db.Preload("Roles").Find(&user, id)  	if res.Error != nil {  		return res.Error  	} @@ -63,8 +59,6 @@ func GetUser(user *User, id uint) error {  func (u *User) del() error {  	res := db.Delete(u) - -	// TODO: handle potential errors  	if res.Error != nil {  		return res.Error  	} @@ -76,21 +70,4 @@ func (u *User) del() error {  	return nil  } -func (u *User) update(changes map[string]interface{}) error { -	res := db.Model(&u). -		Omit("email"). -		Omit("password"). -		Omit("username"). -		Updates(changes) - -	// TODO: handle potential errors -	if res.Error != nil { -		return res.Error -	} - -	if res.RowsAffected == 0 { -		return e.ErrNotFound -	} - -	return nil -} +// TODO: email/password updation (no username changes) with OTP verification or something diff --git a/user/user.go b/user/user.go index dbcbad0..4d0ffcb 100644 --- a/user/user.go +++ b/user/user.go @@ -1,5 +1,5 @@  /* openbills - Server for web based Libre Billing Software - * Copyright (C) 2023-2024  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * Copyright (C) 2023-2025  Vidhu Kant Sharma <vidhukant@vidhukant.com>   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -20,7 +20,6 @@ package user  import (  	d "vidhukant.com/openbills/db"  	e "vidhukant.com/openbills/errors" -  u "vidhukant.com/openbills/util"  	"golang.org/x/crypto/bcrypt"  	"gorm.io/gorm"  	"github.com/spf13/viper" @@ -32,35 +31,45 @@ var db *gorm.DB  func init() {  	db = d.DB -	db.AutoMigrate(&User{}) +	db.AutoMigrate(&User{}, &Role{})  	COST = viper.GetInt("cryptography.password_hashing_cost")  } +var VALID_ROLES []string = []string { +	"customer.*", "customer.read", "customer.write", "customer.delete", +	"item.*", "item.read", "item.write", "item.delete", +	"invoice.*", "invoice.read", "invoice.write", "invoice.delete", +	"admin", "*.*", +} + +type Role struct { +	ID     uint +	UserID uint +	Name   string +} +  type User struct { -	gorm.Model -  u.Address -	TokenVersion  uint // this can be incremented to disable existing refresh token(s) -  FullName      string -  FirmName      string -  Gstin         string -  Phone         string -  Email         string -  Website       string -	Username      string -	Password      string -	LogoFile      string -	SignatureFile string -	IsVerified    bool // this should be removed and tokens should be issued upon verification -	// will be printed with address on the invoice -	Details       string -	// a note is printed on every invoice. -	// This is the default that gets automatically set -	DefaultInvoiceNote string +	ID           uint +	TokenVersion uint // this can be incremented to disable existing refresh token(s) +  Username     string +  Email        string +	Password     string +	Roles        []Role `gorm:"constraint:OnDelete:CASCADE;"` +} + +func RolesToStringList(roles []Role) []string { +	x := []string{} + +	for _, i := range roles { +		x = append(x, i.Name) +	} + +	return x  }  func CheckPassword(user *User, accountName, method, pass string) error { -	err := GetUserWithAccountName(user, accountName, method) +	err := GetUserByAccountName(user, accountName, method)  	if err != nil {  		return err  	} diff --git a/user/validators.go b/user/validators.go index e497122..e9a894c 100644 --- a/user/validators.go +++ b/user/validators.go @@ -1,5 +1,5 @@  /* openbills - Server for web based Libre Billing Software - * Copyright (C) 2023-2024  Vidhu Kant Sharma <vidhukant@vidhukant.com> + * Copyright (C) 2023-2025  Vidhu Kant Sharma <vidhukant@vidhukant.com>   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -40,45 +40,40 @@ func validatePassword(pass string) error {  func validateUsername(username string) error {  	// check if username is too short -	if len(username) < viper.GetInt("username.min_username_length") { +	if len(username) < 2 {  		return errors.ErrUsernameTooShort  	}  	// check if username is too long -	if len(username) > viper.GetInt("username.max_username_length") { +	if len(username) > 32 {  		return errors.ErrUsernameTooLong  	} - -  for _, char := range username { -    if !strings.Contains(username, string(char)) { -      return errors.ErrInvalidUsername -    } -  } +  +	// (11th October 2025) what the fuck even is this  +	// I'm not even deleting this I can't stop laughing +  //  +  // for _, char := range username { +  //   if !strings.Contains(username, string(char)) { +  //     return errors.ErrInvalidUsername +  //   } +  // }    return nil  }  func (u *User) validate() error { -	u.Username = strings.TrimSpace(u.Username)  	u.Email = strings.TrimSpace(u.Email) -  u.Phone = strings.TrimSpace(u.Phone) -  u.Website = strings.TrimSpace(u.Website) -  u.Gstin = strings.TrimSpace(u.Gstin) -	u.IsVerified = false - -  // don't validate if GSTIN is empty -  if u.Gstin != "" && !util.ValidateGstin(u.Gstin) { -    return errors.ErrInvalidGSTIN -  } - -  // don't validate if phone is empty -  if u.Phone != "" && !util.ValidatePhone(u.Phone) { -    return errors.ErrInvalidPhone -  } +  u.Username = strings.TrimSpace(u.Username) -  // don't validate if website is empty -  if u.Website != "" && !util.ValidateWebsite(u.Website) { -    return errors.ErrInvalidWebsite +	// don't accept empty username +  if u.Username == "" { +    return errors.ErrEmptyUsername +  } else { +    // validate username +    err := validateUsername(u.Username) +    if err != nil { +      return err +    }    }    // don't accept empty email @@ -91,17 +86,6 @@ func (u *User) validate() error {      }    } -  // don't accept empty username -  if u.Username == "" { -    return errors.ErrEmptyUsername -  } else { -    // validate username -    err := validateUsername(u.Username) -    if err != nil { -      return err -    } -  } -    // validate password    err := validatePassword(u.Password)    if err != nil {  |