Skip to content

Commit

Permalink
add create account, list accounts, list entries RPCs
Browse files Browse the repository at this point in the history
  • Loading branch information
aradwann committed Mar 17, 2024
1 parent de9b1eb commit 03a1fc4
Show file tree
Hide file tree
Showing 36 changed files with 2,593 additions and 498 deletions.
30 changes: 13 additions & 17 deletions db/store/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package db
import (
"database/sql"
"fmt"
"log"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -51,46 +52,40 @@ func RunDBMigrations(db *sql.DB, migrationsURL string) {
func getSQLFiles(migrationDir string) ([]string, error) {
var sqlFiles []string

err := filepath.WalkDir(migrationDir, func(path string, d os.DirEntry, err error) error {
err := filepath.Walk(migrationDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
return err // Immediately return errors for short-circuiting
}

// Skip directories
if d.IsDir() {
return nil
}

// Check if the file has a .sql extension
if strings.HasSuffix(path, ".sql") {
// Only process regular files with .sql extension
if info.Mode().IsRegular() && strings.HasSuffix(path, ".sql") {
sqlFiles = append(sqlFiles, path)
}

return nil
})

return sqlFiles, err
if err != nil {
return nil, err
}

return sqlFiles, nil
}

func runUnversionedMigrations(db *sql.DB, migrationDir string) error {

sqlFiles, err := getSQLFiles(migrationDir)

if err != nil {
return err
}
// Sort files to ensure execution order
// Note: You may need a custom sorting logic if file names include version numbers
// For simplicity, we assume alphabetical order here.
// Sorting ensures that the files are executed in the correct order.
// sortFiles(sqlFiles)

// Execute each SQL file
for _, file := range sqlFiles {
log.Printf("Executing SQL file: %s", file)

contents, err := os.ReadFile(file)
if err != nil {
return err
return fmt.Errorf("error reading SQL file %s: %w", file, err)
}

// Execute the SQL content
Expand All @@ -99,6 +94,7 @@ func runUnversionedMigrations(db *sql.DB, migrationDir string) error {
return fmt.Errorf("error executing SQL file %s: %w", file, err)
}

log.Printf("Finished executing SQL file: %s", file)
}

return nil
Expand Down
169 changes: 167 additions & 2 deletions doc/swagger/eenergy.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,131 @@
"application/json"
],
"paths": {
"/v1/accounts": {
"get": {
"summary": "user accounts",
"description": "Use this API to get User accounts",
"operationId": "EenergyService_ListUserAccounts",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/pbListUserAccountsResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "username",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "limit",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
},
{
"name": "offset",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
}
],
"tags": [
"EenergyService"
]
},
"post": {
"summary": "create account",
"description": "Use this API to create an account",
"operationId": "EenergyService_CreateAccount",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/pbCreateAccountResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/pbCreateAccountRequest"
}
}
],
"tags": [
"EenergyService"
]
}
},
"/v1/accounts/{accountId}/entries": {
"get": {
"summary": "account entries",
"description": "Use this API to get user account entries",
"operationId": "EenergyService_ListAccountEntries",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/pbListAccountEntriesResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "accountId",
"in": "path",
"required": true,
"type": "string",
"format": "int64"
},
{
"name": "limit",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
},
{
"name": "offset",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
}
],
"tags": [
"EenergyService"
]
}
},
"/v1/energy/transfer": {
"post": {
"summary": "transfer energy",
Expand Down Expand Up @@ -219,6 +344,22 @@
}
}
},
"pbCreateAccountRequest": {
"type": "object",
"properties": {
"username": {
"type": "string"
}
}
},
"pbCreateAccountResponse": {
"type": "object",
"properties": {
"account": {
"$ref": "#/definitions/pbAccount"
}
}
},
"pbCreateUserRequest": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -265,6 +406,30 @@
}
}
},
"pbListAccountEntriesResponse": {
"type": "object",
"properties": {
"entries": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/pbEntry"
}
}
}
},
"pbListUserAccountsResponse": {
"type": "object",
"properties": {
"accounts": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/pbAccount"
}
}
}
},
"pbLoginUserRequest": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -354,8 +519,8 @@
},
"fromEntry": {
"$ref": "#/definitions/pbEntry",
"description": "Entry to_entry = 5;",
"title": "Account to_account = 3;"
"description": "Entry to_entry = 5; // don't expose other user account to the sender",
"title": "Account to_account = 3; // don't expose other user account to the sender"
}
}
},
Expand Down
18 changes: 18 additions & 0 deletions gapi/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ func convertAccount(account db.Account) *pb.Account {
}
}

func convertAccounts(accounts []db.Account) []*pb.Account {
var accs []*pb.Account

for _, acc := range accounts {
accs = append(accs, convertAccount(acc))
}
return accs
}

func convertEntries(entries []db.Entry) []*pb.Entry {
var ents []*pb.Entry

for _, entry := range entries {
ents = append(ents, convertEntry(entry))
}
return ents
}

func convertEntry(entry db.Entry) *pb.Entry {
return &pb.Entry{
Id: entry.ID,
Expand Down
60 changes: 60 additions & 0 deletions gapi/rpc_create_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package gapi

import (
"context"
"errors"

db "github.com/aradwann/eenergy/db/store"
"github.com/aradwann/eenergy/pb"
"github.com/aradwann/eenergy/util"
"github.com/aradwann/eenergy/val"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func (server *Server) CreateAccount(ctx context.Context, req *pb.CreateAccountRequest) (*pb.CreateAccountResponse, error) {
authPayload, err := server.authorizeUser(ctx, []string{util.AdminRole, util.UserRole})
if err != nil {
return nil, unauthenticatedError(err)
}
violations := validateCreateAccountRequest(req)
if violations != nil {
return nil, invalidArgumentError(violations)
}

owner := ""
if authPayload.Role == util.UserRole {
owner = authPayload.Username
} else if authPayload.Role == util.AdminRole {
owner = req.GetUsername()
}

arg := db.CreateAccountParams{
Owner: owner,
Balance: 0,
Unit: util.KWH,
}

acc, err := server.store.CreateAccount(ctx, arg)
if err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return nil, status.Errorf(codes.NotFound, "user not found")
}
return nil, status.Errorf(codes.Internal, "failed to create account: %s", err)
}

rsp := &pb.CreateAccountResponse{
Account: convertAccount(acc),
}
return rsp, nil
}

func validateCreateAccountRequest(req *pb.CreateAccountRequest) (violations []*errdetails.BadRequest_FieldViolation) {
if req.GetUsername() != "" {
if err := val.ValidateUsername(req.GetUsername()); err != nil {
violations = append(violations, fieldViolation("username", err))
}
}
return
}
Loading

0 comments on commit 03a1fc4

Please sign in to comment.