Skip to content

Commit d723599

Browse files
committed
Enhancement: Allow loading categories as sideloads in project responses
When loading single or multiple projects, it will be possible to sideload the category. This avoids an extra request to retrieve the category information.
1 parent 9d710b3 commit d723599

1 file changed

Lines changed: 73 additions & 29 deletions

File tree

projects/project.go

Lines changed: 73 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ type Project struct {
122122
// "projects-template", "personal", "holder-project", "tentative" or
123123
// "global-messages".
124124
Type string `json:"type"`
125+
126+
// Included contains related objects included in the response.
127+
Included struct {
128+
// ProjectCategories contains the categories associated with the project.
129+
//
130+
// The key is the string representation of the project category ID.
131+
ProjectCategories []ProjectCategory `json:"projectCategories"`
132+
}
125133
}
126134

127135
// ProjectCreateRequest represents the request body for creating a new project.
@@ -645,6 +653,31 @@ func ProjectClone(
645653
return twapi.Execute[ProjectCloneRequest, *ProjectCloneResponse](ctx, engine, req)
646654
}
647655

656+
// ProjectRequestSideload contains the possible sideload options when loading
657+
// projects.
658+
type ProjectRequestSideload string
659+
660+
// List of possible sideload options for ProjectRequestSideload.
661+
const (
662+
ProjectRequestSideloadProjectCategories ProjectRequestSideload = "projectCategories"
663+
)
664+
665+
// ProjectRequestFilters contains the filters for loading projects.
666+
type ProjectRequestFilters struct {
667+
// Include specifies related resources to include.
668+
Include []ProjectRequestSideload
669+
}
670+
671+
func (p ProjectRequestFilters) apply(req *http.Request) {
672+
query := req.URL.Query()
673+
if len(p.Include) > 0 {
674+
for _, include := range p.Include {
675+
query.Add("include", string(include))
676+
}
677+
}
678+
req.URL.RawQuery = query.Encode()
679+
}
680+
648681
// ProjectGetRequestPath contains the path parameters for loading a single
649682
// project.
650683
type ProjectGetRequestPath struct {
@@ -658,6 +691,9 @@ type ProjectGetRequestPath struct {
658691
type ProjectGetRequest struct {
659692
// Path contains the path parameters for the request.
660693
Path ProjectGetRequestPath
694+
695+
// Filters contains the filters for loading a single project.
696+
Filters ProjectRequestFilters
661697
}
662698

663699
// NewProjectGetRequest creates a new ProjectGetRequest with the provided
@@ -678,6 +714,7 @@ func (p ProjectGetRequest) HTTPRequest(ctx context.Context, server string) (*htt
678714
if err != nil {
679715
return nil, err
680716
}
717+
p.Filters.apply(req)
681718

682719
return req, nil
683720
}
@@ -715,6 +752,8 @@ func ProjectGet(
715752

716753
// ProjectListRequestFilters contains the filters for loading multiple projects.
717754
type ProjectListRequestFilters struct {
755+
ProjectRequestFilters
756+
718757
// ProjectCategoryIDs is an optional list of project category IDs to filter
719758
// projects by categories.
720759
ProjectCategoryIDs []int64
@@ -737,6 +776,39 @@ type ProjectListRequestFilters struct {
737776
PageSize int64
738777
}
739778

779+
func (p ProjectListRequestFilters) apply(req *http.Request) {
780+
p.ProjectRequestFilters.apply(req)
781+
782+
query := req.URL.Query()
783+
if len(p.ProjectCategoryIDs) > 0 {
784+
categoryIDs := make([]string, len(p.ProjectCategoryIDs))
785+
for i, id := range p.ProjectCategoryIDs {
786+
categoryIDs[i] = strconv.FormatInt(id, 10)
787+
}
788+
query.Set("projectCategoryIds", strings.Join(categoryIDs, ","))
789+
}
790+
if p.SearchTerm != "" {
791+
query.Set("searchTerm", p.SearchTerm)
792+
}
793+
if len(p.TagIDs) > 0 {
794+
tagIDs := make([]string, len(p.TagIDs))
795+
for i, id := range p.TagIDs {
796+
tagIDs[i] = strconv.FormatInt(id, 10)
797+
}
798+
query.Set("projectTagIds", strings.Join(tagIDs, ","))
799+
}
800+
if p.MatchAllTags != nil {
801+
query.Set("matchAllProjectTags", strconv.FormatBool(*p.MatchAllTags))
802+
}
803+
if p.Page > 0 {
804+
query.Set("page", strconv.FormatInt(p.Page, 10))
805+
}
806+
if p.PageSize > 0 {
807+
query.Set("pageSize", strconv.FormatInt(p.PageSize, 10))
808+
}
809+
req.URL.RawQuery = query.Encode()
810+
}
811+
740812
// ProjectListRequest represents the request body for loading multiple projects.
741813
//
742814
// https://apidocs.teamwork.com/docs/teamwork/v3/projects/get-projects-api-v3-projects-json
@@ -763,35 +835,7 @@ func (p ProjectListRequest) HTTPRequest(ctx context.Context, server string) (*ht
763835
if err != nil {
764836
return nil, err
765837
}
766-
767-
query := req.URL.Query()
768-
if len(p.Filters.ProjectCategoryIDs) > 0 {
769-
categoryIDs := make([]string, len(p.Filters.ProjectCategoryIDs))
770-
for i, id := range p.Filters.ProjectCategoryIDs {
771-
categoryIDs[i] = strconv.FormatInt(id, 10)
772-
}
773-
query.Set("projectCategoryIds", strings.Join(categoryIDs, ","))
774-
}
775-
if p.Filters.SearchTerm != "" {
776-
query.Set("searchTerm", p.Filters.SearchTerm)
777-
}
778-
if len(p.Filters.TagIDs) > 0 {
779-
tagIDs := make([]string, len(p.Filters.TagIDs))
780-
for i, id := range p.Filters.TagIDs {
781-
tagIDs[i] = strconv.FormatInt(id, 10)
782-
}
783-
query.Set("projectTagIds", strings.Join(tagIDs, ","))
784-
}
785-
if p.Filters.MatchAllTags != nil {
786-
query.Set("matchAllProjectTags", strconv.FormatBool(*p.Filters.MatchAllTags))
787-
}
788-
if p.Filters.Page > 0 {
789-
query.Set("page", strconv.FormatInt(p.Filters.Page, 10))
790-
}
791-
if p.Filters.PageSize > 0 {
792-
query.Set("pageSize", strconv.FormatInt(p.Filters.PageSize, 10))
793-
}
794-
req.URL.RawQuery = query.Encode()
838+
p.Filters.apply(req)
795839

796840
return req, nil
797841
}

0 commit comments

Comments
 (0)