Skip to content
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ PORT=8080
DB_HOST=localhost
DB_PORT=5432
DB_USER=compsoc
DB_PASSWORD=secretpassword
DB_PASSWORD=123456789
DB_NAME=projects_portal
DB_SSLMODE=disable
4 changes: 4 additions & 0 deletions internal/config/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ func ConnectDatabase() (*gorm.DB, error) {

return db, nil
}

type Database struct {
*gorm.DB
}
36 changes: 36 additions & 0 deletions internal/handlers/project_member_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package handlers

import (
"net/http"

"github.com/ComputerSocietyVITC/projects-portal-backend/internal/config"
"github.com/ComputerSocietyVITC/projects-portal-backend/internal/models"
"github.com/labstack/echo/v5"
"go.uber.org/zap"
)

type ProjectMemberHandler struct {
DB *config.Database
}

func (h *ProjectMemberHandler) AddMember(c *echo.Context) error {
var member models.ProjectMember
if err := c.Bind(&member); err != nil {
zap.L().Error("failed to bind project member data", zap.Error(err))
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid project member data"})
}
if err := h.DB.Create(&member).Error; err != nil {
zap.L().Error("failed to add project member", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to add project member"})
}
return c.JSON(http.StatusCreated, member)
}

func (h *ProjectMemberHandler) RemoveMember(c *echo.Context) error {
id := c.Param("id")
if err := h.DB.Delete(&models.ProjectMember{}, id).Error; err != nil {
zap.L().Error("failed to remove project member", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to remove project member"})
}
return c.JSON(http.StatusOK, map[string]string{"message": "Project member removed successfully"})
}
78 changes: 78 additions & 0 deletions internal/handlers/projects_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package handlers

import (
"net/http"

"github.com/ComputerSocietyVITC/projects-portal-backend/internal/config"
"github.com/ComputerSocietyVITC/projects-portal-backend/internal/models"
"github.com/labstack/echo/v5"
"go.uber.org/zap"
)

type ProjectHandler struct {
DB *config.Database
}

func (h *ProjectHandler) GetProjects(c *echo.Context) error {
var projects []models.Project
if err := h.DB.Find(&projects).Error; err != nil {
zap.L().Error("failed to fetch projects", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to fetch projects"})
}
return c.JSON(http.StatusOK, projects)
}

func (h *ProjectHandler) GetProjectByID(c *echo.Context) error {
id := c.Param("id")
var project models.Project
if err := h.DB.First(&project, id).Error; err != nil {
zap.L().Error("project not found", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusNotFound, map[string]string{"error": "Project not found"})
}
return c.JSON(http.StatusOK, project)
}

func (h *ProjectHandler) CreateProject(c *echo.Context) error {
var project models.Project
if err := c.Bind(&project); err != nil {
zap.L().Error("failed to bind project data", zap.Error(err))
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid project data"})
}
if err := h.DB.Create(&project).Error; err != nil {
zap.L().Error("failed to create project", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to create project"})
}
return c.JSON(http.StatusCreated, project)
}

func (h *ProjectHandler) UpdateProject(c *echo.Context) error {
id := c.Param("id")
var project models.Project
if err := h.DB.First(&project, id).Error; err != nil {
zap.L().Error("project not found", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusNotFound, map[string]string{"error": "Project not found"})
}
if err := c.Bind(&project); err != nil {
zap.L().Error("failed to bind project data", zap.Error(err))
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid project data"})
}
if err := h.DB.Save(&project).Error; err != nil {
zap.L().Error("failed to update project", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to update project"})
}
return c.JSON(http.StatusOK, project)
}

func (h *ProjectHandler) DeleteProject(c *echo.Context) error {
id := c.Param("id")
var project models.Project
if err := h.DB.First(&project, id).Error; err != nil {
zap.L().Error("project not found", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusNotFound, map[string]string{"error": "Project not found"})
}
if err := h.DB.Delete(&project).Error; err != nil {
zap.L().Error("failed to delete project", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to delete project"})
}
return c.JSON(http.StatusOK, map[string]string{"message": "Project deleted successfully"})
}
46 changes: 46 additions & 0 deletions internal/handlers/users_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package handlers

import (
"net/http"

"github.com/ComputerSocietyVITC/projects-portal-backend/internal/config"
"github.com/ComputerSocietyVITC/projects-portal-backend/internal/models"
"github.com/labstack/echo/v5"
"go.uber.org/zap"
)

type UserHandler struct {
DB *config.Database
}

func (h *UserHandler) GetUsers(c *echo.Context) error {
var users []models.User
if err := h.DB.Find(&users).Error; err != nil {
zap.L().Error("failed to fetch users", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to fetch users"})
}
return c.JSON(http.StatusOK, users)
}

func (h *UserHandler) GetUserByID(c *echo.Context) error {
id := c.Param("id")
var user models.User
if err := h.DB.First(&user, id).Error; err != nil {
zap.L().Error("user not found", zap.String("id", id), zap.Error(err))
return c.JSON(http.StatusNotFound, map[string]string{"error": "User not found"})
}
return c.JSON(http.StatusOK, user)
}

func (h *UserHandler) CreateUser(c *echo.Context) error {
var user models.User
if err := c.Bind(&user); err != nil {
zap.L().Error("failed to bind user data", zap.Error(err))
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid user data"})
}
if err := h.DB.Create(&user).Error; err != nil {
zap.L().Error("failed to create user", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to create user"})
}
return c.JSON(http.StatusCreated, user)
}
1 change: 1 addition & 0 deletions logfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bash: postgres: command not found
57 changes: 57 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import (
"os"

"github.com/ComputerSocietyVITC/projects-portal-backend/internal/config"
"github.com/ComputerSocietyVITC/projects-portal-backend/internal/handlers"
"github.com/ComputerSocietyVITC/projects-portal-backend/internal/logger"
"github.com/ComputerSocietyVITC/projects-portal-backend/internal/models"
"github.com/joho/godotenv"
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
"go.uber.org/zap"
)

func main() {

if err := godotenv.Load(); err != nil {
log.Printf("failed to load .env file: %v", err)
}
Expand All @@ -33,6 +36,11 @@ func main() {
if err != nil {
logger.Fatal("failed to get sql db: %v", zap.Error(err))
}

if err := db.AutoMigrate(&models.Project{}); err != nil {
logger.Fatal("failed to auto-migrate database: %v", zap.Error(err))
}

if err := sqlDB.Ping(); err != nil {
logger.Fatal("failed to ping database: %v", zap.Error(err))
}
Expand All @@ -55,6 +63,55 @@ func main() {
return c.String(http.StatusOK, "Server is up and running!")
})

e.GET("/users", func(c *echo.Context) error {
handlers := &handlers.UserHandler{DB: &config.Database{DB: db}}
return handlers.GetUsers(c)
})

e.GET("/users/:id", func(c *echo.Context) error {
handlers := &handlers.UserHandler{DB: &config.Database{DB: db}}
return handlers.GetUserByID(c)
})

e.POST("/users", func(c *echo.Context) error {
handlers := &handlers.UserHandler{DB: &config.Database{DB: db}}
return handlers.CreateUser(c)
})

e.GET("/projects", func(c *echo.Context) error {
handlers := &handlers.ProjectHandler{DB: &config.Database{DB: db}}
return handlers.GetProjects(c)
})
e.GET("/projects/:id", func(c *echo.Context) error {
handlers := &handlers.ProjectHandler{DB: &config.Database{DB: db}}
return handlers.GetProjectByID(c)
})

e.POST("/projects", func(c *echo.Context) error {
handlers := &handlers.ProjectHandler{DB: &config.Database{DB: db}}
return handlers.CreateProject(c)
})

e.PATCH("/projects/:id", func(c *echo.Context) error {
handlers := &handlers.ProjectHandler{DB: &config.Database{DB: db}}
return handlers.UpdateProject(c)
})

e.DELETE("/projects/:id", func(c *echo.Context) error {
handlers := &handlers.ProjectHandler{DB: &config.Database{DB: db}}
return handlers.DeleteProject(c)
})

e.POST("/projects/:id/members", func(c *echo.Context) error {
handlers := &handlers.ProjectMemberHandler{DB: &config.Database{DB: db}}
return handlers.AddMember(c)
})

e.DELETE("/projects/:id/members/:member_id", func(c *echo.Context) error {
handlers := &handlers.ProjectMemberHandler{DB: &config.Database{DB: db}}
return handlers.RemoveMember(c)
})

port := os.Getenv("PORT")
if port == "" {
port = "8080"
Expand Down