diff --git a/backend/README.md b/backend/README.md index 2f6e2e5..16c8709 100644 --- a/backend/README.md +++ b/backend/README.md @@ -464,14 +464,48 @@ Fetch licenses ## POST **/organizations/{organization_id}/license** New licese -## GET **/organizations/{organization_id}/invite/{hash}** +## GET **/invite/{hash}** Open invite link +### Request body +{} +### Example +Request: +```bash +curl --request GET \ + --url http://localhost:8081/invite/YR9vO4ZXYTgtIyi4aScsi6UZr0vNS74x9b8Y8SKF84g= +``` +Response: +```bash +{ + "Ok": true +} +``` -## POST **/organizations/{organization_id}/invite/{hash}/join** +## POST **/invite/{hash}/join** Join with invite link +// todo ## POST **/organizations/{organization_id}/participants/invite** Create new invite link +### Request body +{} empty json +### Example +Request: +```bash +curl --request POST \ + --url http://localhost:8081/organizations/018fb246-1616-7f1b-9fe2-1a3202224695/participants/invite \ + --header 'Authorization: Bearer token' \ + --header 'X-Seed: a b c 1 2 3' \ + --header 'accept: application/json' \ + --header 'content-type: application/json' \ + --data '{}' +``` +Response: +```json +{ + "link": "/018fb246-1616-7f1b-9fe2-1a3202224695/invite/%2nIYC4E6ipLjUpjH0ctbqGFkneMJoF3JW41I4tThgM=" +} +``` # Deprecated ## GET **/{organization_id}/transactions** diff --git a/backend/internal/interface/rest/controllers/auth.go b/backend/internal/interface/rest/controllers/auth.go index f6ad795..6574606 100644 --- a/backend/internal/interface/rest/controllers/auth.go +++ b/backend/internal/interface/rest/controllers/auth.go @@ -32,6 +32,7 @@ type AuthController interface { Login(w http.ResponseWriter, req *http.Request) ([]byte, error) Invite(w http.ResponseWriter, req *http.Request) ([]byte, error) Refresh(w http.ResponseWriter, req *http.Request) ([]byte, error) + InviteGet(w http.ResponseWriter, req *http.Request) ([]byte, error) } type authController struct { @@ -191,16 +192,24 @@ func (c *authController) Invite(w http.ResponseWriter, r *http.Request) ([]byte, "&", "#", ) + createdAt := time.Now() + expDate := createdAt.Add(time.Hour * 24 * 7) + + if request.ExpirationDate > 0 { + expDate = time.UnixMilli(int64(request.ExpirationDate)) + } + c.log.Debug( "", slog.String("link", linkHashString), ) if err := c.repo.AddInvite(ctx, auth.AddInviteParams{ - LinkHash: linkHashString, - CreatedBy: *user, - CreatedAt: time.Now(), - ExpiredAt: time.UnixMilli(int64(request.ExpirationDate)), + LinkHash: linkHashString, + OrganizationID: organizationID, + CreatedBy: *user, + CreatedAt: createdAt, + ExpiredAt: expDate, }); err != nil { return nil, fmt.Errorf("error add new invite link. %w", err) } @@ -209,5 +218,10 @@ func (c *authController) Invite(w http.ResponseWriter, r *http.Request) ([]byte, } func (c *authController) JoinWithInvite(w http.ResponseWriter, req *http.Request) ([]byte, error) { + return nil, nil // implement } + +func (c *authController) InviteGet(w http.ResponseWriter, req *http.Request) ([]byte, error) { + return presenters.ResponseOK() +} diff --git a/backend/internal/interface/rest/server.go b/backend/internal/interface/rest/server.go index 6156ccc..427483c 100644 --- a/backend/internal/interface/rest/server.go +++ b/backend/internal/interface/rest/server.go @@ -96,6 +96,11 @@ func (s *Server) buildRouter() { router.Post("/login", s.handle(s.controllers.Auth.Login, "login")) router.Get("/refresh", s.handle(s.controllers.Auth.Refresh, "refresh")) + // open invite link + router.Get("/invite/{hash}", s.handle(s.controllers.Auth.InviteGet, "invite_open")) + // join via invite link + router.Post("/invite/{hash}/join", s.handle(s.controllers.Auth.JoinWithInvite, "invite_join")) + router.Route("/organizations", func(r chi.Router) { r = r.With(s.withAuthorization) @@ -116,26 +121,18 @@ func (s *Server) buildRouter() { r.Route("/payrolls", func(r chi.Router) { r.Get("/", s.handle(s.controllers.Transactions.ListPayrolls, "list_payrolls")) r.Post("/", s.handle(s.controllers.Transactions.NewPayroll, "new_payroll")) - r.Put("/", nil) // todo }) r.Route("/multisig", func(r chi.Router) { r.Post("/", s.handle(s.controllers.Transactions.NewMultisig, "new_multisig")) r.Get("/", s.handle(s.controllers.Transactions.ListMultisigs, "list_multisig")) - r.Put("/", nil) // todo }) r.Route("/license", func(r chi.Router) { r.Get("/", nil) // list license r.Post("/", nil) // deploy contract - r.Put("/", nil) // todo }) - // open invite link - r.Get("/invite/{hash}", s.handle(nil, "invite_open")) - // join via invite link - r.Post("/invite/{hash}/join", s.handle(s.controllers.Auth.JoinWithInvite, "invite_join")) - r.Route("/participants", func(r chi.Router) { r.Get("/", s.handle(s.controllers.Participants.List, "participants_list")) r.Post("/", s.handle(s.controllers.Participants.New, "new_participant")) diff --git a/backend/internal/usecase/repository/auth/repository.go b/backend/internal/usecase/repository/auth/repository.go index 62a977c..94eeb03 100644 --- a/backend/internal/usecase/repository/auth/repository.go +++ b/backend/internal/usecase/repository/auth/repository.go @@ -185,10 +185,11 @@ func (r *repositorySQL) GetTokens(ctx context.Context, params GetTokenParams) (* } type AddInviteParams struct { - LinkHash string - CreatedBy models.User - CreatedAt time.Time - ExpiredAt time.Time + LinkHash string + OrganizationID uuid.UUID + CreatedBy models.User + CreatedAt time.Time + ExpiredAt time.Time } func (r *repositorySQL) AddInvite( @@ -198,11 +199,13 @@ func (r *repositorySQL) AddInvite( return sqltools.Transaction(ctx, r.db, func(ctx context.Context) error { query := sq.Insert("invites").Columns( "link_hash", + "organization_id", "created_by", "created_at", "expired_at", ).Values( params.LinkHash, + params.OrganizationID, params.CreatedBy.Id(), params.CreatedAt, params.ExpiredAt, diff --git a/backend/migrations/blockd.sql b/backend/migrations/blockd.sql index d434211..13a664c 100644 --- a/backend/migrations/blockd.sql +++ b/backend/migrations/blockd.sql @@ -195,6 +195,7 @@ create index if not exists idx_multisig_confirmations_owners_owner_id create table invites ( link_hash varchar(64) primary key, + organization_id uuid, created_by uuid not null references users(id), created_at timestamp default current_timestamp, expired_at timestamp default null,