Skip to content

Commit

Permalink
Merge pull request #43 from lokalise/feature/KRNL-164_segmentation_api
Browse files Browse the repository at this point in the history
KRNL-164 segmentation api
  • Loading branch information
Dosexe authored Feb 6, 2023
2 parents fb87b56 + 13cfb97 commit 1cc12de
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 4 deletions.
2 changes: 2 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Api struct {
Projects func() *ProjectService
QueuedProcesses func() *QueuedProcessService
Screenshots func() *ScreenshotService
Segments func() *SegmentationService
Snapshots func() *SnapshotService
Tasks func() *TaskService
Teams func() *TeamService
Expand Down Expand Up @@ -65,6 +66,7 @@ func New(apiToken string, options ...ClientOption) (*Api, error) {
c.Tasks = func() *TaskService { return &TaskService{BaseService: bs, listOpts: taskOpts} }

c.Screenshots = func() *ScreenshotService { return &ScreenshotService{BaseService: bs, listOpts: scOpts} }
c.Segments = func() *SegmentationService { return &SegmentationService{BaseService: bs} }
c.Snapshots = func() *SnapshotService { return &SnapshotService{bs} }
c.Languages = func() *LanguageService { return &LanguageService{bs} }
c.Translations = func() *TranslationService { return &TranslationService{BaseService: bs, opts: trOpts} }
Expand Down
7 changes: 4 additions & 3 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
)

const (
baseURLPath = "/api2"
testApiToken = "apiToken"
testProjectID = "3002780358964f9bab5a92.87762498"
baseURLPath = "/api2"
testApiToken = "apiToken"
testProjectID = "3002780358964f9bab5a92.87762498"
assertionTemplate = "%s returned \n%+v\nexpected\n%+v"
)

func setup() (api *Api, mux *http.ServeMux, serverURL string, teardown func()) {
Expand Down
2 changes: 1 addition & 1 deletion svc_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ type CreateKeysRequest struct {
KeyRequestOptions
}

// Separate struct for bulk updating
// BulkUpdateKey Separate struct for bulk updating
type BulkUpdateKey struct {
KeyID int64 `json:"key_id"`
NewKey
Expand Down
157 changes: 157 additions & 0 deletions svc_segment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package lokalise

import (
"fmt"
"github.com/go-resty/resty/v2"
"github.com/google/go-querystring/query"
)

const (
pathSegments = "segments"
)

// SegmentationService supports List, Retrieve and Update commands
type SegmentationService struct {
BaseService

listOpts SegmentsListOptions
retrieveOpts SegmentsRetrieveOptions
}

type Segment struct {
SegmentNumber int64 `json:"segment_number"`
LanguageIso string `json:"language_iso"`
ModifiedAt string `json:"modified_at"`
ModifiedAtTimestamp int64 `json:"modified_at_timestamp"`
ModifiedBy int64 `json:"modified_by"`
ModifiedByEmail string `json:"modified_by_email"`
Value string `json:"value"`
IsFuzzy bool `json:"is_fuzzy"`
IsReviewed bool `json:"is_reviewed"`
ReviewedBy int64 `json:"reviewed_by"`
Words int64 `json:"words"`
CustomTranslationStatuses []TranslationStatus `json:"custom_translation_statuses"`
}

type SegmentsResponse struct {
WithProjectID
Segments []Segment `json:"segments"`
Errors []ErrorKeys `json:"error,omitempty"`
}

type SegmentResponse struct {
WithProjectID
KeyID int64 `json:"key_id"`
LanguageISO string `json:"language_iso"`
Segment Segment `json:"segment"`
}

type SegmentUpdateRequest struct {
Value string `json:"value"` // could be string or json for plural keys.
IsFuzzy *bool `json:"is_fuzzy,omitempty"`
IsReviewed *bool `json:"is_reviewed,omitempty"`
CustomTranslationStatusIds []int64 `json:"custom_translation_status_ids,omitempty"`
}

func (s *SegmentationService) List(projectID string, keyID int64, languageIso string) (r SegmentsResponse, err error) {
resp, err := s.getList(
s.Ctx(),
fmt.Sprintf("%s/%s/%s/%d/%s/%s", pathProjects, projectID, pathKeys, keyID, pathSegments, languageIso),
&r,
s.ListOpts(),
)

if err != nil {
return
}
return r, apiError(resp)
}

func (s *SegmentationService) Retrieve(
projectID string,
keyID int64,
languageIso string,
segmentNumber int64,
) (r SegmentResponse, err error) {
resp, err := s.getList(
s.Ctx(),
segmentPath(projectID, keyID, languageIso, segmentNumber),
&r,
s.RetrieveOpts(),
)

if err != nil {
return
}
return r, apiError(resp)
}

func (s *SegmentationService) Update(
projectID string,
keyID int64,
languageIso string,
segmentNumber int64,
updateRequest SegmentUpdateRequest,
) (r SegmentResponse, err error) {
resp, err := s.put(s.Ctx(), segmentPath(projectID, keyID, languageIso, segmentNumber), &r, updateRequest)

if err != nil {
return
}
return r, apiError(resp)
}

func segmentPath(projectID string, keyID int64, languageIso string, segmentNumber int64) string {
return fmt.Sprintf(
"%s/%s/%s/%d/%s/%s/%d",
pathProjects,
projectID,
pathKeys,
keyID,
pathSegments,
languageIso,
segmentNumber,
)
}

// ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Additional methods
// _____________________________________________________________________________________________________________________

type SegmentsListOptions struct {
// Possible values are 1 and 0.
DisableReferences uint8 `url:"disable_references,omitempty"`
FilterIsReviewed uint8 `url:"filter_is_reviewed,omitempty"`
FilterUnverified uint8 `url:"filter_unverified,omitempty"`
FilterUntranslated uint8 `url:"filter_untranslated,omitempty"`

FilterQAIssues string `url:"filter_qa_issues,omitempty"`
}

func (s *SegmentationService) ListOpts() SegmentsListOptions { return s.listOpts }
func (s *SegmentationService) SetListOptions(o SegmentsListOptions) { s.listOpts = o }
func (s *SegmentationService) WithListOptions(o SegmentsListOptions) *SegmentationService {
s.listOpts = o
return s
}

func (options SegmentsListOptions) Apply(req *resty.Request) {
v, _ := query.Values(options)
req.SetQueryString(v.Encode())
}

type SegmentsRetrieveOptions struct {
DisableReferences uint8 `url:"disable_references,omitempty"`
}

func (options SegmentsRetrieveOptions) Apply(req *resty.Request) {
v, _ := query.Values(options)
req.SetQueryString(v.Encode())
}

func (s *SegmentationService) RetrieveOpts() SegmentsRetrieveOptions { return s.retrieveOpts }
func (s *SegmentationService) SetRetrieveOptions(o SegmentsRetrieveOptions) { s.retrieveOpts = o }
func (s *SegmentationService) WithRetrieveOptions(o SegmentsRetrieveOptions) *SegmentationService {
s.retrieveOpts = o
return s
}
152 changes: 152 additions & 0 deletions svc_segment_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package lokalise

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)

func TestSegmentationService_List(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

var keyID int64 = 640
languageIso := "en_US"

mux.HandleFunc(
fmt.Sprintf("/projects/%s/keys/%d/segments/%s", testProjectID, keyID, languageIso),
func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
testMethod(t, r, "GET")
testHeader(t, r, apiTokenHeader, testApiToken)

_, _ = fmt.Fprint(w, `{
"project_id": "`+testProjectID+`",
"segments": [
{
"segment_number": 1,
"language_iso": "en_US"
}
]
}`)
})

r, err := client.Segments().List(testProjectID, keyID, languageIso)
if err != nil {
t.Errorf("Segments.List returned error: %v", err)
}

want := []Segment{
{
SegmentNumber: 1,
LanguageIso: languageIso,
},
}

if !reflect.DeepEqual(r.Segments, want) {
t.Errorf(assertionTemplate, "Segments.List", r.Segments, want)
}
}

func TestSegmentationService_Retrieve(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

var keyID int64 = 640
languageIso := "en_US"
var segmentNumber int64 = 1

mux.HandleFunc(
fmt.Sprintf("/projects/%s/keys/%d/segments/%s/%d", testProjectID, keyID, languageIso, segmentNumber),
func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
testMethod(t, r, "GET")
testHeader(t, r, apiTokenHeader, testApiToken)

_, _ = fmt.Fprint(w, `{
"project_id": "`+testProjectID+`",
"key_id": 640,
"language_iso": "en_US",
"segment": {
"segment_number": 1,
"language_iso": "en_US"
}
}`)
})

r, err := client.Segments().Retrieve(testProjectID, keyID, languageIso, segmentNumber)
if err != nil {
t.Errorf("Segments.Retrieve returned error: %v", err)
}

want := Segment{
SegmentNumber: segmentNumber,
LanguageIso: languageIso,
}

if !reflect.DeepEqual(r.Segment, want) {
t.Errorf(assertionTemplate, "Segments.Retrieve", r.Segment, want)
}
}

func TestSegmentationService_Update(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

var keyID int64 = 640
languageIso := "en_US"
var segmentNumber int64 = 1

mux.HandleFunc(
fmt.Sprintf("/projects/%s/keys/%d/segments/%s/%d", testProjectID, keyID, languageIso, segmentNumber),
func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
testMethod(t, r, "PUT")
testHeader(t, r, apiTokenHeader, testApiToken)
data := `{
"value": "Quick brown fox jumps over the lazy dog.",
"is_fuzzy": false,
"is_reviewed": true,
"custom_translation_status_ids": [
2, 3
]
}`

req := new(bytes.Buffer)
_ = json.Compact(req, []byte(data))

testBody(t, r, req.String())

_, _ = fmt.Fprint(w, `{
"project_id": "`+testProjectID+`",
"key_id": 640,
"language_iso": "en_US",
"segment": {
"segment_number": 1,
"language_iso": "en_US"
}
}`)
})

r, err := client.Segments().Update(testProjectID, 640, "en_US", 1, SegmentUpdateRequest{
Value: "Quick brown fox jumps over the lazy dog.",
IsFuzzy: Bool(false),
IsReviewed: Bool(true),
CustomTranslationStatusIds: []int64{2, 3},
})
if err != nil {
t.Errorf("Segments.Update returned error: %v", err)
}

want := Segment{
SegmentNumber: segmentNumber,
LanguageIso: languageIso,
}

if !reflect.DeepEqual(r.Segment, want) {
t.Errorf(assertionTemplate, "Segments.Update", r.Segment, want)
}
}

0 comments on commit 1cc12de

Please sign in to comment.