fix: translation (#647)

* fix: translation

* fix: translation

* fix: translation

* fix: remove unused code

* fix: log err
This commit is contained in:
Fabi 2020-08-28 09:44:43 +02:00 committed by GitHub
parent 34ec2508d3
commit 7295383621
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 184 additions and 104 deletions

View File

@ -43,7 +43,7 @@ func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *Tok
} }
} }
userID, clientID, agentID, err := verifyAccessToken(ctx, token, t, method) userID, clientID, agentID, prefLang, err := verifyAccessToken(ctx, token, t, method)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -54,7 +54,7 @@ func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *Tok
if err := checkOrigin(ctx, origins); err != nil { if err := checkOrigin(ctx, origins); err != nil {
return nil, err return nil, err
} }
return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID}), nil return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID, PreferredLanguage: prefLang}), nil
} }
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context { func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {

View File

@ -15,8 +15,8 @@ type testVerifier struct {
grant *Grant grant *Grant
} }
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, error) { func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) {
return "userID", "agentID", nil return "userID", "agentID", "de", nil
} }
func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) { func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) {

View File

@ -19,7 +19,7 @@ type TokenVerifier struct {
} }
type authZRepo interface { type authZRepo interface {
VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID string, err error) VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang string, err error)
VerifierClientID(ctx context.Context, name string) (clientID string, err error) VerifierClientID(ctx context.Context, name string) (clientID string, err error)
ResolveGrants(ctx context.Context) (grant *Grant, err error) ResolveGrants(ctx context.Context) (grant *Grant, err error)
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
@ -30,13 +30,13 @@ func Start(authZRepo authZRepo) (v *TokenVerifier) {
return &TokenVerifier{authZRepo: authZRepo} return &TokenVerifier{authZRepo: authZRepo}
} }
func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID string, err error) { func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID, prefLang string, err error) {
clientID, err = v.clientIDFromMethod(ctx, method) clientID, err = v.clientIDFromMethod(ctx, method)
if err != nil { if err != nil {
return "", "", "", err return "", "", "", "", err
} }
userID, agentID, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID) userID, agentID, prefLang, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID)
return userID, clientID, agentID, err return userID, clientID, agentID, prefLang, err
} }
type client struct { type client struct {
@ -101,10 +101,10 @@ func (v *TokenVerifier) CheckAuthMethod(method string) (Option, bool) {
return authOpt, ok return authOpt, ok
} }
func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID string, err error) { func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID, prefLang string, err error) {
parts := strings.Split(token, BearerPrefix) parts := strings.Split(token, BearerPrefix)
if len(parts) != 2 { if len(parts) != 2 {
return "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header") return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header")
} }
return t.VerifyAccessToken(ctx, parts[1], method) return t.VerifyAccessToken(ctx, parts[1], method)
} }

View File

@ -58,7 +58,7 @@ func Test_VerifyAccessToken(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
_, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method) _, _, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method)
if tt.wantErr && err == nil { if tt.wantErr && err == nil {
t.Errorf("got wrong result, should get err: actual: %v ", err) t.Errorf("got wrong result, should get err: actual: %v ", err)
} }

View File

@ -1,16 +1,15 @@
package grpc package errors
import ( import (
"context" "context"
"github.com/caos/logging" "github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/pkg/grpc/message" "github.com/caos/zitadel/pkg/grpc/message"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
) )
func CaosToGRPCError(ctx context.Context, err error, translator *i18n.Translator) error { func CaosToGRPCError(ctx context.Context, err error) error {
if err == nil { if err == nil {
return nil return nil
} }
@ -19,10 +18,8 @@ func CaosToGRPCError(ctx context.Context, err error, translator *i18n.Translator
return status.Convert(err).Err() return status.Convert(err).Err()
} }
msg := key msg := key
if translator != nil {
msg = translator.LocalizeFromCtx(ctx, key, nil)
msg += " (" + id + ")" msg += " (" + id + ")"
}
s, err := status.New(code, msg).WithDetails(&message.ErrorDetail{Id: id, Message: key}) s, err := status.New(code, msg).WithDetails(&message.ErrorDetail{Id: id, Message: key})
if err != nil { if err != nil {
logging.Log("GRPC-gIeRw").WithError(err).Debug("unable to add detail") logging.Log("GRPC-gIeRw").WithError(err).Debug("unable to add detail")

View File

@ -1,4 +1,4 @@
package grpc package errors
import ( import (
"context" "context"
@ -8,13 +8,11 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n"
) )
func TestCaosToGRPCError(t *testing.T) { func TestCaosToGRPCError(t *testing.T) {
type args struct { type args struct {
err error err error
translator *i18n.Translator
} }
tests := []struct { tests := []struct {
name string name string
@ -28,18 +26,18 @@ func TestCaosToGRPCError(t *testing.T) {
}, },
{ {
"unknown error", "unknown error",
args{errors.New("unknown"), nil}, args{errors.New("unknown")},
true, true,
}, },
{ {
"caos error", "caos error",
args{caos_errs.ThrowInternal(nil, "", "message"), nil}, args{caos_errs.ThrowInternal(nil, "", "message")},
true, true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := CaosToGRPCError(context.Background(), tt.args.err, tt.args.translator); (err != nil) != tt.wantErr { if err := CaosToGRPCError(context.Background(), tt.args.err); (err != nil) != tt.wantErr {
t.Errorf("CaosToGRPCError() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("CaosToGRPCError() error = %v, wantErr %v", err, tt.wantErr)
} }
}) })

View File

@ -21,8 +21,8 @@ var (
type verifierMock struct{} type verifierMock struct{}
func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, error) { func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) {
return "", "", nil return "", "", "", nil
} }
func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) { func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) {
return nil, nil return nil, nil

View File

@ -2,24 +2,20 @@ package middleware
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/api/grpc/errors"
"golang.org/x/text/language"
"google.golang.org/grpc" "google.golang.org/grpc"
grpc_util "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/i18n"
_ "github.com/caos/zitadel/internal/statik" _ "github.com/caos/zitadel/internal/statik"
) )
func ErrorHandler(defaultLanguage language.Tag) grpc.UnaryServerInterceptor { func ErrorHandler() grpc.UnaryServerInterceptor {
translator := newZitadelTranslator(defaultLanguage)
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
return toGRPCError(ctx, req, handler, translator) return toGRPCError(ctx, req, handler)
} }
} }
func toGRPCError(ctx context.Context, req interface{}, handler grpc.UnaryHandler, translator *i18n.Translator) (interface{}, error) { func toGRPCError(ctx context.Context, req interface{}, handler grpc.UnaryHandler) (interface{}, error) {
resp, err := handler(ctx, req) resp, err := handler(ctx, req)
return resp, grpc_util.CaosToGRPCError(ctx, err, translator) return resp, errors.CaosToGRPCError(ctx, err)
} }

View File

@ -50,7 +50,7 @@ func Test_toGRPCError(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
got, err := toGRPCError(tt.args.ctx, tt.args.req, tt.args.handler, nil) got, err := toGRPCError(tt.args.ctx, tt.args.req, tt.args.handler)
if (err != nil) != tt.res.wantErr { if (err != nil) != tt.res.wantErr {
t.Errorf("toGRPCError() error = %v, wantErr %v", err, tt.res.wantErr) t.Errorf("toGRPCError() error = %v, wantErr %v", err, tt.res.wantErr)
return return

View File

@ -18,6 +18,9 @@ func TranslationHandler(defaultLanguage language.Tag) func(ctx context.Context,
if loc, ok := resp.(localizers); ok && resp != nil { if loc, ok := resp.(localizers); ok && resp != nil {
translateFields(ctx, loc, translator) translateFields(ctx, loc, translator)
} }
if err != nil {
err = translateError(ctx, err, translator)
}
return resp, err return resp, err
} }
} }

View File

@ -2,6 +2,8 @@ package middleware
import ( import (
"context" "context"
"errors"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/i18n" "github.com/caos/zitadel/internal/i18n"
@ -26,6 +28,17 @@ func translateFields(ctx context.Context, object localizers, translator *i18n.Tr
} }
} }
func translateError(ctx context.Context, err error, translator *i18n.Translator) error {
if translator == nil || err == nil {
return err
}
caosErr := new(caos_errs.CaosError)
if errors.As(err, &caosErr) {
caosErr.SetMessage(translator.LocalizeFromCtx(ctx, caosErr.GetMessage(), nil))
}
return caosErr
}
func newZitadelTranslator(defaultLanguage language.Tag) *i18n.Translator { func newZitadelTranslator(defaultLanguage language.Tag) *i18n.Translator {
return translatorFromNamespace("zitadel", defaultLanguage) return translatorFromNamespace("zitadel", defaultLanguage)
} }

View File

@ -30,14 +30,13 @@ func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, lang l
middleware.TracingStatsServer(http.Healthz, http.Readiness, http.Validation), middleware.TracingStatsServer(http.Healthz, http.Readiness, http.Validation),
grpc.UnaryInterceptor( grpc.UnaryInterceptor(
grpc_middleware.ChainUnaryServer( grpc_middleware.ChainUnaryServer(
middleware.ErrorHandler(lang), middleware.ErrorHandler(),
middleware.TranslationHandler(lang),
grpc_middleware.ChainUnaryServer(
middleware.AuthorizationInterceptor(verifier, authConfig), middleware.AuthorizationInterceptor(verifier, authConfig),
), middleware.TranslationHandler(lang),
), ),
), ),
) )
} }
func Serve(ctx context.Context, server *grpc.Server, port string) { func Serve(ctx context.Context, server *grpc.Server, port string) {

View File

@ -2,6 +2,8 @@ package oidc
import ( import (
"context" "context"
"github.com/caos/logging"
"golang.org/x/text/language"
"github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/oidc"
"github.com/caos/oidc/pkg/op" "github.com/caos/oidc/pkg/op"
@ -78,6 +80,8 @@ func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, sc
userInfo.PreferredUsername = user.PreferredLoginName userInfo.PreferredUsername = user.PreferredLoginName
userInfo.UpdatedAt = user.ChangeDate userInfo.UpdatedAt = user.ChangeDate
userInfo.Gender = oidc.Gender(getGender(user.Gender)) userInfo.Gender = oidc.Gender(getGender(user.Gender))
userInfo.Locale, err = language.Parse(user.PreferredLanguage)
logging.Log("OIDC-4ks9F").OnError(err).Debug("unable to parse locale")
case scopePhone: case scopePhone:
userInfo.PhoneNumber = user.Phone userInfo.PhoneNumber = user.Phone
userInfo.PhoneNumberVerified = user.IsPhoneVerified userInfo.PhoneNumberVerified = user.IsPhoneVerified

View File

@ -14,7 +14,12 @@ type TokenRepo struct {
} }
func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*token_model.Token, error) { func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*token_model.Token, error) {
token, err := repo.View.CreateToken(agentID, applicationID, userID, audience, scopes, lifetime) preferredLanguage := ""
user, _ := repo.View.UserByID(userID)
if user != nil {
preferredLanguage = user.PreferredLanguage
}
token, err := repo.View.CreateToken(agentID, applicationID, userID, preferredLanguage, audience, scopes, lifetime)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,6 +3,7 @@ package handler
import ( import (
"context" "context"
"encoding/json" "encoding/json"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/logging" "github.com/caos/logging"
@ -43,6 +44,17 @@ func (u *Token) EventQuery() (*models.SearchQuery, error) {
func (u *Token) Reduce(event *models.Event) (err error) { func (u *Token) Reduce(event *models.Event) (err error) {
switch event.Type { switch event.Type {
case user_es_model.UserProfileChanged:
user := new(view_model.UserView)
user.AppendEvent(event)
tokens, err := u.view.TokensByUserID(event.AggregateID)
if err != nil {
return err
}
for _, token := range tokens {
token.PreferredLanguage = user.PreferredLanguage
}
return u.view.PutTokens(tokens, event.Sequence)
case user_es_model.SignedOut: case user_es_model.SignedOut:
id, err := agentIDFromSession(event) id, err := agentIDFromSession(event)
if err != nil { if err != nil {

View File

@ -16,11 +16,15 @@ func (v *View) TokenByID(tokenID string) (*model.Token, error) {
return view.TokenByID(v.Db, tokenTable, tokenID) return view.TokenByID(v.Db, tokenTable, tokenID)
} }
func (v *View) TokensByUserID(userID string) ([]*model.Token, error) {
return view.TokensByUserID(v.Db, tokenTable, userID)
}
func (v *View) IsTokenValid(tokenID string) (bool, error) { func (v *View) IsTokenValid(tokenID string) (bool, error) {
return view.IsTokenValid(v.Db, tokenTable, tokenID) return view.IsTokenValid(v.Db, tokenTable, tokenID)
} }
func (v *View) CreateToken(agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) { func (v *View) CreateToken(agentID, applicationID, userID, preferredLanguage string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) {
id, err := v.idGenerator.Next() id, err := v.idGenerator.Next()
if err != nil { if err != nil {
return nil, err return nil, err
@ -35,6 +39,7 @@ func (v *View) CreateToken(agentID, applicationID, userID string, audience, scop
Scopes: scopes, Scopes: scopes,
Audience: audience, Audience: audience,
Expiration: now.Add(lifetime), Expiration: now.Add(lifetime),
PreferredLanguage: preferredLanguage,
} }
if err := view.PutToken(v.Db, tokenTable, token); err != nil { if err := view.PutToken(v.Db, tokenTable, token); err != nil {
return nil, err return nil, err
@ -50,6 +55,14 @@ func (v *View) PutToken(token *model.Token) error {
return v.ProcessedTokenSequence(token.Sequence) return v.ProcessedTokenSequence(token.Sequence)
} }
func (v *View) PutTokens(token []*model.Token, sequence uint64) error {
err := view.PutTokens(v.Db, tokenTable, token...)
if err != nil {
return err
}
return v.ProcessedTokenSequence(sequence)
}
func (v *View) DeleteToken(tokenID string, eventSequence uint64) error { func (v *View) DeleteToken(tokenID string, eventSequence uint64) error {
err := view.DeleteToken(v.Db, tokenTable, tokenID) err := view.DeleteToken(v.Db, tokenTable, tokenID)
if err != nil { if err != nil {

View File

@ -19,26 +19,26 @@ type TokenVerifierRepo struct {
View *view.View View *view.View
} }
func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, err error) { func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, prefLang string, err error) {
//TODO: use real key //TODO: use real key
tokenID, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32])) tokenID, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32]))
if err != nil { if err != nil {
return "", "", caos_errs.ThrowUnauthenticated(nil, "APP-8EF0zZ", "invalid token") return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-8EF0zZ", "invalid token")
} }
token, err := repo.View.TokenByID(tokenID) token, err := repo.View.TokenByID(tokenID)
if err != nil { if err != nil {
return "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token") return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token")
} }
if !token.Expiration.After(time.Now().UTC()) { if !token.Expiration.After(time.Now().UTC()) {
return "", "", caos_errs.ThrowUnauthenticated(err, "APP-k9KS0", "invalid token") return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-k9KS0", "invalid token")
} }
for _, aud := range token.Audience { for _, aud := range token.Audience {
if clientID == aud { if clientID == aud {
return token.UserID, token.UserAgentID, nil return token.UserID, token.UserAgentID, token.PreferredLanguage, nil
} }
} }
return "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience") return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience")
} }
func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) { func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) {

View File

@ -44,6 +44,10 @@ func (err *CaosError) GetMessage() string {
return err.Message return err.Message
} }
func (err *CaosError) SetMessage(msg string) {
err.Message = msg
}
func (err *CaosError) GetID() string { func (err *CaosError) GetID() string {
return err.ID return err.ID
} }

View File

@ -9,6 +9,7 @@ import (
type Error interface { type Error interface {
GetParent() error GetParent() error
GetMessage() string GetMessage() string
SetMessage(string)
GetID() string GetID() string
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/caos/zitadel/internal/api/authz"
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils" "github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -130,6 +131,10 @@ func (t *Translator) langsFromRequest(r *http.Request) []string {
func (t *Translator) langsFromCtx(ctx context.Context) []string { func (t *Translator) langsFromCtx(ctx context.Context) []string {
langs := make([]string, 0) langs := make([]string, 0)
if ctx != nil { if ctx != nil {
ctxData := authz.GetCtxData(ctx)
if ctxData.PreferredLanguage != "" {
langs = append(langs, authz.GetCtxData(ctx).PreferredLanguage)
}
langs = append(langs, getAcceptLanguageHeader(ctx)) langs = append(langs, getAcceptLanguageHeader(ctx))
} }
return langs return langs

View File

@ -18,6 +18,7 @@ type Token struct {
Expiration time.Time Expiration time.Time
Scopes []string Scopes []string
Sequence uint64 Sequence uint64
PreferredLanguage string
} }
type TokenSearchRequest struct { type TokenSearchRequest struct {

View File

@ -29,6 +29,7 @@ type Token struct {
Scopes pq.StringArray `json:"-" gorm:"column:scopes"` Scopes pq.StringArray `json:"-" gorm:"column:scopes"`
Expiration time.Time `json:"-" gorm:"column:expiration"` Expiration time.Time `json:"-" gorm:"column:expiration"`
Sequence uint64 `json:"-" gorm:"column:sequence"` Sequence uint64 `json:"-" gorm:"column:sequence"`
PreferredLanguage string `json:"-" gorm:"column:preferred_language"`
} }
func TokenFromModel(token *model.Token) *Token { func TokenFromModel(token *model.Token) *Token {
@ -44,6 +45,7 @@ func TokenFromModel(token *model.Token) *Token {
Scopes: token.Scopes, Scopes: token.Scopes,
Expiration: token.Expiration, Expiration: token.Expiration,
Sequence: token.Sequence, Sequence: token.Sequence,
PreferredLanguage: token.PreferredLanguage,
} }
} }
@ -60,5 +62,6 @@ func TokenToModel(token *Token) *model.Token {
Scopes: token.Scopes, Scopes: token.Scopes,
Expiration: token.Expiration, Expiration: token.Expiration,
Sequence: token.Sequence, Sequence: token.Sequence,
PreferredLanguage: token.PreferredLanguage,
} }
} }

View File

@ -1,6 +1,7 @@
package view package view
import ( import (
global_model "github.com/caos/zitadel/internal/model"
"time" "time"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
@ -22,6 +23,20 @@ func TokenByID(db *gorm.DB, table, tokenID string) (*model.Token, error) {
return token, err return token, err
} }
func TokensByUserID(db *gorm.DB, table, userID string) ([]*model.Token, error) {
tokens := make([]*model.Token, 0)
userIDQuery := &token_model.TokenSearchQuery{
Key: token_model.TokenSearchKeyUserID,
Method: global_model.SearchMethodEquals,
Value: userID,
}
query := repository.PrepareSearchQuery(table, model.TokenSearchRequest{
Queries: []*token_model.TokenSearchQuery{userIDQuery},
})
_, err := query(db, &tokens)
return tokens, err
}
func IsTokenValid(db *gorm.DB, table, tokenID string) (bool, error) { func IsTokenValid(db *gorm.DB, table, tokenID string) (bool, error) {
token, err := TokenByID(db, table, tokenID) token, err := TokenByID(db, table, tokenID)
if err == nil { if err == nil {
@ -38,6 +53,15 @@ func PutToken(db *gorm.DB, table string, token *model.Token) error {
return save(db, token) return save(db, token)
} }
func PutTokens(db *gorm.DB, table string, tokens ...*model.Token) error {
save := repository.PrepareBulkSave(table)
t := make([]interface{}, len(tokens))
for i, token := range tokens {
t[i] = token
}
return save(db, t...)
}
func DeleteToken(db *gorm.DB, table, tokenID string) error { func DeleteToken(db *gorm.DB, table, tokenID string) error {
delete := repository.PrepareDeleteByKey(table, model.TokenSearchKey(token_model.TokenSearchKeyTokenID), tokenID) delete := repository.PrepareDeleteByKey(table, model.TokenSearchKey(token_model.TokenSearchKeyTokenID), tokenID)
return delete(db) return delete(db)

View File

@ -2,11 +2,11 @@ package tracing
import ( import (
"fmt" "fmt"
errors2 "github.com/caos/zitadel/internal/api/grpc/errors"
"strconv" "strconv"
"go.opencensus.io/trace" "go.opencensus.io/trace"
"github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
) )
@ -40,7 +40,7 @@ func (s *Span) SetStatusByError(err error) {
} }
func statusFromError(err error) trace.Status { func statusFromError(err error) trace.Status {
code, msg, _, _ := grpc.ExtractCaosError(err) code, msg, _, _ := errors2.ExtractCaosError(err)
return trace.Status{Code: int32(code), Message: msg} return trace.Status{Code: int32(code), Message: msg}
} }

View File

@ -0,0 +1,2 @@
ALTER TABLE auth.tokens ADD COLUMN preferred_language TEXT;