mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-26 05:36:38 +00:00
[fix] Make postgres connections magically work in common setups (#352)
* Don't use the system 'postgres' database by default * Use postgres adapter defaults The pgx code actually goes to great lengths to make postgres connections Just Work(tm) out of the box, including supporting `~/.pg_service.conf`, SSL certificates, UNIX sockets if it can find a socket at a common path, and falling back to TCP to localhost if not. (On Windows, it won't try to use UNIX sockets, but will read credentials from %appdata% as is standard over there.) By applying our flags as overrides only when they're specified, database connections should Just Work(tm) anywhere `psql gotosocial` does.
This commit is contained in:
parent
ef5a9256a8
commit
ed9158fa05
|
@ -34,11 +34,11 @@
|
||||||
TrustedProxies: []string{"127.0.0.1/32"}, // localhost
|
TrustedProxies: []string{"127.0.0.1/32"}, // localhost
|
||||||
|
|
||||||
DbType: "postgres",
|
DbType: "postgres",
|
||||||
DbAddress: "localhost",
|
DbAddress: "",
|
||||||
DbPort: 5432,
|
DbPort: 5432,
|
||||||
DbUser: "postgres",
|
DbUser: "",
|
||||||
DbPassword: "postgres",
|
DbPassword: "",
|
||||||
DbDatabase: "postgres",
|
DbDatabase: "gotosocial",
|
||||||
DbTLSMode: "disable",
|
DbTLSMode: "disable",
|
||||||
DbTLSCACert: "",
|
DbTLSCACert: "",
|
||||||
|
|
||||||
|
|
|
@ -280,29 +280,11 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
|
||||||
return nil, fmt.Errorf("expected db type of %s but got %s", db.DBTypePostgres, viper.GetString(keys.DbType))
|
return nil, fmt.Errorf("expected db type of %s but got %s", db.DBTypePostgres, viper.GetString(keys.DbType))
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate port
|
// these are all optional, the db adapter figures out defaults
|
||||||
port := viper.GetInt(keys.DbPort)
|
port := viper.GetInt(keys.DbPort)
|
||||||
if port == 0 {
|
|
||||||
return nil, errors.New("no port set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate address
|
|
||||||
address := viper.GetString(keys.DbAddress)
|
address := viper.GetString(keys.DbAddress)
|
||||||
if address == "" {
|
|
||||||
return nil, errors.New("no address set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate username
|
|
||||||
username := viper.GetString(keys.DbUser)
|
username := viper.GetString(keys.DbUser)
|
||||||
if username == "" {
|
|
||||||
return nil, errors.New("no user set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate that there's a password
|
|
||||||
password := viper.GetString(keys.DbPassword)
|
password := viper.GetString(keys.DbPassword)
|
||||||
if password == "" {
|
|
||||||
return nil, errors.New("no password set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate database
|
// validate database
|
||||||
database := viper.GetString(keys.DbDatabase)
|
database := viper.GetString(keys.DbDatabase)
|
||||||
|
@ -363,11 +345,21 @@ func deriveBunDBPGOptions() (*pgx.ConnConfig, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, _ := pgx.ParseConfig("")
|
cfg, _ := pgx.ParseConfig("")
|
||||||
cfg.Host = address
|
if address != "" {
|
||||||
cfg.Port = uint16(port)
|
cfg.Host = address
|
||||||
cfg.User = username
|
}
|
||||||
cfg.Password = password
|
if port > 0 {
|
||||||
cfg.TLSConfig = tlsConfig
|
cfg.Port = uint16(port)
|
||||||
|
}
|
||||||
|
if username != "" {
|
||||||
|
cfg.User = username
|
||||||
|
}
|
||||||
|
if password != "" {
|
||||||
|
cfg.Password = password
|
||||||
|
}
|
||||||
|
if tlsConfig != nil {
|
||||||
|
cfg.TLSConfig = tlsConfig
|
||||||
|
}
|
||||||
cfg.Database = database
|
cfg.Database = database
|
||||||
cfg.PreferSimpleProtocol = true
|
cfg.PreferSimpleProtocol = true
|
||||||
cfg.RuntimeParams["application_name"] = viper.GetString(keys.ApplicationName)
|
cfg.RuntimeParams["application_name"] = viper.GetString(keys.ApplicationName)
|
||||||
|
|
|
@ -5,7 +5,7 @@ set -e
|
||||||
echo "STARTING CLI TESTS"
|
echo "STARTING CLI TESTS"
|
||||||
|
|
||||||
echo "TEST_1 Make sure defaults are set correctly."
|
echo "TEST_1 Make sure defaults are set correctly."
|
||||||
TEST_1_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"localhost","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
TEST_1_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
||||||
TEST_1="$(go run ./cmd/gotosocial/... debug config)"
|
TEST_1="$(go run ./cmd/gotosocial/... debug config)"
|
||||||
if [ "${TEST_1}" != "${TEST_1_EXPECTED}" ]; then
|
if [ "${TEST_1}" != "${TEST_1_EXPECTED}" ]; then
|
||||||
echo "TEST_1 not equal TEST_1_EXPECTED"
|
echo "TEST_1 not equal TEST_1_EXPECTED"
|
||||||
|
@ -15,7 +15,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "TEST_2 Override db-address from default using cli flag."
|
echo "TEST_2 Override db-address from default using cli flag."
|
||||||
TEST_2_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
TEST_2_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
||||||
TEST_2="$(go run ./cmd/gotosocial/... --db-address some.db.address debug config)"
|
TEST_2="$(go run ./cmd/gotosocial/... --db-address some.db.address debug config)"
|
||||||
if [ "${TEST_2}" != "${TEST_2_EXPECTED}" ]; then
|
if [ "${TEST_2}" != "${TEST_2_EXPECTED}" ]; then
|
||||||
echo "TEST_2 not equal TEST_2_EXPECTED"
|
echo "TEST_2 not equal TEST_2_EXPECTED"
|
||||||
|
@ -25,7 +25,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "TEST_3 Override db-address from default using env var."
|
echo "TEST_3 Override db-address from default using env var."
|
||||||
TEST_3_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
TEST_3_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
||||||
TEST_3="$(GTS_DB_ADDRESS=some.db.address go run ./cmd/gotosocial/... debug config)"
|
TEST_3="$(GTS_DB_ADDRESS=some.db.address go run ./cmd/gotosocial/... debug config)"
|
||||||
if [ "${TEST_3}" != "${TEST_3_EXPECTED}" ]; then
|
if [ "${TEST_3}" != "${TEST_3_EXPECTED}" ]; then
|
||||||
echo "TEST_3 not equal TEST_3_EXPECTED"
|
echo "TEST_3 not equal TEST_3_EXPECTED"
|
||||||
|
@ -35,7 +35,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "TEST_4 Override db-address from default using both env var and cli flag. The cli flag should take priority."
|
echo "TEST_4 Override db-address from default using both env var and cli flag. The cli flag should take priority."
|
||||||
TEST_4_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.other.db.address","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
TEST_4_EXPECTED='{"account-domain":"","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"","db-address":"some.other.db.address","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"info","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
||||||
TEST_4="$(GTS_DB_ADDRESS=some.db.address go run ./cmd/gotosocial/... --db-address some.other.db.address debug config)"
|
TEST_4="$(GTS_DB_ADDRESS=some.db.address go run ./cmd/gotosocial/... --db-address some.other.db.address debug config)"
|
||||||
if [ "${TEST_4}" != "${TEST_4_EXPECTED}" ]; then
|
if [ "${TEST_4}" != "${TEST_4_EXPECTED}" ]; then
|
||||||
echo "TEST_4 not equal TEST_4_EXPECTED"
|
echo "TEST_4 not equal TEST_4_EXPECTED"
|
||||||
|
@ -105,7 +105,7 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "TEST_11 Test loading a partial config file. Default values should be used apart from those set in the config file."
|
echo "TEST_11 Test loading a partial config file. Default values should be used apart from those set in the config file."
|
||||||
TEST_11_EXPECTED='{"account-domain":"peepee.poopoo","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test2.yaml","db-address":"localhost","db-database":"postgres","db-password":"postgres","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"postgres","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"trace","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
TEST_11_EXPECTED='{"account-domain":"peepee.poopoo","accounts-approval-required":true,"accounts-reason-required":true,"accounts-registration-open":true,"application-name":"gotosocial","bind-address":"0.0.0.0","config-path":"./test/test2.yaml","db-address":"","db-database":"gotosocial","db-password":"","db-port":5432,"db-tls-ca-cert":"","db-tls-mode":"disable","db-type":"postgres","db-user":"","help":false,"host":"","letsencrypt-cert-dir":"/gotosocial/storage/certs","letsencrypt-email-address":"","letsencrypt-enabled":true,"letsencrypt-port":80,"log-level":"trace","media-description-max-chars":500,"media-description-min-chars":0,"media-image-max-size":2097152,"media-video-max-size":10485760,"oidc-client-id":"","oidc-client-secret":"","oidc-enabled":false,"oidc-idp-name":"","oidc-issuer":"","oidc-scopes":["openid","profile","email","groups"],"oidc-skip-verification":false,"port":8080,"protocol":"https","smtp-from":"GoToSocial","smtp-host":"","smtp-password":"","smtp-port":0,"smtp-username":"","software-version":"","statuses-cw-max-chars":100,"statuses-max-chars":5000,"statuses-media-max-files":6,"statuses-poll-max-options":6,"statuses-poll-option-max-chars":50,"storage-backend":"local","storage-local-base-path":"/gotosocial/storage","syslog-address":"localhost:514","syslog-enabled":false,"syslog-protocol":"udp","trusted-proxies":["127.0.0.1/32"],"web-asset-base-dir":"./web/assets/","web-template-base-dir":"./web/template/"}'
|
||||||
TEST_11="$(go run ./cmd/gotosocial/... --config-path ./test/test2.yaml debug config)"
|
TEST_11="$(go run ./cmd/gotosocial/... --config-path ./test/test2.yaml debug config)"
|
||||||
if [ "${TEST_11}" != "${TEST_11_EXPECTED}" ]; then
|
if [ "${TEST_11}" != "${TEST_11_EXPECTED}" ]; then
|
||||||
echo "TEST_11 not equal TEST_11_EXPECTED"
|
echo "TEST_11 not equal TEST_11_EXPECTED"
|
||||||
|
|
Loading…
Reference in a new issue