Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions api/job/ent_job.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package job

// GetJobResponse defines get job response
type GetJobResponse struct {
TranslationJobUID string
JobName string
}

// FindFirstJobByName finds the first job by name from the list of jobs
func FindFirstJobByName(jobs []GetJobResponse, name string) (GetJobResponse, bool) {
for _, job := range jobs {
if job.JobName == name {
return job, true
}
}
return GetJobResponse{}, false
}

type getJobResponse struct {
Response struct {
Code string `json:"code"`
Data struct {
JobName string `json:"jobName"`
TranslationJobUID string `json:"translationJobUid"`
} `json:"data"`
} `json:"response"`
}
type getJobsResponse struct {
Response struct {
Code string `json:"code"`
Data struct {
Items []struct {
JobName string `json:"jobName"`
TranslationJobUID string `json:"translationJobUid"`
} `json:"items"`
} `json:"data"`
} `json:"response"`
}

func toGetJobResponse(r getJobResponse) GetJobResponse {
return GetJobResponse{
TranslationJobUID: r.Response.Data.TranslationJobUID,
JobName: r.Response.Data.JobName,
}
}

func toGetJobsResponse(r getJobsResponse) []GetJobResponse {
res := make([]GetJobResponse, len(r.Response.Data.Items))
for i, job := range r.Response.Data.Items {
res[i] = GetJobResponse{
TranslationJobUID: job.TranslationJobUID,
JobName: job.JobName,
}
}
return res
}
66 changes: 66 additions & 0 deletions api/job/ent_job_progress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package job

import (
"encoding/json"
"fmt"
)

// GetJobProgressResponse defines get job progress response
type GetJobProgressResponse struct {
TranslationJobUID string
TotalWordCount uint32
PercentComplete uint32
Json []byte
}
type getJobProgressResponse struct {
Response struct {
Code string `json:"code"`
Data struct {
ContentProgressReport []struct {
Progress struct {
PercentComplete int `json:"percentComplete"`
TotalWordCount int `json:"totalWordCount"`
} `json:"progress"`
TargetLocaleDescription string `json:"targetLocaleDescription"`
TargetLocaleId string `json:"targetLocaleId"`
UnauthorizedProgressReport struct {
StringCount int `json:"stringCount"`
WordCount int `json:"wordCount"`
} `json:"unauthorizedProgressReport"`
WorkflowProgressReportList []struct {
WorkflowName string `json:"workflowName"`
WorkflowStepSummaryReportItemList []struct {
StringCount int `json:"stringCount"`
WordCount int `json:"wordCount"`
WorkflowStepName string `json:"workflowStepName"`
WorkflowStepType string `json:"workflowStepType"`
WorkflowStepUid string `json:"workflowStepUid"`
} `json:"workflowStepSummaryReportItemList"`
WorkflowUid string `json:"workflowUid"`
} `json:"workflowProgressReportList"`
} `json:"contentProgressReport"`
Progress struct {
PercentComplete int `json:"percentComplete"`
TotalWordCount int `json:"totalWordCount"`
} `json:"progress"`
SummaryReport []struct {
StringCount int `json:"stringCount"`
WordCount int `json:"wordCount"`
WorkflowStepName string `json:"workflowStepName"`
} `json:"summaryReport"`
} `json:"data"`
} `json:"response"`
}

func toGetJobProgressResponse(r getJobProgressResponse, translationJobUID string) (GetJobProgressResponse, error) {
data, err := json.Marshal(r.Response.Data)
if err != nil {
return GetJobProgressResponse{}, fmt.Errorf("failed to marshal job progress response: %w", err)
}
return GetJobProgressResponse{
TranslationJobUID: translationJobUID,
TotalWordCount: uint32(r.Response.Data.Progress.TotalWordCount),
PercentComplete: uint32(r.Response.Data.Progress.PercentComplete),
Json: data,
}, nil
}
83 changes: 74 additions & 9 deletions api/job/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import (
"encoding/json"
"fmt"
"io"
"net/url"

smclient "github.com/Smartling/api-sdk-go/helpers/sm_client"
)

const jobBasePath = "/job-batches-api/v2/projects/"
const jobBasePath = "/jobs-api/v3/projects/"

// Job defines the job behaviour
type Job interface {
GetJob(projectID string, translationJobUID string) (GetJobResponse, error)
Get(projectID string, translationJobUID string) (GetJobResponse, error)
GetAllByName(projectID, name string) (jobs []GetJobResponse, err error)
Progress(projectID string, translationJobUID string) (GetJobProgressResponse, error)
}

// NewJob returns new Job implementation
Expand All @@ -29,27 +32,89 @@ func newHttpJob(client *smclient.Client) httpJob {
return httpJob{client: client}
}

// GetJob gets a job related info
func (h httpJob) GetJob(projectID string, translationJobUID string) (GetJobResponse, error) {
// Get gets a job related info
func (h httpJob) Get(projectID string, translationJobUID string) (GetJobResponse, error) {
url := jobBasePath + projectID + "/jobs/" + translationJobUID
var response getJobResponse
rawMessage, code, err := h.client.Get(url, nil)
if err != nil {
return GetJobResponse{}, err
}
defer func() {
if err := rawMessage.Close(); err != nil {
h.client.Logger.Debugf("failed to close response body: %v", err)
}
}()
body, err := io.ReadAll(rawMessage)
if err != nil {
return GetJobResponse{}, fmt.Errorf("failed to read response body: %w", err)
}
if code != 200 {
body, _ := io.ReadAll(rawMessage)
h.client.Logger.Debugf("response body: %s\n", body)
return GetJobResponse{}, fmt.Errorf("unexpected response code: %d", code)
}
if err := json.Unmarshal(body, &response); err != nil {
return GetJobResponse{}, fmt.Errorf("failed to unmarshal response: %w", err)
}
return toGetJobResponse(response), nil
}

// GetAllByName gets all jobs of a project by name
func (h httpJob) GetAllByName(projectID, name string) ([]GetJobResponse, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please research how to add validation for input parameters? An example for this specific case: we must check that parameters are not empty and projectID follows specific patterns.

P.S. Well, I do not want to broaden the scope of this ticket/PR. Let's make a Jira ticket for research on how to use a declarative approach for validation (rather than imerative).

reqURL := jobBasePath + projectID + "/jobs"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security training reminded me of our bad habits. It would be ideal if you could find a special library that can generate a valid URL path rather than concatenating strings. Let's do it once, and it will make future development easier because we can easily copy and paste best practices.


params := url.Values{}
params.Set("jobName", name)

rawMessage, code, err := h.client.Get(reqURL, params)
if err != nil {
return nil, err
}
defer func() {
if err := rawMessage.Close(); err != nil {
h.client.Logger.Debugf("failed to close response body: %v", err)
}
}()
body, err := io.ReadAll(rawMessage)
if err != nil {
body, _ := io.ReadAll(rawMessage)
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if code != 200 {
h.client.Logger.Debugf("response body: %s\n", body)
return GetJobResponse{}, err
return nil, fmt.Errorf("unexpected response code: %d", code)
}
var res getJobsResponse
if err := json.Unmarshal(body, &res); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
jobs := toGetJobsResponse(res)

return jobs, nil
}

// Progress returns a job related progress
func (h httpJob) Progress(projectID string, translationJobUID string) (GetJobProgressResponse, error) {
url := jobBasePath + projectID + "/jobs/" + translationJobUID + "/progress"
var response getJobProgressResponse
rawMessage, code, err := h.client.Get(url, nil)
if err != nil {
return GetJobProgressResponse{}, err
}
defer func() {
if err := rawMessage.Close(); err != nil {
h.client.Logger.Debugf("failed to close response body: %v", err)
}
}()
body, err := io.ReadAll(rawMessage)
if err != nil {
return GetJobProgressResponse{}, fmt.Errorf("failed to read response body: %w", err)
}
if code != 200 {
h.client.Logger.Debugf("response body: %s\n", body)
return GetJobProgressResponse{}, fmt.Errorf("unexpected response code: %d", code)
}
if err := json.Unmarshal(body, &response); err != nil {
return GetJobResponse{}, fmt.Errorf("failed to unmarshal response: %w", err)
return GetJobProgressResponse{}, fmt.Errorf("failed to unmarshal response: %w", err)
}
return toGetJobResponse(response), nil
return toGetJobProgressResponse(response, translationJobUID)
}
23 changes: 0 additions & 23 deletions api/job/job_ent.go

This file was deleted.

3 changes: 2 additions & 1 deletion download_file_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ package smartling

import (
"fmt"
"github.com/Smartling/api-sdk-go/helpers/sm_file"
"net/url"

"github.com/Smartling/api-sdk-go/helpers/sm_file"
)

// RetrievalType describes type of file download.
Expand Down
2 changes: 0 additions & 2 deletions helpers/sm_file/file_last_modified_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ type FileLastModifiedRequest struct {

func (request *FileLastModifiedRequest) GetForm() (*sm_form.Form, error) {
form, err := request.FileURIRequest.GetForm()

if err != nil {
return nil, err
}

err = form.Writer.WriteField("lastModifiedAfter", request.LastModifiedAfter.String())

if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion helpers/sm_file/files_list_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ package smfile

import (
"fmt"
"github.com/Smartling/api-sdk-go/helpers/utc"
"net/url"

"github.com/Smartling/api-sdk-go/helpers/utc"
)

// FilesListRequest represents request used to filter files returned by
Expand Down
52 changes: 25 additions & 27 deletions helpers/sm_file/get_file_type_by_extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,31 @@ import (
"strings"
)

var (
extensions = map[string]FileType{
"yml": FileTypeYAML,
"yaml": FileTypeYAML,
"html": FileTypeHTML,
"htm": FileTypeHTML,
"xlf": FileTypeXLIFF,
"xliff": FileTypeXLIFF,
"json": FileTypeJSON,
"docx": FileTypeDOCX,
"pptx": FileTypePPTX,
"xlsx": FileTypeXLSX,
"txt": FileTypePlaintext,
"ts": FileTypeQt,
"idml": FileTypeIDML,
"resx": FileTypeResx,
"resw": FileTypeResx,
"csv": FileTypeCSV,
"stringsdict": FileTypeStringsdict,
"strings": FileTypeIOS,
"po": FileTypeGettext,
"pot": FileTypeGettext,
"xml": FileTypeXML,
"properties": FileTypeJavaProperties,
"": FileTypeUnknown,
}
)
var extensions = map[string]FileType{
"yml": FileTypeYAML,
"yaml": FileTypeYAML,
"html": FileTypeHTML,
"htm": FileTypeHTML,
"xlf": FileTypeXLIFF,
"xliff": FileTypeXLIFF,
"json": FileTypeJSON,
"docx": FileTypeDOCX,
"pptx": FileTypePPTX,
"xlsx": FileTypeXLSX,
"txt": FileTypePlaintext,
"ts": FileTypeQt,
"idml": FileTypeIDML,
"resx": FileTypeResx,
"resw": FileTypeResx,
"csv": FileTypeCSV,
"stringsdict": FileTypeStringsdict,
"strings": FileTypeIOS,
"po": FileTypeGettext,
"pot": FileTypeGettext,
"xml": FileTypeXML,
"properties": FileTypeJavaProperties,
"": FileTypeUnknown,
}

func GetFileTypeByExtension(ext string) FileType {
return extensions[strings.TrimPrefix(ext, ".")]
Expand Down