From 05802514f59ffc55422278aa3c3f1b52ca7369a4 Mon Sep 17 00:00:00 2001 From: optclblast Date: Wed, 29 May 2024 01:46:30 +0300 Subject: [PATCH] tmp --- backend/README.md | 149 +++++++++++------- .../interface/rest/controllers/chain.go | 48 ++---- backend/internal/interface/rest/domain/dto.go | 51 ++++-- .../interface/rest/domain/participants.go | 2 + .../interface/rest/presenters/auth.go | 4 +- .../interface/rest/presenters/participants.go | 2 + .../internal/interface/rest/presenters/tx.go | 5 - backend/internal/pkg/models/models.go | 6 + .../interactors/transactions/interactor.go | 29 +--- .../repository/transactions/repository.go | 78 +-------- backend/migrations/blockd.sql | 107 ++++++------- 11 files changed, 207 insertions(+), 274 deletions(-) diff --git a/backend/README.md b/backend/README.md index 36a4e8f..5fc12f0 100644 --- a/backend/README.md +++ b/backend/README.md @@ -454,9 +454,59 @@ Response: ## POST **/organizations/{organization_id}/payrolls** New payroll +### Request body: +* title (string) +* multisig_id (string) + +### Example +Request: +``` bash +curl --request POST \ + --url http://localhost:8081/organizations/018fb666-d7b7-740a-92e5-c2e04c7abafc/payrolls \ + --header 'Authorization: Bearer TOKEN' \ + --header 'content-type: application/json' \ + --data '{ + "title":"sdjkhfjsdk", + "multisig_id":"018fbb03-d4c5-73be-ab07-6c5f8d3afebc" +}' +``` + +Response: +``` json +{ + "ok": true +} +``` ## GET **/organizations/{organization_id}/payrolls** Fetch payrolls +### Request body: +* ids ([]string) +* limit (uint32) + +### Example +Request: +``` bash +curl --request POST \ + --url http://localhost:8081/organizations/018fb666-d7b7-740a-92e5-c2e04c7abafc/payrolls \ + --header 'Authorization: Bearer TOKEN' \ + --header 'content-type: application/json' \ + --data '{ + "title":"sdjkhfjsdk", + "multisig_id":"018fbb03-d4c5-73be-ab07-6c5f8d3afebc" +}' +``` + +Response: +``` json +{ + "ok": true +} +``` + +## PUT **/organizations/{organization_id}/payrolls** +Confirm payroll +// todo ## GET **/organizations/{organization_id}/license** Fetch licenses @@ -506,9 +556,9 @@ curl --request POST \ Response: ```json { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTY5MTgzMzk5OTEsInVpZCI6IjAxOGZiYjI4LTZkODgtNzg2NC04OWMxLTYzODYxNzU3NmFhNiJ9.zobQ9AAEUEHPz2BoetdtZDm5AfgUPCyCVS0JYNEYj5c", + "token": "TOKEN", "token_expired_at": 1716918339991, - "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTczNTAzMzk5OTEsInJ0X2hhc2giOiJzQStTZW42WDFUOVNVOGl1eVFhTy9sejJLSHNBMkpHcnlURDRHR3JQcTg1QUtLTE9XSWc0VTVEcFpXcjkvR1pqaDBGWGkvdWJYdHpIRzRCcUswV09jZz09IiwidWlkIjoiMDE4ZmJiMjgtNmQ4OC03ODY0LTg5YzEtNjM4NjE3NTc2YWE2In0.D0ZAHcJGH0Ga_nXLZojLBW8cMgTf8kNhcQbFVfKrGWs", + "refresh_token": "TOKEN", "refresh_token_expired_at": 1717350339991 } ``` @@ -535,9 +585,10 @@ Response: ``` ## GET **/{organization_id}/transactions** -Feth txs +Fetch txs ### Request body: - +ready_to_confirm (optional) +pending (optional) ### Example Request: @@ -546,61 +597,6 @@ curl --location --request GET 'http://localhost:8081/organizations/018f9078-af60 --header 'Content-Type: application/json' \ --header 'Authorization: Bearer TOKEN' \ --data '{ - "description":"New test tx!", - "amount": 100, - "to":"0x323b5d4c32345ced77393b3530b1eed0f346429d", - "limit":1 -}' -``` - -Response: -``` json -{ - "_type": "transaction", - "_links": { - "self": { - "href": "/organizations/{organization_id}/transactions" - } - }, - "id": "018f8ce2-dada-75fb-9745-8560e5736bec", - "description": "New test tx!", - "organization_id": "018f8ccd-2431-7d21-a0c2-a2735c852764", - "created_by": "018f8ccc-e4fc-7a46-9628-15f9c3301f5b", - "amount": 100, - "to": "MjtdTDI0XO13OTs1MLHu0PNGQp0=", - "max_fee_allowed": 5, - "deadline": 123456767, - "created_at": 1716055628507, - "updated_at": 1716055628507 -} -``` - -## POST **/{organization_id}/transactions** -Add new tx -### Request body: -* ids ([]uuid) -* created_by (uuid) -* to (string) -* cancelled (bool) -* confirmed (bool) -* commited (bool) -* expired (bool) -* pending (bool) -* cursor (string) -* limit (int) -* offset_date (unix milli time) - -### Example -Request: -``` bash -curl --location --request GET 'http://localhost:8081/organizations/018f9112-1805-7b5e-ae30-7fc2151810f3/transactions' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Bearer TOKEN' \ ---data '{ - "to": "0xD53990543641Ee27E2FC670ad2cf3cA65ccDc8BD", - "pending":true, - "limit":1, - "created_by":"018f9111-f0fb-708a-aec1-55295f5496d6" }' ``` @@ -635,3 +631,38 @@ Response: ] } ``` + +## POST **/{organization_id}/transactions** +Add new tx +### Request body: +* description (string, optional) +* amount (float, required) +* to (string, required) + +### Example +Request: +``` bash +// todo +``` + +Response: +``` json +{ + "_type": "transaction", + "_links": { + "self": { + "href": "/organizations/{organization_id}/transactions" + } + }, + "id": "018f8ce2-dada-75fb-9745-8560e5736bec", + "description": "New test tx!", + "organization_id": "018f8ccd-2431-7d21-a0c2-a2735c852764", + "created_by": "018f8ccc-e4fc-7a46-9628-15f9c3301f5b", + "amount": 100, + "to": "MjtdTDI0XO13OTs1MLHu0PNGQp0=", + "max_fee_allowed": 5, + "deadline": 123456767, + "created_at": 1716055628507, + "updated_at": 1716055628507 +} +``` diff --git a/backend/internal/interface/rest/controllers/chain.go b/backend/internal/interface/rest/controllers/chain.go index 818898a..c19b8d2 100644 --- a/backend/internal/interface/rest/controllers/chain.go +++ b/backend/internal/interface/rest/controllers/chain.go @@ -107,49 +107,15 @@ func (c *transactionsController) List(w http.ResponseWriter, r *http.Request) ([ return nil, fmt.Errorf("error fetch organization ID from context. %w", err) } - ids := make(uuid.UUIDs, len(req.IDs)) - - for i, id := range req.IDs { - txUUID, err := uuid.Parse(id) - if err != nil { - return nil, fmt.Errorf("error parse tx id. %w", err) - } - - ids[i] = txUUID - } - - var toAddr []byte - - if req.To != "" { - toAddr = common.HexToAddress(req.To).Bytes() - } - - var createdBy uuid.UUID - if req.CreatedBy != "" { - createdBy, err = uuid.Parse(req.CreatedBy) - if err != nil { - return nil, fmt.Errorf("error parse created by id. %w", err) - } - } - ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second) defer cancel() txs, err := c.txInteractor.List(ctx, transactions.ListParams{ - IDs: ids, OrganizationID: organizationID, - To: toAddr, - - CreatedBy: createdBy, - - Limit: int64(req.Limit), - Cursor: req.Cursor, - - WithCancelled: req.Cancelled, - WithConfirmed: req.Confirmed, - WithCommited: req.Commited, - WithExpired: req.Expired, - WithPending: req.Pending, + Limit: int64(req.Limit), + Cursor: req.Cursor, + Pending: req.Pending, + ReadyToConfirm: req.ReadyToConfirm, }) if err != nil { return nil, fmt.Errorf("error fetch organizations list. %w", err) @@ -376,6 +342,12 @@ func (c *transactionsController) ListPayrolls(w http.ResponseWriter, r *http.Req return c.txPresenter.ResponsePayrolls(ctx, payrolls) } +func (c *transactionsController) SetSalary(w http.ResponseWriter, r *http.Request) ([]byte, error) { + // req, err := presenters.CreateRequest[domain.]() + + return presenters.ResponseOK() +} + func (c *transactionsController) ConfirmPayroll(w http.ResponseWriter, r *http.Request) ([]byte, error) { return nil, nil diff --git a/backend/internal/interface/rest/domain/dto.go b/backend/internal/interface/rest/domain/dto.go index 040fd87..b8d1f6f 100644 --- a/backend/internal/interface/rest/domain/dto.go +++ b/backend/internal/interface/rest/domain/dto.go @@ -65,23 +65,17 @@ type ListOrganizationsRequest struct { // Transactions type NewTransactionRequest struct { - Description string `json:"description,omitempty"` - Amount float64 `json:"amount,omitempty"` - ToAddr string `json:"to,omitempty"` - MaxFeeAllowed float64 `json:"max_fee_allowed,omitempty"` - Deadline int64 `json:"deadline,omitempty"` + Description string `json:"description,omitempty"` + Amount float64 `json:"amount,omitempty"` + ToAddr string `json:"to,omitempty"` + + MultisigID string `json:"multisig_id"` + ConfirmationsRequired int `json:"confirmations_required"` } type ListTransactionsRequest struct { - IDs []string `json:"ids,omitempty"` - CreatedBy string `json:"created_by,omitempty"` - To string `json:"to,omitempty"` - - Cancelled bool `json:"cancelled,omitempty"` - Confirmed bool `json:"confirmed,omitempty"` - Commited bool `json:"commited,omitempty"` - Expired bool `json:"expired,omitempty"` - Pending bool `json:"pending,omitempty"` + ReadyToConfirm bool `json:"ready_to_confirm"` + Pending bool `json:"pending"` Cursor string `json:"cursor,omitempty"` Limit uint8 `json:"limit,omitempty"` // Default: 50, Max: 50 @@ -116,6 +110,15 @@ type NewMultisigRequest struct { Confirmations int `json:"confirmations"` } +type ListMultisigsRequest struct{} + +type NewMultisigDepositRequest struct { + MultisigID string `json:"multisig_id"` + Amount float64 `json:"amount"` +} + +// Payrolls and salaries + type NewPayrollRequest struct { MultisigID string `json:"multisig_id"` Title string `json:"title"` @@ -125,3 +128,23 @@ type ListPayrollsRequest struct { IDs []string `json:"ids"` Limit uint8 `json:"limit"` } + +type SetSalaryRequest struct { + EmployeeID string `json:"employee_id"` + Salary float64 `json:"salary"` + PayrollID string `json:"payroll_id"` +} + +type NewPayoutRequest struct { + EmployeeID string `json:"employee_id"` + SalaryID string `json:"salary_id"` +} + +type NewDepositRequest struct { + PayrollID string `json:"payroll_id"` + Amount float64 `json:"amount"` +} + +type ConfirmSalaryRequest struct { + SalaryID string `json:"salary_id"` +} diff --git a/backend/internal/interface/rest/domain/participants.go b/backend/internal/interface/rest/domain/participants.go index eb8dfb9..b432e46 100644 --- a/backend/internal/interface/rest/domain/participants.go +++ b/backend/internal/interface/rest/domain/participants.go @@ -12,6 +12,8 @@ type Participant struct { UpdatedAt int64 `json:"updated_at"` DeletedAt int64 `json:"deleted_at,omitempty"` + PublicKey string `json:"public_key"` + IsUser bool `json:"is_user"` IsAdmin bool `json:"is_admin"` IsOwner bool `json:"is_owner"` diff --git a/backend/internal/interface/rest/presenters/auth.go b/backend/internal/interface/rest/presenters/auth.go index b4e2c8a..316cfcf 100644 --- a/backend/internal/interface/rest/presenters/auth.go +++ b/backend/internal/interface/rest/presenters/auth.go @@ -36,7 +36,7 @@ func NewAuthPresenter( } func (p *authPresenter) ResponseJoin(user *models.User) ([]byte, error) { - tokens, err := p.jwtInteractor.NewToken(user, 24*time.Hour, "") + tokens, err := p.jwtInteractor.NewToken(user, 24*time.Hour*30, "") if err != nil { return nil, fmt.Errorf("error create access token. %w", err) } @@ -55,7 +55,7 @@ func (p *authPresenter) ResponseJoin(user *models.User) ([]byte, error) { } func (p *authPresenter) ResponseLogin(user *models.User) ([]byte, error) { - tokens, err := p.jwtInteractor.NewToken(user, 24*time.Hour, "") + tokens, err := p.jwtInteractor.NewToken(user, 24*time.Hour*30, "") if err != nil { return nil, fmt.Errorf("error create access token. %w", err) } diff --git a/backend/internal/interface/rest/presenters/participants.go b/backend/internal/interface/rest/presenters/participants.go index f38ae50..cbb6319 100644 --- a/backend/internal/interface/rest/presenters/participants.go +++ b/backend/internal/interface/rest/presenters/participants.go @@ -9,6 +9,7 @@ import ( "github.com/emochka2007/block-accounting/internal/interface/rest/domain/hal" "github.com/emochka2007/block-accounting/internal/pkg/ctxmeta" "github.com/emochka2007/block-accounting/internal/pkg/models" + "github.com/ethereum/go-ethereum/common" ) type ParticipantsPresenter interface { @@ -62,6 +63,7 @@ func (p *participantsPresenter) ResponseParticipantHal( } domainParticipant.Position = user.Position() + domainParticipant.PublicKey = common.Bytes2Hex(user.PublicKey()) domainParticipant.IsUser = true domainParticipant.IsAdmin = user.IsAdmin() domainParticipant.IsOwner = user.IsOwner() diff --git a/backend/internal/interface/rest/presenters/tx.go b/backend/internal/interface/rest/presenters/tx.go index f46469c..2cbeb60 100644 --- a/backend/internal/interface/rest/presenters/tx.go +++ b/backend/internal/interface/rest/presenters/tx.go @@ -61,14 +61,9 @@ func (p *transactionsPresenter) RequestTransaction( Description: r.Description, Amount: r.Amount, ToAddr: toAddress.Bytes(), - MaxFeeAllowed: r.MaxFeeAllowed, CreatedAt: time.Now(), } - if r.Deadline > 0 { - tx.Deadline = time.UnixMilli(r.Deadline) - } - return tx, nil } diff --git a/backend/internal/pkg/models/models.go b/backend/internal/pkg/models/models.go index 4e1c4d9..d7f81d7 100644 --- a/backend/internal/pkg/models/models.go +++ b/backend/internal/pkg/models/models.go @@ -33,3 +33,9 @@ type Payroll struct { CreatedAt time.Time UpdatedAt time.Time } + +type Salary struct { + ID uuid.UUID + EmployeeID uuid.UUID + Amount float64 +} diff --git a/backend/internal/usecase/interactors/transactions/interactor.go b/backend/internal/usecase/interactors/transactions/interactor.go index 2be4b05..09d3f3e 100644 --- a/backend/internal/usecase/interactors/transactions/interactor.go +++ b/backend/internal/usecase/interactors/transactions/interactor.go @@ -19,21 +19,10 @@ import ( type ListParams struct { IDs uuid.UUIDs OrganizationID uuid.UUID - CreatedBy uuid.UUID - - To []byte - - Limit int64 - Cursor string - - WithPending bool - - WithCancelled bool - WithConfirmed bool - WithCommited bool - WithExpired bool - - WithConfirmations bool + Pending bool + ReadyToConfirm bool + Limit int64 + Cursor string } type CreateParams struct { @@ -133,17 +122,11 @@ func (i *transactionsInteractor) List(ctx context.Context, params ListParams) (* } txs, err := i.txRepo.GetTransactions(ctx, transactions.GetTransactionsParams{ - Ids: params.IDs, OrganizationId: params.OrganizationID, - CreatedById: params.CreatedBy, - To: params.To, Limit: params.Limit, CursorId: cursor.Id, - WithCancelled: params.WithCancelled, - WithConfirmed: params.WithConfirmed, - WithCommited: params.WithCommited, - WithExpired: params.WithExpired, - WithPending: params.WithPending, + Pending: params.Pending, + ReadyToConfirm: params.ReadyToConfirm, }) if err != nil { return nil, fmt.Errorf("error fetch transaction from repository. %w", err) diff --git a/backend/internal/usecase/repository/transactions/repository.go b/backend/internal/usecase/repository/transactions/repository.go index e1b1050..026e67d 100644 --- a/backend/internal/usecase/repository/transactions/repository.go +++ b/backend/internal/usecase/repository/transactions/repository.go @@ -17,18 +17,11 @@ import ( type GetTransactionsParams struct { Ids uuid.UUIDs OrganizationId uuid.UUID - CreatedById uuid.UUID - To []byte Limit int64 CursorId uuid.UUID - WithCancelled bool - WithConfirmed bool - WithCommited bool - WithExpired bool - WithPending bool - - WithConfirmations bool + Pending bool + ReadyToConfirm bool } type ConfirmTransactionParams struct { @@ -309,8 +302,10 @@ func buildGetTransactionsQuery(params GetTransactionsParams) sq.SelectBuilder { t.to_addr, t.max_fee_allowed, t.deadline, + t.confirmations_required, t.created_at, t.updated_at, + t.confirmed_at, t.cancelled_at, t.commited_at, @@ -335,73 +330,16 @@ func buildGetTransactionsQuery(params GetTransactionsParams) sq.SelectBuilder { }) } - if params.CreatedById != uuid.Nil { - query = query.Where(sq.Eq{ - "t.created_by": params.CreatedById, - }) - } - if params.OrganizationId != uuid.Nil { query = query.Where(sq.Eq{ "t.organization_id": params.OrganizationId, }) } - if params.To != nil { - query = query.Where(sq.Eq{ - "t.to_addr": params.To, - }) - } - - if params.WithExpired { - query = query.Where(sq.LtOrEq{ - "t.deadline": time.Now(), - }) - } else { - query = query.Where(sq.Or{ - sq.GtOrEq{ - "t.deadline": time.Now(), - }, - sq.Eq{ - "t.deadline": nil, - }, - }) - } - - if params.WithCancelled { - query = query.Where(sq.NotEq{ - "t.cancelled_at": nil, - }) - } - - if params.WithConfirmed { - query = query.Where(sq.NotEq{ - "t.confirmed_at": nil, - }) - } - - if params.WithCommited { - query = query.Where(sq.NotEq{ - "t.commited_at": nil, - }) - } - - if params.Limit <= 0 || params.Limit > 50 { - params.Limit = 50 - } - - if params.WithPending { - query = query.Where(sq.Eq{ - "t.cancelled_at": nil, - "t.commited_at": nil, - "t.confirmed_at": nil, - }) - } - - if params.CursorId != uuid.Nil { - query = query.Where(sq.Gt{ - "t.id": params.CursorId, - }) + if params.Pending { + query = query.InnerJoin("multisig_confirmations as mc on mc.multisig_id = t.multisig_id").Where( + sq.Lt{}, + ) } query = query.Limit(uint64(params.Limit)) diff --git a/backend/migrations/blockd.sql b/backend/migrations/blockd.sql index 308a049..7bf242c 100644 --- a/backend/migrations/blockd.sql +++ b/backend/migrations/blockd.sql @@ -90,72 +90,9 @@ create index if not exists index_organizations_users_organization_id_user_id create index if not exists index_organizations_users_organization_id_employee_id on organizations_users (organization_id, employee_id); - -create table if not exists transactions ( - id uuid primary key, - description text default 'New Transaction', - organization_id uuid not null, - created_by uuid not null, - amount decimal default 0, - - to_addr bytea not null, - tx_index bigint default 0, - - max_fee_allowed decimal default 0, - deadline timestamp default null, - status int default 0, - - created_at timestamp default current_timestamp, - updated_at timestamp default current_timestamp, - - confirmed_at timestamp default null, - cancelled_at timestamp default null, - - commited_at timestamp default null -); - -create index if not exists index_transactions_id_organization_id - on transactions (organization_id); - -create index if not exists index_transactions_id_organization_id_created_by - on transactions (organization_id, created_by); - -create index if not exists index_transactions_organization_id_deadline - on transactions (organization_id, deadline); - -create table transactions_confirmations ( - tx_id uuid not null, - user_id uuid not null, - organization_id uuid not null, - created_at timestamp default current_timestamp, - updated_at timestamp default current_timestamp, - confirmed bool -); - create index if not exists index_transactions_confirmations_tx_id_user_id_organization_id on transactions_confirmations (tx_id, user_id, organization_id); -create table contracts ( - id uuid primary key, - title varchar(250) default 'New Contract', - description text not null, - address bytea not null, - payload bytea not null, - created_by uuid not null references users(id), - organization_id uuid not null references organizations(id), - status smallint default 0, - tx_index bytea default null, - multisig bytea default null, - created_at timestamp default current_timestamp, - updated_at timestamp default current_timestamp -); - -create index if not exists idx_contracts_organization_id_multisig - on contracts (organization_id, multisig); - -create index if not exists idx_contracts_organization_id_created_by - on contracts (organization_id, created_by); - create table multisigs ( id uuid primary key, organization_id uuid not null references organizations(id), @@ -217,3 +154,47 @@ create table payrolls ( created_at timestamp default current_timestamp, updated_at timestamp default current_timestamp ); + +create table if not exists transactions ( + id uuid primary key, + description text default 'New Transaction', + organization_id uuid not null, + created_by uuid not null, + amount decimal default 0, + + to_addr bytea not null, + tx_index bigint default 0, + + max_fee_allowed decimal default 0, + deadline timestamp default null, + confirmations_required bigint default 1, + multisig_id uuid default null, + + status int default 0, + + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + + confirmed_at timestamp default null, + cancelled_at timestamp default null, + + commited_at timestamp default null +); + +create index if not exists index_transactions_id_organization_id + on transactions (organization_id); + +create index if not exists index_transactions_id_organization_id_created_by + on transactions (organization_id, created_by); + +create index if not exists index_transactions_organization_id_deadline + on transactions (organization_id, deadline); + +create table transactions_confirmations ( + tx_id uuid not null, + user_id uuid not null, + organization_id uuid not null, + created_at timestamp default current_timestamp, + updated_at timestamp default current_timestamp, + confirmed bool +); \ No newline at end of file