| /* |
| * 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 |
| }) |
| } |