refactor: improve handling of optional CustomerID in project models and DTOs
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
This commit is contained in:
@@ -12,7 +12,7 @@ type ProjectDto struct {
|
||||
UpdatedAt time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||
LastEditorID string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
||||
Name string `json:"name" example:"Time Tracking App"`
|
||||
CustomerID *string `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
||||
CustomerID *string `json:"customerId,omitempty" example:"01HGW2BBG0000000000000000"`
|
||||
}
|
||||
|
||||
type ProjectCreateDto struct {
|
||||
|
||||
@@ -148,13 +148,17 @@ func (h *ProjectHandler) DeleteProject(c *gin.Context) {
|
||||
// Helper functions for DTO conversion
|
||||
|
||||
func convertProjectToDTO(project *models.Project) dto.ProjectDto {
|
||||
customerId := project.CustomerID.String()
|
||||
var customerIdPtr *string
|
||||
if project.CustomerID != nil {
|
||||
customerIdStr := project.CustomerID.String()
|
||||
customerIdPtr = &customerIdStr
|
||||
}
|
||||
return dto.ProjectDto{
|
||||
ID: project.ID.String(),
|
||||
CreatedAt: project.CreatedAt,
|
||||
UpdatedAt: project.UpdatedAt,
|
||||
Name: project.Name,
|
||||
CustomerID: &customerId,
|
||||
CustomerID: customerIdPtr,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,13 +186,13 @@ func convertUpdateProjectDTOToModel(dto dto.ProjectUpdateDto, id types.ULID) (mo
|
||||
|
||||
if dto.CustomerID.Valid {
|
||||
if dto.CustomerID.Value == nil {
|
||||
update.CustomerID = nil
|
||||
update.CustomerID = types.Null[types.ULID]()
|
||||
} else {
|
||||
customerID, err := types.ULIDFromString(*dto.CustomerID.Value)
|
||||
if err != nil {
|
||||
return models.ProjectUpdate{}, fmt.Errorf("invalid customer ID: %w", err)
|
||||
}
|
||||
update.CustomerID = &customerID
|
||||
update.CustomerID = types.NewNullable(customerID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ func MigrateDB() error {
|
||||
// createConnection creates a new database connection with the given configuration
|
||||
func createConnection(dbConfig config.DatabaseConfig, dbName string) (*gorm.DB, error) {
|
||||
// Create DSN (Data Source Name)
|
||||
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbName=%s sslmode=%s",
|
||||
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
|
||||
dbConfig.Host, dbConfig.Port, dbConfig.User, dbConfig.Password, dbName, dbConfig.SSLMode)
|
||||
|
||||
// Configure GORM logger
|
||||
|
||||
@@ -90,7 +90,7 @@ func UpdateModel(ctx context.Context, model any, updates any) error {
|
||||
updateMap := make(map[string]any)
|
||||
|
||||
// Iterate through all fields
|
||||
for i := 0; i < updateValue.NumField(); i++ {
|
||||
for i := range updateValue.NumField() {
|
||||
field := updateValue.Field(i)
|
||||
fieldType := updateType.Field(i)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
type Project struct {
|
||||
EntityBase
|
||||
Name string `gorm:"column:name;not null"`
|
||||
CustomerID *types.ULID `gorm:"column:customer_id;type:bytea;not null"`
|
||||
CustomerID *types.ULID `gorm:"column:customer_id;type:bytea;index"`
|
||||
|
||||
// Relationships (for Eager Loading)
|
||||
Customer *Customer `gorm:"foreignKey:CustomerID"`
|
||||
@@ -33,9 +33,9 @@ type ProjectCreate struct {
|
||||
|
||||
// ProjectUpdate contains the updatable fields of a project
|
||||
type ProjectUpdate struct {
|
||||
ID types.ULID `gorm:"-"` // Exclude from updates
|
||||
Name *string `gorm:"column:name"`
|
||||
CustomerID *types.ULID `gorm:"column:customer_id"`
|
||||
ID types.ULID `gorm:"-"` // Exclude from updates
|
||||
Name *string `gorm:"column:name"`
|
||||
CustomerID types.Nullable[types.ULID] `gorm:"column:customer_id"`
|
||||
}
|
||||
|
||||
// Validate checks if the Create struct contains valid data
|
||||
@@ -44,7 +44,7 @@ func (pc *ProjectCreate) Validate() error {
|
||||
return errors.New("project name cannot be empty")
|
||||
}
|
||||
// Check for valid CustomerID
|
||||
if pc.CustomerID.Compare(types.ULID{}) == 0 {
|
||||
if pc.CustomerID != nil && pc.CustomerID.Compare(types.ULID{}) == 0 {
|
||||
return errors.New("customerID cannot be empty")
|
||||
}
|
||||
return nil
|
||||
@@ -122,7 +122,7 @@ func CreateProject(ctx context.Context, create ProjectCreate) (*Project, error)
|
||||
}
|
||||
|
||||
// Check if the customer exists
|
||||
if create.CustomerID == nil {
|
||||
if create.CustomerID != nil {
|
||||
customer, err := GetCustomerByID(ctx, *create.CustomerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking the customer: %w", err)
|
||||
@@ -160,13 +160,18 @@ func UpdateProject(ctx context.Context, update ProjectUpdate) (*Project, error)
|
||||
}
|
||||
|
||||
// If CustomerID is updated, check if the customer exists
|
||||
if update.CustomerID != nil {
|
||||
customer, err := GetCustomerByID(ctx, *update.CustomerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking the customer: %w", err)
|
||||
}
|
||||
if customer == nil {
|
||||
return nil, errors.New("the specified customer does not exist")
|
||||
if update.CustomerID.Valid {
|
||||
if update.CustomerID.Value != nil {
|
||||
customer, err := GetCustomerByID(ctx, *update.CustomerID.Value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking the customer: %w", err)
|
||||
}
|
||||
if customer == nil {
|
||||
return nil, errors.New("the specified customer does not exist")
|
||||
}
|
||||
} else {
|
||||
// If CustomerID is nil, set it to nil in the project
|
||||
project.CustomerID = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ func (uc *UserCreate) Validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
if uc.CompanyID.Compare(types.ULID{}) == 0 {
|
||||
if uc.CompanyID != nil && uc.CompanyID.Compare(types.ULID{}) == 0 {
|
||||
return errors.New("companyID cannot be empty")
|
||||
}
|
||||
|
||||
@@ -363,13 +363,15 @@ func CreateUser(ctx context.Context, create UserCreate) (*User, error) {
|
||||
return errors.New("email is already in use")
|
||||
}
|
||||
|
||||
// Check if company exists
|
||||
var companyCount int64
|
||||
if err := tx.Model(&Company{}).Where("id = ?", create.CompanyID).Count(&companyCount).Error; err != nil {
|
||||
return fmt.Errorf("error checking company: %w", err)
|
||||
}
|
||||
if companyCount == 0 {
|
||||
return errors.New("the specified company does not exist")
|
||||
if create.CompanyID != nil {
|
||||
// Check if company exists
|
||||
var companyCount int64
|
||||
if err := tx.Model(&Company{}).Where("id = ?", create.CompanyID).Count(&companyCount).Error; err != nil {
|
||||
return fmt.Errorf("error checking company: %w", err)
|
||||
}
|
||||
if companyCount == 0 {
|
||||
return errors.New("the specified company does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
// Hash password with unique salt
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "YOUR_POSTMAN_ID",
|
||||
"name": "Activity API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "GET /api/activities",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/activities",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"activities"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/activities/:id",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/activities/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"activities",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/activities",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\",\n\t\"billingRate\": 0\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/activities",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"activities"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "PUT /api/activities/:id",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\",\n\t\"billingRate\": 0\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/activities/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"activities",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "DELETE /api/activities/:id",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/activities/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"activities",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "YOUR_POSTMAN_ID",
|
||||
"name": "Company API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "GET /api/companies",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/companies",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"companies"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/companies/:id",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/companies/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"companies",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/companies",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/companies",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"companies"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "PUT /api/companies/:id",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/companies/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"companies",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "DELETE /api/companies/:id",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/companies/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"companies",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "YOUR_POSTMAN_ID",
|
||||
"name": "Customer API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "GET /api/customers",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/customers",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"customers"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/customers/:id",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/customers/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"customers",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/customers/company/:companyId",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/customers/company/:companyId",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"customers",
|
||||
"company",
|
||||
":companyId"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "companyId",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/customers",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\",\n\t\"companyId\": \"\",\n\t\"ownerUserID\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/customers",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"customers"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "PUT /api/customers/:id",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\",\n\t\"companyId\": \"\",\n\t\"ownerUserID\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/customers/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"customers",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "DELETE /api/customers/:id",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/customers/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"customers",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "YOUR_POSTMAN_ID",
|
||||
"name": "Project API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "GET /api/projects",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/projects/with-customers",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects/with-customers",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects",
|
||||
"with-customers"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/projects/:id",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/projects/customer/:customerId",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects/customer/:customerId",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects",
|
||||
"customer",
|
||||
":customerId"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "customerId",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/projects",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\",\n\t\"customerId\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "PUT /api/projects/:id",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"name\": \"\",\n\t\"customerId\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "DELETE /api/projects/:id",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/projects/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"projects",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "YOUR_POSTMAN_ID",
|
||||
"name": "TimeEntry API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "GET /api/time-entries",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/time-entries/me",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/me",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
"me"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/time-entries/range",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/range?start=2023-01-01T00:00:00Z&end=2023-01-02T00:00:00Z",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
"range"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "start",
|
||||
"value": "2023-01-01T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"key": "end",
|
||||
"value": "2023-01-02T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/time-entries/:id",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/time-entries/user/:userId",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/user/:userId",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
"user",
|
||||
":userId"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "userId",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/time-entries/project/:projectId",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/project/:projectId",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
"project",
|
||||
":projectId"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "projectId",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/time-entries",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"userID\": \"\",\n \"projectID\": \"\",\n \"activityID\": \"\",\n \"start\": \"2023-01-01T00:00:00Z\",\n \"end\": \"2023-01-01T01:00:00Z\",\n \"description\": \"\",\n \"billable\": true\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "PUT /api/time-entries/:id",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"userID\": \"\",\n \"projectID\": \"\",\n \"activityID\": \"\",\n \"start\": \"2023-01-01T00:00:00Z\",\n \"end\": \"2023-01-01T01:00:00Z\",\n \"description\": \"\",\n \"billable\": true\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "DELETE /api/time-entries/:id",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/time-entries/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"time-entries",
|
||||
":id"
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "id",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "YOUR_POSTMAN_ID",
|
||||
"name": "User API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Auth",
|
||||
"item": [
|
||||
{
|
||||
"name": "POST /api/auth/login",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"email\": \"\",\n\t\"password\": \"\"\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/auth/login",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"auth",
|
||||
"login"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/auth/register",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"email\": \"\",\n\t\"password\": \"\",\n\t\"role\": \"user\",\n\t\"companyID\": \"\",\n\t\"hourlyRate\": 0\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/auth/register",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"auth",
|
||||
"register"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/auth/me",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/auth/me",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"auth",
|
||||
"me"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Users",
|
||||
"item": [
|
||||
{
|
||||
"name": "GET /api/users",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/users",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"users"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "GET /api/users/:id",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/users/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"users",
|
||||
":id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "POST /api/users",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"email\": \"\",\n\t\"password\": \"\",\n\t\"role\": \"user\",\n\t\"companyID\": \"\",\n\t\"hourlyRate\": 0\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/users",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"users"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "PUT /api/users/:id",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n\t\"email\": \"\",\n\t\"password\": \"\",\n\t\"role\": \"user\",\n\t\"companyID\": \"\",\n\t\"hourlyRate\": 0\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/users/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"users",
|
||||
":id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "DELETE /api/users/:id",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer {{JWT_TOKEN}}",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{API_URL}}/api/users/:id",
|
||||
"host": [
|
||||
"{{API_URL}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"users",
|
||||
":id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user