Allow adding users to rooms
This commit is contained in:
@@ -21,6 +21,8 @@ type CRUDController interface {
|
|||||||
|
|
||||||
type RoomController interface {
|
type RoomController interface {
|
||||||
CRUDController
|
CRUDController
|
||||||
|
GetUsers(*gin.Context)
|
||||||
|
AddUser(*gin.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
type roomController struct {
|
type roomController struct {
|
||||||
@@ -65,7 +67,14 @@ func (rc *roomController) GetById(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rc *roomController) Create(c *gin.Context) {
|
func (rc *roomController) Create(c *gin.Context) {
|
||||||
|
user, exists := c.Get("user")
|
||||||
|
if !exists {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
room, err := models.NewRoom(c)
|
room, err := models.NewRoom(c)
|
||||||
|
room.Admins = append(room.Admins, user.(models.User))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ReplyError(c, err)
|
ReplyError(c, err)
|
||||||
@@ -77,6 +86,14 @@ func (rc *roomController) Create(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//userID := user.(models.User).ID
|
||||||
|
//rc.DB.Model(&models.Room{}).Where("id = ?"), room.ID).Association("Admins").Append(&models.User{ID: userID})
|
||||||
|
|
||||||
|
//if result.Error != nil {
|
||||||
|
// ReplyError(c, fmt.Errorf("Room creation failed: %s", result.Error))
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
ReplyOK(c, "Room was created")
|
ReplyOK(c, "Room was created")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +141,83 @@ func (rc *roomController) Delete(c *gin.Context) {
|
|||||||
ReplyOK(c, "Room was deleted")
|
ReplyOK(c, "Room was deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rc *roomController) GetUsers(c *gin.Context) {
|
||||||
|
//only allow room admin
|
||||||
|
|
||||||
|
roomId, err := strconv.Atoi(c.Param("id"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("Room with Id '%s' does not exist", c.Param("id")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var room models.Room
|
||||||
|
result := rc.DB.First(&room, uint(roomId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("Could not query room: %v", result.Error))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var users []models.User
|
||||||
|
rc.DB.Model(&room).Association("Users").Find(&users)
|
||||||
|
|
||||||
|
var emails []string
|
||||||
|
for _, user := range users {
|
||||||
|
emails = append(emails, user.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplyOK(c, emails)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *roomController) AddUser(c *gin.Context) {
|
||||||
|
//only allow room admin
|
||||||
|
|
||||||
|
var body struct {
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.Bind(&body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "Failed to read body",
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//lookup requested user
|
||||||
|
var user models.User
|
||||||
|
result := rc.DB.First(&user, "email = ?", body.Email)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
|
"error": "Invalid user",
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
roomId, err := strconv.Atoi(c.Param("id"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("Room with Id '%s' does not exist", c.Param("id")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var room models.Room
|
||||||
|
result = rc.DB.First(&room, uint(roomId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("Could not query room: %v", result.Error))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.DB.Model(&room).Association("Users").Append(&user)
|
||||||
|
ReplyOK(c, "Added User to Room")
|
||||||
|
}
|
||||||
|
|
||||||
func ReplyError(ctx *gin.Context, err error) {
|
func ReplyError(ctx *gin.Context, err error) {
|
||||||
ctx.JSON(http.StatusBadRequest, gin.H{ "error": err.Error() })
|
ctx.JSON(http.StatusBadRequest, gin.H{ "error": err.Error() })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import(
|
import(
|
||||||
"os"
|
"os"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
"net/http"
|
"net/http"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
@@ -25,9 +26,10 @@ func NewUserController(db *gorm.DB) UserController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (uc *UserController) Signup(c *gin.Context) {
|
func (uc *UserController) Register(c *gin.Context) {
|
||||||
//Get the email/passwd off req body
|
//Get the email/passwd off req body
|
||||||
var body struct {
|
var body struct {
|
||||||
|
Name string
|
||||||
Email string
|
Email string
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
@@ -54,10 +56,11 @@ func (uc *UserController) Signup(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//create user
|
//create user
|
||||||
user := models.User{Email: body.Email, Password: string(hash)}
|
user := models.User{Name: body.Name, Email: body.Email, Password: string(hash)}
|
||||||
result := uc.DB.Create(&user)
|
result := uc.DB.Create(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
|
fmt.Println("Error: ", result.Error)
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
c.JSON(http.StatusBadRequest, gin.H{
|
||||||
"error": "Failed to create user",
|
"error": "Failed to create user",
|
||||||
})
|
})
|
||||||
@@ -136,9 +139,15 @@ func (uc *UserController) Login(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserController) Validate(c *gin.Context) {
|
func (uc *UserController) Validate(c *gin.Context) {
|
||||||
user, _ := c.Get("user")
|
user, exists := c.Get("user")
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
if exists {
|
||||||
"message": user,
|
c.JSON(http.StatusOK, gin.H{
|
||||||
})
|
"message": fmt.Sprintf("Logged in with userID: %d", user.(models.User).ID),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"message": "Currently not logged in.",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
main.go
17
main.go
@@ -70,15 +70,18 @@ func main() {
|
|||||||
apiRoutes := server.Group("/api")
|
apiRoutes := server.Group("/api")
|
||||||
//apiRoutes.Use(middlewares.BasicAuth())
|
//apiRoutes.Use(middlewares.BasicAuth())
|
||||||
{
|
{
|
||||||
apiRoutes.POST("/rooms", roomController.Create)
|
apiRoutes.POST("/rooms", authValidator.RequireAuth, roomController.Create)
|
||||||
apiRoutes.GET("/rooms", roomController.GetAll)
|
apiRoutes.GET("/rooms", authValidator.OptionalAuth, roomController.GetAll)
|
||||||
apiRoutes.GET("/rooms/:id", roomController.GetById)
|
apiRoutes.GET("/rooms/:id", authValidator.OptionalAuth, roomController.GetById)
|
||||||
apiRoutes.PUT("/rooms/:id", roomController.Update)
|
apiRoutes.PUT("/rooms/:id", authValidator.RequireAuth, roomController.Update)
|
||||||
apiRoutes.DELETE("/rooms/:id", roomController.Delete)
|
apiRoutes.DELETE("/rooms/:id", authValidator.RequireAuth, roomController.Delete)
|
||||||
|
|
||||||
apiRoutes.POST("/users/signup", userController.Signup)
|
apiRoutes.GET("/rooms/:id/users", authValidator.RequireAuth, authValidator.RequireRoomAdmin, roomController.GetUsers)
|
||||||
|
apiRoutes.POST("/rooms/:id/users", authValidator.RequireAuth, roomController.AddUser)
|
||||||
|
|
||||||
|
apiRoutes.POST("/users/register", userController.Register)
|
||||||
apiRoutes.POST("/users/login", userController.Login)
|
apiRoutes.POST("/users/login", userController.Login)
|
||||||
apiRoutes.GET("/users/validate", authValidator.RequireAuth, userController.Validate)
|
apiRoutes.GET("/users/validate", authValidator.OptionalAuth, userController.Validate)
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Run(":"+os.Getenv("PORT"))
|
server.Run(":"+os.Getenv("PORT"))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import(
|
|||||||
"os"
|
"os"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
"strconv"
|
||||||
"net/http"
|
"net/http"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
@@ -16,6 +17,32 @@ type AuthValidator struct {
|
|||||||
DB *gorm.DB
|
DB *gorm.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (av *AuthValidator) RequireRoomAdmin(c *gin.Context) {
|
||||||
|
user, exists := c.Get("user")
|
||||||
|
if !exists {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
roomId, err := strconv.Atoi(c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{ "message": fmt.Sprintf("Room with Id '%s' does not exist", c.Param("id"))})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var rooms []models.Room
|
||||||
|
av.DB.Model(&user).Association("OwnedRooms").Find(&rooms)
|
||||||
|
|
||||||
|
for _, room := range rooms {
|
||||||
|
if room.ID == uint(roomId) {
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
func (av *AuthValidator) RequireAuth(c *gin.Context) {
|
func (av *AuthValidator) RequireAuth(c *gin.Context) {
|
||||||
// Get Cookie
|
// Get Cookie
|
||||||
tokenString, err := c.Cookie("Authorization")
|
tokenString, err := c.Cookie("Authorization")
|
||||||
@@ -68,3 +95,43 @@ func (av *AuthValidator) RequireAuth(c *gin.Context) {
|
|||||||
|
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (av *AuthValidator) OptionalAuth(c *gin.Context) {
|
||||||
|
defer c.Next()
|
||||||
|
|
||||||
|
// Get Cookie
|
||||||
|
tokenString, err := c.Cookie("Authorization")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validate
|
||||||
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
return []byte(os.Getenv("SECRET")), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := token.Claims.(jwt.MapClaims); ok {
|
||||||
|
if float64(time.Now().Unix()) > claims["exp"].(float64) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find user
|
||||||
|
var user models.User
|
||||||
|
result := av.DB.First(&user, claims["sub"])
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Attach to req
|
||||||
|
c.Set("user", user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ type Room struct {
|
|||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Website string `json:"website"`
|
Website string `json:"website"`
|
||||||
Capacity int `json:"capacity"`
|
Capacity int `json:"capacity"`
|
||||||
IsPublic bool `json:"isPublic" gorm:"default:false"`
|
IsPublic bool `json:"isPublic" gorm:"default:true"`
|
||||||
Admins []User `gorm:"many2many:room_admins;"`
|
Admins []User `gorm:"many2many:room_admins;"`
|
||||||
|
Users []User `gorm:"many2many:room_users;"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRoom(ctx *gin.Context) (Room, error) {
|
func NewRoom(ctx *gin.Context) (Room, error) {
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ type User struct {
|
|||||||
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
||||||
Password string `json:"password" binding:"required" gorm:"not null"`
|
Password string `json:"password" binding:"required" gorm:"not null"`
|
||||||
Email string `json:"email" binding:"required,email" gorm:"unique;not null"`
|
Email string `json:"email" binding:"required,email" gorm:"unique;not null"`
|
||||||
|
OwnedRooms []Room `gorm:"many2many:room_admins;"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user