229 lines
8.3 KiB
Go
229 lines
8.3 KiB
Go
package accountapiimp
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
chaingatewayclient "github.com/tech/sendico/gateway/chain/client"
|
|
api "github.com/tech/sendico/pkg/api/http"
|
|
"github.com/tech/sendico/pkg/auth"
|
|
"github.com/tech/sendico/pkg/db/account"
|
|
"github.com/tech/sendico/pkg/db/organization"
|
|
"github.com/tech/sendico/pkg/db/policy"
|
|
"github.com/tech/sendico/pkg/db/refreshtokens"
|
|
"github.com/tech/sendico/pkg/db/transaction"
|
|
"github.com/tech/sendico/pkg/domainprovider"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
"github.com/tech/sendico/pkg/messaging"
|
|
"github.com/tech/sendico/pkg/mlogger"
|
|
"github.com/tech/sendico/pkg/mservice"
|
|
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
|
"github.com/tech/sendico/server/interface/accountservice"
|
|
eapi "github.com/tech/sendico/server/interface/api"
|
|
"github.com/tech/sendico/server/interface/services/fileservice"
|
|
mutil "github.com/tech/sendico/server/internal/mutil/param"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type AccountAPI struct {
|
|
logger mlogger.Logger
|
|
db account.DB
|
|
odb organization.DB
|
|
tf transaction.Factory
|
|
rtdb refreshtokens.DB
|
|
plcdb policy.DB
|
|
domain domainprovider.DomainProvider
|
|
avatars mservice.MicroService
|
|
producer messaging.Producer
|
|
pmanager auth.Manager
|
|
enf auth.Enforcer
|
|
oph mutil.ParamHelper
|
|
aph mutil.ParamHelper
|
|
tph mutil.ParamHelper
|
|
accountsPermissionRef primitive.ObjectID
|
|
accService accountservice.AccountService
|
|
chainGateway chainWalletClient
|
|
chainAsset *chainv1.Asset
|
|
}
|
|
|
|
type chainWalletClient interface {
|
|
CreateManagedWallet(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error)
|
|
Close() error
|
|
}
|
|
|
|
func (a *AccountAPI) Name() mservice.Type {
|
|
return mservice.Accounts
|
|
}
|
|
|
|
func (a *AccountAPI) Finish(ctx context.Context) error {
|
|
if err := a.avatars.Finish(ctx); err != nil {
|
|
return err
|
|
}
|
|
if a.chainGateway != nil {
|
|
if err := a.chainGateway.Close(); err != nil {
|
|
a.logger.Warn("Failed to close chain gateway client", zap.Error(err))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func CreateAPI(a eapi.API) (*AccountAPI, error) {
|
|
p := new(AccountAPI)
|
|
p.logger = a.Logger().Named(p.Name())
|
|
var err error
|
|
if p.db, err = a.DBFactory().NewAccountDB(); err != nil {
|
|
p.logger.Error("Failed to create accounts database", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
if p.rtdb, err = a.DBFactory().NewRefreshTokensDB(); err != nil {
|
|
p.logger.Error("Failed to create refresh tokens database", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
if p.odb, err = a.DBFactory().NewOrganizationDB(); err != nil {
|
|
p.logger.Error("Failed to create organizations database", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
if p.plcdb, err = a.DBFactory().NewPoliciesDB(); err != nil {
|
|
p.logger.Error("Failed to create policies database", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
p.domain = a.DomainProvider()
|
|
p.producer = a.Register().Messaging().Producer()
|
|
p.tf = a.DBFactory().TransactionFactory()
|
|
p.pmanager = a.Permissions().Manager()
|
|
p.enf = a.Permissions().Enforcer()
|
|
p.oph = mutil.CreatePH(mservice.Organizations)
|
|
p.aph = mutil.CreatePH(mservice.Accounts)
|
|
p.tph = mutil.CreatePH("token")
|
|
|
|
if p.accService, err = accountservice.NewAccountService(p.logger, a.DBFactory(), p.enf, p.pmanager.Role(), &a.Config().Mw.Password); err != nil {
|
|
p.logger.Error("Failed to create account manager", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Account related api endpoints
|
|
a.Register().Handler(mservice.Accounts, "/signup", api.Post, p.signup)
|
|
a.Register().Handler(mservice.Accounts, "/signup/availability", api.Get, p.signupAvailability)
|
|
|
|
a.Register().AccountHandler(mservice.Accounts, "", api.Put, p.updateProfile)
|
|
a.Register().AccountHandler(mservice.Accounts, "", api.Get, p.getProfile)
|
|
|
|
a.Register().AccountHandler(mservice.Accounts, p.oph.AddRef("/employee"), api.Put, p.updateEmployee)
|
|
|
|
a.Register().AccountHandler(mservice.Accounts, "/dzone", api.Get, p.dzone)
|
|
a.Register().AccountHandler(mservice.Accounts, p.oph.AddRef("/profile"), api.Delete, p.deleteProfile)
|
|
a.Register().AccountHandler(mservice.Accounts, p.oph.AddRef("/organization"), api.Delete, p.deleteOrganization)
|
|
a.Register().AccountHandler(mservice.Accounts, p.oph.AddRef("/all"), api.Delete, p.deleteAll)
|
|
|
|
a.Register().AccountHandler(mservice.Accounts, p.oph.AddRef("/list"), api.Get, p.getEmployees)
|
|
|
|
a.Register().AccountHandler(mservice.Accounts, "/password", api.Post, p.checkPassword)
|
|
a.Register().AccountHandler(mservice.Accounts, "/password", api.Patch, p.changePassword)
|
|
a.Register().Handler(mservice.Accounts, "/password", api.Put, p.forgotPassword)
|
|
a.Register().Handler(mservice.Accounts, p.tph.AddRef(p.aph.AddRef("/password/reset")), api.Post, p.resetPassword)
|
|
|
|
a.Register().Handler(mservice.Accounts, mutil.AddToken("/verify"), api.Get, p.verify)
|
|
a.Register().Handler(mservice.Accounts, "/email", api.Post, p.resendVerificationMail)
|
|
a.Register().Handler(mservice.Accounts, "/email", api.Put, p.resendVerification)
|
|
|
|
if p.avatars, err = fileservice.CreateAPI(a, p.Name()); err != nil {
|
|
p.logger.Error("Failed to create image server", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
accountsPolicy, err := a.Permissions().GetPolicyDescription(context.Background(), mservice.Accounts)
|
|
if err != nil {
|
|
p.logger.Warn("Failed to fetch account permission policy description", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
p.accountsPermissionRef = accountsPolicy.ID
|
|
|
|
cfg := a.Config()
|
|
if cfg == nil {
|
|
p.logger.Error("Failed to fetch service configuration")
|
|
return nil, merrors.InvalidArgument("No configuration provided")
|
|
}
|
|
if err := p.initChainGateway(cfg.ChainGateway); err != nil {
|
|
p.logger.Error("Failed to initialize chain gateway client", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
func (a *AccountAPI) initChainGateway(cfg *eapi.ChainGatewayConfig) error {
|
|
if cfg == nil {
|
|
return merrors.InvalidArgument("chain gateway configuration is not provided")
|
|
}
|
|
|
|
cfg.Address = strings.TrimSpace(cfg.Address)
|
|
if cfg.Address == "" {
|
|
cfg.Address = strings.TrimSpace(os.Getenv(cfg.AddressEnv))
|
|
}
|
|
if cfg.Address == "" {
|
|
return merrors.InvalidArgument(fmt.Sprintf("chain gateway address is not specified and address env %s is empty", cfg.AddressEnv))
|
|
}
|
|
|
|
clientCfg := chaingatewayclient.Config{
|
|
Address: cfg.Address,
|
|
DialTimeout: time.Duration(cfg.DialTimeoutSeconds) * time.Second,
|
|
CallTimeout: time.Duration(cfg.CallTimeoutSeconds) * time.Second,
|
|
Insecure: cfg.Insecure,
|
|
}
|
|
|
|
client, err := chaingatewayclient.New(context.Background(), clientCfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
asset, err := buildGatewayAsset(cfg.DefaultAsset)
|
|
if err != nil {
|
|
_ = client.Close()
|
|
return err
|
|
}
|
|
|
|
a.chainGateway = client
|
|
a.chainAsset = asset
|
|
return nil
|
|
}
|
|
|
|
func buildGatewayAsset(cfg eapi.ChainGatewayAssetConfig) (*chainv1.Asset, error) {
|
|
chain, err := parseChainNetwork(cfg.Chain)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tokenSymbol := strings.TrimSpace(cfg.TokenSymbol)
|
|
if tokenSymbol == "" {
|
|
return nil, merrors.InvalidArgument("chain gateway token symbol is required")
|
|
}
|
|
return &chainv1.Asset{
|
|
Chain: chain,
|
|
TokenSymbol: strings.ToUpper(tokenSymbol),
|
|
ContractAddress: strings.ToLower(strings.TrimSpace(cfg.ContractAddress)),
|
|
}, nil
|
|
}
|
|
|
|
func parseChainNetwork(value string) (chainv1.ChainNetwork, error) {
|
|
switch strings.ToUpper(strings.TrimSpace(value)) {
|
|
case "ETHEREUM_MAINNET", "CHAIN_NETWORK_ETHEREUM_MAINNET":
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, nil
|
|
case "ARBITRUM_ONE", "CHAIN_NETWORK_ARBITRUM_ONE":
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil
|
|
case "OTHER_EVM", "CHAIN_NETWORK_OTHER_EVM":
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil
|
|
case "TRON_MAINNET", "CHAIN_NETWORK_TRON_MAINNET":
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_MAINNET, nil
|
|
case "TRON_NILE", "CHAIN_NETWORK_TRON_NILE":
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_TRON_NILE, nil
|
|
case "", "CHAIN_NETWORK_UNSPECIFIED":
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("chain network must be specified")
|
|
default:
|
|
return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument(fmt.Sprintf("unsupported chain network %s", value))
|
|
}
|
|
}
|