implement graphQL and init postgres

This commit is contained in:
Fran Jurmanović
2025-07-06 19:19:36 +02:00
parent 016728532c
commit 26a0d33592
25 changed files with 1713 additions and 314 deletions

148
local/model/project.go Normal file
View File

@@ -0,0 +1,148 @@
package model
import (
"errors"
"strings"
"gorm.io/gorm"
)
// Project represents a project in the system
type Project struct {
BaseModel
Name string `json:"name" gorm:"not null;type:varchar(255)"`
Description string `json:"description" gorm:"type:text"`
OwnerID string `json:"owner_id" gorm:"not null;type:uuid;index;references:users(id)"`
TypeID string `json:"type_id" gorm:"not null;type:uuid;index;references:types(id)"`
Owner User `json:"owner,omitempty" gorm:"foreignKey:OwnerID"`
Type Type `json:"type,omitempty" gorm:"foreignKey:TypeID"`
Tasks []Task `json:"tasks,omitempty" gorm:"foreignKey:ProjectID"`
Members []User `json:"members,omitempty" gorm:"many2many:project_members;"`
}
// ProjectCreateRequest represents the request to create a new project
type ProjectCreateRequest struct {
Name string `json:"name" validate:"required,min=1,max=255"`
Description string `json:"description" validate:"max=1000"`
OwnerID string `json:"owner_id" validate:"required,uuid"`
TypeID string `json:"type_id" validate:"required,uuid"`
}
// ProjectUpdateRequest represents the request to update a project
type ProjectUpdateRequest struct {
Name *string `json:"name,omitempty" validate:"omitempty,min=1,max=255"`
Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
TypeID *string `json:"type_id,omitempty" validate:"omitempty,uuid"`
}
// ProjectInfo represents public project information
type ProjectInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
OwnerID string `json:"owner_id"`
TypeID string `json:"type_id"`
Owner UserInfo `json:"owner,omitempty"`
Type TypeInfo `json:"type,omitempty"`
TaskCount int64 `json:"task_count"`
MemberCount int64 `json:"member_count"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// ProjectMember represents the many-to-many relationship between projects and users
type ProjectMember struct {
ProjectID string `json:"project_id" gorm:"type:uuid;primaryKey"`
UserID string `json:"user_id" gorm:"type:uuid;primaryKey"`
RoleID string `json:"role_id" gorm:"type:uuid;not null;references:roles(id)"`
Project Project `json:"project,omitempty" gorm:"foreignKey:ProjectID"`
User User `json:"user,omitempty" gorm:"foreignKey:UserID"`
Role Role `json:"role,omitempty" gorm:"foreignKey:RoleID"`
}
// BeforeCreate is called before creating a project
func (p *Project) BeforeCreate(tx *gorm.DB) error {
p.BaseModel.BeforeCreate()
// Normalize name and description
p.Name = strings.TrimSpace(p.Name)
p.Description = strings.TrimSpace(p.Description)
return p.Validate()
}
// BeforeUpdate is called before updating a project
func (p *Project) BeforeUpdate(tx *gorm.DB) error {
p.BaseModel.BeforeUpdate()
// Normalize fields if they're being updated
if p.Name != "" {
p.Name = strings.TrimSpace(p.Name)
}
if p.Description != "" {
p.Description = strings.TrimSpace(p.Description)
}
return p.Validate()
}
// Validate validates project data
func (p *Project) Validate() error {
if p.Name == "" {
return errors.New("name is required")
}
if len(p.Name) > 255 {
return errors.New("name must not exceed 255 characters")
}
if p.OwnerID == "" {
return errors.New("owner_id is required")
}
if p.TypeID == "" {
return errors.New("type_id is required")
}
return nil
}
// ToProjectInfo converts Project to ProjectInfo (public information)
func (p *Project) ToProjectInfo() ProjectInfo {
projectInfo := ProjectInfo{
ID: p.ID,
Name: p.Name,
Description: p.Description,
OwnerID: p.OwnerID,
TypeID: p.TypeID,
CreatedAt: p.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
UpdatedAt: p.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
}
// Add owner info if loaded
if p.Owner.ID != "" {
projectInfo.Owner = p.Owner.ToUserInfo()
}
// Add type info if loaded
if p.Type.ID != "" {
projectInfo.Type = p.Type.ToTypeInfo()
}
return projectInfo
}
// HasMember checks if a user is a member of the project
func (p *Project) HasMember(userID string) bool {
for _, member := range p.Members {
if member.ID == userID {
return true
}
}
return false
}
// IsOwner checks if a user is the owner of the project
func (p *Project) IsOwner(userID string) bool {
return p.OwnerID == userID
}