datasource/mongo/account.go (161 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package mongo import ( "context" "fmt" "strconv" "time" "github.com/apache/servicecomb-service-center/datasource/rbac" dmongo "github.com/go-chassis/cari/db/mongo" rbacmodel "github.com/go-chassis/cari/rbac" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "github.com/apache/servicecomb-service-center/datasource" "github.com/apache/servicecomb-service-center/datasource/mongo/dao" "github.com/apache/servicecomb-service-center/datasource/mongo/model" "github.com/apache/servicecomb-service-center/datasource/mongo/sync" mutil "github.com/apache/servicecomb-service-center/datasource/mongo/util" "github.com/apache/servicecomb-service-center/pkg/log" ) func init() { rbac.Install("mongo", NewRbacDAO) } func NewRbacDAO(_ rbac.Options) (rbac.DAO, error) { return &RbacDAO{}, nil } type RbacDAO struct { } func (ds *RbacDAO) CreateAccount(ctx context.Context, a *rbacmodel.Account) error { exist, err := ds.AccountExist(ctx, a.Name) if err != nil { msg := fmt.Sprintf("failed to query account, account name %s", a.Name) log.Error(msg, err) return err } if exist { return rbac.ErrAccountDuplicated } err = createAccountTxn(ctx, a) if err != nil { if dao.IsDuplicateKey(err) { return rbac.ErrAccountDuplicated } return err } log.Info("succeed to create new account: " + a.ID) return nil } func createAccountTxn(ctx context.Context, a *rbacmodel.Account) error { return dmongo.GetClient().ExecTxn(ctx, func(sessionContext mongo.SessionContext) error { _, err := dmongo.GetClient().GetDB().Collection(model.CollectionAccount).InsertOne(sessionContext, a) if err != nil { return err } err = sync.DoCreateOpts(sessionContext, datasource.ResourceAccount, a) return err }) } func (ds *RbacDAO) AccountExist(ctx context.Context, name string) (bool, error) { filter := mutil.NewFilter(mutil.AccountName(name)) count, err := dmongo.GetClient().GetDB().Collection(model.CollectionAccount).CountDocuments(ctx, filter) if err != nil { return false, err } if count == 0 { return false, nil } return true, nil } func (ds *RbacDAO) GetAccount(ctx context.Context, name string) (*rbacmodel.Account, error) { filter := mutil.NewFilter(mutil.AccountName(name)) result := dmongo.GetClient().GetDB().Collection(model.CollectionAccount).FindOne(ctx, filter) if err := result.Err(); err != nil { if err == mongo.ErrNoDocuments { return nil, rbac.ErrAccountNotExist } msg := fmt.Sprintf("failed to query account, account name %s", name) log.Error(msg, result.Err()) return nil, rbac.ErrQueryAccountFailed } var account rbacmodel.Account err := result.Decode(&account) if err != nil { log.Error("failed to decode account", err) return nil, err } return &account, nil } func (ds *RbacDAO) ListAccount(ctx context.Context) ([]*rbacmodel.Account, int64, error) { filter := mutil.NewFilter() cursor, err := dmongo.GetClient().GetDB().Collection(model.CollectionAccount).Find(ctx, filter) if err != nil { return nil, 0, err } var accounts []*rbacmodel.Account defer cursor.Close(ctx) for cursor.Next(ctx) { var account rbacmodel.Account err = cursor.Decode(&account) if err != nil { log.Error("failed to decode account", err) continue } account.Password = "" accounts = append(accounts, &account) } return accounts, int64(len(accounts)), nil } func (ds *RbacDAO) DeleteAccount(ctx context.Context, names []string) (bool, error) { if len(names) == 0 { return false, nil } err := deleteAccountTxn(ctx, names, ds) if err != nil { return false, err } return true, nil } func deleteAccountTxn(ctx context.Context, names []string, ds *RbacDAO) error { return dmongo.GetClient().ExecTxn(ctx, func(sessionContext mongo.SessionContext) error { for _, name := range names { account, err := ds.GetAccount(sessionContext, name) if err != nil { return err } err = sync.DoDeleteOpts(sessionContext, datasource.ResourceAccount, account.Name, account) if err != nil { return err } } inFilter := mutil.NewFilter(mutil.In(names)) filter := mutil.NewFilter(mutil.AccountName(inFilter)) _, err := dmongo.GetClient().GetDB().Collection(model.CollectionAccount).DeleteMany(ctx, filter) return err }) } func (ds *RbacDAO) UpdateAccount(ctx context.Context, name string, account *rbacmodel.Account) error { filter := mutil.NewFilter(mutil.AccountName(name)) setFilter := mutil.NewFilter( mutil.ID(account.ID), mutil.Password(account.Password), mutil.Roles(account.Roles), mutil.TokenExpirationTime(account.TokenExpirationTime), mutil.CurrentPassword(account.CurrentPassword), mutil.Status(account.Status), mutil.AccountUpdateTime(strconv.FormatInt(time.Now().Unix(), 10)), ) updateFilter := mutil.NewFilter(mutil.Set(setFilter)) return updateAccountTxn(ctx, filter, updateFilter, account) } func updateAccountTxn(ctx context.Context, filter bson.M, updateFilter bson.M, account *rbacmodel.Account) error { return dmongo.GetClient().ExecTxn(ctx, func(sessionContext mongo.SessionContext) error { res, err := dmongo.GetClient().GetDB().Collection(model.CollectionAccount).UpdateMany(sessionContext, filter, updateFilter) if err != nil { return err } if res.ModifiedCount == 0 { return mutil.ErrNoDataToUpdate } err = sync.DoUpdateOpts(sessionContext, datasource.ResourceAccount, account) return err }) }