Compare commits

...

21 Commits

Author SHA1 Message Date
VLADIMIR 0ed38b7cc0 add text waste route
continuous-integration/drone/push Build is failing
2024-11-28 06:43:05 +07:00
VLADIMIR 26ca649e8e add create waste route
continuous-integration/drone/push Build is passing
2024-11-25 16:38:03 +07:00
VLADIMIR 675c2884b7 add create categories route
continuous-integration/drone/push Build is passing
2024-11-25 13:36:14 +07:00
VLADIMIR 130a3236e0 add add user to budget route
continuous-integration/drone/push Build is passing
2024-11-24 22:24:44 +07:00
VLADIMIR 95fe8b530e add get budgets method
continuous-integration/drone/push Build is passing
2024-11-24 16:53:52 +07:00
VLADIMIR bf85f31056 add create budget route
continuous-integration/drone/push Build is passing
2024-11-24 16:02:13 +07:00
VLADIMIR 866009cf09 add login
continuous-integration/drone/push Build is passing
2024-11-21 16:02:36 +07:00
VLADIMIR f2011b953c remane vars
continuous-integration/drone/push Build is passing
2024-11-21 15:11:21 +07:00
VLADIMIR 66df21c6c9 update api
continuous-integration/drone/push Build is failing
2024-11-21 02:10:29 +07:00
VLADIMIR a8b6e9ab9b update db
continuous-integration/drone/push Build is passing
2024-11-21 01:05:03 +07:00
VLADIMIR 2078e008f3 update db
continuous-integration/drone/push Build is passing
2024-11-21 01:02:15 +07:00
VLADIMIR f4523de5a4 fix db
continuous-integration/drone/push Build is passing
2024-11-21 00:47:44 +07:00
VLADIMIR 0d6bd456d6 Merge pull request 'add auth' (#16) from auth into master
continuous-integration/drone/push Build is passing
Reviewed-on: #16
2024-11-20 16:35:33 +00:00
VLADIMIR ee3e10d46d add auth 2024-11-20 23:26:51 +07:00
VLADIMIR 6c99309caf Merge pull request 'add create user method' (#15) from add_create_user_method into master
continuous-integration/drone/push Build is passing
Reviewed-on: #15
2024-11-20 08:33:56 +00:00
VLADIMIR bd6b5fe4a8 add create user method 2024-11-20 15:32:43 +07:00
VLADIMIR 074a202dc2 Merge pull request 'add category insert' (#14) from add_categories_api into master
continuous-integration/drone/push Build is passing
Reviewed-on: #14
2024-11-20 07:57:50 +00:00
VLADIMIR 718d2e5e98 add category insert 2024-11-19 22:45:31 +07:00
VLADIMIR 20652b127c Merge pull request 'add api' (#13) from add_categories_api into master
continuous-integration/drone/push Build is passing
Reviewed-on: #13
2024-11-19 14:48:03 +00:00
VLADIMIR fdb92455ba update server 2024-11-19 15:16:01 +07:00
VLADIMIR be0ce71de6 add api 2024-11-19 15:13:01 +07:00
25 changed files with 5969 additions and 46 deletions
+5 -1
View File
@@ -5,7 +5,11 @@
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/smm_core"
"program": "${workspaceFolder}/cmd/smm_core",
"env": {
"DATABASE_URL": "user=crab password=crab dbname=smm-core host=localhost port=5432 sslmode=disable",
"AUTHORIZATION": "Y3JhYjpjcmFi"
}
},
]
}
+22
View File
@@ -0,0 +1,22 @@
{
"sqltools.connections": [
{
"previewLimit": 50,
"server": "localhost",
"port": 5432,
"driver": "PostgreSQL",
"name": "smm",
"database": "smm-core",
"username": "crab",
"password": "crab"
}
],
"cSpell.words": [
"рублей",
"caser",
"dbpool",
"jackc",
"pgconn",
"pgxpool"
]
}
+240 -1
View File
@@ -3,7 +3,6 @@ syntax = "proto3";
package crabs.smm_core;
import "google/api/annotations.proto";
import "google/api/httpbody.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
option go_package = "pkg/proto";
@@ -11,13 +10,253 @@ option go_package = "pkg/proto";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {};
service SmmCore {
// ping
rpc Ping(PingReq) returns (PingRsp) {
option (google.api.http) = {
get: "/ping"
};
}
// login
rpc Login(LoginReq) returns (User) {
option (google.api.http) = {
post: "/login",
body: "*"
};
}
// budgets
rpc AddBudget(AddBudgetReq) returns (Budget) {
option (google.api.http) = {
post: "/budgets",
body: "*"
};
}
rpc UpdateBudget(UpdateBudgetReq) returns (Budget) {
option (google.api.http) = {
put: "/budgets/{id}",
body: "*"
};
}
rpc GetBudgets(GetBudgetsReq) returns (Budgets) {
option (google.api.http) = {
get: "/budgets"
};
}
rpc DeleteBudget(DeleteBudgetReq) returns (Budget) {
option (google.api.http) = {
delete: "/budgets/{id}"
};
}
// budget users
rpc AddUserToBudget(AddUserToBudgetReq) returns (OK) {
option (google.api.http) = {
put: "/budgets/{budget_id}/users",
body: "*"
};
}
rpc GetBudgetUsers(GetBudgetUsersReq) returns (Users) {
option (google.api.http) = {
get: "/budgets/{id}/users"
};
}
rpc RemoveUserFromBudget(RemoveUserFromBudgetReq) returns (Budget) {
option (google.api.http) = {
delete: "/budgets/{budget_id}/users/{user_id}"
};
}
rpc GetBudgetCategories(GetBudgetCategoriesReq) returns (Categories) {
option (google.api.http) = {
get: "/budgets/{budget_id}/categories"
};
}
// categories
rpc AddCategory(AddCategoryReq) returns (Category) {
option (google.api.http) = {
post: "/categories",
body: "*"
};
}
rpc UpdateCategory(UpdateCategoryReq) returns (Category) {
option (google.api.http) = {
put: "/categories/{id}"
};
}
rpc DeleteCategories(DeleteCategoriesReq) returns (Category) {
option (google.api.http) = {
delete: "/categories/{id}"
};
}
// wastes
rpc AddWaste(AddWasteReq) returns (Waste) {
option (google.api.http) = {
post: "/wastes",
body: "*"
};
}
rpc AddWasteByText(AddWasteTextReq) returns (Waste) {
option (google.api.http) = {
post: "/wastes/text",
body: "*"
};
}
rpc DeleteWaste(DeleteWasteReq) returns (Waste) {
option (google.api.http) = {
delete: "/wastes/{id}"
};
}
// stat
rpc GetCategoriesStat(GetCategoriesStatReq) returns (CategoriesStat) {
option (google.api.http) = {
get: "/stat"
};
}
}
message PingReq {}
message PingRsp {}
message OK {}
message AddUserReq {
string username = 1;
string password = 2;
}
message User {
int32 id = 1;
string username = 2;
}
message LoginReq {
string username = 1;
string password = 2;
}
message AddBudgetReq {
string name = 1;
int32 start_day = 2;
int32 monthly_limit = 3;
}
message Budget {
int32 id = 1;
string name = 2;
int32 start_day = 3;
int32 monthly_limit = 4;
repeated Category categories = 5;
}
message UpdateBudgetReq {
int32 id = 1;
string name = 2;
int32 start_day = 3;
int32 monthly_limit = 4;
}
message GetBudgetsReq {}
message Budgets {
repeated Budget budgets = 1;
}
message DeleteBudgetReq {
int32 id = 1;
}
message AddUserToBudgetReq {
int32 user_id = 1;
int32 budget_id = 2;
}
message GetBudgetUsersReq {
int32 id = 1;
}
message Users {
repeated User users = 1;
}
message RemoveUserFromBudgetReq {
int32 user_id = 1;
int32 budget_id = 2;
}
message GetBudgetCategoriesReq {
int32 budget_id = 2;
}
message AddCategoryReq {
string name = 1;
int32 budget_id = 2;
bool favorite = 3;
int32 monthly_limit = 4;
}
message Category {
int32 id = 1;
string name = 2;
int32 budget_id = 3;
bool favorite = 4;
int32 monthly_limit = 5;
}
message UpdateCategoryReq {
int32 id = 1;
string name = 2;
bool favorite = 3;
int32 monthly_limit = 4;
}
message Categories {
repeated Category categories = 1;
}
message DeleteCategoriesReq {
int32 id = 1;
}
message AddWasteReq {
string name = 1;
int32 price = 2;
float amount = 3;
int32 category_id = 4;
int32 budget_id = 5;
}
message AddWasteTextReq {
string text = 1;
int32 category_id = 2;
int32 budget_id = 3;
}
message Waste {
int32 id = 1;
string name = 2;
int32 price = 3;
float amount = 4;
}
message DeleteWasteReq {
int32 id = 1;
}
message GetCategoriesStatReq {
repeated int32 ids = 1;
}
message CategoriesStat {
repeated CategoriesStat stat = 1;
}
message CategoryStat {
string name = 1;
int32 monthly_limit = 2;
int32 amount = 3;
}
+56 -3
View File
@@ -2,15 +2,24 @@ package main
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"git.3crabs.ru/save_my_money/smm_core/internal/app"
"git.3crabs.ru/save_my_money/smm_core/internal/services/budget"
"git.3crabs.ru/save_my_money/smm_core/internal/services/category"
"git.3crabs.ru/save_my_money/smm_core/internal/services/user"
"git.3crabs.ru/save_my_money/smm_core/internal/services/waste"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/jackc/pgx/v5/pgxpool"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
proto "git.3crabs.ru/save_my_money/smm_core/proto"
)
@@ -22,10 +31,49 @@ func main() {
log.Fatalln("Failed to listen:", err)
}
dbpool, err := pgxpool.New(context.Background(), os.Getenv("DATABASE_URL"))
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to create connection pool: %v\n", err)
os.Exit(1)
}
defer dbpool.Close()
categoryService := category.NewCategoryService(dbpool)
userService := user.NewUserService(dbpool)
budgetService := budget.NewBudgetService(dbpool, categoryService)
wasteService := waste.NewWasteService(dbpool, categoryService)
// Create a gRPC server object
s := grpc.NewServer()
s := grpc.NewServer(
grpc.UnaryInterceptor(
func(
ctx context.Context,
req any,
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp any, err error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok || len(md["authorization"]) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "no auth token")
}
authToken := md["authorization"][0]
if authToken != os.Getenv("AUTHORIZATION") {
return nil, status.Errorf(codes.Unauthenticated, "invalid token")
}
return handler(ctx, req)
},
),
)
// Attach the Greeter service to the server
proto.RegisterSmmCoreServer(s, app.NewServer())
proto.RegisterSmmCoreServer(
s,
app.NewServer(
categoryService,
userService,
budgetService,
wasteService,
),
)
// Serve gRPC server
log.Println("Serving gRPC on 0.0.0.0:8080")
go func() {
@@ -42,7 +90,12 @@ func main() {
log.Fatalln("Failed to dial server:", err)
}
mux := runtime.NewServeMux()
mux := runtime.NewServeMux(
runtime.WithMetadata(func(ctx context.Context, request *http.Request) metadata.MD {
header := request.Header.Get("User-Id")
return metadata.Pairs("user-id", header)
}),
)
// Register Greeter
err = proto.RegisterSmmCoreHandler(context.Background(), mux, conn)
if err != nil {
+12 -3
View File
@@ -10,9 +10,18 @@ require (
)
require (
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.19.0 // indirect
github.com/cweill/gotests v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.27.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+43
View File
@@ -1,13 +1,55 @@
github.com/cweill/gotests v1.6.0 h1:KJx+/p4EweijYzqPb4Y/8umDCip1Cv6hEVyOx0mE9W8=
github.com/cweill/gotests v1.6.0/go.mod h1:CaRYbxQZGQOxXDvM9l0XJVV2Tjb2E5H53vq+reR2GrA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw=
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
@@ -21,5 +63,6 @@ google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+52
View File
@@ -0,0 +1,52 @@
package app
import (
"git.3crabs.ru/save_my_money/smm_core/internal/services/budget"
"git.3crabs.ru/save_my_money/smm_core/internal/services/category"
"git.3crabs.ru/save_my_money/smm_core/internal/services/user"
"git.3crabs.ru/save_my_money/smm_core/internal/services/waste"
proto "git.3crabs.ru/save_my_money/smm_core/proto"
)
func mapUser(user *user.UserEntity) *proto.User {
return &proto.User{
Id: int32(user.Id),
Username: user.Username,
}
}
func mapBudget(budget *budget.BudgetEntity) *proto.Budget {
return &proto.Budget{
Id: int32(budget.Id),
Name: budget.Name,
StartDay: int32(budget.StartDay),
MonthlyLimit: int32(budget.MonthlyLimit),
Categories: mapCategories(budget.Categories),
}
}
func mapCategory(category *category.CategoryEntity) *proto.Category {
return &proto.Category{
Id: int32(category.Id),
Name: category.Name,
Favorite: category.Favorite,
MonthlyLimit: int32(category.MonthlyLimit),
}
}
func mapCategories(categories []*category.CategoryEntity) []*proto.Category {
res := make([]*proto.Category, 0, len(categories))
for _, item := range categories {
res = append(res, mapCategory(item))
}
return res
}
func mapWaste(waste *waste.WasteEntity) *proto.Waste {
return &proto.Waste{
Id: int32(waste.Id),
Name: waste.Name,
Price: int32(waste.Price),
Amount: waste.Amount,
}
}
+183 -3
View File
@@ -3,17 +3,197 @@ package app
import (
"context"
"git.3crabs.ru/save_my_money/smm_core/internal/services/budget"
"git.3crabs.ru/save_my_money/smm_core/internal/services/category"
"git.3crabs.ru/save_my_money/smm_core/internal/services/user"
"git.3crabs.ru/save_my_money/smm_core/internal/services/waste"
proto "git.3crabs.ru/save_my_money/smm_core/proto"
)
type Server struct {
proto.UnsafeSmmCoreServer
categoryService *category.CategoryService
userService *user.UserService
budgetService *budget.BudgetService
wasteService *waste.WasteService
}
func NewServer() *Server {
return &Server{}
func NewServer(
categoryService *category.CategoryService,
userService *user.UserService,
budgetService *budget.BudgetService,
wasteService *waste.WasteService,
) proto.SmmCoreServer {
return &Server{
categoryService: categoryService,
userService: userService,
budgetService: budgetService,
wasteService: wasteService,
}
}
func (s *Server) Ping(_ context.Context, _ *proto.PingReq) (*proto.PingRsp, error) {
func (s *Server) Ping(context.Context, *proto.PingReq) (*proto.PingRsp, error) {
return &proto.PingRsp{}, nil
}
func (s *Server) Login(ctx context.Context, req *proto.LoginReq) (*proto.User, error) {
user, err := s.userService.Login(
ctx,
&user.UserEntity{
Username: req.Username,
Password: req.Password,
},
)
if err != nil {
return nil, err
}
return mapUser(user), nil
}
func (s *Server) AddBudget(ctx context.Context, req *proto.AddBudgetReq) (*proto.Budget, error) {
budget, err := s.budgetService.AddBudget(
ctx,
&budget.BudgetEntity{
Name: req.Name,
StartDay: int(req.StartDay),
MonthlyLimit: int(req.MonthlyLimit),
},
)
if err != nil {
return nil, err
}
return mapBudget(budget), nil
}
func (s *Server) GetBudgets(ctx context.Context, req *proto.GetBudgetsReq) (*proto.Budgets, error) {
budgets, err := s.budgetService.GetBudgets(
ctx,
)
if err != nil {
return nil, err
}
res := make([]*proto.Budget, 0, len(budgets))
for _, budget := range budgets {
res = append(res, mapBudget(budget))
}
return &proto.Budgets{
Budgets: res,
}, nil
}
func (s *Server) AddUserToBudget(ctx context.Context, req *proto.AddUserToBudgetReq) (*proto.OK, error) {
_, err := s.budgetService.AddUserToBudget(
ctx,
int(req.BudgetId),
int(req.UserId),
)
if err != nil {
return nil, err
}
return &proto.OK{}, nil
}
func (s *Server) AddCategory(ctx context.Context, req *proto.AddCategoryReq) (*proto.Category, error) {
category, err := s.categoryService.AddCategory(
ctx,
&category.CategoryEntity{
Name: req.Name,
BudgetId: int(req.BudgetId),
Favorite: req.Favorite,
MonthlyLimit: int(req.MonthlyLimit),
},
)
if err != nil {
return nil, err
}
return mapCategory(category), nil
}
func (s *Server) GetBudgetCategories(ctx context.Context, req *proto.GetBudgetCategoriesReq) (*proto.Categories, error) {
categories, err := s.budgetService.GetBudgetCategories(
ctx,
int(req.BudgetId),
)
if err != nil {
return nil, err
}
res := make([]*proto.Category, 0, len(categories))
for _, category := range categories {
res = append(res, mapCategory(category))
}
return &proto.Categories{
Categories: res,
}, nil
}
func (s *Server) AddWaste(ctx context.Context, req *proto.AddWasteReq) (*proto.Waste, error) {
waste, err := s.wasteService.AddWaste(
ctx,
&waste.WasteEntity{
Name: req.Name,
Price: int(req.Price),
Amount: req.Amount,
CategoryId: int(req.CategoryId),
BudgetId: int(req.BudgetId),
},
)
if err != nil {
return nil, err
}
return mapWaste(waste), nil
}
func (s *Server) AddWasteByText(ctx context.Context, req *proto.AddWasteTextReq) (*proto.Waste, error) {
waste, err := s.wasteService.AddWasteByText(
ctx,
&waste.WasteTextEntity{
Text: req.Text,
CategoryId: int(req.CategoryId),
BudgetId: int(req.BudgetId),
},
)
if err != nil {
return nil, err
}
return mapWaste(waste), nil
}
// GetCategoriesStat implements proto.SmmCoreServer.
func (s *Server) GetCategoriesStat(context.Context, *proto.GetCategoriesStatReq) (*proto.CategoriesStat, error) {
panic("unimplemented")
}
// DeleteBudget implements proto.SmmCoreServer.
func (s *Server) DeleteBudget(context.Context, *proto.DeleteBudgetReq) (*proto.Budget, error) {
panic("unimplemented")
}
// DeleteCategories implements proto.SmmCoreServer.
func (s *Server) DeleteCategories(context.Context, *proto.DeleteCategoriesReq) (*proto.Category, error) {
panic("unimplemented")
}
// DeleteWaste implements proto.SmmCoreServer.
func (s *Server) DeleteWaste(context.Context, *proto.DeleteWasteReq) (*proto.Waste, error) {
panic("unimplemented")
}
// GetBudgetUsers implements proto.SmmCoreServer.
func (s *Server) GetBudgetUsers(context.Context, *proto.GetBudgetUsersReq) (*proto.Users, error) {
panic("unimplemented")
}
// RemoveUserFromBudget implements proto.SmmCoreServer.
func (s *Server) RemoveUserFromBudget(context.Context, *proto.RemoveUserFromBudgetReq) (*proto.Budget, error) {
panic("unimplemented")
}
// UpdateBudget implements proto.SmmCoreServer.
func (s *Server) UpdateBudget(context.Context, *proto.UpdateBudgetReq) (*proto.Budget, error) {
panic("unimplemented")
}
// UpdateCategory implements proto.SmmCoreServer.
func (s *Server) UpdateCategory(context.Context, *proto.UpdateCategoryReq) (*proto.Category, error) {
panic("unimplemented")
}
+139
View File
@@ -0,0 +1,139 @@
package budget
import (
"context"
"fmt"
"git.3crabs.ru/save_my_money/smm_core/internal/services/category"
"git.3crabs.ru/save_my_money/smm_core/internal/services/context_utils"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
type BudgetEntity struct {
Id int
Name string
StartDay int
MonthlyLimit int
Categories []*category.CategoryEntity
}
type BudgetService struct {
db *pgxpool.Pool
categoryService *category.CategoryService
}
func NewBudgetService(
db *pgxpool.Pool,
categoryService *category.CategoryService,
) *BudgetService {
return &BudgetService{
db: db,
categoryService: categoryService,
}
}
func (s *BudgetService) AddBudget(ctx context.Context, budget *BudgetEntity) (*BudgetEntity, error) {
userId, err := context_utils.GetUserId(ctx)
if err != nil {
return nil, err
}
tx, err := s.db.Begin(ctx)
if err != nil {
return nil, err
}
defer tx.Rollback(ctx)
query := `INSERT INTO budgets (name, start_day, monthly_limit) VALUES (@name, @start_day, @monthly_limit) RETURNING id`
args := pgx.NamedArgs{
"name": budget.Name,
"start_day": budget.StartDay,
"monthly_limit": budget.MonthlyLimit,
}
if err := s.db.QueryRow(ctx, query, args).Scan(&budget.Id); err != nil {
return nil, fmt.Errorf("unable to insert row: %w", err)
}
_, err = s.AddUserToBudget(ctx, budget.Id, userId)
if err != nil {
return nil, err
}
if err = tx.Commit(ctx); err != nil {
return nil, err
}
return budget, nil
}
func (s *BudgetService) GetBudgets(ctx context.Context) ([]*BudgetEntity, error) {
userId, err := context_utils.GetUserId(ctx)
if err != nil {
return nil, err
}
query := `SELECT b.id, b.name, b.start_day, b.monthly_limit FROM budgets b JOIN users_budgets ub ON ub.budget_id = b.id WHERE ub.user_id = @user_id`
args := pgx.NamedArgs{
"user_id": userId,
}
rows, err := s.db.Query(ctx, query, args)
if err != nil {
return nil, err
}
budgets := []*BudgetEntity{}
defer rows.Close()
for rows.Next() {
budget := &BudgetEntity{}
err = rows.Scan(&budget.Id, &budget.Name, &budget.StartDay, &budget.MonthlyLimit)
if err != nil {
return nil, err
}
budget.Categories, err = s.GetBudgetCategories(ctx, budget.Id)
budgets = append(budgets, budget)
}
return budgets, nil
}
func (s *BudgetService) AddUserToBudget(
ctx context.Context,
budgetId int,
userId int,
) (int, error) {
query := `INSERT INTO users_budgets (user_id, budget_id) VALUES (@user_id, @budget_id) RETURNING id`
args := pgx.NamedArgs{
"user_id": userId,
"budget_id": budgetId,
}
id := 0
if err := s.db.QueryRow(ctx, query, args).Scan(&id); err != nil {
return 0, fmt.Errorf("unable to insert row: %w", err)
}
return id, nil
}
func (s *BudgetService) GetBudgetCategories(
ctx context.Context,
budgetId int,
) ([]*category.CategoryEntity, error) {
query := `SELECT id, name, favorite, monthly_limit FROM categories WHERE budget_id = @budget_id`
args := pgx.NamedArgs{
"budget_id": budgetId,
}
rows, err := s.db.Query(ctx, query, args)
if err != nil {
return nil, err
}
categories := []*category.CategoryEntity{}
defer rows.Close()
for rows.Next() {
category := &category.CategoryEntity{}
err = rows.Scan(&category.Id, &category.Name, &category.Favorite, &category.MonthlyLimit)
if err != nil {
return nil, err
}
categories = append(categories, category)
}
return categories, nil
}
@@ -0,0 +1,68 @@
package category
import (
"context"
"fmt"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
type CategoryEntity struct {
Id int
Name string
BudgetId int
Favorite bool
MonthlyLimit int
}
type CategoryService struct {
db *pgxpool.Pool
}
func NewCategoryService(
db *pgxpool.Pool,
) *CategoryService {
return &CategoryService{
db: db,
}
}
func (s *CategoryService) AddCategory(ctx context.Context, category *CategoryEntity) (*CategoryEntity, error) {
query := `INSERT INTO categories (name, budget_id, favorite, monthly_limit) VALUES (@name, @budget_id, @favorite, @monthly_limit) RETURNING id`
args := pgx.NamedArgs{
"name": category.Name,
"budget_id": category.BudgetId,
"favorite": category.Favorite,
"monthly_limit": category.MonthlyLimit,
}
if err := s.db.QueryRow(ctx, query, args).Scan(&category.Id); err != nil {
return nil, fmt.Errorf("unable to insert row: %w", err)
}
return category, nil
}
func (s *CategoryService) GetCategory(ctx context.Context, budgetId int, name string) (*CategoryEntity, error) {
query := `SELECT id, name, budget_id, favorite, monthly_limit FROM categories WHERE LOWER(name) = LOWER(@name)`
args := pgx.NamedArgs{
"name": name,
}
rows, err := s.db.Query(ctx, query, args)
if err != nil {
return nil, err
}
categories := []*CategoryEntity{}
defer rows.Close()
for rows.Next() {
category := &CategoryEntity{}
err = rows.Scan(&category.Id, &category.Name, &category.BudgetId, &category.Favorite, &category.MonthlyLimit)
if err != nil {
return nil, err
}
categories = append(categories, category)
}
if len(categories) > 0 {
return categories[0], nil
}
return nil, nil
}
@@ -0,0 +1,26 @@
package context_utils
import (
"context"
"strconv"
"google.golang.org/grpc/metadata"
)
type UnauthorizedErr struct{}
func (e *UnauthorizedErr) Error() string {
return "user not autorize"
}
func GetUserId(ctx context.Context) (int, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return 0, &UnauthorizedErr{}
}
id, err := strconv.Atoi(md["user-id"][0])
if err != nil {
return 0, &UnauthorizedErr{}
}
return id, nil
}
File diff suppressed because one or more lines are too long
+66
View File
@@ -0,0 +1,66 @@
package user
import (
"context"
"crypto/md5"
"encoding/hex"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
type UserEntity struct {
Id int
Username string
Password string
}
type UsernameAlreadyExistsErr struct{}
func (e *UsernameAlreadyExistsErr) Error() string {
return "username already exists error"
}
type UserNotFoundErr struct{}
func (e *UserNotFoundErr) Error() string {
return "user not found error"
}
type UserService struct {
db *pgxpool.Pool
}
func NewUserService(
db *pgxpool.Pool,
) *UserService {
return &UserService{
db: db,
}
}
func (s *UserService) Login(ctx context.Context, user *UserEntity) (*UserEntity, error) {
args := pgx.NamedArgs{
"username": user.Username,
"password": hashPassword(user.Username, user.Password, "crab"),
}
query := `SELECT id FROM users WHERE username = @username AND password = @password LIMIT 1`
if err := s.db.QueryRow(ctx, query, args).Scan(&user.Id); err != nil {
query := `INSERT INTO users (username, password) VALUES (@username, @password) RETURNING id`
if err := s.db.QueryRow(ctx, query, args).Scan(&user.Id); err != nil {
return user, err
}
}
return user, nil
}
func hashPassword(username string, password string, salt string) string {
return getMD5Hash(username + password + salt)
}
func getMD5Hash(text string) string {
hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:])
}
+190
View File
@@ -0,0 +1,190 @@
package waste
import (
"context"
"fmt"
"strconv"
"strings"
"git.3crabs.ru/save_my_money/smm_core/internal/services/category"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
type WasteEntity struct {
Id int
Name string
Price int
Amount float32
CategoryId int
CategoryName string
BudgetId int
}
type WasteTextEntity struct {
Text string
CategoryId int
BudgetId int
}
type WasteService struct {
db *pgxpool.Pool
categoryService *category.CategoryService
}
func NewWasteService(
db *pgxpool.Pool,
categoryService *category.CategoryService,
) *WasteService {
return &WasteService{
db: db,
categoryService: categoryService,
}
}
func (s *WasteService) AddWaste(ctx context.Context, waste *WasteEntity) (*WasteEntity, error) {
query := `INSERT INTO wastes (name, price, amount, budget_id, category_id) VALUES (@name, @price, @amount, @budget_id, @category_id) RETURNING id`
args := pgx.NamedArgs{
"name": waste.Name,
"price": waste.Price,
"amount": waste.Amount,
"budget_id": waste.BudgetId,
"category_id": waste.CategoryId,
}
if err := s.db.QueryRow(ctx, query, args).Scan(&waste.Id); err != nil {
return nil, fmt.Errorf("unable to insert row: %w", err)
}
return waste, nil
}
func (s *WasteService) GetWaste(ctx context.Context, budgetId int, name string) (*WasteEntity, error) {
query := `SELECT id, name, price, amount, budget_id, category_id FROM wastes WHERE budget_id = @budget_id AND LOWER(name) = LOWER(@name) LIMIT 1`
args := pgx.NamedArgs{
"name": name,
"budget_id": budgetId,
}
rows, err := s.db.Query(ctx, query, args)
if err != nil {
return nil, err
}
wastes := []*WasteEntity{}
defer rows.Close()
for rows.Next() {
waste := &WasteEntity{}
err = rows.Scan(&waste.Id, &waste.Name, &waste.Price, &waste.Amount, &waste.BudgetId, &waste.CategoryId)
if err != nil {
return nil, err
}
wastes = append(wastes, waste)
}
if len(wastes) > 0 {
return wastes[0], nil
}
return nil, nil
}
func (s *WasteService) AddWasteByText(ctx context.Context, wasteText *WasteTextEntity) (*WasteEntity, error) {
waste := s.parseWaste(wasteText.Text)
var categoryId *int
if waste.CategoryName != "" {
c, err := s.categoryService.GetCategory(ctx, wasteText.BudgetId, waste.CategoryName)
if err != nil {
return nil, err
}
if c == nil {
c, err = s.categoryService.AddCategory(ctx, &category.CategoryEntity{
Name: waste.CategoryName,
BudgetId: int(wasteText.BudgetId),
})
if err != nil {
return nil, err
}
}
categoryId = &c.Id
}
if categoryId == nil {
w, err := s.GetWaste(ctx, wasteText.BudgetId, waste.Name)
if err != nil {
return nil, err
}
if w != nil {
categoryId = &w.CategoryId
}
}
if categoryId == nil {
return nil, fmt.Errorf("bad request")
}
query := `INSERT INTO wastes (name, price, amount, budget_id, category_id) VALUES (@name, @price, @amount, @budget_id, @category_id) RETURNING id`
args := pgx.NamedArgs{
"name": waste.Name,
"price": waste.Price,
"amount": waste.Amount,
"budget_id": wasteText.BudgetId,
"category_id": *categoryId,
}
if err := s.db.QueryRow(ctx, query, args).Scan(&waste.Id); err != nil {
return nil, fmt.Errorf("unable to insert row: %w", err)
}
return waste, nil
}
func (s *WasteService) parseWaste(text string) *WasteEntity {
text = strings.TrimSpace(text)
arr := strings.Split(text, ":")
waste := &WasteEntity{}
switch len(arr) {
case 1:
arr = strings.Split(strings.TrimSpace(arr[0]), " ")
case 2:
waste.CategoryName = strToName(arr[0])
arr = strings.Split(strings.TrimSpace(arr[1]), " ")
}
switch len(arr) {
case 2:
waste.Name = strToName(arr[0])
waste.Amount = 1
waste.Price = strToPrice(arr[1])
case 3:
waste.Name = strToName(arr[0])
waste.Amount = strToAmount(arr[1])
waste.Price = strToPrice(arr[2])
}
return waste
}
func strToFloat(s string) float32 {
a, err := strconv.ParseFloat(s, 32)
if err != nil {
panic(err)
}
return float32(a)
}
func strToPrice(s string) int {
s = strings.TrimSpace(s)
s = strings.TrimSuffix(s, "/кг")
s = strings.TrimSuffix(s, "/шт")
s = strings.TrimSuffix(s, "р")
s = strings.TrimSuffix(s, "руб")
s = strings.TrimSuffix(s, "рублей")
return int(strToFloat(s) * 100)
}
func strToAmount(s string) float32 {
s = strings.TrimSpace(s)
s = strings.TrimSuffix(s, "шт")
s = strings.TrimSuffix(s, "кг")
return strToFloat(s)
}
func strToName(s string) string {
caser := cases.Title(language.Russian)
return caser.String(strings.TrimSpace(strings.ToLower(s)))
}
@@ -0,0 +1,83 @@
package waste
import (
"reflect"
"testing"
)
func TestWasteService_parseWaste(t *testing.T) {
type args struct {
text string
}
tests := []struct {
name string
args args
want *WasteEntity
}{
{
name: "full",
args: args{
text: "Транспорт: такси 2 200",
},
want: &WasteEntity{
CategoryName: "транспорт",
Name: "такси",
Amount: 2,
Price: 20000,
},
},
{
name: "full without amount",
args: args{
text: "Транспорт: такси 200",
},
want: &WasteEntity{
CategoryName: "транспорт",
Name: "такси",
Amount: 1,
Price: 20000,
},
},
{
name: "without category",
args: args{
text: "такси 2 200",
},
want: &WasteEntity{
Name: "такси",
Amount: 2,
Price: 20000,
},
},
{
name: "without amount",
args: args{
text: "такси 200",
},
want: &WasteEntity{
Name: "такси",
Amount: 1,
Price: 20000,
},
},
{
name: "р",
args: args{
text: "такси 200р",
},
want: &WasteEntity{
Name: "такси",
Amount: 1,
Price: 20000,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &WasteService{}
if got := s.parseWaste(tt.args.text); !reflect.DeepEqual(got, tt.want) {
t.Errorf("WasteService.parseWaste() = %v, want %v", got, tt.want)
}
})
}
}
@@ -2,7 +2,9 @@
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
chat_id TEXT NOT NULL
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
-- +goose StatementEnd
@@ -0,0 +1,15 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS budgets (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
start_day INT NOT NULL,
monthly_limit INT DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS budgets;
-- +goose StatementEnd
@@ -3,9 +3,11 @@
CREATE TABLE IF NOT EXISTS categories (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
user_id INT REFERENCES users(id),
budget_id INT REFERENCES budgets(id) ON DELETE CASCADE,
favorite BOOLEAN DEFAULT FALSE,
monthly_limit INT DEFAULT 0
monthly_limit INT DEFAULT 0,
UNIQUE (budget_id, name),
created_at TIMESTAMP DEFAULT NOW()
);
-- +goose StatementEnd
@@ -0,0 +1,18 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS wastes (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price INT NOT NULL,
amount FLOAT NOT NULL,
budget_id INT REFERENCES budgets(id) ON DELETE CASCADE,
category_id INT REFERENCES categories(id) ON DELETE RESTRICT,
created_at TIMESTAMP DEFAULT NOW()
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS wastes;
-- +goose StatementEnd
А
@@ -0,0 +1,14 @@
-- +goose Up
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS users_budgets (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id) ON DELETE CASCADE,
budget_id INT REFERENCES budgets(id) ON DELETE RESTRICT,
created_at TIMESTAMP DEFAULT NOW()
);
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
DROP TABLE IF EXISTS users_budgets;
-- +goose StatementEnd
+1798 -27
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+623 -1
View File
@@ -19,14 +19,53 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
SmmCore_Ping_FullMethodName = "/crabs.smm_core.SmmCore/Ping"
SmmCore_Ping_FullMethodName = "/crabs.smm_core.SmmCore/Ping"
SmmCore_Login_FullMethodName = "/crabs.smm_core.SmmCore/Login"
SmmCore_AddBudget_FullMethodName = "/crabs.smm_core.SmmCore/AddBudget"
SmmCore_UpdateBudget_FullMethodName = "/crabs.smm_core.SmmCore/UpdateBudget"
SmmCore_GetBudgets_FullMethodName = "/crabs.smm_core.SmmCore/GetBudgets"
SmmCore_DeleteBudget_FullMethodName = "/crabs.smm_core.SmmCore/DeleteBudget"
SmmCore_AddUserToBudget_FullMethodName = "/crabs.smm_core.SmmCore/AddUserToBudget"
SmmCore_GetBudgetUsers_FullMethodName = "/crabs.smm_core.SmmCore/GetBudgetUsers"
SmmCore_RemoveUserFromBudget_FullMethodName = "/crabs.smm_core.SmmCore/RemoveUserFromBudget"
SmmCore_GetBudgetCategories_FullMethodName = "/crabs.smm_core.SmmCore/GetBudgetCategories"
SmmCore_AddCategory_FullMethodName = "/crabs.smm_core.SmmCore/AddCategory"
SmmCore_UpdateCategory_FullMethodName = "/crabs.smm_core.SmmCore/UpdateCategory"
SmmCore_DeleteCategories_FullMethodName = "/crabs.smm_core.SmmCore/DeleteCategories"
SmmCore_AddWaste_FullMethodName = "/crabs.smm_core.SmmCore/AddWaste"
SmmCore_AddWasteByText_FullMethodName = "/crabs.smm_core.SmmCore/AddWasteByText"
SmmCore_DeleteWaste_FullMethodName = "/crabs.smm_core.SmmCore/DeleteWaste"
SmmCore_GetCategoriesStat_FullMethodName = "/crabs.smm_core.SmmCore/GetCategoriesStat"
)
// SmmCoreClient is the client API for SmmCore service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SmmCoreClient interface {
// ping
Ping(ctx context.Context, in *PingReq, opts ...grpc.CallOption) (*PingRsp, error)
// login
Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*User, error)
// budgets
AddBudget(ctx context.Context, in *AddBudgetReq, opts ...grpc.CallOption) (*Budget, error)
UpdateBudget(ctx context.Context, in *UpdateBudgetReq, opts ...grpc.CallOption) (*Budget, error)
GetBudgets(ctx context.Context, in *GetBudgetsReq, opts ...grpc.CallOption) (*Budgets, error)
DeleteBudget(ctx context.Context, in *DeleteBudgetReq, opts ...grpc.CallOption) (*Budget, error)
// budget users
AddUserToBudget(ctx context.Context, in *AddUserToBudgetReq, opts ...grpc.CallOption) (*OK, error)
GetBudgetUsers(ctx context.Context, in *GetBudgetUsersReq, opts ...grpc.CallOption) (*Users, error)
RemoveUserFromBudget(ctx context.Context, in *RemoveUserFromBudgetReq, opts ...grpc.CallOption) (*Budget, error)
GetBudgetCategories(ctx context.Context, in *GetBudgetCategoriesReq, opts ...grpc.CallOption) (*Categories, error)
// categories
AddCategory(ctx context.Context, in *AddCategoryReq, opts ...grpc.CallOption) (*Category, error)
UpdateCategory(ctx context.Context, in *UpdateCategoryReq, opts ...grpc.CallOption) (*Category, error)
DeleteCategories(ctx context.Context, in *DeleteCategoriesReq, opts ...grpc.CallOption) (*Category, error)
// wastes
AddWaste(ctx context.Context, in *AddWasteReq, opts ...grpc.CallOption) (*Waste, error)
AddWasteByText(ctx context.Context, in *AddWasteTextReq, opts ...grpc.CallOption) (*Waste, error)
DeleteWaste(ctx context.Context, in *DeleteWasteReq, opts ...grpc.CallOption) (*Waste, error)
// stat
GetCategoriesStat(ctx context.Context, in *GetCategoriesStatReq, opts ...grpc.CallOption) (*CategoriesStat, error)
}
type smmCoreClient struct {
@@ -47,11 +86,194 @@ func (c *smmCoreClient) Ping(ctx context.Context, in *PingReq, opts ...grpc.Call
return out, nil
}
func (c *smmCoreClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*User, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(User)
err := c.cc.Invoke(ctx, SmmCore_Login_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) AddBudget(ctx context.Context, in *AddBudgetReq, opts ...grpc.CallOption) (*Budget, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Budget)
err := c.cc.Invoke(ctx, SmmCore_AddBudget_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) UpdateBudget(ctx context.Context, in *UpdateBudgetReq, opts ...grpc.CallOption) (*Budget, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Budget)
err := c.cc.Invoke(ctx, SmmCore_UpdateBudget_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) GetBudgets(ctx context.Context, in *GetBudgetsReq, opts ...grpc.CallOption) (*Budgets, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Budgets)
err := c.cc.Invoke(ctx, SmmCore_GetBudgets_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) DeleteBudget(ctx context.Context, in *DeleteBudgetReq, opts ...grpc.CallOption) (*Budget, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Budget)
err := c.cc.Invoke(ctx, SmmCore_DeleteBudget_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) AddUserToBudget(ctx context.Context, in *AddUserToBudgetReq, opts ...grpc.CallOption) (*OK, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OK)
err := c.cc.Invoke(ctx, SmmCore_AddUserToBudget_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) GetBudgetUsers(ctx context.Context, in *GetBudgetUsersReq, opts ...grpc.CallOption) (*Users, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Users)
err := c.cc.Invoke(ctx, SmmCore_GetBudgetUsers_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) RemoveUserFromBudget(ctx context.Context, in *RemoveUserFromBudgetReq, opts ...grpc.CallOption) (*Budget, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Budget)
err := c.cc.Invoke(ctx, SmmCore_RemoveUserFromBudget_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) GetBudgetCategories(ctx context.Context, in *GetBudgetCategoriesReq, opts ...grpc.CallOption) (*Categories, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Categories)
err := c.cc.Invoke(ctx, SmmCore_GetBudgetCategories_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) AddCategory(ctx context.Context, in *AddCategoryReq, opts ...grpc.CallOption) (*Category, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Category)
err := c.cc.Invoke(ctx, SmmCore_AddCategory_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) UpdateCategory(ctx context.Context, in *UpdateCategoryReq, opts ...grpc.CallOption) (*Category, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Category)
err := c.cc.Invoke(ctx, SmmCore_UpdateCategory_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) DeleteCategories(ctx context.Context, in *DeleteCategoriesReq, opts ...grpc.CallOption) (*Category, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Category)
err := c.cc.Invoke(ctx, SmmCore_DeleteCategories_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) AddWaste(ctx context.Context, in *AddWasteReq, opts ...grpc.CallOption) (*Waste, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Waste)
err := c.cc.Invoke(ctx, SmmCore_AddWaste_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) AddWasteByText(ctx context.Context, in *AddWasteTextReq, opts ...grpc.CallOption) (*Waste, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Waste)
err := c.cc.Invoke(ctx, SmmCore_AddWasteByText_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) DeleteWaste(ctx context.Context, in *DeleteWasteReq, opts ...grpc.CallOption) (*Waste, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Waste)
err := c.cc.Invoke(ctx, SmmCore_DeleteWaste_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *smmCoreClient) GetCategoriesStat(ctx context.Context, in *GetCategoriesStatReq, opts ...grpc.CallOption) (*CategoriesStat, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CategoriesStat)
err := c.cc.Invoke(ctx, SmmCore_GetCategoriesStat_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// SmmCoreServer is the server API for SmmCore service.
// All implementations must embed UnimplementedSmmCoreServer
// for forward compatibility.
type SmmCoreServer interface {
// ping
Ping(context.Context, *PingReq) (*PingRsp, error)
// login
Login(context.Context, *LoginReq) (*User, error)
// budgets
AddBudget(context.Context, *AddBudgetReq) (*Budget, error)
UpdateBudget(context.Context, *UpdateBudgetReq) (*Budget, error)
GetBudgets(context.Context, *GetBudgetsReq) (*Budgets, error)
DeleteBudget(context.Context, *DeleteBudgetReq) (*Budget, error)
// budget users
AddUserToBudget(context.Context, *AddUserToBudgetReq) (*OK, error)
GetBudgetUsers(context.Context, *GetBudgetUsersReq) (*Users, error)
RemoveUserFromBudget(context.Context, *RemoveUserFromBudgetReq) (*Budget, error)
GetBudgetCategories(context.Context, *GetBudgetCategoriesReq) (*Categories, error)
// categories
AddCategory(context.Context, *AddCategoryReq) (*Category, error)
UpdateCategory(context.Context, *UpdateCategoryReq) (*Category, error)
DeleteCategories(context.Context, *DeleteCategoriesReq) (*Category, error)
// wastes
AddWaste(context.Context, *AddWasteReq) (*Waste, error)
AddWasteByText(context.Context, *AddWasteTextReq) (*Waste, error)
DeleteWaste(context.Context, *DeleteWasteReq) (*Waste, error)
// stat
GetCategoriesStat(context.Context, *GetCategoriesStatReq) (*CategoriesStat, error)
mustEmbedUnimplementedSmmCoreServer()
}
@@ -65,6 +287,54 @@ type UnimplementedSmmCoreServer struct{}
func (UnimplementedSmmCoreServer) Ping(context.Context, *PingReq) (*PingRsp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented")
}
func (UnimplementedSmmCoreServer) Login(context.Context, *LoginReq) (*User, error) {
return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
}
func (UnimplementedSmmCoreServer) AddBudget(context.Context, *AddBudgetReq) (*Budget, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddBudget not implemented")
}
func (UnimplementedSmmCoreServer) UpdateBudget(context.Context, *UpdateBudgetReq) (*Budget, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateBudget not implemented")
}
func (UnimplementedSmmCoreServer) GetBudgets(context.Context, *GetBudgetsReq) (*Budgets, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBudgets not implemented")
}
func (UnimplementedSmmCoreServer) DeleteBudget(context.Context, *DeleteBudgetReq) (*Budget, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteBudget not implemented")
}
func (UnimplementedSmmCoreServer) AddUserToBudget(context.Context, *AddUserToBudgetReq) (*OK, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddUserToBudget not implemented")
}
func (UnimplementedSmmCoreServer) GetBudgetUsers(context.Context, *GetBudgetUsersReq) (*Users, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBudgetUsers not implemented")
}
func (UnimplementedSmmCoreServer) RemoveUserFromBudget(context.Context, *RemoveUserFromBudgetReq) (*Budget, error) {
return nil, status.Errorf(codes.Unimplemented, "method RemoveUserFromBudget not implemented")
}
func (UnimplementedSmmCoreServer) GetBudgetCategories(context.Context, *GetBudgetCategoriesReq) (*Categories, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBudgetCategories not implemented")
}
func (UnimplementedSmmCoreServer) AddCategory(context.Context, *AddCategoryReq) (*Category, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddCategory not implemented")
}
func (UnimplementedSmmCoreServer) UpdateCategory(context.Context, *UpdateCategoryReq) (*Category, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateCategory not implemented")
}
func (UnimplementedSmmCoreServer) DeleteCategories(context.Context, *DeleteCategoriesReq) (*Category, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteCategories not implemented")
}
func (UnimplementedSmmCoreServer) AddWaste(context.Context, *AddWasteReq) (*Waste, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddWaste not implemented")
}
func (UnimplementedSmmCoreServer) AddWasteByText(context.Context, *AddWasteTextReq) (*Waste, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddWasteByText not implemented")
}
func (UnimplementedSmmCoreServer) DeleteWaste(context.Context, *DeleteWasteReq) (*Waste, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteWaste not implemented")
}
func (UnimplementedSmmCoreServer) GetCategoriesStat(context.Context, *GetCategoriesStatReq) (*CategoriesStat, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetCategoriesStat not implemented")
}
func (UnimplementedSmmCoreServer) mustEmbedUnimplementedSmmCoreServer() {}
func (UnimplementedSmmCoreServer) testEmbeddedByValue() {}
@@ -104,6 +374,294 @@ func _SmmCore_Ping_Handler(srv interface{}, ctx context.Context, dec func(interf
return interceptor(ctx, in, info, handler)
}
func _SmmCore_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LoginReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).Login(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_Login_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).Login(ctx, req.(*LoginReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_AddBudget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddBudgetReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).AddBudget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_AddBudget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).AddBudget(ctx, req.(*AddBudgetReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_UpdateBudget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateBudgetReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).UpdateBudget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_UpdateBudget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).UpdateBudget(ctx, req.(*UpdateBudgetReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_GetBudgets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBudgetsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).GetBudgets(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_GetBudgets_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).GetBudgets(ctx, req.(*GetBudgetsReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_DeleteBudget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteBudgetReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).DeleteBudget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_DeleteBudget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).DeleteBudget(ctx, req.(*DeleteBudgetReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_AddUserToBudget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddUserToBudgetReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).AddUserToBudget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_AddUserToBudget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).AddUserToBudget(ctx, req.(*AddUserToBudgetReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_GetBudgetUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBudgetUsersReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).GetBudgetUsers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_GetBudgetUsers_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).GetBudgetUsers(ctx, req.(*GetBudgetUsersReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_RemoveUserFromBudget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveUserFromBudgetReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).RemoveUserFromBudget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_RemoveUserFromBudget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).RemoveUserFromBudget(ctx, req.(*RemoveUserFromBudgetReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_GetBudgetCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBudgetCategoriesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).GetBudgetCategories(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_GetBudgetCategories_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).GetBudgetCategories(ctx, req.(*GetBudgetCategoriesReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_AddCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddCategoryReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).AddCategory(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_AddCategory_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).AddCategory(ctx, req.(*AddCategoryReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_UpdateCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateCategoryReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).UpdateCategory(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_UpdateCategory_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).UpdateCategory(ctx, req.(*UpdateCategoryReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_DeleteCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteCategoriesReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).DeleteCategories(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_DeleteCategories_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).DeleteCategories(ctx, req.(*DeleteCategoriesReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_AddWaste_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddWasteReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).AddWaste(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_AddWaste_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).AddWaste(ctx, req.(*AddWasteReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_AddWasteByText_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddWasteTextReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).AddWasteByText(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_AddWasteByText_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).AddWasteByText(ctx, req.(*AddWasteTextReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_DeleteWaste_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteWasteReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).DeleteWaste(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_DeleteWaste_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).DeleteWaste(ctx, req.(*DeleteWasteReq))
}
return interceptor(ctx, in, info, handler)
}
func _SmmCore_GetCategoriesStat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetCategoriesStatReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SmmCoreServer).GetCategoriesStat(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: SmmCore_GetCategoriesStat_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SmmCoreServer).GetCategoriesStat(ctx, req.(*GetCategoriesStatReq))
}
return interceptor(ctx, in, info, handler)
}
// SmmCore_ServiceDesc is the grpc.ServiceDesc for SmmCore service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -115,6 +673,70 @@ var SmmCore_ServiceDesc = grpc.ServiceDesc{
MethodName: "Ping",
Handler: _SmmCore_Ping_Handler,
},
{
MethodName: "Login",
Handler: _SmmCore_Login_Handler,
},
{
MethodName: "AddBudget",
Handler: _SmmCore_AddBudget_Handler,
},
{
MethodName: "UpdateBudget",
Handler: _SmmCore_UpdateBudget_Handler,
},
{
MethodName: "GetBudgets",
Handler: _SmmCore_GetBudgets_Handler,
},
{
MethodName: "DeleteBudget",
Handler: _SmmCore_DeleteBudget_Handler,
},
{
MethodName: "AddUserToBudget",
Handler: _SmmCore_AddUserToBudget_Handler,
},
{
MethodName: "GetBudgetUsers",
Handler: _SmmCore_GetBudgetUsers_Handler,
},
{
MethodName: "RemoveUserFromBudget",
Handler: _SmmCore_RemoveUserFromBudget_Handler,
},
{
MethodName: "GetBudgetCategories",
Handler: _SmmCore_GetBudgetCategories_Handler,
},
{
MethodName: "AddCategory",
Handler: _SmmCore_AddCategory_Handler,
},
{
MethodName: "UpdateCategory",
Handler: _SmmCore_UpdateCategory_Handler,
},
{
MethodName: "DeleteCategories",
Handler: _SmmCore_DeleteCategories_Handler,
},
{
MethodName: "AddWaste",
Handler: _SmmCore_AddWaste_Handler,
},
{
MethodName: "AddWasteByText",
Handler: _SmmCore_AddWasteByText_Handler,
},
{
MethodName: "DeleteWaste",
Handler: _SmmCore_DeleteWaste_Handler,
},
{
MethodName: "GetCategoriesStat",
Handler: _SmmCore_GetCategoriesStat_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "smm_core.proto",
+785 -4
View File
@@ -16,8 +16,415 @@
"application/json"
],
"paths": {
"/budgets": {
"get": {
"operationId": "SmmCore_GetBudgets",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreBudgets"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"SmmCore"
]
},
"post": {
"summary": "budgets",
"operationId": "SmmCore_AddBudget",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreBudget"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/smm_coreAddBudgetReq"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/budgets/{budgetId}/categories": {
"get": {
"operationId": "SmmCore_GetBudgetCategories",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreCategories"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "budgetId",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
}
},
"/budgets/{budgetId}/users": {
"put": {
"summary": "budget users",
"operationId": "SmmCore_AddUserToBudget",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreOK"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "budgetId",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/SmmCoreAddUserToBudgetBody"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/budgets/{budgetId}/users/{userId}": {
"delete": {
"operationId": "SmmCore_RemoveUserFromBudget",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreBudget"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "budgetId",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "userId",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
}
},
"/budgets/{id}": {
"delete": {
"operationId": "SmmCore_DeleteBudget",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreBudget"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
},
"put": {
"operationId": "SmmCore_UpdateBudget",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreBudget"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/SmmCoreUpdateBudgetBody"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/budgets/{id}/users": {
"get": {
"operationId": "SmmCore_GetBudgetUsers",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreUsers"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
}
},
"/categories": {
"post": {
"summary": "categories",
"operationId": "SmmCore_AddCategory",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreCategory"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/smm_coreAddCategoryReq"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/categories/{id}": {
"delete": {
"operationId": "SmmCore_DeleteCategories",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreCategory"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
},
"put": {
"operationId": "SmmCore_UpdateCategory",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreCategory"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "name",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "favorite",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "monthlyLimit",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
}
},
"/login": {
"post": {
"summary": "login",
"operationId": "SmmCore_Login",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreUser"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/smm_coreLoginReq"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/ping": {
"get": {
"summary": "ping",
"operationId": "SmmCore_Ping",
"responses": {
"200": {
@@ -37,19 +444,174 @@
"SmmCore"
]
}
},
"/stat": {
"get": {
"summary": "stat",
"operationId": "SmmCore_GetCategoriesStat",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreCategoriesStat"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "ids",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "integer",
"format": "int32"
},
"collectionFormat": "multi"
}
],
"tags": [
"SmmCore"
]
}
},
"/wastes": {
"post": {
"summary": "wastes",
"operationId": "SmmCore_AddWaste",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreWaste"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/smm_coreAddWasteReq"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/wastes/text": {
"post": {
"operationId": "SmmCore_AddWasteByText",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreWaste"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/smm_coreAddWasteTextReq"
}
}
],
"tags": [
"SmmCore"
]
}
},
"/wastes/{id}": {
"delete": {
"operationId": "SmmCore_DeleteWaste",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/smm_coreWaste"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"tags": [
"SmmCore"
]
}
}
},
"definitions": {
"SmmCoreAddUserToBudgetBody": {
"type": "object",
"properties": {
"userId": {
"type": "integer",
"format": "int32"
}
}
},
"SmmCoreUpdateBudgetBody": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"startDay": {
"type": "integer",
"format": "int32"
},
"monthlyLimit": {
"type": "integer",
"format": "int32"
}
}
},
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string",
"description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics."
"type": "string"
}
},
"additionalProperties": {},
"description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }"
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
@@ -70,8 +632,227 @@
}
}
},
"smm_coreAddBudgetReq": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"startDay": {
"type": "integer",
"format": "int32"
},
"monthlyLimit": {
"type": "integer",
"format": "int32"
}
}
},
"smm_coreAddCategoryReq": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"budgetId": {
"type": "integer",
"format": "int32"
},
"favorite": {
"type": "boolean"
},
"monthlyLimit": {
"type": "integer",
"format": "int32"
}
}
},
"smm_coreAddWasteReq": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"price": {
"type": "integer",
"format": "int32"
},
"amount": {
"type": "number",
"format": "float"
},
"categoryId": {
"type": "integer",
"format": "int32"
},
"budgetId": {
"type": "integer",
"format": "int32"
}
}
},
"smm_coreAddWasteTextReq": {
"type": "object",
"properties": {
"text": {
"type": "string"
},
"categoryId": {
"type": "integer",
"format": "int32"
},
"budgetId": {
"type": "integer",
"format": "int32"
}
}
},
"smm_coreBudget": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string"
},
"startDay": {
"type": "integer",
"format": "int32"
},
"monthlyLimit": {
"type": "integer",
"format": "int32"
},
"categories": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/smm_coreCategory"
}
}
}
},
"smm_coreBudgets": {
"type": "object",
"properties": {
"budgets": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/smm_coreBudget"
}
}
}
},
"smm_coreCategories": {
"type": "object",
"properties": {
"categories": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/smm_coreCategory"
}
}
}
},
"smm_coreCategoriesStat": {
"type": "object",
"properties": {
"stat": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/smm_coreCategoriesStat"
}
}
}
},
"smm_coreCategory": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string"
},
"budgetId": {
"type": "integer",
"format": "int32"
},
"favorite": {
"type": "boolean"
},
"monthlyLimit": {
"type": "integer",
"format": "int32"
}
}
},
"smm_coreLoginReq": {
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
}
}
},
"smm_coreOK": {
"type": "object"
},
"smm_corePingRsp": {
"type": "object"
},
"smm_coreUser": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"username": {
"type": "string"
}
}
},
"smm_coreUsers": {
"type": "object",
"properties": {
"users": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/smm_coreUser"
}
}
}
},
"smm_coreWaste": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"name": {
"type": "string"
},
"price": {
"type": "integer",
"format": "int32"
},
"amount": {
"type": "number",
"format": "float"
}
}
}
}
}
+1
View File
@@ -0,0 +1 @@
SELECT b.id, b.name, b.start_day, b.monthly_limit FROM budgets b JOIN users_budgets ub ON ub.budget_id = b.id WHERE ub.user_id = 1;