diff --git a/Jenkinsfile b/Jenkinsfile index 7388373..9c51d6b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,12 +1,11 @@ pipeline { environment { + BUILD_IMAGE = 'gobuild:1.18' + BUILD_ARGS = '-e GOCACHE=/gocache -e HOME=${WORKSPACE} -v /var/lib/jenkins/gocache:/gocache -v /var/lib/jenkins/go/pkg:/go/pkg' PATH = '/go/bin:~/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin' composeFile = "deployments/docker-compose-integration.yaml" networkName = "network-${env.BUILD_TAG}" - registry = 'tyrm/relay' registryCredential = 'docker-io-feditools' - dockerImage = '' - gitDescribe = '' } agent any @@ -16,8 +15,8 @@ pipeline { stage('Build Static Assets') { agent { docker { - image 'gobuild:1.18' - args '-e HOME=${WORKSPACE}' + image "${BUILD_IMAGE}" + args "${BUILD_ARGS}" reuseNode true } } @@ -53,8 +52,8 @@ pipeline { stage('Test') { agent { docker { - image 'gobuild:1.18' - args '--network ${networkName} -e HOME=${WORKSPACE}' + image "${BUILD_IMAGE}" + args "--network ${networkName} ${BUILD_ARGS}" reuseNode true } } @@ -79,8 +78,8 @@ pipeline { stage('Build Snapshot') { agent { docker { - image 'gobuild:1.18' - args '--network ${networkName} -e HOME=${WORKSPACE}' + image "${BUILD_IMAGE}" + args "--network ${networkName} ${BUILD_ARGS}" reuseNode true } } diff --git a/Makefile b/Makefile index 6d0f118..f56fca3 100644 --- a/Makefile +++ b/Makefile @@ -31,13 +31,13 @@ fmt: @go fmt $(shell go list ./... | grep -v /vendor/) i18n-extract: - goi18n extract -outdir locales + goi18n extract -format yaml -outdir web/locales i18n-merge: - goi18n merge -outdir locales locales/active.*.toml locales/translate.*.toml + goi18n merge -format yaml -outdir locales web/locales/active.*.toml web/locales/translate.*.toml i18n-translations: - goi18n merge -outdir locales locales/active.*.toml + goi18n merge -format yaml -outdir locales web/locales/active.*.toml lint: @echo linting @@ -66,4 +66,4 @@ tidy: vendor: tidy go mod vendor -.PHONY: build-snapshot bun-new-migration clean fmt lint stage-static npm-scss npm-upgrade docker-restart docker-start docker-stop release stage-static test test-ext test-race test-race-ext test-verbose tidy vendor +.PHONY: build-snapshot bun-new-migration clean fmt i18n-extract i18n-merge i18n-translations lint stage-static npm-scss npm-upgrade docker-restart docker-start docker-stop release stage-static test test-ext test-race test-race-ext test-verbose tidy vendor diff --git a/cmd/relay/action/server/http_server.go b/cmd/relay/action/server/http_server.go index 49c068b..3265a4b 100644 --- a/cmd/relay/action/server/http_server.go +++ b/cmd/relay/action/server/http_server.go @@ -3,7 +3,6 @@ package server import ( "context" "github.com/feditools/go-lib" - liblanguage "github.com/feditools/go-lib/language" "github.com/feditools/go-lib/metrics" "github.com/feditools/relay/internal/config" "github.com/feditools/relay/internal/db" @@ -12,6 +11,7 @@ import ( "github.com/feditools/relay/internal/http/activitypub" "github.com/feditools/relay/internal/http/static" "github.com/feditools/relay/internal/http/webapp" + liblanguage "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/logic" "github.com/feditools/relay/internal/runner" "github.com/feditools/relay/internal/token" diff --git a/cmd/relay/action/server/start.go b/cmd/relay/action/server/start.go index 0b886f7..64cc9bc 100644 --- a/cmd/relay/action/server/start.go +++ b/cmd/relay/action/server/start.go @@ -3,7 +3,6 @@ package server import ( "context" "fmt" - "github.com/feditools/go-lib/language" "github.com/feditools/go-lib/metrics/statsd" "github.com/feditools/relay/cmd/relay/action" "github.com/feditools/relay/internal/clock" @@ -12,6 +11,7 @@ import ( "github.com/feditools/relay/internal/fedi" "github.com/feditools/relay/internal/http" "github.com/feditools/relay/internal/kv/redis" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/logic/logic1" "github.com/feditools/relay/internal/runner/faktory" "github.com/feditools/relay/internal/token" @@ -111,7 +111,7 @@ var Start action.Action = func(topCtx context.Context) error { // create logic module l.Debug("creating logic module") - logicMod, err := logic1.New(ctx, clockMod, dbClient, httpClient, tokz) + logicMod, err := logic1.New(ctx, clockMod, dbClient, httpClient, kvClient, tokz) if err != nil { l.Errorf("logic: %s", err.Error()) cancel() diff --git a/cmd/relay/flag/server.go b/cmd/relay/flag/server.go index e169daf..29ccead 100644 --- a/cmd/relay/flag/server.go +++ b/cmd/relay/flag/server.go @@ -23,6 +23,8 @@ func Server(cmd *cobra.Command, values config.Values) { cmd.PersistentFlags().String(config.Keys.WebappBootstrapCSSIntegrity, values.WebappBootstrapCSSIntegrity, usage.WebappBootstrapCSSIntegrity) cmd.PersistentFlags().String(config.Keys.WebappBootstrapJSURI, values.WebappBootstrapJSURI, usage.WebappBootstrapJSURI) cmd.PersistentFlags().String(config.Keys.WebappBootstrapJSIntegrity, values.WebappBootstrapJSIntegrity, usage.WebappBootstrapJSIntegrity) + cmd.PersistentFlags().String(config.Keys.WebappChartJSURI, values.WebappChartJSURI, usage.WebappChartJSURI) + cmd.PersistentFlags().String(config.Keys.WebappChartJSIntegrity, values.WebappChartJSIntegrity, usage.WebappChartJSIntegrity) cmd.PersistentFlags().String(config.Keys.WebappFontAwesomeCSSURI, values.WebappFontAwesomeCSSURI, usage.WebappFontAwesomeCSSURI) cmd.PersistentFlags().String(config.Keys.WebappFontAwesomeCSSIntegrity, values.WebappFontAwesomeCSSIntegrity, usage.WebappFontAwesomeCSSIntegrity) cmd.PersistentFlags().String(config.Keys.WebappLogoSrcDark, values.WebappLogoSrcDark, usage.WebappLogoSrcDark) diff --git a/go.mod b/go.mod index 7cdb315..288b466 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/contribsys/faktory v1.6.1 github.com/contribsys/faktory_worker_go v1.6.0 - github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e + github.com/feditools/go-lib v0.16.0 github.com/go-fed/activity v1.0.0 github.com/go-fed/httpsig v1.1.0 github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 @@ -19,6 +19,7 @@ require ( github.com/jackc/pgconn v1.13.0 github.com/jackc/pgx/v4 v4.17.0 github.com/nickname76/telegrambot v1.1.1 + github.com/nicksnyder/go-i18n/v2 v2.2.0 github.com/rbcervilla/redisstore/v8 v8.1.0 github.com/sirupsen/logrus v1.9.0 github.com/speps/go-hashids/v2 v2.0.1 @@ -33,6 +34,8 @@ require ( github.com/uptrace/bun/extra/bundebug v1.1.7 golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 + golang.org/x/text v0.3.7 + gopkg.in/yaml.v2 v2.4.0 modernc.org/sqlite v1.17.1 ) @@ -71,7 +74,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nickname76/repeater v1.0.1 // indirect - github.com/nicksnyder/go-i18n/v2 v2.2.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect @@ -88,11 +90,9 @@ require ( golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect - golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect gopkg.in/ini.v1 v1.66.6 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.36.0 // indirect diff --git a/go.sum b/go.sum index d95481f..5e25dd1 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -90,8 +90,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e h1:cvxBlyoDUq1KOnWD0Xb8muGu+X70T8vFe2UYdvpS9Es= -github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e/go.mod h1:LtdLBvApYAhdblS6rTGQ12ZzySI9/6PyTiZlxw5uX10= +github.com/feditools/go-lib v0.16.0 h1:sxAxvRb97Xn/jaDOSljMsWiXTVulbCZZHhr4sMRDrZE= +github.com/feditools/go-lib v0.16.0/go.mod h1:kMw3Dl5vJ2j0dHtD5OHPy9lsm8v+p/szKM01yqX+gMY= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= diff --git a/internal/config/keys.go b/internal/config/keys.go index 9ad8319..ca6a577 100644 --- a/internal/config/keys.go +++ b/internal/config/keys.go @@ -45,6 +45,8 @@ type KeyNames struct { WebappBootstrapCSSIntegrity string WebappBootstrapJSURI string WebappBootstrapJSIntegrity string + WebappChartJSURI string + WebappChartJSIntegrity string WebappFontAwesomeCSSURI string WebappFontAwesomeCSSIntegrity string WebappLogoSrcDark string @@ -104,6 +106,8 @@ var Keys = KeyNames{ WebappBootstrapCSSIntegrity: "webapp-bootstrap-css-integrity", WebappBootstrapJSURI: "webapp-bootstrap-js-uri", WebappBootstrapJSIntegrity: "webapp-bootstrap-js-integrity", + WebappChartJSURI: "webapp-chart-js-uri", + WebappChartJSIntegrity: "webapp-chart-js-integrity", WebappFontAwesomeCSSURI: "webapp-fontawesome-css-uri", WebappFontAwesomeCSSIntegrity: "webapp-fontawesome-css-integrity", WebappLogoSrcDark: "webapp-logo-src-dark", diff --git a/internal/config/values.go b/internal/config/values.go index 54e7d2d..d2d1766 100644 --- a/internal/config/values.go +++ b/internal/config/values.go @@ -45,6 +45,8 @@ type Values struct { WebappBootstrapCSSIntegrity string WebappBootstrapJSURI string WebappBootstrapJSIntegrity string + WebappChartJSURI string + WebappChartJSIntegrity string WebappFontAwesomeCSSURI string WebappFontAwesomeCSSIntegrity string WebappLogoSrcDark string @@ -104,6 +106,8 @@ var Defaults = Values{ WebappBootstrapCSSIntegrity: "sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor", WebappBootstrapJSURI: "https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js", WebappBootstrapJSIntegrity: "sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2", + WebappChartJSURI: "https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js", + WebappChartJSIntegrity: "sha384-9MhbyIRcBVQiiC7FSd7T38oJNj2Zh+EfxS7/vjhBi4OOT78NlHSnzM31EZRWR1LZ", WebappFontAwesomeCSSURI: "https://cdn.fedi.tools/vendor/fontawesome-free-6.1.1/css/all.min.css", WebappFontAwesomeCSSIntegrity: "sha384-/frq1SRXYH/bSyou/HUp/hib7RVN1TawQYja658FEOodR/FQBKVqT9Ol+Oz3Olq5", WebappLogoSrcDark: "https://cdn.fedi.tools/img/feditools-logo-dark.svg", diff --git a/internal/http/activitypub/inbox.go b/internal/http/activitypub/inbox.go index 2f486c1..8555d4d 100644 --- a/internal/http/activitypub/inbox.go +++ b/internal/http/activitypub/inbox.go @@ -1,6 +1,7 @@ package activitypub import ( + "context" "encoding/json" "errors" "github.com/feditools/go-lib/fedihelper" @@ -120,5 +121,7 @@ func (m *Module) inboxPostHandler(w nethttp.ResponseWriter, r *nethttp.Request) return } + go m.logic.MetricsIncReceived(context.Background(), instance.ID) + w.WriteHeader(nethttp.StatusAccepted) } diff --git a/internal/http/template/admin_instance_view.go b/internal/http/template/admin_instance_view.go new file mode 100644 index 0000000..960ee5f --- /dev/null +++ b/internal/http/template/admin_instance_view.go @@ -0,0 +1,16 @@ +package template + +import ( + "github.com/feditools/relay/internal/models" +) + +// AdminInstanceViewName is the name of the admin block list template. +const AdminInstanceViewName = "admin_instance_view" + +// AdminInstanceView contains the variables for the admin block list template. +type AdminInstanceView struct { + Common + + Instance *models.Instance + Breadcrumbs *[]Breadcrumb +} diff --git a/internal/http/template/breadcrumb.go b/internal/http/template/breadcrumb.go new file mode 100644 index 0000000..d0cd43f --- /dev/null +++ b/internal/http/template/breadcrumb.go @@ -0,0 +1,6 @@ +package template + +type Breadcrumb struct { + HRef string + Text string +} diff --git a/internal/http/template/common.go b/internal/http/template/common.go index 0f00cf0..7610147 100644 --- a/internal/http/template/common.go +++ b/internal/http/template/common.go @@ -1,8 +1,8 @@ package template import ( - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" ) diff --git a/internal/http/template/template.go b/internal/http/template/template.go index 775df5f..dbdd967 100644 --- a/internal/http/template/template.go +++ b/internal/http/template/template.go @@ -1,9 +1,9 @@ package template import ( - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/config" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/path" "github.com/feditools/relay/internal/token" @@ -41,6 +41,7 @@ func New(tokz *token.Tokenizer) (*template.Template, error) { "pathAppAdminBlockExportCSV": path.GenAppAdminBlockExportCSV, "pathAppAdminBlockExportJSON": path.GenAppAdminBlockExportJSON, "pathAppAdminHome": path.GenAppAdminHomePath, + "pathAppAdminInstanceView": path.GenAppAdminInstanceViewPath, "pathAppHome": path.GenAppHomePath, "pathAppLog": path.GenAppLogPath, "pathAppLogin": path.GenAppLoginPath, diff --git a/internal/http/webapp/admin_block.go b/internal/http/webapp/admin_block.go index fd7853f..f0e45f6 100644 --- a/internal/http/webapp/admin_block.go +++ b/internal/http/webapp/admin_block.go @@ -2,9 +2,9 @@ package webapp import ( libhttp "github.com/feditools/go-lib/http" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/path" "net/http" ) diff --git a/internal/http/webapp/admin_block_add.go b/internal/http/webapp/admin_block_add.go index 3590422..df74ba6 100644 --- a/internal/http/webapp/admin_block_add.go +++ b/internal/http/webapp/admin_block_add.go @@ -1,8 +1,8 @@ package webapp import ( - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/util" "net/http" @@ -93,7 +93,7 @@ func (m *Module) doAddBlock(w http.ResponseWriter, r *http.Request) { FormAddError: &libtemplate.Alert{ Color: libtemplate.ColorDanger, - Text: localizer.TextBlockExists(domain).String(), + Text: localizer.TextBlockExistsDomain(domain).String(), }, FormAddDomainValue: domain, diff --git a/internal/http/webapp/admin_block_delete.go b/internal/http/webapp/admin_block_delete.go index c70ec2c..389feff 100644 --- a/internal/http/webapp/admin_block_delete.go +++ b/internal/http/webapp/admin_block_delete.go @@ -2,9 +2,9 @@ package webapp import ( "errors" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/db" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/token" "net/http" diff --git a/internal/http/webapp/admin_block_edit.go b/internal/http/webapp/admin_block_edit.go index fcdee80..50f761b 100644 --- a/internal/http/webapp/admin_block_edit.go +++ b/internal/http/webapp/admin_block_edit.go @@ -3,9 +3,9 @@ package webapp import ( "errors" "fmt" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/db" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/token" "github.com/feditools/relay/internal/util" diff --git a/internal/http/webapp/admin_block_import.go b/internal/http/webapp/admin_block_import.go index 35bb25d..bd554b2 100644 --- a/internal/http/webapp/admin_block_import.go +++ b/internal/http/webapp/admin_block_import.go @@ -5,8 +5,8 @@ import ( "encoding/json" "fmt" libhttp "github.com/feditools/go-lib/http" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/util" "io" diff --git a/internal/http/webapp/admin_home.go b/internal/http/webapp/admin_home.go index 5ef80bb..70b581e 100644 --- a/internal/http/webapp/admin_home.go +++ b/internal/http/webapp/admin_home.go @@ -2,9 +2,9 @@ package webapp import ( "context" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "net/http" ) diff --git a/internal/http/webapp/admin_instance.go b/internal/http/webapp/admin_instance.go index f113079..4905f16 100644 --- a/internal/http/webapp/admin_instance.go +++ b/internal/http/webapp/admin_instance.go @@ -2,9 +2,9 @@ package webapp import ( libhttp "github.com/feditools/go-lib/http" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/path" "net/http" ) diff --git a/internal/http/webapp/admin_instance_view.go b/internal/http/webapp/admin_instance_view.go new file mode 100644 index 0000000..ca1a947 --- /dev/null +++ b/internal/http/webapp/admin_instance_view.go @@ -0,0 +1,113 @@ +package webapp + +import ( + "errors" + libtemplate "github.com/feditools/go-lib/template" + "github.com/feditools/relay/internal/db" + "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" + "github.com/feditools/relay/internal/models" + "github.com/feditools/relay/internal/path" + "github.com/feditools/relay/internal/token" + "github.com/gorilla/mux" + "net/http" +) + +// AdminInstanceViewGetHandler serves the instance info page. +func (m *Module) AdminInstanceViewGetHandler(w http.ResponseWriter, r *http.Request) { + l := logger.WithField("func", "AdminInstanceViewGetHandler") + + // lookup instance + vars := mux.Vars(r) + kind, id, err := m.tokz.DecodeToken(vars[path.VarInstanceID]) + if err != nil { + l.Debugf("decode token: %s", err.Error()) + m.returnErrorPage(w, r, http.StatusBadRequest, "bad token") + + return + } + if kind != token.KindInstance { + l.Debug("token is wrong kind") + m.returnErrorPage(w, r, http.StatusBadRequest, "bad token") + + return + } + instance, err := m.db.ReadInstance(r.Context(), id) + if err != nil && !errors.Is(err, db.ErrNoEntries) { + l.Errorf("db read instance: %s", err.Error()) + m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error()) + + return + } + if errors.Is(err, db.ErrNoEntries) { + m.returnErrorPage(w, r, http.StatusNotFound, vars[path.VarInstanceID]) + + return + } + + m.displayAdminInstanceView(w, r, displayAdminInstanceViewConfig{ + Instance: instance, + }) +} + +type displayAdminInstanceViewConfig struct { + Alerts *[]libtemplate.Alert + + Instance *models.Instance +} + +func (m *Module) displayAdminInstanceView(w http.ResponseWriter, r *http.Request, config displayAdminInstanceViewConfig) { + l := logger.WithField("func", "displayAdminInstanceView") + + // get localizer + localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) //nolint + + // Init template variables + tmplVars := &template.AdminInstanceView{ + Common: template.Common{ + PageTitle: localizer.TextInstance(1).String() + " " + config.Instance.UnicodeDomain(), + }, + + Breadcrumbs: &[]template.Breadcrumb{ + { + Text: localizer.TextInstance(2).String(), + HRef: path.AppAdminInstance, + }, + { + Text: config.Instance.UnicodeDomain(), + }, + }, + + Instance: config.Instance, + } + + // alerts + tmplVars.Alerts = config.Alerts + + // get metrics + deliverErrors, err := m.logic.MetricsGetDeliverErrorWeek(r.Context(), config.Instance.ID) + if err != nil { + l.Errorf("get metrics deliver error: %s", err.Error()) + m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error()) + + return + } + deliverSuccess, err := m.logic.MetricsGetDeliverSuccessWeek(r.Context(), config.Instance.ID) + if err != nil { + l.Errorf("get metrics deliver error: %s", err.Error()) + m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error()) + + return + } + received, err := m.logic.MetricsGetReceivedWeek(r.Context(), config.Instance.ID) + if err != nil { + l.Errorf("get metrics deliver error: %s", err.Error()) + m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error()) + + return + } + tmplVars.AddFooterExtraScript(JSAdminInstanceView(deliverErrors, deliverSuccess, received)) + tmplVars.AddFooterScript(m.footerScriptChartJS) + + m.executeTemplate(w, r, template.AdminInstanceViewName, tmplVars) +} diff --git a/internal/http/webapp/blocks.go b/internal/http/webapp/blocks.go index 4c08359..c732f7b 100644 --- a/internal/http/webapp/blocks.go +++ b/internal/http/webapp/blocks.go @@ -1,8 +1,8 @@ package webapp import ( - "github.com/feditools/go-lib/language" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "net/http" ) diff --git a/internal/http/webapp/home.go b/internal/http/webapp/home.go index f1e2de2..92d180f 100644 --- a/internal/http/webapp/home.go +++ b/internal/http/webapp/home.go @@ -1,8 +1,8 @@ package webapp import ( - "github.com/feditools/go-lib/language" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/path" "net/http" diff --git a/internal/http/webapp/js.go b/internal/http/webapp/js.go index e743bee..a181cf1 100644 --- a/internal/http/webapp/js.go +++ b/internal/http/webapp/js.go @@ -2,7 +2,7 @@ package webapp import ( "fmt" - "github.com/feditools/go-lib/language" + "github.com/feditools/relay/internal/language" ) const jsAdminBlock = ` diff --git a/internal/http/webapp/js_chart.go b/internal/http/webapp/js_chart.go new file mode 100644 index 0000000..8a31bc0 --- /dev/null +++ b/internal/http/webapp/js_chart.go @@ -0,0 +1,82 @@ +package webapp + +import ( + "fmt" + "github.com/feditools/relay/internal/logic" + "strconv" + "strings" +) + +const jsAdminInstanceView = ` +new Chart(document.getElementById("deliveryChartContainer"), { + type: 'line', + data: { + labels: [%s], + datasets: [{ + data: [%s], + label: "Error", + borderColor: "#c45850", + fill: false, + lineTension: 0.2 + }, { + data: [%s], + label: "Success", + borderColor: "#3cba9f", + fill: false, + lineTension: 0.2 + } + ] + }, + options: {} +}); + +new Chart(document.getElementById("receiveChartContainer"), { + type: 'line', + data: { + labels: [%s], + datasets: [{ + data: [%s], + label: "Received", + borderColor: "#3e95cd", + fill: false, + lineTension: 0.2 + } + ] + }, + options: {} +}); +` + +func JSAdminInstanceView(deliverErrors, deliverSuccess, receive *logic.MetricsDataPointsTime) string { + labels := make([]string, len(*deliverErrors)) + for i, dp := range *deliverErrors { + labels[i] = dp.X.Format("\"Jan 02 2006\"") + } + + deliverErrorsLen := len(*deliverErrors) + deliverErrorsData := make([]string, deliverErrorsLen) + for i, dp := range *deliverErrors { + deliverErrorsData[deliverErrorsLen-1-i] = strconv.FormatInt(int64(dp.Y), 10) + } + + deliverSuccessLen := len(*deliverSuccess) + deliverSuccessData := make([]string, deliverSuccessLen) + for i, dp := range *deliverSuccess { + deliverSuccessData[deliverSuccessLen-1-i] = strconv.FormatInt(int64(dp.Y), 10) + } + + receiveLen := len(*receive) + receiveData := make([]string, receiveLen) + for i, dp := range *receive { + receiveData[receiveLen-1-i] = strconv.FormatInt(int64(dp.Y), 10) + } + + return fmt.Sprintf( + jsAdminInstanceView, + strings.Join(labels, ","), + strings.Join(deliverErrorsData, ","), + strings.Join(deliverSuccessData, ","), + strings.Join(labels, ","), + strings.Join(receiveData, ","), + ) +} diff --git a/internal/http/webapp/login.go b/internal/http/webapp/login.go index 8bed123..e624670 100644 --- a/internal/http/webapp/login.go +++ b/internal/http/webapp/login.go @@ -3,10 +3,10 @@ package webapp import ( "errors" "github.com/feditools/go-lib" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/db" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/path" nethttp "net/http" diff --git a/internal/http/webapp/logs.go b/internal/http/webapp/logs.go index 9baf2eb..f21e544 100644 --- a/internal/http/webapp/logs.go +++ b/internal/http/webapp/logs.go @@ -2,9 +2,9 @@ package webapp import ( libhttp "github.com/feditools/go-lib/http" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/path" "net/http" ) diff --git a/internal/http/webapp/middleware.go b/internal/http/webapp/middleware.go index 1cc90b2..97dbbb0 100644 --- a/internal/http/webapp/middleware.go +++ b/internal/http/webapp/middleware.go @@ -3,7 +3,7 @@ package webapp import ( "context" libhttp "github.com/feditools/go-lib/http" - "github.com/feditools/go-lib/language" + "github.com/feditools/relay/internal/language" "net/http" ) diff --git a/internal/http/webapp/redirect.go b/internal/http/webapp/redirect.go deleted file mode 100644 index 0350f60..0000000 --- a/internal/http/webapp/redirect.go +++ /dev/null @@ -1 +0,0 @@ -package webapp diff --git a/internal/http/webapp/route.go b/internal/http/webapp/route.go index d32fd62..5d2b1a0 100644 --- a/internal/http/webapp/route.go +++ b/internal/http/webapp/route.go @@ -39,6 +39,7 @@ func (m *Module) Route(s *http.Server) error { admin.HandleFunc(path.AppAdminSubHome, m.AdminHomeGetHandler).Methods(nethttp.MethodGet) admin.HandleFunc(path.AppAdminSubHome, m.AdminHomePostHandler).Methods(nethttp.MethodPost) admin.HandleFunc(path.AppAdminSubInstance, m.AdminInstanceGetHandler).Methods(nethttp.MethodGet) + admin.HandleFunc(path.AppAdminSubInstanceView, m.AdminInstanceViewGetHandler).Methods(nethttp.MethodGet) return nil } diff --git a/internal/http/webapp/settings.go b/internal/http/webapp/settings.go index 3c11b76..a65a709 100644 --- a/internal/http/webapp/settings.go +++ b/internal/http/webapp/settings.go @@ -3,9 +3,9 @@ package webapp import ( "context" "fmt" - "github.com/feditools/go-lib/language" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "net/http" ) diff --git a/internal/http/webapp/template.go b/internal/http/webapp/template.go index 80b5c5b..f2b019a 100644 --- a/internal/http/webapp/template.go +++ b/internal/http/webapp/template.go @@ -2,8 +2,8 @@ package webapp import ( "bytes" - "github.com/feditools/go-lib/language" "github.com/feditools/relay/internal/http/template" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/models" "github.com/feditools/relay/internal/path" "github.com/sirupsen/logrus" @@ -97,12 +97,6 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) { FAIcon: "house", URL: path.AppHome, }, - { - Text: l.TextActivityLog(1).String(), - MatchStr: path.ReAppLog, - FAIcon: "newspaper", - URL: path.AppLog, - }, } // show blocks page if any exist diff --git a/internal/http/webapp/webapp.go b/internal/http/webapp/webapp.go index 0e0b487..ce7ad51 100644 --- a/internal/http/webapp/webapp.go +++ b/internal/http/webapp/webapp.go @@ -3,7 +3,6 @@ package webapp import ( "context" "encoding/gob" - "github.com/feditools/go-lib/language" "github.com/feditools/go-lib/metrics" libtemplate "github.com/feditools/go-lib/template" "github.com/feditools/relay/internal/config" @@ -12,6 +11,7 @@ import ( ihttp "github.com/feditools/relay/internal/http" itemplate "github.com/feditools/relay/internal/http/template" "github.com/feditools/relay/internal/kv" + "github.com/feditools/relay/internal/language" "github.com/feditools/relay/internal/logic" "github.com/feditools/relay/internal/path" "github.com/feditools/relay/internal/runner" @@ -44,11 +44,12 @@ type Module struct { templates *template.Template tokz *token.Tokenizer - domain string - logoSrcDark string - logoSrcLight string - headLinks []libtemplate.HeadLink - footerScripts []libtemplate.Script + domain string + logoSrcDark string + logoSrcLight string + headLinks []libtemplate.HeadLink + footerScripts []libtemplate.Script + footerScriptChartJS libtemplate.Script sigCache map[string]string sigCacheLock sync.RWMutex @@ -143,6 +144,12 @@ func New( }, } + fsCanvasJS := libtemplate.Script{ + Src: viper.GetString(config.Keys.WebappChartJSURI), + CrossOrigin: COAnonymous, + Integrity: viper.GetString(config.Keys.WebappChartJSIntegrity), + } + return &Module{ db: d, fedi: f, @@ -155,11 +162,12 @@ func New( templates: tmpl, tokz: tokz, - domain: viper.GetString(config.Keys.ServerExternalHostname), - logoSrcDark: viper.GetString(config.Keys.WebappLogoSrcDark), - logoSrcLight: viper.GetString(config.Keys.WebappLogoSrcLight), - headLinks: hl, - footerScripts: fs, + domain: viper.GetString(config.Keys.ServerExternalHostname), + logoSrcDark: viper.GetString(config.Keys.WebappLogoSrcDark), + logoSrcLight: viper.GetString(config.Keys.WebappLogoSrcLight), + headLinks: hl, + footerScripts: fs, + footerScriptChartJS: fsCanvasJS, sigCache: map[string]string{}, }, nil diff --git a/internal/kv/keys.go b/internal/kv/keys.go index e05b73e..e1fe247 100644 --- a/internal/kv/keys.go +++ b/internal/kv/keys.go @@ -1,6 +1,9 @@ package kv -import "strconv" +import ( + "strconv" + "time" +) const ( keyBase = "relay:" @@ -16,6 +19,15 @@ const ( keyInstance = keyBase + "instance:" keyInstanceOAuth = keyInstance + "oauth:" + keyMetrics = keyBase + "metrics:" + keyMetricsDeliver = keyMetrics + "deliver:" + keyMetricsDeliverError = keyMetricsDeliver + "e:" + keyMetricsDeliverErrorTotal = keyMetricsDeliver + "et:" + keyMetricsDeliverSuccess = keyMetricsDeliver + "s:" + keyMetricsDeliverSuccessTotal = keyMetricsDeliver + "st:" + keyMetricsReceived = keyMetrics + "received:" + keyMetricsReceivedTotal = keyMetrics + "receivedt:" + keySession = keyBase + "session:" ) @@ -34,5 +46,35 @@ func KeyFediHostMeta(d string) string { return keyFediHostMeta + d } // KeyInstanceOAuth returns the kv key which holds an instance's oauth tokens. func KeyInstanceOAuth(i int64) string { return keyInstanceOAuth + strconv.FormatInt(i, 10) } +// KeyMetricsDeliverError returns the kv key which holds the number of delivery errors to an instance. +func KeyMetricsDeliverError(t time.Time) string { + return keyMetricsDeliverError + t.Format("2006:01:02") +} + +// KeyMetricsDeliverErrorTotal returns the kv key which holds the number of delivery errors +func KeyMetricsDeliverErrorTotal(t time.Time) string { + return keyMetricsDeliverErrorTotal + t.Format("2006:01:02") +} + +// KeyMetricsDeliverSuccess returns the kv key which holds the number of delivery successes to an instance. +func KeyMetricsDeliverSuccess(t time.Time) string { + return keyMetricsDeliverSuccess + t.Format("2006:01:02") +} + +// KeyMetricsDeliverSuccessTotal returns the kv key which holds the number of delivery successes to an instance. +func KeyMetricsDeliverSuccessTotal(t time.Time) string { + return keyMetricsDeliverSuccessTotal + t.Format("2006:01:02") +} + +// KeyMetricsReceived returns the kv key which holds the number of receives from an instance. +func KeyMetricsReceived(t time.Time) string { + return keyMetricsReceived + t.Format("2006:01:02") +} + +// KeyMetricsReceivedTotal returns the kv key which holds the number of receives. +func KeyMetricsReceivedTotal(t time.Time) string { + return keyMetricsReceivedTotal + t.Format("2006:01:02") +} + // KeySession returns the base kv key prefix. func KeySession() string { return keySession } diff --git a/internal/kv/kv.go b/internal/kv/kv.go index f61f423..574a8a3 100644 --- a/internal/kv/kv.go +++ b/internal/kv/kv.go @@ -1,10 +1,26 @@ package kv import ( + "context" "github.com/feditools/go-lib/fedihelper" + "time" ) // KV represents a key value store. type KV interface { fedihelper.KV + + GetMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) (int, Error) + GetMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) (int, Error) + GetMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) (int, Error) + GetMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) (int, Error) + GetMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) (int, Error) + GetMetricsReceivedTotal(ctx context.Context, timestamp time.Time) (int, Error) + + IncMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) Error + IncMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) Error + IncMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) Error + IncMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) Error + IncMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) Error + IncMetricsReceivedTotal(ctx context.Context, timestamp time.Time) Error } diff --git a/internal/kv/redis/metrics.go b/internal/kv/redis/metrics.go new file mode 100644 index 0000000..19bd2a0 --- /dev/null +++ b/internal/kv/redis/metrics.go @@ -0,0 +1,116 @@ +package redis + +import ( + "context" + "github.com/feditools/relay/internal/kv" + "strconv" + "time" +) + +func (c *Client) GetMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) (int, kv.Error) { + count, err := c.redis.HGet(ctx, kv.KeyMetricsDeliverError(timestamp), strconv.FormatInt(instanceID, 10)).Int() + if err != nil { + return 0, c.ProcessError(err) + } + + return count, nil +} + +func (c *Client) GetMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) (int, kv.Error) { + count, err := c.redis.Get(ctx, kv.KeyMetricsDeliverErrorTotal(timestamp)).Int() + if err != nil { + return 0, c.ProcessError(err) + } + + return count, nil +} + +func (c *Client) GetMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) (int, kv.Error) { + count, err := c.redis.HGet(ctx, kv.KeyMetricsDeliverSuccess(timestamp), strconv.FormatInt(instanceID, 10)).Int() + if err != nil { + return 0, c.ProcessError(err) + } + + return count, nil +} + +func (c *Client) GetMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) (int, kv.Error) { + count, err := c.redis.Get(ctx, kv.KeyMetricsDeliverSuccessTotal(timestamp)).Int() + if err != nil { + return 0, c.ProcessError(err) + } + + return count, nil +} + +func (c *Client) GetMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) (int, kv.Error) { + count, err := c.redis.HGet(ctx, kv.KeyMetricsReceived(timestamp), strconv.FormatInt(instanceID, 10)).Int() + if err != nil { + return 0, c.ProcessError(err) + } + + return count, nil +} + +func (c *Client) GetMetricsReceivedTotal(ctx context.Context, timestamp time.Time) (int, kv.Error) { + count, err := c.redis.Get(ctx, kv.KeyMetricsReceivedTotal(timestamp)).Int() + if err != nil { + return 0, c.ProcessError(err) + } + + return count, nil +} + +func (c *Client) IncMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) kv.Error { + _, err := c.redis.HIncrBy(ctx, kv.KeyMetricsDeliverError(timestamp), strconv.FormatInt(instanceID, 10), 1).Result() + if err != nil { + return c.ProcessError(err) + } + + return nil +} + +func (c *Client) IncMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) kv.Error { + _, err := c.redis.IncrBy(ctx, kv.KeyMetricsDeliverErrorTotal(timestamp), 1).Result() + if err != nil { + return c.ProcessError(err) + } + + return nil +} + +func (c *Client) IncMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) kv.Error { + _, err := c.redis.HIncrBy(ctx, kv.KeyMetricsDeliverSuccess(timestamp), strconv.FormatInt(instanceID, 10), 1).Result() + if err != nil { + return c.ProcessError(err) + } + + return nil +} + +func (c *Client) IncMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) kv.Error { + _, err := c.redis.IncrBy(ctx, kv.KeyMetricsDeliverSuccessTotal(timestamp), 1).Result() + if err != nil { + return c.ProcessError(err) + } + + return nil +} + +func (c *Client) IncMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) kv.Error { + _, err := c.redis.HIncrBy(ctx, kv.KeyMetricsReceived(timestamp), strconv.FormatInt(instanceID, 10), 1).Result() + if err != nil { + return c.ProcessError(err) + } + + return nil +} + +func (c *Client) IncMetricsReceivedTotal(ctx context.Context, timestamp time.Time) kv.Error { + _, err := c.redis.IncrBy(ctx, kv.KeyMetricsReceivedTotal(timestamp), 1).Result() + if err != nil { + return c.ProcessError(err) + } + + return nil +} diff --git a/vendor/github.com/feditools/go-lib/language/const.go b/internal/language/const.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/const.go rename to internal/language/const.go diff --git a/vendor/github.com/feditools/go-lib/language/language.go b/internal/language/language.go similarity index 81% rename from vendor/github.com/feditools/go-lib/language/language.go rename to internal/language/language.go index 5ef4b19..01163a2 100644 --- a/vendor/github.com/feditools/go-lib/language/language.go +++ b/internal/language/language.go @@ -1,19 +1,14 @@ package language import ( - "embed" - "io/ioutil" - "strings" - + "github.com/feditools/relay/web" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/text/language" "gopkg.in/yaml.v2" + "io/ioutil" + "strings" ) -// Locales contains static files required by the application -//go:embed locales/active.*.yaml -var Locales embed.FS - // DefaultLanguage is the default language of the application. var DefaultLanguage = language.English @@ -34,7 +29,7 @@ func New() (*Module, error) { module.langBundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal) - dir, err := Locales.ReadDir("locales") + dir, err := web.Files.ReadDir("locales") if err != nil { return nil, err } @@ -45,7 +40,7 @@ func New() (*Module, error) { l.Debugf("loading language file: %s", d.Name()) // open it - file, err := Locales.Open("locales/" + d.Name()) + file, err := web.Files.Open("locales/" + d.Name()) if err != nil { return nil, err } @@ -68,3 +63,16 @@ func New() (*Module, error) { // Language returns the default language. func (m Module) Language() language.Tag { return m.lang } + +func isEmptyYaml(b []byte) bool { + switch string(b) { + case "": + return true + case "---": + return true + case "---\n": + return true + default: + return false + } +} diff --git a/internal/language/language_test.go b/internal/language/language_test.go new file mode 100644 index 0000000..af572c0 --- /dev/null +++ b/internal/language/language_test.go @@ -0,0 +1,114 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +const ( + testCantGetLocalizer = "[%d] can't get localizer for %s: %s" + testGotInvalidLanguage = "[%d] got invalid language for %s, got: %v, want: %v" + testGotInvalidTranslation = "[%d] got invalid translation for %s, got: %v, want: %v" + testTranslatedTo = "[%d] Translating to %s" +) + +func TestNew(t *testing.T) { + langMod, err := New() + if err != nil { + t.Errorf("can't get new language module: %s", err.Error()) + + return + } + + if langMod == nil { + t.Errorf("language module is nil") + + return + } + + if langMod.langBundle == nil { + t.Errorf("language module's bundle is nil") + + return + } + + if langMod.Language() != DefaultLanguage { + t.Errorf("got invalid language, got: %v, want: %v,", langMod.Language().String(), DefaultLanguage.String()) + + return + } +} + +func TestIsEmptyYaml(t *testing.T) { + t.Parallel() + + tables := []struct { + input string + output bool + }{ + {"", true}, + {"---", true}, + {"---\n", true}, + {"---\nvalid: yaml", false}, + } + + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf("[%d] running isEmptyYaml", i) + t.Run(name, func(t *testing.T) { + t.Parallel() + + result := isEmptyYaml([]byte(table.input)) + if result != table.output { + t.Errorf("[%d] got invalid response, got: %v, want: %v,", i, result, table.output) + } + }) + } +} + +// text testers + +type testTextTable struct { + inputLang language.Tag + inputCount int + inputStrings []string + + outputString string + outputLang language.Tag +} + +func testText(t *testing.T, tid int, translate func() *LocalizedString, table testTextTable) { + t.Helper() + + result := translate() + testTextCheckResults(t, tid, result, table) +} + +func testTextWithCount(t *testing.T, tid int, translate func(int) *LocalizedString, table testTextTable) { + t.Helper() + + result := translate(table.inputCount) + testTextCheckResults(t, tid, result, table) +} + +func testTextWith1String(t *testing.T, tid int, translate func(string) *LocalizedString, table testTextTable) { + t.Helper() + + result := translate(table.inputStrings[0]) + testTextCheckResults(t, tid, result, table) +} + +func testTextCheckResults(t *testing.T, tid int, result *LocalizedString, table testTextTable) { + t.Helper() + + if result.String() != table.outputString { + t.Errorf(testGotInvalidTranslation, tid, table.inputLang, result.String(), table.outputString) + } + if result.Language() != table.outputLang { + t.Errorf(testGotInvalidLanguage, tid, table.inputLang, result.Language(), table.outputLang) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/localizer.go b/internal/language/localizer.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/localizer.go rename to internal/language/localizer.go diff --git a/internal/language/localizer_test.go b/internal/language/localizer_test.go new file mode 100644 index 0000000..170aedd --- /dev/null +++ b/internal/language/localizer_test.go @@ -0,0 +1,26 @@ +package language + +import "testing" + +func TestNewLocalizer(t *testing.T) { + langMod, _ := New() + + localizer, err := langMod.NewLocalizer() + if err != nil { + t.Errorf("can't get new language module: %s", err.Error()) + + return + } + + if localizer == nil { + t.Errorf("localizer module is nil") + + return + } + + if localizer.localizer == nil { + t.Errorf("localizer module's localizer is nil") + + return + } +} diff --git a/vendor/github.com/feditools/go-lib/language/logger.go b/internal/language/logger.go similarity index 62% rename from vendor/github.com/feditools/go-lib/language/logger.go rename to internal/language/logger.go index 9a16865..141999e 100644 --- a/vendor/github.com/feditools/go-lib/language/logger.go +++ b/internal/language/logger.go @@ -1,8 +1,6 @@ package language -import ( - "github.com/feditools/go-lib/log" -) +import "github.com/feditools/relay/internal/log" type empty struct{} diff --git a/internal/language/text_a.go b/internal/language/text_a.go new file mode 100644 index 0000000..58ccd57 --- /dev/null +++ b/internal/language/text_a.go @@ -0,0 +1,111 @@ +package language + +import "github.com/nicksnyder/go-i18n/v2/i18n" + +// TextAccount returns a translated phrase. +func (l *Localizer) TextAccount(count int) *LocalizedString { + lg := logger.WithField("func", "TextAccount") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "Account", + One: "Account", + Other: "Accounts", + }, + PluralCount: count, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + +// TextActivityLog returns a translated phrase. +func (l *Localizer) TextActivityLog(count int) *LocalizedString { + lg := logger.WithField("func", "TextActivityLog") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "ActivityLog", + One: "Activity Log", + Other: "Activity Logs", + }, + PluralCount: count, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + +// TextActorURI returns a translated phrase. +func (l *Localizer) TextActorURI(count int) *LocalizedString { + lg := logger.WithField("func", "TextActorURI") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "ActorURI", + One: "Actor URI", + Other: "Actor URIs", + }, + PluralCount: count, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + +// TextAddBlock returns a translated phrase. +func (l *Localizer) TextAddBlock(count int) *LocalizedString { + lg := logger.WithField("func", "TextAddBlock") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "AddBlock", + One: "Add Block", + Other: "Add Blocks", + }, + PluralCount: count, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + +// TextAdmin returns a translated phrase. +func (l *Localizer) TextAdmin() *LocalizedString { + lg := logger.WithField("func", "TextAdmin") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "Admin", + Other: "Admin", + }, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} diff --git a/internal/language/text_a_test.go b/internal/language/text_a_test.go new file mode 100644 index 0000000..7782c07 --- /dev/null +++ b/internal/language/text_a_test.go @@ -0,0 +1,196 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextAccount(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Account", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Accounts", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextAccount, table) + }) + } +} + +func TestLocalizer_TextActivityLog(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Activity Log", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Activity Logs", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextActivityLog, table) + }) + } +} + +func TestLocalizer_TextActorURI(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Actor URI", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Actor URIs", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextActorURI, table) + }) + } +} + +func TestLocalizer_TextAddBlock(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Add Block", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Add Blocks", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextAddBlock, table) + }) + } +} + +func TestLocalizer_TextAdmin(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Admin", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextAdmin, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_b.go b/internal/language/text_b.go similarity index 91% rename from vendor/github.com/feditools/go-lib/language/text_b.go rename to internal/language/text_b.go index 6859692..3827395 100644 --- a/vendor/github.com/feditools/go-lib/language/text_b.go +++ b/internal/language/text_b.go @@ -24,13 +24,13 @@ func (l *Localizer) TextBlock(count int) *LocalizedString { } } -// TextBlockExists returns a translated phrase. -func (l *Localizer) TextBlockExists(domain string) *LocalizedString { - lg := logger.WithField("func", "TextBlockExists") +// TextBlockExistsDomain returns a translated phrase. +func (l *Localizer) TextBlockExistsDomain(domain string) *LocalizedString { + lg := logger.WithField("func", "TextBlockExistsDomain") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "BlockExists", + ID: "BlockExistsDomain", Other: "Block for domain {{.Domain}} already exists.", }, TemplateData: map[string]interface{}{ diff --git a/internal/language/text_b_test.go b/internal/language/text_b_test.go new file mode 100644 index 0000000..66d65a6 --- /dev/null +++ b/internal/language/text_b_test.go @@ -0,0 +1,195 @@ +package language + +import ( + "fmt" + "golang.org/x/text/language" + "testing" +) + +func TestLocalizer_TextBlock(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Block", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Blocks", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextBlock, table) + }) + } +} + +func TestLocalizer_TextBlockExistsDomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputStrings: []string{"example.com"}, + outputString: "Block for domain example.com already exists.", + outputLang: language.English, + }, + { + inputLang: language.English, + inputStrings: []string{"example2.com"}, + outputString: "Block for domain example2.com already exists.", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWith1String(t, i, localizer.TextBlockExistsDomain, table) + }) + } +} + +func TestLocalizer_TextBlockSubdomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Block Subdomain", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Block Subdomains", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextBlockSubdomain, table) + }) + } +} + +func TestLocalizer_TextBlocked(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Blocked", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextBlocked, table) + }) + } +} + +func TestLocalizer_TextBlockedDomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Blocked Domain", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Blocked Domains", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextBlockedDomain, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_o.go b/internal/language/text_c.go similarity index 54% rename from vendor/github.com/feditools/go-lib/language/text_o.go rename to internal/language/text_c.go index 51fb890..9a66965 100644 --- a/vendor/github.com/feditools/go-lib/language/text_o.go +++ b/internal/language/text_c.go @@ -2,35 +2,15 @@ package language import "github.com/nicksnyder/go-i18n/v2/i18n" -// TextOauth returns a translated phrase. -func (l *Localizer) TextOauth() *LocalizedString { - lg := logger.WithField("func", "TextOauth") +// TextChatID returns a translated phrase. +func (l *Localizer) TextChatID(count int) *LocalizedString { + lg := logger.WithField("func", "TextChatID") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "Oauth", - Other: "OAuth", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextOauth20Client returns a translated phrase. -func (l *Localizer) TextOauth20Client(count int) *LocalizedString { - lg := logger.WithField("func", "TextOauth20Client") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Oauth20Client", - One: "OAuth 2.0 Client", - Other: "OAuth 2.0 Clients", + ID: "ChatID", + One: "Chat ID", + Other: "Chat IDs", }, PluralCount: count, }) @@ -44,14 +24,14 @@ func (l *Localizer) TextOauth20Client(count int) *LocalizedString { } } -// TextOauth20Settings returns a translated phrase. -func (l *Localizer) TextOauth20Settings() *LocalizedString { - lg := logger.WithField("func", "TextOauth20Settings") +// TextClose returns a translated phrase. +func (l *Localizer) TextClose() *LocalizedString { + lg := logger.WithField("func", "TextClose") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "Oauth20Settings", - Other: "OAuth 2.0 Settings", + ID: "Close", + Other: "Close", }, }) if err != nil { @@ -64,15 +44,15 @@ func (l *Localizer) TextOauth20Settings() *LocalizedString { } } -// TextObfuscatedDomain returns a translated phrase. -func (l *Localizer) TextObfuscatedDomain(count int) *LocalizedString { - lg := logger.WithField("func", "TextObfuscatedDomain") +// TextConfig returns a translated phrase. +func (l *Localizer) TextConfig(count int) *LocalizedString { + lg := logger.WithField("func", "TextConfig") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "ObfuscatedDomain", - One: "Obfuscated Domain", - Other: "Obfuscated Domains", + ID: "Config", + One: "Config", + Other: "Configs", }, PluralCount: count, }) @@ -85,3 +65,23 @@ func (l *Localizer) TextObfuscatedDomain(count int) *LocalizedString { string: text, } } + +// TextCreate returns a translated phrase. +func (l *Localizer) TextCreate() *LocalizedString { + lg := logger.WithField("func", "TextCreate") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "Create", + Other: "Create", + }, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} diff --git a/internal/language/text_c_test.go b/internal/language/text_c_test.go new file mode 100644 index 0000000..a48d27e --- /dev/null +++ b/internal/language/text_c_test.go @@ -0,0 +1,150 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextChatID(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Chat ID", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Chat IDs", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextChatID, table) + }) + } +} + +func TestLocalizer_TextClose(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Close", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextClose, table) + }) + } +} + +func TestLocalizer_TextConfig(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Config", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Configs", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextConfig, table) + }) + } +} + +func TestLocalizer_TextCreate(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Create", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextCreate, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_d.go b/internal/language/text_d.go similarity index 79% rename from vendor/github.com/feditools/go-lib/language/text_d.go rename to internal/language/text_d.go index 6cf88aa..c44cd92 100644 --- a/vendor/github.com/feditools/go-lib/language/text_d.go +++ b/internal/language/text_d.go @@ -2,28 +2,6 @@ package language import "github.com/nicksnyder/go-i18n/v2/i18n" -// TextDashboard returns a translated phrase. -func (l *Localizer) TextDashboard(count int) *LocalizedString { - lg := logger.WithField("func", "TextDashboard") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Dashboard", - One: "Dashboard", - Other: "Dashboards", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - // TextDelete returns a translated phrase. func (l *Localizer) TextDelete() *LocalizedString { lg := logger.WithField("func", "TextDelete") @@ -90,18 +68,18 @@ func (l *Localizer) TextDeleteBlockConfirmDomain(domain string) *LocalizedString } } -// TextDemocrablock returns a translated phrase. -func (l *Localizer) TextDemocrablock() *LocalizedString { - lg := logger.WithField("func", "TextDemocrablock") - +// TextDeliveryStat returns a translated phrase. +func (l *Localizer) TextDeliveryStat(count int) *LocalizedString { text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "Democrablock", - Other: "Democrablock", + ID: "DeliveryStat", + One: "Delivery Stat", + Other: "Delivery Stats", }, + PluralCount: count, }) if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) + logger.WithField("func", "TextDeliveryStat").Warningf(missingTranslationWarning, err.Error()) } return &LocalizedString{ diff --git a/internal/language/text_d_test.go b/internal/language/text_d_test.go new file mode 100644 index 0000000..9254a78 --- /dev/null +++ b/internal/language/text_d_test.go @@ -0,0 +1,235 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextDelete(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Delete", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextDelete, table) + }) + } +} + +func TestLocalizer_TextDeleteBlockDomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputStrings: []string{"example.com"}, + outputString: "Delete Block example.com", + outputLang: language.English, + }, + { + inputLang: language.English, + inputStrings: []string{"example2.com"}, + outputString: "Delete Block example2.com", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWith1String(t, i, localizer.TextDeleteBlockDomain, table) + }) + } +} + +func TestLocalizer_TextDeleteBlockConfirmDomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputStrings: []string{"example.com"}, + outputString: "Are you sure you want to delete the block for example.com?", + outputLang: language.English, + }, + { + inputLang: language.English, + inputStrings: []string{"example2.com"}, + outputString: "Are you sure you want to delete the block for example2.com?", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWith1String(t, i, localizer.TextDeleteBlockConfirmDomain, table) + }) + } +} + +func TestLocalizer_TextDeliveryStat(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Delivery Stat", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Delivery Stats", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextDeliveryStat, table) + }) + } +} + +func TestLocalizer_TextDescription(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Description", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Descriptions", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextDescription, table) + }) + } +} + +func TestLocalizer_TextDomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Domain", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Domains", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextDomain, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_e.go b/internal/language/text_e.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/text_e.go rename to internal/language/text_e.go diff --git a/internal/language/text_e_test.go b/internal/language/text_e_test.go new file mode 100644 index 0000000..bc2331b --- /dev/null +++ b/internal/language/text_e_test.go @@ -0,0 +1,110 @@ +package language + +import ( + "fmt" + "golang.org/x/text/language" + "testing" +) + +func TestLocalizer_TextEditBlock(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputStrings: []string{"example.com"}, + outputString: "Edit Block example.com", + outputLang: language.English, + }, + { + inputLang: language.English, + inputStrings: []string{"example2.com"}, + outputString: "Edit Block example2.com", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWith1String(t, i, localizer.TextEditBlockDomain, table) + }) + } +} + +func TestLocalizer_TextEnabled(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Enabled", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextEnabled, table) + }) + } +} + +func TestLocalizer_TextErrorDatabase(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "database error", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextErrorDatabase, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_f.go b/internal/language/text_f.go similarity index 79% rename from vendor/github.com/feditools/go-lib/language/text_f.go rename to internal/language/text_f.go index 92b881c..2a2c8e8 100644 --- a/vendor/github.com/feditools/go-lib/language/text_f.go +++ b/internal/language/text_f.go @@ -2,14 +2,14 @@ package language import "github.com/nicksnyder/go-i18n/v2/i18n" -// TextFediverse returns a translated phrase. -func (l *Localizer) TextFediverse() *LocalizedString { - lg := logger.WithField("func", "TextFediverse") +// TextFederation returns a translated phrase. +func (l *Localizer) TextFederation() *LocalizedString { + lg := logger.WithField("func", "TextFederation") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "Fediverse", - Other: "Fediverse", + ID: "Federation", + Other: "Federation", }, }) if err != nil { diff --git a/internal/language/text_f_test.go b/internal/language/text_f_test.go new file mode 100644 index 0000000..d4b0817 --- /dev/null +++ b/internal/language/text_f_test.go @@ -0,0 +1,72 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextFederation(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Federation", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextFederation, table) + }) + } +} + +func TestLocalizer_TextFollowing(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Following", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextFollowing, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_g.go b/internal/language/text_g.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/text_g.go rename to internal/language/text_g.go diff --git a/internal/language/text_g_test.go b/internal/language/text_g_test.go new file mode 100644 index 0000000..98ad50d --- /dev/null +++ b/internal/language/text_g_test.go @@ -0,0 +1,39 @@ +package language + +import ( + "fmt" + "golang.org/x/text/language" + "testing" +) + +func TestLocalizer_TextGeneral(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "General", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextGeneral, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_h.go b/internal/language/text_h.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/text_h.go rename to internal/language/text_h.go diff --git a/internal/language/text_h_test.go b/internal/language/text_h_test.go new file mode 100644 index 0000000..3af221f --- /dev/null +++ b/internal/language/text_h_test.go @@ -0,0 +1,104 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextHomeWeb(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Home", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextHomeWeb, table) + }) + } +} + +func TestLocalizer_TextHomePageBody(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Home Page Body", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextHomePageBody, table) + }) + } +} + +func TestLocalizer_TextHowToJoin(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "How to Join", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextHowToJoin, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_i.go b/internal/language/text_i.go similarity index 88% rename from vendor/github.com/feditools/go-lib/language/text_i.go rename to internal/language/text_i.go index d37686a..b025130 100644 --- a/vendor/github.com/feditools/go-lib/language/text_i.go +++ b/internal/language/text_i.go @@ -44,6 +44,28 @@ func (l *Localizer) TextImportBlockList(count int) *LocalizedString { } } +// TextInboxURI returns a translated phrase. +func (l *Localizer) TextInboxURI(count int) *LocalizedString { + lg := logger.WithField("func", "TextInboxURI") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "InboxURI", + One: "Inbox URI", + Other: "Inbox URIs", + }, + PluralCount: count, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + // TextInstance returns a translated phrase. func (l *Localizer) TextInstance(count int) *LocalizedString { lg := logger.WithField("func", "TextInstance") @@ -65,25 +87,3 @@ func (l *Localizer) TextInstance(count int) *LocalizedString { string: text, } } - -// TextInvalidURI returns a translated phrase. -func (l *Localizer) TextInvalidURI(count int) *LocalizedString { - lg := logger.WithField("func", "TextInvalidURI") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "InvalidURI", - One: "Invalid URI", - Other: "Invalid URIs", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} diff --git a/internal/language/text_i_test.go b/internal/language/text_i_test.go new file mode 100644 index 0000000..abfdf4b --- /dev/null +++ b/internal/language/text_i_test.go @@ -0,0 +1,157 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextImport(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Import", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextImport, table) + }) + } +} + +func TestLocalizer_TextImportBlockList(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Import Block List", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Import Block Lists", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextImportBlockList, table) + }) + } +} + +func TestLocalizer_TextInboxURI(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Inbox URI", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Inbox URIs", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextInboxURI, table) + }) + } +} + +func TestLocalizer_TextInstance(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Instance", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Instances", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextInstance, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_l.go b/internal/language/text_l.go similarity index 74% rename from vendor/github.com/feditools/go-lib/language/text_l.go rename to internal/language/text_l.go index c24b4c8..e58a169 100644 --- a/vendor/github.com/feditools/go-lib/language/text_l.go +++ b/internal/language/text_l.go @@ -2,28 +2,6 @@ package language import "github.com/nicksnyder/go-i18n/v2/i18n" -// TextList returns a translated phrase. -func (l *Localizer) TextList(count int) *LocalizedString { - lg := logger.WithField("func", "TextList") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "List", - One: "List", - Other: "Lists", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - // TextLogin returns a translated phrase. func (l *Localizer) TextLogin() *LocalizedString { lg := logger.WithField("func", "TextLogin") diff --git a/internal/language/text_l_test.go b/internal/language/text_l_test.go new file mode 100644 index 0000000..5550ebe --- /dev/null +++ b/internal/language/text_l_test.go @@ -0,0 +1,104 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextLogin(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Login", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextLogin, table) + }) + } +} + +func TestLocalizer_TextLogout(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Logout", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextLogout, table) + }) + } +} + +func TestLocalizer_TextLookGood(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Looks Good!", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextLooksGood, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_m.go b/internal/language/text_m.go similarity index 77% rename from vendor/github.com/feditools/go-lib/language/text_m.go rename to internal/language/text_m.go index e4c03f0..98f6a17 100644 --- a/vendor/github.com/feditools/go-lib/language/text_m.go +++ b/internal/language/text_m.go @@ -2,15 +2,17 @@ package language import "github.com/nicksnyder/go-i18n/v2/i18n" -// TextModeration returns a translated phrase. -func (l *Localizer) TextModeration() *LocalizedString { - lg := logger.WithField("func", "TextLogin") +// TextMetric returns a translated phrase. +func (l *Localizer) TextMetric(count int) *LocalizedString { + lg := logger.WithField("func", "TextMetric") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "Moderation", - Other: "Moderation", + ID: "Metric", + One: "Metric", + Other: "Metrics", }, + PluralCount: count, }) if err != nil { lg.Warningf(missingTranslationWarning, err.Error()) diff --git a/internal/language/text_m_test.go b/internal/language/text_m_test.go new file mode 100644 index 0000000..07f6e14 --- /dev/null +++ b/internal/language/text_m_test.go @@ -0,0 +1,85 @@ +package language + +import ( + "fmt" + "golang.org/x/text/language" + "testing" +) + +func TestLocalizer_TextMetric(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Metric", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Metrics", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextMetric, table) + }) + } +} + +func TestLocalizer_TextModerator(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Moderator", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Moderators", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextModerator, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_n.go b/internal/language/text_n.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/text_n.go rename to internal/language/text_n.go diff --git a/internal/language/text_n_test.go b/internal/language/text_n_test.go new file mode 100644 index 0000000..e3d3e56 --- /dev/null +++ b/internal/language/text_n_test.go @@ -0,0 +1,46 @@ +package language + +import ( + "fmt" + "golang.org/x/text/language" + "testing" +) + +func TestLocalizer_TextNotification(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Notification", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Notifications", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextNotification, table) + }) + } +} diff --git a/internal/language/text_o.go b/internal/language/text_o.go new file mode 100644 index 0000000..36a167e --- /dev/null +++ b/internal/language/text_o.go @@ -0,0 +1,41 @@ +package language + +import "github.com/nicksnyder/go-i18n/v2/i18n" + +// TextOAuthConfigured returns a translated phrase. +func (l *Localizer) TextOAuthConfigured() *LocalizedString { + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "OAuthConfigured", + Other: "OAuth Configured", + }, + }) + if err != nil { + logger.WithField("func", "TextOAuthConfigured").Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + +// TextObfuscatedDomain returns a translated phrase. +func (l *Localizer) TextObfuscatedDomain(count int) *LocalizedString { + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "ObfuscatedDomain", + One: "Obfuscated Domain", + Other: "Obfuscated Domains", + }, + PluralCount: count, + }) + if err != nil { + logger.WithField("func", "TextObfuscatedDomain").Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} diff --git a/internal/language/text_o_test.go b/internal/language/text_o_test.go new file mode 100644 index 0000000..9baf40d --- /dev/null +++ b/internal/language/text_o_test.go @@ -0,0 +1,79 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextOAuthConfigured(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "OAuth Configured", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextOAuthConfigured, table) + }) + } +} + +func TestLocalizer_TextObfuscatedDomain(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Obfuscated Domain", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Obfuscated Domains", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextObfuscatedDomain, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_r.go b/internal/language/text_r.go similarity index 63% rename from vendor/github.com/feditools/go-lib/language/text_r.go rename to internal/language/text_r.go index 89d6e76..a7d4e76 100644 --- a/vendor/github.com/feditools/go-lib/language/text_r.go +++ b/internal/language/text_r.go @@ -2,6 +2,26 @@ package language import "github.com/nicksnyder/go-i18n/v2/i18n" +// TextReceivedStat returns a translated phrase. +func (l *Localizer) TextReceivedStat(count int) *LocalizedString { + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "ReceivedStat", + One: "Received Stat", + Other: "Received Stats", + }, + PluralCount: count, + }) + if err != nil { + logger.WithField("func", "TextReceivedStat").Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + // TextRelay returns a translated phrase. func (l *Localizer) TextRelay(count int) *LocalizedString { text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ @@ -22,40 +42,18 @@ func (l *Localizer) TextRelay(count int) *LocalizedString { } } -// TextRequired returns a translated phrase. -func (l *Localizer) TextRequired() *LocalizedString { - lg := logger.WithField("func", "TextRequired") - +// TextRepo returns a translated phrase. +func (l *Localizer) TextRepo(count int) *LocalizedString { text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "Required", - Other: "Required", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextRedirectURI returns a translated phrase. -func (l *Localizer) TextRedirectURI(count int) *LocalizedString { - lg := logger.WithField("func", "TextRedirectURI") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "RedirectURI", - One: "Redirect URI", - Other: "Redirect URIs", + ID: "Repo", + One: "Repo", + Other: "Repos", }, PluralCount: count, }) if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) + logger.WithField("func", "TextRepo").Warningf(missingTranslationWarning, err.Error()) } return &LocalizedString{ diff --git a/internal/language/text_r_test.go b/internal/language/text_r_test.go new file mode 100644 index 0000000..3f39872 --- /dev/null +++ b/internal/language/text_r_test.go @@ -0,0 +1,125 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextReceivedStat(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Received Stat", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Received Stats", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextReceivedStat, table) + }) + } +} + +func TestLocalizer_TextRelay(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Relay", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Relays", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextRelay, table) + }) + } +} + +func TestLocalizer_TextRepo(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Repo", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Repos", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextRepo, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_s.go b/internal/language/text_s.go similarity index 64% rename from vendor/github.com/feditools/go-lib/language/text_s.go rename to internal/language/text_s.go index 4e7cdb4..d3ccbd4 100644 --- a/vendor/github.com/feditools/go-lib/language/text_s.go +++ b/internal/language/text_s.go @@ -22,6 +22,28 @@ func (l *Localizer) TextSave() *LocalizedString { } } +// TextServerHostname returns a translated phrase. +func (l *Localizer) TextServerHostname(count int) *LocalizedString { + lg := logger.WithField("func", "TextServerHostname") + + text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ + DefaultMessage: &i18n.Message{ + ID: "ServerHostname", + One: "Server Hostname", + Other: "Server Hostnames", + }, + PluralCount: count, + }) + if err != nil { + lg.Warningf(missingTranslationWarning, err.Error()) + } + + return &LocalizedString{ + language: tag, + string: text, + } +} + // TextSetting returns a translated phrase. func (l *Localizer) TextSetting(count int) *LocalizedString { lg := logger.WithField("func", "TextSetting") @@ -44,17 +66,15 @@ func (l *Localizer) TextSetting(count int) *LocalizedString { } } -// TextSystem returns a translated phrase. -func (l *Localizer) TextSystem(count int) *LocalizedString { - lg := logger.WithField("func", "TextSystem") +// TextSoftware returns a translated phrase. +func (l *Localizer) TextSoftware() *LocalizedString { + lg := logger.WithField("func", "TextSoftware") text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ DefaultMessage: &i18n.Message{ - ID: "System", - One: "System", - Other: "Systems", + ID: "Software", + Other: "Software", }, - PluralCount: count, }) if err != nil { lg.Warningf(missingTranslationWarning, err.Error()) diff --git a/internal/language/text_s_test.go b/internal/language/text_s_test.go new file mode 100644 index 0000000..a7e10018 --- /dev/null +++ b/internal/language/text_s_test.go @@ -0,0 +1,150 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextSave(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Save", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextSave, table) + }) + } +} + +func TestLocalizer_TextServerHostname(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Server Hostname", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Server Hostnames", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextServerHostname, table) + }) + } +} + +func TestLocalizer_TextSetting(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Setting", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Settings", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextSetting, table) + }) + } +} + +func TestLocalizer_TextSoftware(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Software", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextSoftware, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_t.go b/internal/language/text_t.go similarity index 100% rename from vendor/github.com/feditools/go-lib/language/text_t.go rename to internal/language/text_t.go diff --git a/internal/language/text_t_test.go b/internal/language/text_t_test.go new file mode 100644 index 0000000..607dbd9 --- /dev/null +++ b/internal/language/text_t_test.go @@ -0,0 +1,86 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextTimestamp(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Timestamp", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Timestamps", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextTimestamp, table) + }) + } +} + +func TestLocalizer_TextToken(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Token", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Tokens", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextToken, table) + }) + } +} diff --git a/vendor/github.com/feditools/go-lib/language/text_u.go b/internal/language/text_u.go similarity index 67% rename from vendor/github.com/feditools/go-lib/language/text_u.go rename to internal/language/text_u.go index 5b97221..40c406b 100644 --- a/vendor/github.com/feditools/go-lib/language/text_u.go +++ b/internal/language/text_u.go @@ -43,25 +43,3 @@ func (l *Localizer) TextUpdate(count int) *LocalizedString { string: text, } } - -// TextUsername returns a translated phrase. -func (l *Localizer) TextUsername(count int) *LocalizedString { - lg := logger.WithField("func", "TextUsername") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Username", - One: "Username", - Other: "Usernames", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} diff --git a/internal/language/text_u_test.go b/internal/language/text_u_test.go new file mode 100644 index 0000000..df30a52 --- /dev/null +++ b/internal/language/text_u_test.go @@ -0,0 +1,79 @@ +package language + +import ( + "fmt" + "testing" + + "golang.org/x/text/language" +) + +func TestLocalizer_TextUnauthorized(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + outputString: "Unauthorized", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testText(t, i, localizer.TextUnauthorized, table) + }) + } +} + +func TestLocalizer_TextUpdate(t *testing.T) { + t.Parallel() + + tables := []testTextTable{ + { + inputLang: language.English, + inputCount: 1, + outputString: "Update", + outputLang: language.English, + }, + { + inputLang: language.English, + inputCount: 2, + outputString: "Updates", + outputLang: language.English, + }, + } + + langMod, _ := New() + for i, table := range tables { + i := i + table := table + + name := fmt.Sprintf(testTranslatedTo, i, table.inputLang) + t.Run(name, func(t *testing.T) { + t.Parallel() + + localizer, err := langMod.NewLocalizer(table.inputLang.String()) + if err != nil { + t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error()) + + return + } + + testTextWithCount(t, i, localizer.TextUpdate, table) + }) + } +} diff --git a/internal/logic/logic.go b/internal/logic/logic.go index 373990b..45d6598 100644 --- a/internal/logic/logic.go +++ b/internal/logic/logic.go @@ -25,6 +25,12 @@ type Logic interface { GetLoginURL(ctx context.Context, instance *models.Instance) (*url.URL, error) GetPeers(ctx context.Context) (*[]string, error) IsDomainBlocked(ctx context.Context, d string) (bool, error) + MetricsGetDeliverErrorWeek(ctx context.Context, instanceID int64) (*MetricsDataPointsTime, error) + MetricsGetDeliverSuccessWeek(ctx context.Context, instanceID int64) (*MetricsDataPointsTime, error) + MetricsGetReceivedWeek(ctx context.Context, instanceID int64) (*MetricsDataPointsTime, error) + MetricsIncDeliverError(ctx context.Context, instanceID int64) + MetricsIncDeliverSuccess(ctx context.Context, instanceID int64) + MetricsIncReceived(ctx context.Context, instanceID int64) ProcessActivity(ctx context.Context, jid string, instanceID int64, actorIRI *url.URL, activity fedihelper.Activity) error ProcessBlockAdd(ctx context.Context, blockID int64) error ProcessBlockDelete(ctx context.Context, blockID int64) error diff --git a/internal/logic/logic1/activity.go b/internal/logic/logic1/activity.go index 69231bf..3d6ae4d 100644 --- a/internal/logic/logic1/activity.go +++ b/internal/logic/logic1/activity.go @@ -47,11 +47,16 @@ func (l *Logic) DeliverActivity(ctx context.Context, jid string, instanceID int6 log.Debugf("sending activity: %s to %s", string(body), inboxIRI.String()) resp, err := l.transport.InstancePost(ctx, inboxIRI, body, libhttp.MimeAppActivityJSON, libhttp.MimeAppActivityJSON) if err != nil { - log.Errorf("can't post to instance: %s\n%s", err.Error(), resp) + msg := fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp) + log.Error(msg.Error()) - return fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp) + l.MetricsIncDeliverError(ctx, instance.ID) + + return msg } + l.MetricsIncDeliverSuccess(ctx, instance.ID) + return nil } @@ -166,26 +171,9 @@ func (l *Logic) doFollow(ctx context.Context, jid string, instanceID int64, acti // send accept outgoingActivity := genActivityAccept(l.domain, instance.ActorIRI, id) - body, err := json.Marshal(outgoingActivity) + err = l.runner.EnqueueDeliverActivity(ctx, instance.ID, outgoingActivity) if err != nil { - log.Errorf("can't marshal response: %s", err.Error()) - - return fmt.Errorf("can't marshal response: %s", err.Error()) - } - - inboxIRI, err := url.Parse(instance.InboxIRI) - if err != nil { - log.Errorf("can't parse actor iri: %s", err.Error()) - - return fmt.Errorf("can't parse actor iri: %s", err.Error()) - } - - log.Debugf("sending activity: %s", string(body)) - resp, err := l.transport.InstancePost(ctx, inboxIRI, body, libhttp.MimeAppActivityJSON, libhttp.MimeAppActivityJSON) - if err != nil { - log.Errorf("can't post to instance: %s\n%s", err.Error(), resp) - - return fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp) + log.Errorf("enqueueing delivery: %s", err.Error()) } go l.runner.EnqueueSendNotification( @@ -391,26 +379,9 @@ func (l *Logic) doUndo(ctx context.Context, jid string, instanceID int64, activi // send undo outgoingActivity := genActivityUndo(l.domain, instance.ActorIRI) - body, err := json.Marshal(outgoingActivity) + err = l.runner.EnqueueDeliverActivity(ctx, instance.ID, outgoingActivity) if err != nil { - log.Errorf("can't marshal response: %s", err.Error()) - - return fmt.Errorf("can't marshal response: %s", err.Error()) - } - - inboxIRI, err := url.Parse(instance.InboxIRI) - if err != nil { - log.Errorf("can't parse actor iri: %s", err.Error()) - - return fmt.Errorf("can't parse actor iri: %s", err.Error()) - } - - log.Debugf("sending activity: %s", string(body)) - resp, err := l.transport.InstancePost(ctx, inboxIRI, body, libhttp.MimeAppActivityJSON, libhttp.MimeAppActivityJSON) - if err != nil { - log.Errorf("can't post to instance: %s\n%s", err.Error(), resp) - - return fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp) + log.Errorf("enqueueing delivery: %s", err.Error()) } go l.runner.EnqueueSendNotification( diff --git a/internal/logic/logic1/logic.go b/internal/logic/logic1/logic.go index 61fe625..73a36a3 100644 --- a/internal/logic/logic1/logic.go +++ b/internal/logic/logic1/logic.go @@ -7,6 +7,7 @@ import ( "github.com/feditools/relay/internal/db" "github.com/feditools/relay/internal/fedi" ihttp "github.com/feditools/relay/internal/http" + "github.com/feditools/relay/internal/kv" "github.com/feditools/relay/internal/notification" "github.com/feditools/relay/internal/path" "github.com/feditools/relay/internal/runner" @@ -25,6 +26,7 @@ import ( type Logic struct { db db.DB fedi *fedi.Module + kv kv.KV notifier notification.Notifier runner runner.Runner tokz *token.Tokenizer @@ -48,7 +50,7 @@ type Logic struct { } // New created a new logic module -func New(ctx context.Context, c pub.Clock, d db.DB, h *ihttp.Client, tokz *token.Tokenizer) (*Logic, error) { +func New(ctx context.Context, c pub.Clock, d db.DB, h *ihttp.Client, k kv.KV, tokz *token.Tokenizer) (*Logic, error) { log := logger.WithFields(logrus.Fields{ "func": "New", }) @@ -56,6 +58,7 @@ func New(ctx context.Context, c pub.Clock, d db.DB, h *ihttp.Client, tokz *token // create module l := Logic{ db: d, + kv: k, tokz: tokz, domain: viper.GetString(config.Keys.ServerExternalHostname), diff --git a/internal/logic/logic1/metrics_get.go b/internal/logic/logic1/metrics_get.go new file mode 100644 index 0000000..8262eb4 --- /dev/null +++ b/internal/logic/logic1/metrics_get.go @@ -0,0 +1,81 @@ +package logic1 + +import ( + "context" + "errors" + "github.com/feditools/relay/internal/kv" + "github.com/feditools/relay/internal/logic" + "time" +) + +func (l *Logic) MetricsGetDeliverErrorWeek(ctx context.Context, instanceID int64) (*logic.MetricsDataPointsTime, error) { + now := time.Now().UTC() + now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) + + var days logic.MetricsDataPointsTime = make([]logic.MetricsDataPointTime, 7) + for i := 0; i < 7; i++ { + day := now.Add(-24 * time.Duration(i) * time.Hour) + + count := 0 + var err error + count, err = l.kv.GetMetricsDeliverError(ctx, instanceID, day) + if err != nil && !errors.Is(err, kv.ErrNil) { + return nil, err + } + + days[i] = logic.MetricsDataPointTime{ + X: day, + Y: count, + } + } + + return &days, nil +} + +func (l *Logic) MetricsGetDeliverSuccessWeek(ctx context.Context, instanceID int64) (*logic.MetricsDataPointsTime, error) { + now := time.Now().UTC() + now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) + + var days logic.MetricsDataPointsTime = make([]logic.MetricsDataPointTime, 7) + for i := 0; i < 7; i++ { + day := now.Add(-24 * time.Duration(i) * time.Hour) + + count := 0 + var err error + count, err = l.kv.GetMetricsDeliverSuccess(ctx, instanceID, day) + if err != nil && !errors.Is(err, kv.ErrNil) { + return nil, err + } + + days[i] = logic.MetricsDataPointTime{ + X: day, + Y: count, + } + } + + return &days, nil +} + +func (l *Logic) MetricsGetReceivedWeek(ctx context.Context, instanceID int64) (*logic.MetricsDataPointsTime, error) { + now := time.Now().UTC() + now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC) + + var days logic.MetricsDataPointsTime = make([]logic.MetricsDataPointTime, 7) + for i := 0; i < 7; i++ { + day := now.Add(-24 * time.Duration(i) * time.Hour) + + count := 0 + var err error + count, err = l.kv.GetMetricsReceived(ctx, instanceID, day) + if err != nil && !errors.Is(err, kv.ErrNil) { + return nil, err + } + + days[i] = logic.MetricsDataPointTime{ + X: day, + Y: count, + } + } + + return &days, nil +} diff --git a/internal/logic/logic1/metrics_inc.go b/internal/logic/logic1/metrics_inc.go new file mode 100644 index 0000000..712a675 --- /dev/null +++ b/internal/logic/logic1/metrics_inc.go @@ -0,0 +1,54 @@ +package logic1 + +import ( + "context" + "time" +) + +func (l *Logic) MetricsIncDeliverError(ctx context.Context, instanceID int64) { + log := logger.WithField("func", "MetricsIncDeliverError") + + now := time.Now().UTC() + + err := l.kv.IncMetricsDeliverError(ctx, instanceID, now) + if err != nil { + log.Warnf("instance: %s", err.Error()) + } + + err = l.kv.IncMetricsDeliverErrorTotal(ctx, now) + if err != nil { + log.Warnf("total: %s", err.Error()) + } +} + +func (l *Logic) MetricsIncDeliverSuccess(ctx context.Context, instanceID int64) { + log := logger.WithField("func", "MetricsIncDeliverSuccess") + + now := time.Now().UTC() + + err := l.kv.IncMetricsDeliverSuccess(ctx, instanceID, now) + if err != nil { + log.Warnf("instance: %s", err.Error()) + } + + err = l.kv.IncMetricsDeliverSuccessTotal(ctx, now) + if err != nil { + log.Warnf("total: %s", err.Error()) + } +} + +func (l *Logic) MetricsIncReceived(ctx context.Context, instanceID int64) { + log := logger.WithField("func", "MetricsIncReceived") + + now := time.Now().UTC() + + err := l.kv.IncMetricsReceived(ctx, instanceID, now) + if err != nil { + log.Warnf("instance: %s", err.Error()) + } + + err = l.kv.IncMetricsReceivedTotal(ctx, now) + if err != nil { + log.Warnf("total: %s", err.Error()) + } +} diff --git a/internal/logic/metrics.go b/internal/logic/metrics.go new file mode 100644 index 0000000..b45ca90 --- /dev/null +++ b/internal/logic/metrics.go @@ -0,0 +1,10 @@ +package logic + +import "time" + +type MetricsDataPointsTime []MetricsDataPointTime + +type MetricsDataPointTime struct { + X time.Time + Y int +} diff --git a/internal/path/gen.go b/internal/path/gen.go index 57ddf80..1cb9e9e 100644 --- a/internal/path/gen.go +++ b/internal/path/gen.go @@ -27,6 +27,11 @@ func GenAppAdminHomePath() string { return AppAdminHome } +// GenAppAdminInstanceViewPath returns a path for the admin instance view page. +func GenAppAdminInstanceViewPath(t string) string { + return AppAdminPreInstanceView + t +} + // GenAppHomePath returns a path for the home page. func GenAppHomePath() string { return AppHome diff --git a/internal/path/path_webapp.go b/internal/path/path_webapp.go index 652e02d..981c258 100644 --- a/internal/path/path_webapp.go +++ b/internal/path/path_webapp.go @@ -69,4 +69,8 @@ const ( AppAdminInstance = AppAdmin + AppAdminSubInstance // AppAdminSubInstance is the sub path for the admin instances page. AppAdminSubInstance = "/" + PartInstance + // AppAdminPreInstanceView is the prefix path for the admin instance view page. + AppAdminPreInstanceView = AppAdmin + AppAdminSubInstance + "/" + // AppAdminSubInstanceView is the sub path for the admin instance view page. + AppAdminSubInstanceView = AppAdminSubInstance + "/" + VarInstance ) diff --git a/test/fake_metrics.sh b/test/fake_metrics.sh new file mode 100755 index 0000000..0ec17d5 --- /dev/null +++ b/test/fake_metrics.sh @@ -0,0 +1,38 @@ +#!/bin/bash -x + +METRIC_MAX=500 + +KEY_DELIVERY_S="relay:metrics:deliver:s:" +KEY_DELIVERY_S_TOTAL="relay:metrics:deliver:st:" +KEY_DELIVERY_E="relay:metrics:deliver:e:" +KEY_DELIVERY_E_TOTAL="relay:metrics:deliver:et:" +KEY_RECEIVED="relay:metrics:received:" +KEY_RECEIVED_TOTAL="relay:metrics:receivedt:" + +for day in {0..30}; do + #echo $day + + DATE1=$(date -v -${day}d +"%Y:%m:%d") + + DELIVERY_S_TOTAL=0 + DELIVERY_E_TOTAL=0 + RECEIVED_TOTAL=0 + + for instance in {2..3}; do + DELIVERY_S=$((1 + $RANDOM % ${METRIC_MAX})) + DELIVERY_E=$((1 + $RANDOM % ${METRIC_MAX})) + RECEIVED=$((1 + $RANDOM % ${METRIC_MAX})) + + DELIVERY_S_TOTAL=$(expr ${DELIVERY_S_TOTAL} + ${DELIVERY_S}) + DELIVERY_E_TOTAL=$(expr ${DELIVERY_E_TOTAL} + ${DELIVERY_E}) + RECEIVED_TOTAL=$(expr ${RECEIVED_TOTAL} + ${RECEIVED}) + + docker exec -it relay_redis_1 redis-cli --pass test HSET ${KEY_DELIVERY_S}${DATE1} ${instance} ${DELIVERY_S} + docker exec -it relay_redis_1 redis-cli --pass test HSET ${KEY_DELIVERY_E}${DATE1} ${instance} ${DELIVERY_E} + docker exec -it relay_redis_1 redis-cli --pass test HSET ${KEY_RECEIVED}${DATE1} ${instance} ${RECEIVED} + done + + docker exec -it relay_redis_1 redis-cli --pass test SET ${KEY_DELIVERY_S_TOTAL}${DATE1} ${DELIVERY_S_TOTAL} + docker exec -it relay_redis_1 redis-cli --pass test SET ${KEY_DELIVERY_E_TOTAL}${DATE1} ${DELIVERY_E_TOTAL} + docker exec -it relay_redis_1 redis-cli --pass test SET ${KEY_RECEIVED_TOTAL}${DATE1} ${RECEIVED_TOTAL} +done diff --git a/vendor/github.com/feditools/go-lib/Jenkinsfile b/vendor/github.com/feditools/go-lib/Jenkinsfile index 83eca8b..9ac9e80 100644 --- a/vendor/github.com/feditools/go-lib/Jenkinsfile +++ b/vendor/github.com/feditools/go-lib/Jenkinsfile @@ -1,6 +1,6 @@ pipeline { environment { - BUILD_IMAGE = 'gobuild:1.17' + BUILD_IMAGE = 'gobuild:1.18' BUILD_ARGS = '-e GOCACHE=/gocache -e HOME=${WORKSPACE} -v /var/lib/jenkins/gocache:/gocache -v /var/lib/jenkins/go/pkg:/go/pkg' PATH = '/go/bin:~/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin' } diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.af.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.af.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.af.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.ar.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.ar.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.ar.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.ca.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.ca.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.ca.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.cs.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.cs.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.cs.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.da.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.da.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.da.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.de.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.de.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.de.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.el.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.el.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.el.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.es.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.es.yaml deleted file mode 100644 index fdc4612..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.es.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -Account: - one: Cuenta - other: Cuentas -AddOauth20Client: - one: Añadir Cliente OAuth 2.0 - other: Añadir Clientes de OAuth 2.0 -Client: - one: Cliente - other: Clientes -ClientID: - one: ID de Cliente - other: IDs de Cliente -ClientSecret: - one: Secreto de Cliente - other: Secretos del Cliente -Create: Crear -Dashboard: - one: Tablero - other: Tableros -Description: - one: Descripción - other: Descripciones -HomeWeb: Inicio -InvalidURI: - one: URI Inválidas - other: URIs Inválidas -Login: Ingresar -LooksGood: '¡Se ve bien!' -Oauth: OAuth -Oauth20Client: - one: Cliente OAuth 2.0 - other: Clientes de OAuth 2.0 -Oauth20Settings: Configuración de OAuth 2.0 -RedirectURI: - one: Redirigir URI - other: Redirigir URIs -Required: Requerido -Unauthorized: No Autorizado diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.fi.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.fi.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.fi.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.fr.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.fr.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.fr.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.he.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.he.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.he.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.hu.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.hu.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.hu.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.it.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.it.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.it.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.ja.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.ja.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.ja.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.ko.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.ko.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.ko.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.nl.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.nl.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.nl.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.no.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.no.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.no.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.pl.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.pl.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.pl.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.pt.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.pt.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.pt.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.ro.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.ro.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.ro.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.ru.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.ru.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.ru.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.sr.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.sr.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.sr.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.sv.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.sv.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.sv.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.tr.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.tr.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.tr.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.uk.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.uk.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.uk.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.vi.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.vi.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.vi.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.zh.yaml b/vendor/github.com/feditools/go-lib/language/locales/active.zh.yaml deleted file mode 100644 index ed97d53..0000000 --- a/vendor/github.com/feditools/go-lib/language/locales/active.zh.yaml +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/vendor/github.com/feditools/go-lib/language/text_a.go b/vendor/github.com/feditools/go-lib/language/text_a.go deleted file mode 100644 index ef2ce45..0000000 --- a/vendor/github.com/feditools/go-lib/language/text_a.go +++ /dev/null @@ -1,196 +0,0 @@ -package language - -import "github.com/nicksnyder/go-i18n/v2/i18n" - -// TextAccount returns a translated phrase. -func (l *Localizer) TextAccount(count int) *LocalizedString { - lg := logger.WithField("func", "TextAccount") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Account", - One: "Account", - Other: "Accounts", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextActivityLog returns a translated phrase. -func (l *Localizer) TextActivityLog(count int) *LocalizedString { - lg := logger.WithField("func", "TextActivityLog") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "ActivityLog", - One: "Activity Log", - Other: "Activity Logs", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextAddBlock returns a translated phrase. -func (l *Localizer) TextAddBlock(count int) *LocalizedString { - lg := logger.WithField("func", "TextAddBlock") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "AddBlock", - One: "Add Block", - Other: "Add Blocks", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextAddOauth20Client returns a translated phrase. -func (l *Localizer) TextAddOauth20Client(count int) *LocalizedString { - lg := logger.WithField("func", "TextAddOauth20Client") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "AddOauth20Client", - One: "Add OAuth 2.0 Client", - Other: "Add OAuth 2.0 Clients", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextAdmin returns a translated phrase. -func (l *Localizer) TextAdmin() *LocalizedString { - lg := logger.WithField("func", "TextAdmin") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Admin", - Other: "Admin", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextAllow returns a translated phrase. -func (l *Localizer) TextAllow() *LocalizedString { - lg := logger.WithField("func", "TextAllow") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Allow", - Other: "Allow", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextApplicationToken returns a translated phrase. -func (l *Localizer) TextApplicationToken(count int) *LocalizedString { - lg := logger.WithField("func", "TextApplicationToken") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "ApplicationToken", - One: "Application Token", - Other: "Application Tokens", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextAuthorize returns a translated phrase. -func (l *Localizer) TextAuthorize() *LocalizedString { - lg := logger.WithField("func", "TextAuthorize") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Authorize", - Other: "Authorize", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextAuthorizeApplicationDescription returns a translated phrase. -func (l *Localizer) TextAuthorizeApplicationDescription(description string) *LocalizedString { - lg := logger.WithField("func", "TextAuthorizeApplicationDescription") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "AuthorizeApplicationDescription", - Other: "Authorize {{.Description}}", - }, - TemplateData: map[string]interface{}{ - "Description": description, - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} diff --git a/vendor/github.com/feditools/go-lib/language/text_c.go b/vendor/github.com/feditools/go-lib/language/text_c.go deleted file mode 100644 index 9c29b83..0000000 --- a/vendor/github.com/feditools/go-lib/language/text_c.go +++ /dev/null @@ -1,173 +0,0 @@ -package language - -import "github.com/nicksnyder/go-i18n/v2/i18n" - -// TextChatID returns a translated phrase. -func (l *Localizer) TextChatID(count int) *LocalizedString { - lg := logger.WithField("func", "TextChatID") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "ChatID", - One: "Chat ID", - Other: "Chat IDs", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextChatIDOrUsername returns a translated phrase. -func (l *Localizer) TextChatIDOrUsername() *LocalizedString { - lg := logger.WithField("func", "TextChatIDOrUsername") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "ChatIDOrUsername", - Other: "Chat ID or Username", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextClient returns a translated phrase. -func (l *Localizer) TextClient(count int) *LocalizedString { - lg := logger.WithField("func", "TextClient") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Client", - One: "Client", - Other: "Clients", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextClientID returns a translated phrase. -func (l *Localizer) TextClientID(count int) *LocalizedString { - lg := logger.WithField("func", "TextClientID") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "ClientID", - One: "Client ID", - Other: "Client IDs", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextClientSecret returns a translated phrase. -func (l *Localizer) TextClientSecret(count int) *LocalizedString { - lg := logger.WithField("func", "TextClientSecret") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "ClientSecret", - One: "Client Secret", - Other: "Client Secrets", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextClose returns a translated phrase. -func (l *Localizer) TextClose() *LocalizedString { - lg := logger.WithField("func", "TextClose") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Close", - Other: "Close", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextConfig returns a translated phrase. -func (l *Localizer) TextConfig(count int) *LocalizedString { - lg := logger.WithField("func", "TextConfig") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Config", - One: "Config", - Other: "Configs", - }, - PluralCount: count, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} - -// TextCreate returns a translated phrase. -func (l *Localizer) TextCreate() *LocalizedString { - lg := logger.WithField("func", "TextCreate") - - text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{ - DefaultMessage: &i18n.Message{ - ID: "Create", - Other: "Create", - }, - }) - if err != nil { - lg.Warningf(missingTranslationWarning, err.Error()) - } - - return &LocalizedString{ - language: tag, - string: text, - } -} diff --git a/vendor/github.com/feditools/go-lib/language/util.go b/vendor/github.com/feditools/go-lib/language/util.go deleted file mode 100644 index fb77c58..0000000 --- a/vendor/github.com/feditools/go-lib/language/util.go +++ /dev/null @@ -1,14 +0,0 @@ -package language - -func isEmptyYaml(b []byte) bool { - switch string(b) { - case "": - return true - case "---": - return true - case "---\n": - return true - default: - return false - } -} diff --git a/vendor/github.com/feditools/go-lib/template/form_label.go b/vendor/github.com/feditools/go-lib/template/form_label.go index a13423b..ef89a11 100644 --- a/vendor/github.com/feditools/go-lib/template/form_label.go +++ b/vendor/github.com/feditools/go-lib/template/form_label.go @@ -1,9 +1,7 @@ package template -import liblanguage "github.com/feditools/go-lib/language" - type FormLabel struct { - Text *liblanguage.LocalizedString + Text LocalizedString Badge *Badge Class string } diff --git a/vendor/github.com/feditools/go-lib/template/form_radio.go b/vendor/github.com/feditools/go-lib/template/form_radio.go index 7ee5a05..7423a0f 100644 --- a/vendor/github.com/feditools/go-lib/template/form_radio.go +++ b/vendor/github.com/feditools/go-lib/template/form_radio.go @@ -1,7 +1,6 @@ package template import ( - "github.com/feditools/go-lib/language" "strconv" ) @@ -9,7 +8,7 @@ import ( type FormRadio struct { ID string Name string - Values map[string]*language.LocalizedString + Values map[string]LocalizedString Selected string Disabled bool Required bool diff --git a/vendor/github.com/feditools/go-lib/template/localized_string.go b/vendor/github.com/feditools/go-lib/template/localized_string.go new file mode 100644 index 0000000..f74080a --- /dev/null +++ b/vendor/github.com/feditools/go-lib/template/localized_string.go @@ -0,0 +1,8 @@ +package template + +import "golang.org/x/text/language" + +type LocalizedString interface { + Language() language.Tag + String() string +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b684305..1bbd60c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -21,14 +21,13 @@ github.com/dgryski/go-rendezvous # github.com/fatih/color v1.13.0 ## explicit; go 1.13 github.com/fatih/color -# github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e +# github.com/feditools/go-lib v0.16.0 ## explicit; go 1.17 github.com/feditools/go-lib github.com/feditools/go-lib/database github.com/feditools/go-lib/fedihelper github.com/feditools/go-lib/fedihelper/mastodon github.com/feditools/go-lib/http -github.com/feditools/go-lib/language github.com/feditools/go-lib/log github.com/feditools/go-lib/metrics github.com/feditools/go-lib/metrics/statsd diff --git a/vendor/github.com/feditools/go-lib/language/locales/active.en.yaml b/web/locales/active.en.yaml similarity index 60% rename from vendor/github.com/feditools/go-lib/language/locales/active.en.yaml rename to web/locales/active.en.yaml index 4ec50dd..5cfde2e 100644 --- a/vendor/github.com/feditools/go-lib/language/locales/active.en.yaml +++ b/web/locales/active.en.yaml @@ -5,23 +5,17 @@ Account: ActivityLog: one: Activity Log other: Activity Logs +ActorURI: + one: Actor URI + other: Actor URIs AddBlock: one: Add Block other: Add Blocks -AddOauth20Client: - one: Add OAuth 2.0 Client - other: Add OAuth 2.0 Clients Admin: Admin -Allow: Allow -ApplicationToken: - one: Application Token - other: Application Tokens -Authorize: Authorize -AuthorizeApplicationDescription: Authorize {{.Description}} Block: one: Block other: Blocks -BlockExists: Block for domain {{.Domain}} already exists. +BlockExistsDomain: Block for domain {{.Domain}} already exists. BlockSubdomain: one: Block Subdomain other: Block Subdomains @@ -32,28 +26,17 @@ BlockedDomain: ChatID: one: Chat ID other: Chat IDs -ChatIDOrUsername: Chat ID or Username -Client: - one: Client - other: Clients -ClientID: - one: Client ID - other: Client IDs -ClientSecret: - one: Client Secret - other: Client Secrets Close: Close Config: one: Config other: Configs Create: Create -Dashboard: - one: Dashboard - other: Dashboards Delete: Delete DeleteBlockConfirmDomain: Are you sure you want to delete the block for {{.Domain}}? DeleteBlockDomain: Delete Block {{.Domain}} -Democrablock: Democrablock +DeliveryStat: + one: Delivery Stat + other: Delivery Stats Description: one: Description other: Descriptions @@ -63,7 +46,7 @@ Domain: EditBlockDomain: Edit Block {{.Domain}} Enabled: Enabled ErrorDatabase: database error -Fediverse: Fediverse +Federation: Federation Following: Following General: General HomePageBody: Home Page Body @@ -73,47 +56,45 @@ Import: Import ImportBlockList: one: Import Block List other: Import Block Lists +InboxURI: + one: Inbox URI + other: Inbox URIs Instance: one: Instance other: Instances -InvalidURI: - one: Invalid URI - other: Invalid URIs -List: - one: List - other: Lists Login: Login Logout: Logout LooksGood: Looks Good! -Moderation: Moderation +Metric: + one: Metric + other: Metrics Moderator: one: Moderator other: Moderators Notification: one: Notification other: Notifications -Oauth: OAuth -Oauth20Client: - one: OAuth 2.0 Client - other: OAuth 2.0 Clients -Oauth20Settings: OAuth 2.0 Settings +OAuthConfigured: OAuth Configured ObfuscatedDomain: one: Obfuscated Domain other: Obfuscated Domains -RedirectURI: - one: Redirect URI - other: Redirect URIs +ReceivedStat: + one: Received Stat + other: Received Stats Relay: one: Relay other: Relays -Required: Required +Repo: + one: Repo + other: Repos Save: Save +ServerHostname: + one: Server Hostname + other: Server Hostnames Setting: one: Setting other: Settings -System: - one: System - other: Systems +Software: Software Timestamp: one: Timestamp other: Timestamps @@ -124,6 +105,3 @@ Unauthorized: Unauthorized Update: one: Update other: Updates -Username: - one: Username - other: Usernames diff --git a/web/template/admin_instance.gohtml b/web/template/admin_instance.gohtml index 75f9227..717c02c 100644 --- a/web/template/admin_instance.gohtml +++ b/web/template/admin_instance.gohtml @@ -26,17 +26,17 @@ {{- range $instance := .Instances }} - {{- $token := token $instance }} - - {{ $instance.Domain }}{{ if $instance.IsPunycode }} ({{ $instance.UnicodeDomain }}){{ end }} - {{ if $instance.IsFollowing }}{{ else }}{{ end }} - {{ if ne $instance.BlockID 0 }}{{ else }}{{ end }} - - - - + {{- $token := token $instance }} + + {{ $instance.Domain }}{{ if $instance.IsPunycode }} ({{ $instance.UnicodeDomain }}){{ end }} + {{ if $instance.IsFollowing }}{{ else }}{{ end }} + {{ if ne $instance.BlockID 0 }}{{ else }}{{ end }} + + + + {{- end }} diff --git a/web/template/admin_instance_view.gohtml b/web/template/admin_instance_view.gohtml new file mode 100644 index 0000000..ac2486e --- /dev/null +++ b/web/template/admin_instance_view.gohtml @@ -0,0 +1,133 @@ +{{ define "admin_instance_view" -}} +{{- $textActorURI := .Localizer.TextActorURI 1 -}} +{{- $textBlock := .Localizer.TextBlock 1 -}} +{{- $textDeliveryStats := .Localizer.TextDeliveryStat 2 -}} +{{- $textDomain := .Localizer.TextDomain 1 -}} +{{- $textFederation := .Localizer.TextFederation -}} +{{- $textFollowing := .Localizer.TextFollowing -}} +{{- $textGeneral := .Localizer.TextGeneral -}} +{{- $textInboxURI := .Localizer.TextInboxURI 1 -}} +{{- $textInstance := .Localizer.TextInstance 1 -}} +{{- $textMetrics := .Localizer.TextMetric 2 -}} +{{- $textOAuthConfigured := .Localizer.TextOAuthConfigured -}} +{{- $textReceivedStats := .Localizer.TextReceivedStat 2 -}} +{{- $textServerHostname := .Localizer.TextServerHostname 1 -}} +{{- $textSoftware := .Localizer.TextSoftware -}} +{{- template "header" . }} +
+
+
+

{{ $textInstance }} {{ .Instance.UnicodeDomain }}

+
+
+
+
+{{- template "breadcrumbs" .Breadcrumbs }} +
+
+
+
+

{{ $textGeneral }}

+
+
+
+
+ {{ $textDomain }} +
+
+ {{ .Instance.Domain }} +
+
+
+
+ {{ $textServerHostname }} +
+
+ {{ .Instance.ServerHostname }} +
+
+
+
+ {{ $textSoftware }} +
+
+ {{- if .Instance.Software }} + {{ .Instance.Software }} + {{- else }} + unknown + {{- end}} +
+
+
+
+ {{ $textFollowing }} +
+
+ {{ if .Instance.IsFollowing }}{{ else }}{{ end }} +
+
+
+
+ {{ $textOAuthConfigured }} +
+
+ {{ if .Instance.OAuthClientID }}{{ else }}{{ end }} +
+
+
+
+ {{ $textBlock }} +
+
+ {{ if .Instance.Block }} + {{ .Instance.Block.Domain }} ({{ token .Instance.Block }}) + {{ else }} + none + {{ end }} +
+
+
+
+
+
+

{{ $textFederation }}

+
+
+
+
+ {{ $textActorURI }} +
+
+ {{ .Instance.ActorIRI }} +
+
+
+
+ {{ $textInboxURI }} +
+
+ {{ .Instance.InboxIRI }} +
+
+
+
+
+
+

{{ $textMetrics }}

+
+
+
+
+
{{ $textDeliveryStats }}
+ +
+
+
{{ $textReceivedStats }}
+ +
+
+
+
+
+{{ template "footer" . }} +{{ end }} \ No newline at end of file diff --git a/web/template/breadcrumb.gohtml b/web/template/breadcrumb.gohtml new file mode 100644 index 0000000..0938609 --- /dev/null +++ b/web/template/breadcrumb.gohtml @@ -0,0 +1,13 @@ +{{ define "breadcrumbs" -}} + +{{- end }} \ No newline at end of file diff --git a/web/template/footer.gohtml b/web/template/footer.gohtml index 6e756c1..8f93fc0 100644 --- a/web/template/footer.gohtml +++ b/web/template/footer.gohtml @@ -1,5 +1,7 @@ {{ define "footer" -}} -{{- $textClose := .Localizer.TextClose -}} +{{- $textActivityLog := .Localizer.TextActivityLog 1 -}} +{{- $textHome := .Localizer.TextHomeWeb -}} +{{- $textRepo := .Localizer.TextRepo 1 -}}
diff --git a/web/web.go b/web/web.go index 42a7fdc..485dc77 100644 --- a/web/web.go +++ b/web/web.go @@ -3,6 +3,7 @@ package web import "embed" // Files contains static files required by the application +//go:embed locales/active.*.yaml //go:embed static/css/default.min.css //go:embed static/css/error.min.css //go:embed static/css/login.min.css