diff --git a/jira/internal/issue_archive_impl.go b/jira/internal/issue_archive_impl.go new file mode 100644 index 00000000..4369db15 --- /dev/null +++ b/jira/internal/issue_archive_impl.go @@ -0,0 +1,133 @@ +package internal + +import ( + "context" + "fmt" + model "github.com/ctreminiom/go-atlassian/v2/pkg/infra/models" + "github.com/ctreminiom/go-atlassian/v2/service" + "github.com/ctreminiom/go-atlassian/v2/service/jira" + "net/http" + "path" +) + +func NewIssueArchivalService(client service.Connector, version string) *IssueArchivalService { + return &IssueArchivalService{ + internalClient: &internalIssueArchivalImpl{c: client, version: version}, + } +} + +type IssueArchivalService struct { + internalClient jira.ArchiveService +} + +func (i *IssueArchivalService) Preserve(ctx context.Context, issueIdsOrKeys []string) (*model.IssueArchivalSyncResponseScheme, *model.ResponseScheme, error) { + return i.internalClient.Preserve(ctx, issueIdsOrKeys) +} + +func (i *IssueArchivalService) PreserveByJQL(ctx context.Context, jql string) (string, *model.ResponseScheme, error) { + return i.internalClient.PreserveByJQL(ctx, jql) +} + +func (i *IssueArchivalService) Restore(ctx context.Context, issueIdsOrKeys []string) (*model.IssueArchivalSyncResponseScheme, *model.ResponseScheme, error) { + return i.internalClient.Restore(ctx, issueIdsOrKeys) +} + +func (i *IssueArchivalService) Export(ctx context.Context, payload *model.IssueArchivalExportPayloadScheme) (string, *model.ResponseScheme, error) { + return i.internalClient.Export(ctx, payload) +} + +type internalIssueArchivalImpl struct { + c service.Connector + version string +} + +func (i *internalIssueArchivalImpl) Preserve(ctx context.Context, issueIdsOrKeys []string) (result *model.IssueArchivalSyncResponseScheme, response *model.ResponseScheme, err error) { + + if len(issueIdsOrKeys) == 0 { + return nil, nil, model.ErrNoIssuesSlice + } + + payload := make(map[string]interface{}) + payload["issueIdsOrKeys"] = issueIdsOrKeys + + endpoint := fmt.Sprintf("rest/api/%s/issue/archive", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return nil, nil, err + } + + report := new(model.IssueArchivalSyncResponseScheme) + response, err = i.c.Call(request, report) + if err != nil { + return nil, response, err + } + + return report, response, nil +} + +func (i *internalIssueArchivalImpl) PreserveByJQL(ctx context.Context, jql string) (taskID string, response *model.ResponseScheme, err error) { + + if jql == "" { + return "", nil, model.ErrNoJQL + } + + payload := make(map[string]interface{}) + payload["jql"] = jql + + endpoint := fmt.Sprintf("rest/api/%s/issue/archive", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPost, endpoint, "", payload) + if err != nil { + return "", nil, err + } + + response, err = i.c.Call(request, nil) + if err != nil { + return "", response, err + } + + return path.Base(response.Bytes.String()), response, nil +} + +func (i *internalIssueArchivalImpl) Restore(ctx context.Context, issueIdsOrKeys []string) (result *model.IssueArchivalSyncResponseScheme, response *model.ResponseScheme, err error) { + + if len(issueIdsOrKeys) == 0 { + return nil, nil, model.ErrNoIssuesSlice + } + + payload := make(map[string]interface{}) + payload["issueIdsOrKeys"] = issueIdsOrKeys + + endpoint := fmt.Sprintf("rest/api/%s/issue/unarchive", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return nil, nil, err + } + + report := new(model.IssueArchivalSyncResponseScheme) + response, err = i.c.Call(request, report) + if err != nil { + return nil, response, err + } + + return report, response, nil +} + +func (i *internalIssueArchivalImpl) Export(ctx context.Context, payload *model.IssueArchivalExportPayloadScheme) (taskID string, response *model.ResponseScheme, err error) { + + endpoint := fmt.Sprintf("rest/api/%s/issues/archive/export", i.version) + + request, err := i.c.NewRequest(ctx, http.MethodPut, endpoint, "", payload) + if err != nil { + return "", nil, err + } + + response, err = i.c.Call(request, nil) + if err != nil { + return "", response, err + } + + return "", response, nil +} diff --git a/jira/v2/api_client_impl.go b/jira/v2/api_client_impl.go index 0b4ed10c..28a688f1 100644 --- a/jira/v2/api_client_impl.go +++ b/jira/v2/api_client_impl.go @@ -397,6 +397,8 @@ func New(httpClient common.HTTPClient, site string) (*Client, error) { client.NotificationScheme = projectNotificationScheme client.Team = internal.NewTeamService(client) + client.Archive = internal.NewIssueArchivalService(client, APIVersion) + return client, nil } @@ -423,6 +425,8 @@ type Client struct { JQL *internal.JQLService NotificationScheme *internal.NotificationSchemeService Team *internal.TeamService + + Archive *internal.IssueArchivalService } // NewRequest creates an API request. diff --git a/jira/v3/api_client_impl.go b/jira/v3/api_client_impl.go index e29db9e4..30cb60e3 100644 --- a/jira/v3/api_client_impl.go +++ b/jira/v3/api_client_impl.go @@ -397,6 +397,8 @@ func New(httpClient common.HTTPClient, site string) (*Client, error) { client.NotificationScheme = projectNotificationScheme client.Team = internal.NewTeamService(client) + client.Archival = internal.NewIssueArchivalService(client, APIVersion) + return client, nil } @@ -423,6 +425,8 @@ type Client struct { JQL *internal.JQLService NotificationScheme *internal.NotificationSchemeService Team *internal.TeamService + + Archival *internal.IssueArchivalService } // NewRequest creates an API request. diff --git a/pkg/infra/models/issue_archival.go b/pkg/infra/models/issue_archival.go new file mode 100644 index 00000000..1c4a22e9 --- /dev/null +++ b/pkg/infra/models/issue_archival.go @@ -0,0 +1,33 @@ +package models + +type IssueArchivalSyncResponseScheme struct { + Errors *IssueArchivalSyncErrorScheme `json:"errors"` + NumberOfIssuesUpdated int `json:"numberOfIssuesUpdated"` +} + +type IssueArchivalSyncErrorScheme struct { + IssueIsSubtask *IssueArchivalErrorScheme `json:"issueIsSubtask"` + IssuesInArchivedProjects *IssueArchivalErrorScheme `json:"issuesInArchivedProjects"` + IssuesInUnlicensedProjects *IssueArchivalErrorScheme `json:"issuesInUnlicensedProjects"` + IssuesNotFound *IssueArchivalErrorScheme `json:"issuesNotFound"` + UserDoesNotHavePermission *IssueArchivalErrorScheme `json:"userDoesNotHavePermission"` +} + +type IssueArchivalErrorScheme struct { + Count int `json:"count"` + IssueIdsOrKeys []string `json:"issueIdsOrKeys"` + Message string `json:"message"` +} + +type IssueArchivalExportPayloadScheme struct { + ArchivedBy []string `json:"archivedBy"` + ArchivedDateRange *DateRangeFilterRequestScheme `json:"archivedDateRange,omitempty"` + IssueTypes []string `json:"issueTypes"` + Projects []string `json:"projects"` + Reporters []string `json:"reporters"` +} + +type DateRangeFilterRequestScheme struct { + DateAfter string `json:"dateAfter,omitempty"` + DateBefore string `json:"dateBefore,omitempty"` +} diff --git a/service/jira/archive.go b/service/jira/archive.go new file mode 100644 index 00000000..f8cf1ac1 --- /dev/null +++ b/service/jira/archive.go @@ -0,0 +1,79 @@ +package jira + +import ( + "context" + "github.com/ctreminiom/go-atlassian/v2/pkg/infra/models" +) + +// ArchiveService provides methods to manage issue archival operations, including preserving, restoring, and exporting archived issues. +type ArchiveService interface { + + // Preserve archives the given issues based on their issue IDs or keys. + // + // Parameters: + // - ctx: The context for controlling request lifecycle and deadlines. + // - issueIdsOrKeys: A list of issue IDs or keys to be archived. + // + // Returns: + // - result: A structure containing details of the archival synchronization process. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // result, response, err := issue.archive.Preserve(ctx, []string{"ISSUE-123", "ISSUE-456"}) + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role + Preserve(ctx context.Context, issueIdsOrKeys []string) (result *models.IssueArchivalSyncResponseScheme, response *models.ResponseScheme, err error) + + // PreserveByJQL archives issues that match the provided JQL query. + // + // Parameters: + // - ctx: The context for request lifecycle management. + // - jql: The JQL query to select issues for archival. + // + // Returns: + // - taskID: A unique identifier for the asynchronous archival task. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // taskID, response, err := issue.Archive.PreserveByJQL(ctx, "project = ABC AND status = 'Resolved'") + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role + PreserveByJQL(ctx context.Context, jql string) (taskID string, response *models.ResponseScheme, err error) + + // Restore brings back the given archived issues using their issue IDs or keys. + // + // Parameters: + // - ctx: The context for controlling request execution. + // - issueIdsOrKeys: A list of issue IDs or keys to be restored from the archive. + // + // Returns: + // - result: A structure containing details of the restoration process. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // result, response, err := issue.Archive.Restore(ctx, []string{"ISSUE-789"}) + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role + Restore(ctx context.Context, issueIdsOrKeys []string) (result *models.IssueArchivalSyncResponseScheme, response *models.ResponseScheme, err error) + + // Export generates an export of archived issues based on the provided payload. + // + // Parameters: + // - ctx: The context for controlling request execution. + // - payload: The export configuration, including filters and format specifications. + // + // Returns: + // - taskID: A unique identifier for the asynchronous export task. + // - response: The HTTP response scheme for the request. + // - err: An error if the operation fails. + // + // Example Usage: + // exportPayload := &models.IssueArchivalExportPayloadScheme{Format: "CSV", Fields: []string{"summary", "status"}} + // taskID, response, err := issue.Archive.Export(ctx, exportPayload) + // + // https://docs.go-atlassian.io/jira-software-cloud/application-roles#get-application-role + Export(ctx context.Context, payload *models.IssueArchivalExportPayloadScheme) (taskID string, response *models.ResponseScheme, err error) +}