mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-01-18 15:36:27 +00:00
invite join implemented
This commit is contained in:
parent
c3854a7606
commit
4b85cdf811
@ -384,7 +384,7 @@ curl --request POST \
|
|||||||
Response:
|
Response:
|
||||||
``` json
|
``` json
|
||||||
{
|
{
|
||||||
"Ok": true
|
"ok": true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -475,15 +475,43 @@ curl --request GET \
|
|||||||
--url http://localhost:8081/invite/YR9vO4ZXYTgtIyi4aScsi6UZr0vNS74x9b8Y8SKF84g=
|
--url http://localhost:8081/invite/YR9vO4ZXYTgtIyi4aScsi6UZr0vNS74x9b8Y8SKF84g=
|
||||||
```
|
```
|
||||||
Response:
|
Response:
|
||||||
```bash
|
```json
|
||||||
{
|
{
|
||||||
"Ok": true
|
"ok": true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## POST **/invite/{hash}/join**
|
## POST **/invite/{hash}/join**
|
||||||
Join with invite link
|
Join with invite link
|
||||||
// todo
|
### Request body
|
||||||
|
name (string)
|
||||||
|
credentials (email, phone, telegram) (optional, string)
|
||||||
|
mnemonic (string)
|
||||||
|
### Example
|
||||||
|
Request:
|
||||||
|
```bash
|
||||||
|
curl --request POST \
|
||||||
|
--url 'http://localhost:8081/invite/RYPJ9HZfIM5vlRdaNhiDMsaVDPvQxylGVk$ZOaVFqyM=/join' \
|
||||||
|
--header 'content-type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"name": "ower",
|
||||||
|
"credentals": {
|
||||||
|
"email": "ower@gmail.com",
|
||||||
|
"phone": "+79999999999",
|
||||||
|
"telegram": "@ower"
|
||||||
|
},
|
||||||
|
"mnemonic": "short orient camp maple lend pole balance token pledge fat analyst badge art happy property"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTY5MTgzMzk5OTEsInVpZCI6IjAxOGZiYjI4LTZkODgtNzg2NC04OWMxLTYzODYxNzU3NmFhNiJ9.zobQ9AAEUEHPz2BoetdtZDm5AfgUPCyCVS0JYNEYj5c",
|
||||||
|
"token_expired_at": 1716918339991,
|
||||||
|
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTczNTAzMzk5OTEsInJ0X2hhc2giOiJzQStTZW42WDFUOVNVOGl1eVFhTy9sejJLSHNBMkpHcnlURDRHR3JQcTg1QUtLTE9XSWc0VTVEcFpXcjkvR1pqaDBGWGkvdWJYdHpIRzRCcUswV09jZz09IiwidWlkIjoiMDE4ZmJiMjgtNmQ4OC03ODY0LTg5YzEtNjM4NjE3NTc2YWE2In0.D0ZAHcJGH0Ga_nXLZojLBW8cMgTf8kNhcQbFVfKrGWs",
|
||||||
|
"refresh_token_expired_at": 1717350339991
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## POST **/organizations/{organization_id}/participants/invite**
|
## POST **/organizations/{organization_id}/participants/invite**
|
||||||
Create new invite link
|
Create new invite link
|
||||||
@ -495,7 +523,6 @@ Request:
|
|||||||
curl --request POST \
|
curl --request POST \
|
||||||
--url http://localhost:8081/organizations/018fb246-1616-7f1b-9fe2-1a3202224695/participants/invite \
|
--url http://localhost:8081/organizations/018fb246-1616-7f1b-9fe2-1a3202224695/participants/invite \
|
||||||
--header 'Authorization: Bearer token' \
|
--header 'Authorization: Bearer token' \
|
||||||
--header 'X-Seed: a b c 1 2 3' \
|
|
||||||
--header 'accept: application/json' \
|
--header 'accept: application/json' \
|
||||||
--header 'content-type: application/json' \
|
--header 'content-type: application/json' \
|
||||||
--data '{}'
|
--data '{}'
|
||||||
|
@ -69,6 +69,7 @@ func provideAuthController(
|
|||||||
authPresenter presenters.AuthPresenter,
|
authPresenter presenters.AuthPresenter,
|
||||||
jwtInteractor jwt.JWTInteractor,
|
jwtInteractor jwt.JWTInteractor,
|
||||||
repo auth.Repository,
|
repo auth.Repository,
|
||||||
|
orgInteractor organizations.OrganizationsInteractor,
|
||||||
) controllers.AuthController {
|
) controllers.AuthController {
|
||||||
return controllers.NewAuthController(
|
return controllers.NewAuthController(
|
||||||
log.WithGroup("auth-controller"),
|
log.WithGroup("auth-controller"),
|
||||||
@ -76,6 +77,7 @@ func provideAuthController(
|
|||||||
usersInteractor,
|
usersInteractor,
|
||||||
jwtInteractor,
|
jwtInteractor,
|
||||||
repo,
|
repo,
|
||||||
|
orgInteractor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +28,10 @@ func ProvideService(c config.Config) (service.Service, func(), error) {
|
|||||||
authRepository := provideAuthRepository(db)
|
authRepository := provideAuthRepository(db)
|
||||||
jwtInteractor := provideJWTInteractor(c, usersInteractor, authRepository)
|
jwtInteractor := provideJWTInteractor(c, usersInteractor, authRepository)
|
||||||
authPresenter := provideAuthPresenter(jwtInteractor)
|
authPresenter := provideAuthPresenter(jwtInteractor)
|
||||||
authController := provideAuthController(logger, usersInteractor, authPresenter, jwtInteractor, authRepository)
|
|
||||||
client, cleanup2 := provideRedisConnection(c)
|
client, cleanup2 := provideRedisConnection(c)
|
||||||
cache := provideRedisCache(client, logger)
|
cache := provideRedisCache(client, logger)
|
||||||
organizationsInteractor := provideOrganizationsInteractor(logger, organizationsRepository, cache)
|
organizationsInteractor := provideOrganizationsInteractor(logger, organizationsRepository, cache)
|
||||||
|
authController := provideAuthController(logger, usersInteractor, authPresenter, jwtInteractor, authRepository, organizationsInteractor)
|
||||||
organizationsPresenter := provideOrganizationsPresenter()
|
organizationsPresenter := provideOrganizationsPresenter()
|
||||||
organizationsController := provideOrganizationsController(logger, organizationsInteractor, organizationsPresenter)
|
organizationsController := provideOrganizationsController(logger, organizationsInteractor, organizationsPresenter)
|
||||||
transactionsInteractor := provideTxInteractor(logger, transactionsRepository, organizationsInteractor)
|
transactionsInteractor := provideTxInteractor(logger, transactionsRepository, organizationsInteractor)
|
||||||
|
@ -17,8 +17,10 @@ import (
|
|||||||
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
"github.com/emochka2007/block-accounting/internal/pkg/ctxmeta"
|
||||||
"github.com/emochka2007/block-accounting/internal/pkg/hdwallet"
|
"github.com/emochka2007/block-accounting/internal/pkg/hdwallet"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/interactors/jwt"
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/jwt"
|
||||||
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/organizations"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/interactors/users"
|
"github.com/emochka2007/block-accounting/internal/usecase/interactors/users"
|
||||||
"github.com/emochka2007/block-accounting/internal/usecase/repository/auth"
|
"github.com/emochka2007/block-accounting/internal/usecase/repository/auth"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -41,6 +43,7 @@ type authController struct {
|
|||||||
usersInteractor users.UsersInteractor
|
usersInteractor users.UsersInteractor
|
||||||
jwtInteractor jwt.JWTInteractor
|
jwtInteractor jwt.JWTInteractor
|
||||||
repo auth.Repository
|
repo auth.Repository
|
||||||
|
orgInteractor organizations.OrganizationsInteractor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthController(
|
func NewAuthController(
|
||||||
@ -49,6 +52,7 @@ func NewAuthController(
|
|||||||
usersInteractor users.UsersInteractor,
|
usersInteractor users.UsersInteractor,
|
||||||
jwtInteractor jwt.JWTInteractor,
|
jwtInteractor jwt.JWTInteractor,
|
||||||
repo auth.Repository,
|
repo auth.Repository,
|
||||||
|
orgInteractor organizations.OrganizationsInteractor,
|
||||||
) AuthController {
|
) AuthController {
|
||||||
return &authController{
|
return &authController{
|
||||||
log: log,
|
log: log,
|
||||||
@ -56,6 +60,7 @@ func NewAuthController(
|
|||||||
usersInteractor: usersInteractor,
|
usersInteractor: usersInteractor,
|
||||||
jwtInteractor: jwtInteractor,
|
jwtInteractor: jwtInteractor,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
|
orgInteractor: orgInteractor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +86,8 @@ func (c *authController) Join(w http.ResponseWriter, req *http.Request) ([]byte,
|
|||||||
Tg: request.Credentals.Telegram,
|
Tg: request.Credentals.Telegram,
|
||||||
Mnemonic: request.Mnemonic,
|
Mnemonic: request.Mnemonic,
|
||||||
Activate: true,
|
Activate: true,
|
||||||
|
Owner: true,
|
||||||
|
Admin: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error create new user. %w", err)
|
return nil, fmt.Errorf("error create new user. %w", err)
|
||||||
@ -185,7 +192,7 @@ func (c *authController) Invite(w http.ResponseWriter, r *http.Request) ([]byte,
|
|||||||
strings.ReplaceAll(
|
strings.ReplaceAll(
|
||||||
strings.ReplaceAll(
|
strings.ReplaceAll(
|
||||||
base64.StdEncoding.EncodeToString(linkHash.Sum(nil)),
|
base64.StdEncoding.EncodeToString(linkHash.Sum(nil)),
|
||||||
"/", "%",
|
"/", "$",
|
||||||
),
|
),
|
||||||
"?", "@",
|
"?", "@",
|
||||||
),
|
),
|
||||||
@ -217,11 +224,66 @@ func (c *authController) Invite(w http.ResponseWriter, r *http.Request) ([]byte,
|
|||||||
return c.presenter.ResponseNewInvite(ctx, organizationID, linkHashString)
|
return c.presenter.ResponseNewInvite(ctx, organizationID, linkHashString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *authController) JoinWithInvite(w http.ResponseWriter, req *http.Request) ([]byte, error) {
|
func (c *authController) JoinWithInvite(w http.ResponseWriter, r *http.Request) ([]byte, error) {
|
||||||
|
c.log.Debug("join with link request")
|
||||||
|
|
||||||
return nil, nil // implement
|
request, err := presenters.CreateRequest[domain.JoinRequest](r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error create join request. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *authController) InviteGet(w http.ResponseWriter, req *http.Request) ([]byte, error) {
|
c.log.Debug("join with invite request", slog.Any("request", request))
|
||||||
|
|
||||||
|
if !bip39.IsMnemonicValid(request.Mnemonic) {
|
||||||
|
return nil, fmt.Errorf("error invalid mnemonic. %w", ErrorAuthInvalidMnemonic)
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := chi.URLParam(r, "hash")
|
||||||
|
|
||||||
|
if hash == "" {
|
||||||
|
return nil, fmt.Errorf("error fetch invite hash from request")
|
||||||
|
}
|
||||||
|
|
||||||
|
usedAt := time.Now()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
organizationID, err := c.repo.MarkAsUsedLink(ctx, hash, usedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error mark invite link as used. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := c.usersInteractor.Create(ctx, users.CreateParams{
|
||||||
|
Name: request.Name,
|
||||||
|
Email: request.Credentals.Email,
|
||||||
|
Phone: request.Credentals.Phone,
|
||||||
|
Tg: request.Credentals.Telegram,
|
||||||
|
Mnemonic: request.Mnemonic,
|
||||||
|
Activate: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error create new user with invire link. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.orgInteractor.AddUser(ctx, organizations.AddUserParams{
|
||||||
|
User: user,
|
||||||
|
OrganizationID: organizationID,
|
||||||
|
SkipRights: true,
|
||||||
|
}); err != nil {
|
||||||
|
c.log.Error(
|
||||||
|
"error add user into organization",
|
||||||
|
slog.String("organization id", organizationID.String()),
|
||||||
|
slog.String("user id", user.Id().String()),
|
||||||
|
slog.String("invire hash", hash),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("error add user into organization. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.presenter.ResponseJoin(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *authController) InviteGet(w http.ResponseWriter, r *http.Request) ([]byte, error) {
|
||||||
return presenters.ResponseOK()
|
return presenters.ResponseOK()
|
||||||
}
|
}
|
||||||
|
@ -105,10 +105,10 @@ func (c *participantsController) New(w http.ResponseWriter, r *http.Request) ([]
|
|||||||
return nil, fmt.Errorf("error fetch organization id from context. %w", err)
|
return nil, fmt.Errorf("error fetch organization id from context. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(r.Context(), 3000*time.Second)
|
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
participant, err := c.orgInteractor.AddParticipant(ctx, organizations.AddParticipantParams{
|
participant, err := c.orgInteractor.AddEmployee(ctx, organizations.AddParticipantParams{
|
||||||
OrganizationID: organizationID,
|
OrganizationID: organizationID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Position: req.Position,
|
Position: req.Position,
|
||||||
|
@ -93,7 +93,7 @@ func (p *authPresenter) ResponseNewInvite(
|
|||||||
link string,
|
link string,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
out, err := json.Marshal(map[string]string{
|
out, err := json.Marshal(map[string]string{
|
||||||
"link": "/" + organizationID.String() + "/invite/" + link,
|
"link": "/invite/" + link + "/join",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error marshal refresh response. %w", err)
|
return nil, fmt.Errorf("error marshal refresh response. %w", err)
|
||||||
|
@ -25,7 +25,7 @@ func CreateRequest[T any](r *http.Request) (*T, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ok struct {
|
type ok struct {
|
||||||
Ok bool
|
Ok bool `json:"ok"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResponseOK() ([]byte, error) {
|
func ResponseOK() ([]byte, error) {
|
||||||
|
@ -38,6 +38,10 @@ func (b *LoggerBuilder) WithSource() *LoggerBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *LoggerBuilder) Build() *slog.Logger {
|
func (b *LoggerBuilder) Build() *slog.Logger {
|
||||||
|
if len(b.writers) == 0 {
|
||||||
|
b.writers = append(b.writers, os.Stdout)
|
||||||
|
}
|
||||||
|
|
||||||
w := io.MultiWriter(b.writers...)
|
w := io.MultiWriter(b.writers...)
|
||||||
|
|
||||||
if b.local {
|
if b.local {
|
||||||
@ -53,17 +57,12 @@ func (b *LoggerBuilder) Build() *slog.Logger {
|
|||||||
return slog.New(handler)
|
return slog.New(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
return slog.New(
|
return newLogger(b.lvl, w)
|
||||||
slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
|
||||||
Level: b.lvl,
|
|
||||||
AddSource: b.addSource,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLogger(lvl slog.Level, w io.Writer) *slog.Logger {
|
func newLogger(lvl slog.Level, w io.Writer) *slog.Logger {
|
||||||
return slog.New(
|
return slog.New(
|
||||||
slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: lvl}),
|
slog.NewJSONHandler(w, &slog.HandlerOptions{Level: lvl}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,11 +124,15 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
return fmt.Errorf("error parse chain-api response body. %w", err)
|
return fmt.Errorf("error parse chain-api response body. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
multisigAddress := common.Hex2Bytes(respObject.Address)
|
if respObject.Address == "" {
|
||||||
|
return fmt.Errorf("error multisig address is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
multisigAddress := common.Hex2Bytes(respObject.Address[2:])
|
||||||
|
|
||||||
createdAt := time.Now()
|
createdAt := time.Now()
|
||||||
|
|
||||||
if err := i.txRepository.AddMultisig(ctx, models.Multisig{
|
msg := models.Multisig{
|
||||||
ID: uuid.Must(uuid.NewV7()),
|
ID: uuid.Must(uuid.NewV7()),
|
||||||
Title: params.Title,
|
Title: params.Title,
|
||||||
Address: multisigAddress,
|
Address: multisigAddress,
|
||||||
@ -137,15 +141,20 @@ func (i *chainInteractor) NewMultisig(ctx context.Context, params NewMultisigPar
|
|||||||
ConfirmationsRequired: params.Confirmations,
|
ConfirmationsRequired: params.Confirmations,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
UpdatedAt: createdAt,
|
UpdatedAt: createdAt,
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("error add new multisig. %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i.log.Debug(
|
i.log.Debug(
|
||||||
"deploy multisig response",
|
"deploy multisig response",
|
||||||
slog.Int("code", resp.StatusCode),
|
slog.Int("code", resp.StatusCode),
|
||||||
|
slog.String("body", string(raw)),
|
||||||
|
slog.Any("parsed", respObject),
|
||||||
|
slog.Any("multisig object", msg),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if err := i.txRepository.AddMultisig(ctx, msg); err != nil {
|
||||||
|
return fmt.Errorf("error add new multisig. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,8 @@ type OrganizationsInteractor interface {
|
|||||||
|
|
||||||
Participant(ctx context.Context, params ParticipantParams) (models.OrganizationParticipant, error)
|
Participant(ctx context.Context, params ParticipantParams) (models.OrganizationParticipant, error)
|
||||||
Participants(ctx context.Context, params ParticipantsParams) ([]models.OrganizationParticipant, error)
|
Participants(ctx context.Context, params ParticipantsParams) ([]models.OrganizationParticipant, error)
|
||||||
AddParticipant(ctx context.Context, params AddParticipantParams) (models.OrganizationParticipant, error)
|
AddEmployee(ctx context.Context, params AddParticipantParams) (models.OrganizationParticipant, error)
|
||||||
|
AddUser(ctx context.Context, params AddUserParams) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type organizationsInteractor struct {
|
type organizationsInteractor struct {
|
||||||
@ -310,7 +311,7 @@ type AddParticipantParams struct {
|
|||||||
WalletAddress string
|
WalletAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *organizationsInteractor) AddParticipant(
|
func (i *organizationsInteractor) AddEmployee(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
params AddParticipantParams,
|
params AddParticipantParams,
|
||||||
) (models.OrganizationParticipant, error) {
|
) (models.OrganizationParticipant, error) {
|
||||||
@ -329,7 +330,7 @@ func (i *organizationsInteractor) AddParticipant(
|
|||||||
return nil, fmt.Errorf("error fetch actor. %w", err)
|
return nil, fmt.Errorf("error fetch actor. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !actor.IsOwner() {
|
if !actor.IsAdmin() || !actor.IsOwner() {
|
||||||
return nil, fmt.Errorf("error actor not an owner")
|
return nil, fmt.Errorf("error actor not an owner")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,3 +356,50 @@ func (i *organizationsInteractor) AddParticipant(
|
|||||||
|
|
||||||
return &empl, nil
|
return &empl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AddUserParams struct {
|
||||||
|
User *models.User
|
||||||
|
IsAdmin bool
|
||||||
|
IsOwner bool
|
||||||
|
OrganizationID uuid.UUID
|
||||||
|
SkipRights bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *organizationsInteractor) AddUser(ctx context.Context, params AddUserParams) error {
|
||||||
|
if !params.SkipRights {
|
||||||
|
user, err := ctxmeta.User(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error fetch user from context. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actor, err := i.Participant(ctx, ParticipantParams{
|
||||||
|
ID: user.Id(),
|
||||||
|
OrganizationID: params.OrganizationID,
|
||||||
|
ActiveOnly: true,
|
||||||
|
UsersOnly: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error fetch actor. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !actor.IsAdmin() || !actor.IsOwner() {
|
||||||
|
return fmt.Errorf("error actor not an owner")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i.log.Debug(
|
||||||
|
"add user",
|
||||||
|
slog.Any("params", params),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := i.orgRepository.AddParticipant(ctx, organizations.AddParticipantParams{
|
||||||
|
OrganizationId: params.OrganizationID,
|
||||||
|
UserId: params.User.Id(),
|
||||||
|
IsAdmin: params.IsAdmin,
|
||||||
|
IsOwner: params.IsOwner,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("error add user into organization. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -25,6 +25,8 @@ type CreateParams struct {
|
|||||||
Tg string
|
Tg string
|
||||||
Mnemonic string
|
Mnemonic string
|
||||||
Activate bool
|
Activate bool
|
||||||
|
Owner bool
|
||||||
|
Admin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetParams struct {
|
type GetParams struct {
|
||||||
|
@ -63,7 +63,7 @@ type Repository interface {
|
|||||||
RefreshToken(ctx context.Context, params RefreshTokenParams) error
|
RefreshToken(ctx context.Context, params RefreshTokenParams) error
|
||||||
|
|
||||||
AddInvite(ctx context.Context, params AddInviteParams) error
|
AddInvite(ctx context.Context, params AddInviteParams) error
|
||||||
MarkAsUsedLink(ctx context.Context, linkHash string, usedAt time.Time) error
|
MarkAsUsedLink(ctx context.Context, linkHash string, usedAt time.Time) (uuid.UUID, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type repositorySQL struct {
|
type repositorySQL struct {
|
||||||
@ -223,32 +223,38 @@ func (r *repositorySQL) MarkAsUsedLink(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
linkHash string,
|
linkHash string,
|
||||||
usedAt time.Time,
|
usedAt time.Time,
|
||||||
) error {
|
) (uuid.UUID, error) {
|
||||||
return sqltools.Transaction(ctx, r.db, func(ctx context.Context) error {
|
var orgID uuid.UUID
|
||||||
query := sq.Select("expired_at").From("invites").Where(sq.Eq{
|
|
||||||
|
if err := sqltools.Transaction(ctx, r.db, func(ctx context.Context) error {
|
||||||
|
query := sq.Select("organization_id", "expired_at").From("invites").Where(sq.Eq{
|
||||||
"link_hash": linkHash,
|
"link_hash": linkHash,
|
||||||
}).Limit(1).PlaceholderFormat(sq.Dollar)
|
}).Limit(1).PlaceholderFormat(sq.Dollar)
|
||||||
|
|
||||||
var expAt time.Time
|
var expAt time.Time
|
||||||
|
|
||||||
if err := query.RunWith(r.Conn(ctx)).QueryRowContext(ctx).Scan(&expAt); err != nil {
|
if err := query.RunWith(r.Conn(ctx)).QueryRowContext(ctx).Scan(&orgID, &expAt); err != nil {
|
||||||
return fmt.Errorf("error fetch expiration date from database. %w", err)
|
return fmt.Errorf("error fetch expiration date from database. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expAt.After(time.Now()) {
|
if expAt.Before(time.Now()) {
|
||||||
return ErrorInviteLinkExpired
|
return ErrorInviteLinkExpired
|
||||||
}
|
}
|
||||||
|
|
||||||
updateQuery := sq.Update("invites").SetMap(sq.Eq{
|
updateQuery := sq.Update("invites").SetMap(sq.Eq{
|
||||||
"used_at": usedAt,
|
"used_at": usedAt,
|
||||||
})
|
}).PlaceholderFormat(sq.Dollar)
|
||||||
|
|
||||||
if _, err := updateQuery.RunWith(r.Conn(ctx)).ExecContext(ctx); err != nil {
|
if _, err := updateQuery.RunWith(r.Conn(ctx)).ExecContext(ctx); err != nil {
|
||||||
return fmt.Errorf("error add invite link. %w", err)
|
return fmt.Errorf("error add invite link. %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
}); err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return orgID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepository(db *sql.DB) Repository {
|
func NewRepository(db *sql.DB) Repository {
|
||||||
|
Loading…
Reference in New Issue
Block a user