1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-08-08 22:36:41 +02:00

updates from review, WIP

This commit is contained in:
Lee Brown
2019-08-22 17:33:47 -08:00
parent d3b97a6608
commit 998d1bf13e
15 changed files with 158 additions and 25 deletions

7
build/README.md Normal file
View File

@ -0,0 +1,7 @@
# `/build`
Packaging and Continuous Integration.
Put your cloud (AMI), container (Docker), OS (deb, rpm, pkg) package configurations and scripts in the /build/package
directory.

View File

@ -200,6 +200,13 @@ If you have a lot of migrations, it can be a pain to run all them. For example,
the app into a clean database. To prevent this, use the initSchema function that will run as-if no migration was run the app into a clean database. To prevent this, use the initSchema function that will run as-if no migration was run
before (in a new clean database). before (in a new clean database).
**Migrations should be backwards compatible with the existing deployed code.** Refrain from `drop table`. Instead of
renaming columns, add a new column and copy the data from the old column using an `update`.
Ideally migrations should be idempotent to avoid possible data loss since data could have been generated between
migration runs.
Another bonus with the globally defined schema is that it enables your testing package the ability to dynamically [spin Another bonus with the globally defined schema is that it enables your testing package the ability to dynamically [spin
up database containers](https://gitlab.com/geeks-accelerator/oss/saas-starter-kit/blob/issue8/datadog-lambda-func/internal/platform/tests/main.go#L127) up database containers](https://gitlab.com/geeks-accelerator/oss/saas-starter-kit/blob/issue8/datadog-lambda-func/internal/platform/tests/main.go#L127)
on-demand and automatically include all the migrations. This allows the testing package to on-demand and automatically include all the migrations. This allows the testing package to

12
cmd/README.md Normal file
View File

@ -0,0 +1,12 @@
# `/cmd`
Main applications for this project.
The directory name for each application should match the name of the executable you want to have (e.g., `/cmd/myapp`).
Don't put a lot of code in the application directory. If you think the code can be imported and used in other projects,
then it should live in the `/pkg` directory. If the code is not reusable or if you don't want others to reuse it,
put that code in the `/internal` directory. You'll be surprised what others will do, so be explicit about your intentions!
It's common to have a small `main` function that imports and invokes the code from the `/internal` and `/pkg`
directories and nothing else.

View File

@ -567,11 +567,13 @@ func main() {
// Need defined functions below since they require config values, able to add additional functions // Need defined functions below since they require config values, able to add additional functions
// here to extend functionality. // here to extend functionality.
tmplFuncs := template.FuncMap{ tmplFuncs := template.FuncMap{
// BuildInfo returns the specific key from BuildInfo set in the current config.
"BuildInfo": func(k string) string { "BuildInfo": func(k string) string {
r := reflect.ValueOf(cfg.BuildInfo) r := reflect.ValueOf(cfg.BuildInfo)
f := reflect.Indirect(r).FieldByName(k) f := reflect.Indirect(r).FieldByName(k)
return f.String() return f.String()
}, },
// SiteBaseUrl returns the absolute URL for a relative path using the base site URL set in the config.
"SiteBaseUrl": func(p string) string { "SiteBaseUrl": func(p string) string {
u, err := url.Parse(cfg.Service.BaseUrl) u, err := url.Parse(cfg.Service.BaseUrl)
if err != nil { if err != nil {
@ -580,21 +582,10 @@ func main() {
u.Path = p u.Path = p
return u.String() return u.String()
}, },
"AssetUrl": func(p string) string { // SiteAssetUrl returns the absolute URL for a relative path that either served locally, from the public S3
var u string // bucket or from Cloudfront depending on the current config settings for StaticFiles. The defined static asset
if staticUrlFormatter != nil { // prefix to the path defined in the current config settings for StaticFiles. The response URL includes a cache
u = staticUrlFormatter(p) // busting query param based on the current commit.
} else {
if !strings.HasPrefix(p, "/") {
p = "/" + p
}
u = p
}
u = browserCacheBusterFunc(u)
return u
},
"SiteAssetUrl": func(p string) string { "SiteAssetUrl": func(p string) string {
var u string var u string
if staticUrlFormatter != nil { if staticUrlFormatter != nil {
@ -610,6 +601,8 @@ func main() {
return u return u
}, },
// SiteS3Url returns the URL that for an S3 Key path that has been uploaded to S3 to the specific public s3 key
// prefix that returns the absolute S3 URL or the CloudFront equivalent if enabled.
"SiteS3Url": func(p string) string { "SiteS3Url": func(p string) string {
var u string var u string
if staticUrlFormatter != nil { if staticUrlFormatter != nil {
@ -619,6 +612,8 @@ func main() {
} }
return u return u
}, },
// S3Url returns the URL that for an S3 Key path that has been uploaded to S3 to the public s3 key
// prefix that returns the absolute S3 URL or the CloudFront equivalent if enabled.
"S3Url": func(p string) string { "S3Url": func(p string) string {
var u string var u string
if staticUrlFormatter != nil { if staticUrlFormatter != nil {
@ -628,6 +623,7 @@ func main() {
} }
return u return u
}, },
// ValidationErrorHasField checks if the error is a validation error and has an error for the specified field.
"ValidationErrorHasField": func(err interface{}, fieldName string) bool { "ValidationErrorHasField": func(err interface{}, fieldName string) bool {
if err == nil { if err == nil {
return false return false
@ -643,6 +639,7 @@ func main() {
} }
return false return false
}, },
// ValidationFieldErrors returns the list of validation field errors.
"ValidationFieldErrors": func(err interface{}, fieldName string) []weberror.FieldError { "ValidationFieldErrors": func(err interface{}, fieldName string) []weberror.FieldError {
if err == nil { if err == nil {
return []weberror.FieldError{} return []weberror.FieldError{}
@ -659,6 +656,7 @@ func main() {
} }
return l return l
}, },
// ValidationFieldClass returns a CSS class for validation if the field exists in the validation errors.
"ValidationFieldClass": func(err interface{}, fieldName string) string { "ValidationFieldClass": func(err interface{}, fieldName string) string {
if err == nil { if err == nil {
return "" return ""
@ -675,6 +673,7 @@ func main() {
} }
return "is-valid" return "is-valid"
}, },
// ErrorMessage returns the error message that is formatted as a response for end users to consume.
"ErrorMessage": func(ctx context.Context, err error) string { "ErrorMessage": func(ctx context.Context, err error) string {
werr, ok := err.(*weberror.Error) werr, ok := err.(*weberror.Error)
if ok { if ok {
@ -685,6 +684,7 @@ func main() {
} }
return fmt.Sprintf("%s", err) return fmt.Sprintf("%s", err)
}, },
// ErrorDetails returns the full error for dev and stage envs to help with debugging.
"ErrorDetails": func(ctx context.Context, err error) string { "ErrorDetails": func(ctx context.Context, err error) string {
var displayFullError bool var displayFullError bool
switch webcontext.ContextEnv(ctx) { switch webcontext.ContextEnv(ctx) {
@ -707,8 +707,7 @@ func main() {
return fmt.Sprintf("%+v", err) return fmt.Sprintf("%+v", err)
}, },
// Returns the current user from the session. // ContextUser returns the current user and caches the result.
// @TODO: Need to add logging for the errors.
"ContextUser": func(ctx context.Context) *user.UserResponse { "ContextUser": func(ctx context.Context) *user.UserResponse {
sess := webcontext.ContextSession(ctx) sess := webcontext.ContextSession(ctx)
@ -716,6 +715,7 @@ func main() {
u := &user.UserResponse{} u := &user.UserResponse{}
if err := redisClient.Get(cacheKey).Scan(u); err != nil && err != redis.Nil { if err := redisClient.Get(cacheKey).Scan(u); err != nil && err != redis.Nil {
log.Printf("main : ContextUser : Redis Get failed - %+v ", err.Error())
return nil return nil
} }
@ -737,13 +737,13 @@ func main() {
err = redisClient.Set(cacheKey, u, time.Hour).Err() err = redisClient.Set(cacheKey, u, time.Hour).Err()
if err != nil { if err != nil {
log.Printf("main : ContextAccount : Redis Set failed - %+v ", err.Error())
return nil return nil
} }
return u return u
}, },
// Returns the current account from the session. // ContextAccount returns the account for current context user with auth is using and caches the result.
// @TODO: Need to add logging for the errors.
"ContextAccount": func(ctx context.Context) *account.AccountResponse { "ContextAccount": func(ctx context.Context) *account.AccountResponse {
sess := webcontext.ContextSession(ctx) sess := webcontext.ContextSession(ctx)
@ -751,6 +751,7 @@ func main() {
a := &account.AccountResponse{} a := &account.AccountResponse{}
if err := redisClient.Get(cacheKey).Scan(a); err != nil && err != redis.Nil { if err := redisClient.Get(cacheKey).Scan(a); err != nil && err != redis.Nil {
log.Printf("main : ContextAccount : Redis Get failed - %+v ", err.Error())
return nil return nil
} }
@ -772,11 +773,13 @@ func main() {
err = redisClient.Set(cacheKey, a, time.Hour).Err() err = redisClient.Set(cacheKey, a, time.Hour).Err()
if err != nil { if err != nil {
log.Printf("main : ContextAccount : Redis Set failed - %+v ", err.Error())
return nil return nil
} }
return a return a
}, },
// ContextCanSwitchAccount returns if the current context user has multiple accounts.
"ContextCanSwitchAccount": func(ctx context.Context) bool { "ContextCanSwitchAccount": func(ctx context.Context) bool {
claims, err := auth.ClaimsFromContext(ctx) claims, err := auth.ClaimsFromContext(ctx)
if err != nil || len(claims.AccountIDs) < 2 { if err != nil || len(claims.AccountIDs) < 2 {
@ -784,6 +787,7 @@ func main() {
} }
return true return true
}, },
// ContextIsVirtualSession returns true if the current context user with auth is in a virtual session.
"ContextIsVirtualSession": func(ctx context.Context) bool { "ContextIsVirtualSession": func(ctx context.Context) bool {
claims, err := auth.ClaimsFromContext(ctx) claims, err := auth.ClaimsFromContext(ctx)
if err != nil { if err != nil {
@ -797,6 +801,63 @@ func main() {
} }
return false return false
}, },
// T creates the translation for the locale given the 'key' and params passed in.
"T": func(ctx context.Context, key string, params ...string) string {
trns := webcontext.ContextTranslator(ctx)
if trns == nil {
return key
}
res, err := trns.T(key, params...)
if err != nil {
log.Printf("main : Translate.T : Failed to translate %s with '%s' - %+v", trns.Locale(), key, err.Error())
return key
}
return res
},
// C creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in
"C": func(ctx context.Context, key string, num float64, digits uint64, param string) string {
trns := webcontext.ContextTranslator(ctx)
if trns == nil {
return key
}
res, err := trns.C(key, num, digits, param)
if err != nil {
log.Printf("main : Translate.C : Failed to translate %s with '%s' - %+v", trns.Locale(), key, err.Error())
return key
}
return res
},
// O creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments and param passed in
"O": func(ctx context.Context, key string, num float64, digits uint64, param string) string {
trns := webcontext.ContextTranslator(ctx)
if trns == nil {
return key
}
res, err := trns.O(key, num, digits, param)
if err != nil {
log.Printf("main : Translate.O : Failed to translate %s with '%s' - %+v", trns.Locale(), key, err.Error())
return key
}
return res
},
// R creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and 'digit2'
// arguments and 'param1' and 'param2' passed in
"R": func(ctx context.Context, key string, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) string {
trns := webcontext.ContextTranslator(ctx)
if trns == nil {
return key
}
res, err := trns.R(key, num1, digits1, num2, digits2, param1, param2)
if err != nil {
log.Printf("main : Translate.R : Failed to translate %s with '%s' - %+v", trns.Locale(), key, err.Error())
return key
}
return res
},
} }
imgUrlFormatter := staticUrlFormatter imgUrlFormatter := staticUrlFormatter

3
configs/README.md Normal file
View File

@ -0,0 +1,3 @@
# `/configs`
Configuration file templates or default configs.

4
deployments/README.md Normal file
View File

@ -0,0 +1,4 @@
# `/deployments`
IaaS, PaaS, system and container orchestration deployment configurations and templates (docker-compose, kubernetes/helm,
mesos, terraform, bosh).

View File

@ -38,7 +38,7 @@ services:
datadog: datadog:
image: example-project/datadog:latest image: example-project/datadog:latest
build: build:
context: docker/datadog-agent context: build/docker/datadog-agent
dockerfile: Dockerfile dockerfile: Dockerfile
ports: ports:
- 8125:8125 # metrics - 8125:8125 # metrics

2
go.mod
View File

@ -41,7 +41,7 @@ require (
github.com/tinylib/msgp v1.1.0 // indirect github.com/tinylib/msgp v1.1.0 // indirect
github.com/urfave/cli v1.21.0 github.com/urfave/cli v1.21.0
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
gitlab.com/geeks-accelerator/oss/devops v1.0.3 gitlab.com/geeks-accelerator/oss/devops v1.0.7
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de // indirect golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de // indirect

9
go.sum
View File

@ -1,6 +1,7 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@ -78,10 +79,14 @@ github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg=
github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
github.com/gobuffalo/packr/v2 v2.5.2 h1:4EvjeIpQLZuRIljwnidYgbRXbr1yIzVRrESiLjqKj6s=
github.com/gobuffalo/packr/v2 v2.5.2/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= github.com/gobuffalo/packr/v2 v2.5.2/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -117,6 +122,7 @@ github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhB
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
@ -170,6 +176,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sethgrid/pester v0.0.0-20190127155807-68a33a018ad0 h1:X9XMOYjxEfAYSy3xK1DzO5dMkkWhs9E9UCcS1IERx2k= github.com/sethgrid/pester v0.0.0-20190127155807-68a33a018ad0 h1:X9XMOYjxEfAYSy3xK1DzO5dMkkWhs9E9UCcS1IERx2k=
@ -208,6 +215,8 @@ github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryB
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY= github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
gitlab.com/geeks-accelerator/oss/devops v1.0.3 h1:SE2ZD4Csvmm3t/50RoJkVLjDcwXKHayQYawSkpOSqIw= gitlab.com/geeks-accelerator/oss/devops v1.0.3 h1:SE2ZD4Csvmm3t/50RoJkVLjDcwXKHayQYawSkpOSqIw=
gitlab.com/geeks-accelerator/oss/devops v1.0.3/go.mod h1:rvI71qNJyNiO99ZgGnv/PmJCVrjJjupsXBmfYFXdjGM= gitlab.com/geeks-accelerator/oss/devops v1.0.3/go.mod h1:rvI71qNJyNiO99ZgGnv/PmJCVrjJjupsXBmfYFXdjGM=
gitlab.com/geeks-accelerator/oss/devops v1.0.7 h1:ZlQufuVnRN3DwJ0I5c5KA5edhQs7OstXc0uUZ9V0ixI=
gitlab.com/geeks-accelerator/oss/devops v1.0.7/go.mod h1:JEl0T87/zftowrIzY1D+rhDMhG0AxnghuZB+VzEWuqM=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=

5
internal/README.md Normal file
View File

@ -0,0 +1,5 @@
# `/internal`
Private application and library code. This is the code you don't want others importing in their applications or libraries.
You can optionally add a bit of extra structure to your internal packages to separate your shared and non-shared internal code. It's not required, but it's nice to have visual clues showing the intended package use. Your actual application code can go in the /internal/app directory (e.g., /internal/app/myapp) and the code shared by those apps in the /internal/pkg directory (e.g., /internal/pkg/myprivlib).

View File

@ -373,8 +373,6 @@ func (r *TemplateRenderer) Render(ctx context.Context, w http.ResponseWriter, re
data["error"] = terr data["error"] = terr
} }
data["trans"] = webcontext.ContextTranslator(ctx)
// Append request data map to render data last so any previous value can be overwritten. // Append request data map to render data last so any previous value can be overwritten.
if data != nil { if data != nil {
for k, v := range data { for k, v := range data {

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"log" "log"
"os" "os"
"path/filepath"
"reflect" "reflect"
"strings" "strings"
@ -65,8 +66,24 @@ func init() {
// Provide one or more arguments for additional supported locales. // Provide one or more arguments for additional supported locales.
uniTrans = ut.New(en, en, fr, id, ja, nl, zh) uniTrans = ut.New(en, en, fr, id, ja, nl, zh)
if _, err := os.Stat("templates/content/translations"); !os.IsNotExist(err) { // Try to load the Template directory from an environment variable for release images else it's local development.
err := uniTrans.Import(ut.FormatJSON, "templates/content/translations") var transDir string
if ev := os.Getenv("TRANSLATIONS_DIR"); ev != "" {
transDir = ev
} else {
if ev := os.Getenv("SHARED_TEMPLATE_DIR"); ev != "" {
transDir = ev
} else if ev := os.Getenv("TEMPLATE_DIR"); ev != "" {
transDir = ev
} else {
transDir = "./templates"
}
transDir = filepath.Join(transDir, "translations")
}
if _, err := os.Stat(transDir); !os.IsNotExist(err) {
err := uniTrans.Import(ut.FormatJSON, transDir)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

10
tools/README.md Normal file
View File

@ -0,0 +1,10 @@
# `/tools`
Supporting tools for this project. Note that these tools can import code from the /pkg and /internal directories.
Current Tools:
* [schema](https://gitlab.com/geeks-accelerator/oss/saas-starter-kit/tree/master/tools/schema) - A command line tool for
local development that executes database migrations.
* [text-translator](https://gitlab.com/geeks-accelerator/oss/saas-starter-kit/tree/master/tools/text-translator) - A
command line tool for supporting internazionalied go-templates.