From 6d628f99e97fced015ba24551746a13862435f1a Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Mon, 11 May 2020 22:12:27 -0500 Subject: [PATCH 1/9] Add UpdateURL resolver to gqlapi * Add `URLUpdater` to url usecase * Update dependency injection and generated code * Update go module checksum --- backend/app/adapter/gqlapi/api_test.go | 12 +- .../adapter/gqlapi/resolver/authmutation.go | 23 +++ .../app/adapter/gqlapi/resolver/mutation.go | 5 +- .../app/adapter/gqlapi/resolver/resolver.go | 2 + backend/app/usecase/url/urlupdater.go | 95 ++++++++++++ backend/app/usecase/url/urlupdater_test.go | 143 ++++++++++++++++++ backend/dep/wire.go | 2 + backend/dep/wire_gen.go | 1 + backend/go.sum | 1 + 9 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 backend/app/usecase/url/urlupdater.go create mode 100644 backend/app/usecase/url/urlupdater_test.go diff --git a/backend/app/adapter/gqlapi/api_test.go b/backend/app/adapter/gqlapi/api_test.go index bcccf3dc8..3f816d6e2 100644 --- a/backend/app/adapter/gqlapi/api_test.go +++ b/backend/app/adapter/gqlapi/api_test.go @@ -50,7 +50,17 @@ func TestGraphQlAPI(t *testing.T) { riskDetector, ) - s := requester.NewReCaptchaFake(requester.VerifyResponse{}) + updater := url.NewUpdaterPersist( + &urlRepo, + &urlRelationRepo, + keyGen, + longLinkValidator, + customAliasValidator, + tm, + riskDetector, + ) + + s := external.NewReCaptchaFake(external.VerifyResponse{}) verifier := requester.NewVerifier(s) auth := authenticator.NewAuthenticatorFake(time.Now(), time.Hour) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index 25a327928..b5280a712 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -17,6 +17,7 @@ type AuthMutation struct { authenticator authenticator.Authenticator changeLog changelog.ChangeLog urlCreator url.Creator + urlUpdater url.Updater } // URLInput represents possible URL attributes @@ -77,6 +78,26 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { } } +func (a AuthMutation) UpdateURL(oldAlias string, urlInput URLInput, isPublic *bool) (*URL, error) { + user, err := viewer(a.authToken, a.authenticator) + if err != nil { + return nil, ErrInvalidAuthToken{} + } + + update := entity.URL{ + Alias: *urlInput.CustomAlias, + OriginalURL: urlInput.OriginalURL, + ExpireAt: urlInput.ExpireAt, + } + + newURL, err := a.urlUpdater.UpdateURL(oldAlias, update, user) + if err != nil { + return nil, err + } + + return &URL{url: newURL}, nil +} + // CreateChange creates a Change in the change log func (a AuthMutation) CreateChange(args *CreateChangeArgs) (Change, error) { change, err := a.changeLog.CreateChange(args.Change.Title, args.Change.SummaryMarkdown) @@ -99,11 +120,13 @@ func newAuthMutation( authenticator authenticator.Authenticator, changeLog changelog.ChangeLog, urlCreator url.Creator, + urlUpdater url.Updater, ) AuthMutation { return AuthMutation{ authToken: authToken, authenticator: authenticator, changeLog: changeLog, urlCreator: urlCreator, + urlUpdater: urlUpdater, } } diff --git a/backend/app/adapter/gqlapi/resolver/mutation.go b/backend/app/adapter/gqlapi/resolver/mutation.go index af19cddd2..633bf1976 100644 --- a/backend/app/adapter/gqlapi/resolver/mutation.go +++ b/backend/app/adapter/gqlapi/resolver/mutation.go @@ -12,6 +12,7 @@ import ( type Mutation struct { logger logger.Logger urlCreator url.Creator + urlUpdater url.Updater requesterVerifier requester.Verifier authenticator authenticator.Authenticator changeLog changelog.ChangeLog @@ -35,7 +36,7 @@ func (m Mutation) AuthMutation(args *AuthMutationArgs) (*AuthMutation, error) { return nil, ErrNotHuman{} } - authMutation := newAuthMutation(args.AuthToken, m.authenticator, m.changeLog, m.urlCreator) + authMutation := newAuthMutation(args.AuthToken, m.authenticator, m.changeLog, m.urlCreator, m.urlUpdater) return &authMutation, nil } @@ -43,6 +44,7 @@ func newMutation( logger logger.Logger, changeLog changelog.ChangeLog, urlCreator url.Creator, + urlUpdater url.Updater, requesterVerifier requester.Verifier, authenticator authenticator.Authenticator, ) Mutation { @@ -50,6 +52,7 @@ func newMutation( logger: logger, changeLog: changeLog, urlCreator: urlCreator, + urlUpdater: urlUpdater, requesterVerifier: requesterVerifier, authenticator: authenticator, } diff --git a/backend/app/adapter/gqlapi/resolver/resolver.go b/backend/app/adapter/gqlapi/resolver/resolver.go index f3f2bba85..8f12e94da 100644 --- a/backend/app/adapter/gqlapi/resolver/resolver.go +++ b/backend/app/adapter/gqlapi/resolver/resolver.go @@ -20,6 +20,7 @@ func NewResolver( urlRetriever url.Retriever, urlCreator url.Creator, changeLog changelog.ChangeLog, + urlUpdater url.Updater, requesterVerifier requester.Verifier, authenticator authenticator.Authenticator, ) Resolver { @@ -29,6 +30,7 @@ func NewResolver( logger, changeLog, urlCreator, + urlUpdater, requesterVerifier, authenticator, ), diff --git a/backend/app/usecase/url/urlupdater.go b/backend/app/usecase/url/urlupdater.go new file mode 100644 index 000000000..30c9ee81d --- /dev/null +++ b/backend/app/usecase/url/urlupdater.go @@ -0,0 +1,95 @@ +package url + +import ( + "github.com/short-d/app/fw/timer" + "github.com/short-d/short/backend/app/entity" + "github.com/short-d/short/backend/app/usecase/keygen" + "github.com/short-d/short/backend/app/usecase/repository" + "github.com/short-d/short/backend/app/usecase/risk" + "github.com/short-d/short/backend/app/usecase/validator" +) + +var _ Updater = (*UpdaterPersist)(nil) + +type Updater interface { + UpdateURL(oldAlias string, update entity.URL, user entity.User) (entity.URL, error) +} + +type UpdaterPersist struct { + urlRepo repository.URL + userURLRelationRepo repository.UserURLRelation + keyGen keygen.KeyGenerator + longLinkValidator validator.LongLink + aliasValidator validator.CustomAlias + timer timer.Timer + riskDetector risk.Detector +} + +func (u UpdaterPersist) UpdateURL( + oldAlias string, + update entity.URL, + user entity.User, +) (entity.URL, error) { + oldURL, err := u.urlRepo.GetByAlias(oldAlias) + + if err != nil { + return entity.URL{}, err + } + + update = u.updateAlias(oldURL, update) + update = u.updateLongLink(oldURL, update) + + if u.riskDetector.IsURLMalicious(update.OriginalURL) { + return entity.URL{}, ErrMaliciousLongLink(update.OriginalURL) + } + + if !u.aliasValidator.IsValid(&update.Alias) { + return entity.URL{}, ErrInvalidCustomAlias(oldAlias) + } + + if !u.longLinkValidator.IsValid(&update.OriginalURL) { + return entity.URL{}, ErrInvalidLongLink(update.OriginalURL) + } + + return u.urlRepo.UpdateURL(oldAlias, update) +} + +func (u UpdaterPersist) updateAlias(url, update entity.URL) entity.URL { + newAlias := update.Alias + + if newAlias == "" { + update.Alias = url.Alias + } + + return update +} + +func (u *UpdaterPersist) updateLongLink(url, update entity.URL) entity.URL { + newLongLink := update.OriginalURL + + if newLongLink == "" { + url.OriginalURL = update.OriginalURL + } + + return update +} + +func NewUpdaterPersist( + urlRepo repository.URL, + userURLRelationRepo repository.UserURLRelation, + keyGen keygen.KeyGenerator, + longLinkValidator validator.LongLink, + aliasValidator validator.CustomAlias, + timer timer.Timer, + riskDetector risk.Detector, +) UpdaterPersist { + return UpdaterPersist{ + urlRepo, + userURLRelationRepo, + keyGen, + longLinkValidator, + aliasValidator, + timer, + riskDetector, + } +} diff --git a/backend/app/usecase/url/urlupdater_test.go b/backend/app/usecase/url/urlupdater_test.go new file mode 100644 index 000000000..635ff45fd --- /dev/null +++ b/backend/app/usecase/url/urlupdater_test.go @@ -0,0 +1,143 @@ +// +build !integration all + +package url + +import ( + "testing" + "time" + + "github.com/short-d/app/fw/assert" + "github.com/short-d/app/fw/timer" + "github.com/short-d/short/backend/app/entity" + "github.com/short-d/short/backend/app/usecase/external" + "github.com/short-d/short/backend/app/usecase/keygen" + "github.com/short-d/short/backend/app/usecase/repository" + "github.com/short-d/short/backend/app/usecase/risk" + "github.com/short-d/short/backend/app/usecase/validator" +) + +func TestURLUpdaterPersist_UpdateURL(t *testing.T) { + t.Parallel() + + now := time.Now().UTC() + alias := "boGp9w35" + validNewAlias := "eBJRJJty" + validNewLongLink := "https://httpbin.org/get?p1=v1" + + testCases := []struct { + name string + alias *string + availableKeys []external.Key + urls urlMap + user entity.User + urlUpdate entity.URL + relationUsers []entity.User + relationURLs []entity.URL + expHasErr bool + expectedURL entity.URL + }{ + { + name: "successfully update existing long link", + alias: &alias, + urls: urlMap{ + "boGp9w35": entity.URL{ + Alias: "boGp9w35", + OriginalURL: "https://httpbin.org", + }, + }, + user: entity.User{ + Email: "gopher@golang.org", + }, + urlUpdate: entity.URL{ + OriginalURL: validNewLongLink, + }, + expHasErr: false, + expectedURL: entity.URL{ + Alias: "boGp9w35", + OriginalURL: validNewLongLink, + }, + }, + { + name: "alias doesn't exist", + alias: &validNewAlias, + urls: urlMap{ + "boGp9w35zzzz": entity.URL{ + Alias: "boGp9w35zzzz", + OriginalURL: "https://httpbin.org", + }, + }, + user: entity.User{ + Email: "gopher@golang.org", + }, + urlUpdate: entity.URL{ + OriginalURL: validNewLongLink, + }, + expHasErr: true, + expectedURL: entity.URL{}, + }, + { + name: "long link is invalid", + alias: &alias, + urls: urlMap{ + "boGp9w35": entity.URL{ + Alias: "boGp9w35", + OriginalURL: "https://httpbin.org", + }, + }, + user: entity.User{ + Email: "gopher@golang.org", + }, + urlUpdate: entity.URL{ + OriginalURL: "", + }, + expHasErr: true, + expectedURL: entity.URL{}, + }, + } + + for _, testCase := range testCases { + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + blockedHash := map[string]bool{} + tm := timer.NewStub(now) + urlRepo := repository.NewURLFake(testCase.urls) + userURLRepo := repository.NewUserURLRepoFake( + testCase.relationUsers, + testCase.relationURLs, + ) + keyFetcher := external.NewKeyFetcherFake(testCase.availableKeys) + keyGen, err := keygen.NewKeyGenerator(2, &keyFetcher) + assert.Equal(t, nil, err) + longLinkValidator := validator.NewLongLink() + aliasValidator := validator.NewCustomAlias() + blacklist := risk.NewBlackListFake(blockedHash) + riskDetector := risk.NewDetector(blacklist) + updater := NewUpdaterPersist( + &urlRepo, + &userURLRepo, + keyGen, + longLinkValidator, + aliasValidator, + tm, + riskDetector, + ) + + url, err := updater.UpdateURL(*testCase.alias, testCase.urlUpdate, testCase.user) + if testCase.expHasErr { + assert.NotEqual(t, nil, err) + + _, err = urlRepo.GetByAlias(testCase.expectedURL.Alias) + assert.NotEqual(t, nil, err) + + isExist := userURLRepo.IsRelationExist(testCase.user, testCase.expectedURL) + assert.Equal(t, false, isExist) + return + } + assert.Equal(t, nil, err) + assert.Equal(t, testCase.expectedURL.OriginalURL, url.OriginalURL) + assert.Equal(t, testCase.expectedURL.Alias, url.Alias) + assert.Equal(t, testCase.expectedURL.CreatedAt, url.CreatedAt) + assert.NotEqual(t, testCase.expectedURL.UpdatedAt, url.UpdatedAt) + }) + } +} diff --git a/backend/dep/wire.go b/backend/dep/wire.go index 253d5a36e..abb186f6c 100644 --- a/backend/dep/wire.go +++ b/backend/dep/wire.go @@ -159,6 +159,7 @@ func InjectGraphQLService( wire.Bind(new(changelog.ChangeLog), new(changelog.Persist)), wire.Bind(new(url.Retriever), new(url.RetrieverPersist)), wire.Bind(new(url.Creator), new(url.CreatorPersist)), + wire.Bind(new(url.Updater), new(url.UpdaterPersist)), observabilitySet, authSet, @@ -186,6 +187,7 @@ func InjectGraphQLService( changelog.NewPersist, url.NewRetrieverPersist, url.NewCreatorPersist, + url.NewUpdaterPersist, requester.NewVerifier, ) return service.GraphQL{}, nil diff --git a/backend/dep/wire_gen.go b/backend/dep/wire_gen.go index 66212359d..db7eebea6 100644 --- a/backend/dep/wire_gen.go +++ b/backend/dep/wire_gen.go @@ -89,6 +89,7 @@ func InjectGraphQLService(runtime2 env.Runtime, prefix provider.LogPrefix, logLe safeBrowsing := provider.NewSafeBrowsing(googleAPIKey, http) detector := risk.NewDetector(safeBrowsing) creatorPersist := url.NewCreatorPersist(urlSql, userURLRelationSQL, keyGenerator, longLink, customAlias, system, detector) + updaterPersist := url.NewUpdaterPersist(urlSql, userURLRelationSQL, keyGenerator, longLink, customAlias, system, detector) changeLogSQL := sqldb.NewChangeLogSQL(sqlDB) userChangeLogSQL := sqldb.NewUserChangeLogSQL(sqlDB) persist := changelog.NewPersist(keyGenerator, system, changeLogSQL, userChangeLogSQL) diff --git a/backend/go.sum b/backend/go.sum index 8be3b1e6d..f8e0494c5 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -342,6 +342,7 @@ github.com/short-d/kgs v0.0.0-20200419183416-2deb6aa8d7ed h1:goDxEfMeotHFO2J8cg5 github.com/short-d/kgs v0.0.0-20200419183416-2deb6aa8d7ed/go.mod h1:b0Uw5WfhgcBsheLrDNm8RO0lb4C5UggG+WzBe4rxn7U= github.com/short-d/kgs v0.0.0-20200505215800-7d538f015ea1 h1:a75oDPkkATM03ONinwZDshyqA9L5WXFw4PH0+YcWW/w= github.com/short-d/kgs v0.0.0-20200505215800-7d538f015ea1/go.mod h1:b0Uw5WfhgcBsheLrDNm8RO0lb4C5UggG+WzBe4rxn7U= +github.com/short-d/short v0.0.0-20200519020837-bc5d6e75c393 h1:0bb5FRcuamv2iJ5WnEVeF74GTSuxfEnMSprB1Wj96/4= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= From 09ab9b976fecd6aefb8740ce1196668a6d81ce3f Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Thu, 14 May 2020 23:56:47 -0500 Subject: [PATCH 2/9] Fix AuthMutation implementation * Update UpdateURL args to satisfy schema changes. * Clean up code layout --- backend/app/adapter/gqlapi/resolver/authmutation.go | 10 +++++++++- backend/app/adapter/gqlapi/schema.go | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index b5280a712..76d017f88 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -78,7 +78,15 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { } } -func (a AuthMutation) UpdateURL(oldAlias string, urlInput URLInput, isPublic *bool) (*URL, error) { +type UpdateURLArgs struct { + OldAlias string + Url URLInput + IsPublic bool +} + +func (a AuthMutation) UpdateURL(args *UpdateURLArgs) (*URL, error) { + oldAlias := args.OldAlias + urlInput := args.Url user, err := viewer(a.authToken, a.authenticator) if err != nil { return nil, ErrInvalidAuthToken{} diff --git a/backend/app/adapter/gqlapi/schema.go b/backend/app/adapter/gqlapi/schema.go index 21e8a5c7a..a51ed30eb 100644 --- a/backend/app/adapter/gqlapi/schema.go +++ b/backend/app/adapter/gqlapi/schema.go @@ -34,6 +34,7 @@ type Change { type AuthMutation { createURL(url: URLInput!, isPublic: Boolean!): URL + updateURL(oldAlias: String!, url: URLInput!): URL createChange(change: ChangeInput!): Change! viewChangeLog: Time! } From c8dc98bff9d258e18a71ace384602d44e5c6ccfb Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Sun, 17 May 2020 01:53:34 -0500 Subject: [PATCH 3/9] Update URLUpdate Resolver * Update schema to allow flexible changes i.e. one field or multiple fields * Fix url `UPDATE` statement * Remove `external` package imports * Update dependency checksums --- backend/app/adapter/gqlapi/api_test.go | 2 +- .../adapter/gqlapi/resolver/authmutation.go | 39 +++++++++++++++---- backend/app/adapter/gqlapi/schema.go | 8 +++- backend/app/adapter/sqldb/short_link.go | 2 +- backend/app/usecase/url/urlupdater.go | 32 +++++++-------- backend/app/usecase/url/urlupdater_test.go | 7 ++-- 6 files changed, 59 insertions(+), 31 deletions(-) diff --git a/backend/app/adapter/gqlapi/api_test.go b/backend/app/adapter/gqlapi/api_test.go index 3f816d6e2..d35067968 100644 --- a/backend/app/adapter/gqlapi/api_test.go +++ b/backend/app/adapter/gqlapi/api_test.go @@ -60,7 +60,7 @@ func TestGraphQlAPI(t *testing.T) { riskDetector, ) - s := external.NewReCaptchaFake(external.VerifyResponse{}) + s := requester.NewReCaptchaFake(requester.VerifyResponse{}) verifier := requester.NewVerifier(s) auth := authenticator.NewAuthenticatorFake(time.Now(), time.Hour) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index 76d017f88..78a797c3a 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -1,6 +1,7 @@ package resolver import ( + "errors" "time" "github.com/short-d/short/backend/app/adapter/gqlapi/scalar" @@ -80,25 +81,47 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { type UpdateURLArgs struct { OldAlias string - Url URLInput + Url URLUpdateInput IsPublic bool } +type URLUpdateInput struct { + OriginalURL *string + CustomAlias *string + ExpireAt *time.Time +} + +func (u URLUpdateInput) isValid() bool { + return u != URLUpdateInput{} +} + func (a AuthMutation) UpdateURL(args *UpdateURLArgs) (*URL, error) { - oldAlias := args.OldAlias - urlInput := args.Url + originalURL := args.Url.OriginalURL + customAlias := args.Url.CustomAlias + expireAt := args.Url.ExpireAt + user, err := viewer(a.authToken, a.authenticator) if err != nil { return nil, ErrInvalidAuthToken{} } - update := entity.URL{ - Alias: *urlInput.CustomAlias, - OriginalURL: urlInput.OriginalURL, - ExpireAt: urlInput.ExpireAt, + if !args.Url.isValid() { + return nil, errors.New("Empty Update") + } + + update := &entity.URL{ + ExpireAt: expireAt, + } + + if originalURL != nil { + update.OriginalURL = *originalURL + } + + if customAlias != nil { + update.Alias = *customAlias } - newURL, err := a.urlUpdater.UpdateURL(oldAlias, update, user) + newURL, err := a.urlUpdater.UpdateURL(args.OldAlias, *update, user) if err != nil { return nil, err } diff --git a/backend/app/adapter/gqlapi/schema.go b/backend/app/adapter/gqlapi/schema.go index a51ed30eb..c01ef3b5c 100644 --- a/backend/app/adapter/gqlapi/schema.go +++ b/backend/app/adapter/gqlapi/schema.go @@ -34,7 +34,7 @@ type Change { type AuthMutation { createURL(url: URLInput!, isPublic: Boolean!): URL - updateURL(oldAlias: String!, url: URLInput!): URL + updateURL(oldAlias: String!, url: URLUpdateInput!): URL createChange(change: ChangeInput!): Change! viewChangeLog: Time! } @@ -50,6 +50,12 @@ input ChangeInput { summaryMarkdown: String } +input URLUpdateInput { + originalURL: String + customAlias: String + expireAt: Time +} + type URL { alias: String originalURL: String diff --git a/backend/app/adapter/sqldb/short_link.go b/backend/app/adapter/sqldb/short_link.go index 01335a0a9..f817e90ba 100644 --- a/backend/app/adapter/sqldb/short_link.go +++ b/backend/app/adapter/sqldb/short_link.go @@ -73,7 +73,7 @@ WHERE "%s"=$5;`, table.URL.ColumnOriginalURL, table.URL.ColumnExpireAt, table.URL.ColumnUpdatedAt, - oldAlias, + table.URL.ColumnAlias, ) _, err := u.db.Exec( diff --git a/backend/app/usecase/url/urlupdater.go b/backend/app/usecase/url/urlupdater.go index 30c9ee81d..3eecce022 100644 --- a/backend/app/usecase/url/urlupdater.go +++ b/backend/app/usecase/url/urlupdater.go @@ -30,48 +30,48 @@ func (u UpdaterPersist) UpdateURL( update entity.URL, user entity.User, ) (entity.URL, error) { - oldURL, err := u.urlRepo.GetByAlias(oldAlias) + url, err := u.urlRepo.GetByAlias(oldAlias) if err != nil { return entity.URL{}, err } - update = u.updateAlias(oldURL, update) - update = u.updateLongLink(oldURL, update) + url = u.updateAlias(url, update) + url = u.updateLongLink(url, update) - if u.riskDetector.IsURLMalicious(update.OriginalURL) { - return entity.URL{}, ErrMaliciousLongLink(update.OriginalURL) + if u.riskDetector.IsURLMalicious(url.OriginalURL) { + return entity.URL{}, ErrMaliciousLongLink(url.OriginalURL) } - if !u.aliasValidator.IsValid(&update.Alias) { - return entity.URL{}, ErrInvalidCustomAlias(oldAlias) + if !u.aliasValidator.IsValid(&url.Alias) { + return entity.URL{}, ErrInvalidCustomAlias(url.Alias) } - if !u.longLinkValidator.IsValid(&update.OriginalURL) { - return entity.URL{}, ErrInvalidLongLink(update.OriginalURL) + if !u.longLinkValidator.IsValid(&url.OriginalURL) { + return entity.URL{}, ErrInvalidLongLink(url.OriginalURL) } - return u.urlRepo.UpdateURL(oldAlias, update) + return u.urlRepo.UpdateURL(oldAlias, url) } func (u UpdaterPersist) updateAlias(url, update entity.URL) entity.URL { newAlias := update.Alias - if newAlias == "" { - update.Alias = url.Alias + if newAlias != "" { + url.Alias = newAlias } - return update + return url } func (u *UpdaterPersist) updateLongLink(url, update entity.URL) entity.URL { newLongLink := update.OriginalURL - if newLongLink == "" { - url.OriginalURL = update.OriginalURL + if newLongLink != "" { + url.OriginalURL = newLongLink } - return update + return url } func NewUpdaterPersist( diff --git a/backend/app/usecase/url/urlupdater_test.go b/backend/app/usecase/url/urlupdater_test.go index 635ff45fd..eedca4c3f 100644 --- a/backend/app/usecase/url/urlupdater_test.go +++ b/backend/app/usecase/url/urlupdater_test.go @@ -9,7 +9,6 @@ import ( "github.com/short-d/app/fw/assert" "github.com/short-d/app/fw/timer" "github.com/short-d/short/backend/app/entity" - "github.com/short-d/short/backend/app/usecase/external" "github.com/short-d/short/backend/app/usecase/keygen" "github.com/short-d/short/backend/app/usecase/repository" "github.com/short-d/short/backend/app/usecase/risk" @@ -27,7 +26,7 @@ func TestURLUpdaterPersist_UpdateURL(t *testing.T) { testCases := []struct { name string alias *string - availableKeys []external.Key + availableKeys []keygen.Key urls urlMap user entity.User urlUpdate entity.URL @@ -88,7 +87,7 @@ func TestURLUpdaterPersist_UpdateURL(t *testing.T) { Email: "gopher@golang.org", }, urlUpdate: entity.URL{ - OriginalURL: "", + OriginalURL: "aaaaaaaaaaaaaaaaaaa", }, expHasErr: true, expectedURL: entity.URL{}, @@ -105,7 +104,7 @@ func TestURLUpdaterPersist_UpdateURL(t *testing.T) { testCase.relationUsers, testCase.relationURLs, ) - keyFetcher := external.NewKeyFetcherFake(testCase.availableKeys) + keyFetcher := keygen.NewKeyFetcherFake(testCase.availableKeys) keyGen, err := keygen.NewKeyGenerator(2, &keyFetcher) assert.Equal(t, nil, err) longLinkValidator := validator.NewLongLink() From 09c05cc2846dfac5a959f7190a31f0d3cad65217 Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Sun, 17 May 2020 16:27:01 -0500 Subject: [PATCH 4/9] Remove unused isPublic field --- .../adapter/gqlapi/resolver/authmutation.go | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index 78a797c3a..b48cd0185 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -82,7 +82,6 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { type UpdateURLArgs struct { OldAlias string Url URLUpdateInput - IsPublic bool } type URLUpdateInput struct { @@ -95,30 +94,35 @@ func (u URLUpdateInput) isValid() bool { return u != URLUpdateInput{} } -func (a AuthMutation) UpdateURL(args *UpdateURLArgs) (*URL, error) { - originalURL := args.Url.OriginalURL - customAlias := args.Url.CustomAlias - expireAt := args.Url.ExpireAt +func (u *URLUpdateInput) createUpdate() (*entity.URL, error) { + if !u.isValid() { + return nil, errors.New("Empty Update") + } - user, err := viewer(a.authToken, a.authenticator) - if err != nil { - return nil, ErrInvalidAuthToken{} + update := &entity.URL{ + ExpireAt: u.ExpireAt, } - if !args.Url.isValid() { - return nil, errors.New("Empty Update") + if u.OriginalURL != nil { + update.OriginalURL = *u.OriginalURL } - update := &entity.URL{ - ExpireAt: expireAt, + if u.CustomAlias != nil { + update.Alias = *u.CustomAlias } - if originalURL != nil { - update.OriginalURL = *originalURL + return update, nil +} + +func (a AuthMutation) UpdateURL(args *UpdateURLArgs) (*URL, error) { + user, err := viewer(a.authToken, a.authenticator) + if err != nil { + return nil, ErrInvalidAuthToken{} } - if customAlias != nil { - update.Alias = *customAlias + update, err := args.Url.createUpdate() + if err != nil { + return nil, err } newURL, err := a.urlUpdater.UpdateURL(args.OldAlias, *update, user) From a6c3ce4692290a4339f81a967e3be24128347f61 Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 19 May 2020 01:23:59 -0500 Subject: [PATCH 5/9] Rebase with upstream changes * Fix merge conflicts * Tidy up go.sum --- backend/app/adapter/gqlapi/api_test.go | 2 +- backend/app/adapter/gqlapi/resolver/resolver.go | 2 +- backend/go.sum | 15 --------------- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/backend/app/adapter/gqlapi/api_test.go b/backend/app/adapter/gqlapi/api_test.go index d35067968..acffa0765 100644 --- a/backend/app/adapter/gqlapi/api_test.go +++ b/backend/app/adapter/gqlapi/api_test.go @@ -71,7 +71,7 @@ func TestGraphQlAPI(t *testing.T) { changeLogRepo := repository.NewChangeLogFake([]entity.Change{}) userChangeLogRepo := repository.NewUserChangeLogFake(map[string]time.Time{}) changeLog := changelog.NewPersist(keyGen, tm, &changeLogRepo, &userChangeLogRepo) - r := resolver.NewResolver(lg, retriever, creator, changeLog, verifier, auth) + r := resolver.NewResolver(lg, retriever, creator, updater, changeLog, verifier, auth) graphqlAPI := NewShort(r) assert.Equal(t, true, graphql.IsGraphQlAPIValid(graphqlAPI)) } diff --git a/backend/app/adapter/gqlapi/resolver/resolver.go b/backend/app/adapter/gqlapi/resolver/resolver.go index 8f12e94da..8d9407a96 100644 --- a/backend/app/adapter/gqlapi/resolver/resolver.go +++ b/backend/app/adapter/gqlapi/resolver/resolver.go @@ -19,8 +19,8 @@ func NewResolver( logger logger.Logger, urlRetriever url.Retriever, urlCreator url.Creator, - changeLog changelog.ChangeLog, urlUpdater url.Updater, + changeLog changelog.ChangeLog, requesterVerifier requester.Verifier, authenticator authenticator.Authenticator, ) Resolver { diff --git a/backend/go.sum b/backend/go.sum index f8e0494c5..1d2c3dd6b 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -210,8 +210,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.4.0 h1:TmtCFbH+Aw0AixwyttznSMQDgbR5Yed/Gg6S8Funrhc= -github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.5.2 h1:yTSXVswvWUOQ3k1sd7vJfDrbSl8lKuscqFJRqjC0ifw= github.com/lib/pq v1.5.2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -314,8 +312,6 @@ github.com/rogpeppe/go-internal v1.4.0 h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cS github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1 h1:G7j/gxkXAL80NMLOWi6EEctDET1Iuxl3sBMJXDnu2z0= github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY= -github.com/rubenv/sql-migrate v0.0.0-20200402132117-435005d389bc h1:+2DdDcxVYlarHjYcZTt8dZ4Ec8cXZirzL5ko0mkKPjU= -github.com/rubenv/sql-migrate v0.0.0-20200402132117-435005d389bc/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= github.com/rubenv/sql-migrate v0.0.0-20200429072036-ae26b214fa43 h1:0i6uTtxUGc/jpK/CngM4T2S2NFnqYUUxH+lKDgBLw8U= github.com/rubenv/sql-migrate v0.0.0-20200429072036-ae26b214fa43/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -338,11 +334,8 @@ github.com/short-d/eventbus v0.0.0-20200105092235-2dfc4be1f9ee h1:LNafZ4caEAcTlg github.com/short-d/eventbus v0.0.0-20200105092235-2dfc4be1f9ee/go.mod h1:S3Nww0QNubrzHbWTpfzAg8YQLwXuM9GH2cGshOU6GJQ= github.com/short-d/eventbus v0.0.0-20200515152349-a8a7cb883a47 h1:Goj2PHNcRwk2CYxuQdyG7983FnP6HYovFlvoY7QjBz8= github.com/short-d/eventbus v0.0.0-20200515152349-a8a7cb883a47/go.mod h1:S3Nww0QNubrzHbWTpfzAg8YQLwXuM9GH2cGshOU6GJQ= -github.com/short-d/kgs v0.0.0-20200419183416-2deb6aa8d7ed h1:goDxEfMeotHFO2J8cg5JDA5aoGULS6Ov9xr2SaGjb7c= -github.com/short-d/kgs v0.0.0-20200419183416-2deb6aa8d7ed/go.mod h1:b0Uw5WfhgcBsheLrDNm8RO0lb4C5UggG+WzBe4rxn7U= github.com/short-d/kgs v0.0.0-20200505215800-7d538f015ea1 h1:a75oDPkkATM03ONinwZDshyqA9L5WXFw4PH0+YcWW/w= github.com/short-d/kgs v0.0.0-20200505215800-7d538f015ea1/go.mod h1:b0Uw5WfhgcBsheLrDNm8RO0lb4C5UggG+WzBe4rxn7U= -github.com/short-d/short v0.0.0-20200519020837-bc5d6e75c393 h1:0bb5FRcuamv2iJ5WnEVeF74GTSuxfEnMSprB1Wj96/4= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= @@ -436,8 +429,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -467,8 +458,6 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -509,8 +498,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb h1:nAFaltAMbNVA0rixtwvdnqgSVLX3HFUUvMkEklmzbYM= -google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587 h1:1Ym+vvUpq1ZHvxzn34gENJX8U4aKO+vhy2P/2+Xl6qQ= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -525,8 +512,6 @@ google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRn google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.29.0 h1:2pJjwYOdkZ9HlN4sWRYBg9ttH5bCOlsueaM+b/oYjwo= -google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= From 6297f58d044a4a21b2c6a639e5b3ffc1db756ada Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 19 May 2020 02:22:05 -0500 Subject: [PATCH 6/9] Refactor graphql authmutation resolver * Reduce URL input types to one for reuse * Update CreateURL to use refactored URL input. * Cleanup update creation so that it only runs at one level of abstraction. * Update `wire_gen.go` --- .../adapter/gqlapi/resolver/authmutation.go | 61 +++++++++++-------- backend/app/adapter/gqlapi/schema.go | 10 +-- backend/dep/wire_gen.go | 3 +- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index b48cd0185..23cb4a1f6 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -23,11 +23,34 @@ type AuthMutation struct { // URLInput represents possible URL attributes type URLInput struct { - OriginalURL string + OriginalURL *string CustomAlias *string ExpireAt *time.Time } +// isEmpty checks if the input contains only nil pointers +func (u *URLInput) isEmpty() bool { + return *u == URLInput{} +} + +// originalURL returns the URLInput OrignalURL and an empty string if the +// pointer references a nil value. +func (u *URLInput) originalURL() string { + if u.OriginalURL == nil { + return "" + } + return *u.OriginalURL +} + +// customAlias returns the URLInput CustomAlias and an empty string if the +// pointer references a nil value. +func (u *URLInput) customAlias() string { + if u.CustomAlias == nil { + return "" + } + return *u.CustomAlias +} + // CreateURLArgs represents the possible parameters for CreateURL endpoint type CreateURLArgs struct { URL URLInput @@ -52,9 +75,10 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { return nil, ErrInvalidAuthToken{} } + originalURL := args.URL.originalURL() customAlias := args.URL.CustomAlias u := entity.URL{ - OriginalURL: args.URL.OriginalURL, + OriginalURL: originalURL, ExpireAt: args.URL.ExpireAt, } @@ -81,37 +105,20 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { type UpdateURLArgs struct { OldAlias string - Url URLUpdateInput + Url URLInput } -type URLUpdateInput struct { - OriginalURL *string - CustomAlias *string - ExpireAt *time.Time -} - -func (u URLUpdateInput) isValid() bool { - return u != URLUpdateInput{} -} - -func (u *URLUpdateInput) createUpdate() (*entity.URL, error) { - if !u.isValid() { +func (u *URLInput) createUpdate() (*entity.URL, error) { + if u.isEmpty() { return nil, errors.New("Empty Update") } - update := &entity.URL{ - ExpireAt: u.ExpireAt, - } - - if u.OriginalURL != nil { - update.OriginalURL = *u.OriginalURL - } - - if u.CustomAlias != nil { - update.Alias = *u.CustomAlias - } + return &entity.URL{ + Alias: u.customAlias(), + OriginalURL: u.originalURL(), + ExpireAt: u.ExpireAt, + }, nil - return update, nil } func (a AuthMutation) UpdateURL(args *UpdateURLArgs) (*URL, error) { diff --git a/backend/app/adapter/gqlapi/schema.go b/backend/app/adapter/gqlapi/schema.go index c01ef3b5c..eee7b2bc5 100644 --- a/backend/app/adapter/gqlapi/schema.go +++ b/backend/app/adapter/gqlapi/schema.go @@ -34,13 +34,13 @@ type Change { type AuthMutation { createURL(url: URLInput!, isPublic: Boolean!): URL - updateURL(oldAlias: String!, url: URLUpdateInput!): URL + updateURL(oldAlias: String!, url: URLInput!): URL createChange(change: ChangeInput!): Change! viewChangeLog: Time! } input URLInput { - originalURL: String! + originalURL: String customAlias: String expireAt: Time } @@ -50,12 +50,6 @@ input ChangeInput { summaryMarkdown: String } -input URLUpdateInput { - originalURL: String - customAlias: String - expireAt: Time -} - type URL { alias: String originalURL: String diff --git a/backend/dep/wire_gen.go b/backend/dep/wire_gen.go index db7eebea6..950033c0a 100644 --- a/backend/dep/wire_gen.go +++ b/backend/dep/wire_gen.go @@ -7,7 +7,6 @@ package dep import ( "database/sql" - "github.com/google/wire" "github.com/short-d/app/fw/analytics" "github.com/short-d/app/fw/cli" @@ -97,7 +96,7 @@ func InjectGraphQLService(runtime2 env.Runtime, prefix provider.LogPrefix, logLe verifier := requester.NewVerifier(reCaptcha) tokenizer := provider.NewJwtGo(jwtSecret) authenticator := provider.NewAuthenticator(tokenizer, system, tokenValidDuration) - resolverResolver := resolver.NewResolver(loggerLogger, retrieverPersist, creatorPersist, persist, verifier, authenticator) + resolverResolver := resolver.NewResolver(loggerLogger, retrieverPersist, creatorPersist, updaterPersist, persist, verifier, authenticator) api := gqlapi.NewShort(resolverResolver) graphGopherHandler := graphql.NewGraphGopherHandler(api) graphQL := provider.NewGraphQLService(graphqlPath, graphGopherHandler, loggerLogger) From 429b3fd843aa3dee310301583c1bebdd4a448257 Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 19 May 2020 02:45:23 -0500 Subject: [PATCH 7/9] Add empty update input error type --- .../adapter/gqlapi/resolver/authmutation.go | 3 +-- backend/app/adapter/gqlapi/resolver/error.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index 23cb4a1f6..cae7cb555 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -1,7 +1,6 @@ package resolver import ( - "errors" "time" "github.com/short-d/short/backend/app/adapter/gqlapi/scalar" @@ -110,7 +109,7 @@ type UpdateURLArgs struct { func (u *URLInput) createUpdate() (*entity.URL, error) { if u.isEmpty() { - return nil, errors.New("Empty Update") + return nil, ErrEmptyUpdate{} } return &entity.URL{ diff --git a/backend/app/adapter/gqlapi/resolver/error.go b/backend/app/adapter/gqlapi/resolver/error.go index 8451aa572..cb10d6892 100644 --- a/backend/app/adapter/gqlapi/resolver/error.go +++ b/backend/app/adapter/gqlapi/resolver/error.go @@ -12,6 +12,7 @@ const ( ErrCodeInvalidCustomAlias = "invalidCustomAlias" ErrCodeMaliciousContent = "maliciousContent" ErrCodeInvalidAuthToken = "invalidAuthToken" + ErrCodeEmptyUpdate = "emptyUpdate" ) // GraphQlError represents a GraphAPI error. @@ -151,3 +152,21 @@ func (e ErrMaliciousContent) Extensions() map[string]interface{} { func (e ErrMaliciousContent) Error() string { return "contains malicious content" } + +// ErrEmptyUpdate signifies that input does not contain any URL fields to update. +type ErrEmptyUpdate struct{} + +var _ GraphQlError = (*ErrEmptyUpdate)(nil) + +// Extensions keeps structured error metadata so that the clients can reliably +// handle the error. +func (e ErrEmptyUpdate) Extensions() map[string]interface{} { + return map[string]interface{}{ + "code": ErrCodeEmptyUpdate, + } +} + +// Error retrieves the human readable error message. +func (e ErrEmptyUpdate) Error() string { + return "all input fields empty" +} From cfb097a35eefdefeec8b701f5c4162de2d96ff6d Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 19 May 2020 22:19:44 -0500 Subject: [PATCH 8/9] Add docs for resolver and urlupdater exports --- backend/app/adapter/gqlapi/resolver/authmutation.go | 2 ++ backend/app/usecase/url/urlupdater.go | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/backend/app/adapter/gqlapi/resolver/authmutation.go b/backend/app/adapter/gqlapi/resolver/authmutation.go index cae7cb555..5ec0a25e0 100644 --- a/backend/app/adapter/gqlapi/resolver/authmutation.go +++ b/backend/app/adapter/gqlapi/resolver/authmutation.go @@ -102,6 +102,7 @@ func (a AuthMutation) CreateURL(args *CreateURLArgs) (*URL, error) { } } +// UpdateURLArgs represents the possible parameters for updateURL endpoint type UpdateURLArgs struct { OldAlias string Url URLInput @@ -120,6 +121,7 @@ func (u *URLInput) createUpdate() (*entity.URL, error) { } +// UpdateURL updates a short link mapping that belongs to a user func (a AuthMutation) UpdateURL(args *UpdateURLArgs) (*URL, error) { user, err := viewer(a.authToken, a.authenticator) if err != nil { diff --git a/backend/app/usecase/url/urlupdater.go b/backend/app/usecase/url/urlupdater.go index 3eecce022..bbf112e48 100644 --- a/backend/app/usecase/url/urlupdater.go +++ b/backend/app/usecase/url/urlupdater.go @@ -11,10 +11,12 @@ import ( var _ Updater = (*UpdaterPersist)(nil) +// Updater represents a short link attribute updater. type Updater interface { UpdateURL(oldAlias string, update entity.URL, user entity.User) (entity.URL, error) } +// CreatorPersist represents a short link updater that persists the given changes type UpdaterPersist struct { urlRepo repository.URL userURLRelationRepo repository.UserURLRelation @@ -25,6 +27,7 @@ type UpdaterPersist struct { riskDetector risk.Detector } +// UpdateURL persists mutations for a given short link in the repository. func (u UpdaterPersist) UpdateURL( oldAlias string, update entity.URL, @@ -74,6 +77,7 @@ func (u *UpdaterPersist) updateLongLink(url, update entity.URL) entity.URL { return url } +// NewUpdaterPersist creates a new UpdaterPersist instance. func NewUpdaterPersist( urlRepo repository.URL, userURLRelationRepo repository.UserURLRelation, From 1e77b97f932b200663067fe016e3550659090164 Mon Sep 17 00:00:00 2001 From: Oscar Tovar Date: Tue, 19 May 2020 22:25:26 -0500 Subject: [PATCH 9/9] Fix error in UpdaterPersist documentation --- backend/app/usecase/url/urlupdater.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app/usecase/url/urlupdater.go b/backend/app/usecase/url/urlupdater.go index bbf112e48..59fa3a4b6 100644 --- a/backend/app/usecase/url/urlupdater.go +++ b/backend/app/usecase/url/urlupdater.go @@ -16,7 +16,7 @@ type Updater interface { UpdateURL(oldAlias string, update entity.URL, user entity.User) (entity.URL, error) } -// CreatorPersist represents a short link updater that persists the given changes +// UpdaterPersist represents a short link updater that persists the given changes type UpdaterPersist struct { urlRepo repository.URL userURLRelationRepo repository.UserURLRelation