diff --git a/.env.example b/.env.example index f7e4f58..86ad524 100644 --- a/.env.example +++ b/.env.example @@ -6,3 +6,8 @@ SMTP_USER=evening_detective@crabs-games.art SMTP_PASSWORD=your_password JWT_SECRET=your_secret + +S3_HOST=http://0.0.0.0:9000 +S3_USER=rustfs +S3_PASSWORD=your_password +S3_BUCKET=evening-detective diff --git a/.vscode/settings.json b/.vscode/settings.json index b18cd0d..110b012 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,10 @@ "cSpell.words": [ "Аркхема", "healthcheck", + "httpbody", + "openapiv2", "pgxpool", + "protoc", "rustfs", "timestamppb" ] diff --git a/api/google/api/httpbody.proto b/api/google/api/httpbody.proto new file mode 100644 index 0000000..3fd226a --- /dev/null +++ b/api/google/api/httpbody.proto @@ -0,0 +1,80 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/any.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; +option java_multiple_files = true; +option java_outer_classname = "HttpBodyProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Message that represents an arbitrary HTTP body. It should only be used for +// payload formats that can't be represented as JSON, such as raw binary or +// an HTML page. +// +// +// This message can be used both in streaming and non-streaming API methods in +// the request as well as the response. +// +// It can be used as a top-level request field, which is convenient if one +// wants to extract parameters from either the URL or HTTP template into the +// request fields and also want access to the raw HTTP body. +// +// Example: +// +// message GetResourceRequest { +// // A unique request id. +// string request_id = 1; +// +// // The raw HTTP body is bound to this field. +// google.api.HttpBody http_body = 2; +// +// } +// +// service ResourceService { +// rpc GetResource(GetResourceRequest) +// returns (google.api.HttpBody); +// rpc UpdateResource(google.api.HttpBody) +// returns (google.protobuf.Empty); +// +// } +// +// Example with streaming methods: +// +// service CaldavService { +// rpc GetCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// rpc UpdateCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// +// } +// +// Use of this type only changes how the request and response bodies are +// handled, all other features will continue to work unchanged. +message HttpBody { + // The HTTP Content-Type header value specifying the content type of the body. + string content_type = 1; + + // The HTTP request/response body as raw binary. + bytes data = 2; + + // Application specific response metadata. Must be set in the first response + // for streaming APIs. + repeated google.protobuf.Any extensions = 3; +} diff --git a/api/main.proto b/api/main.proto index 00082a3..f48d8e4 100644 --- a/api/main.proto +++ b/api/main.proto @@ -5,6 +5,7 @@ package crabs.evening_detective_server; import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; +import "google/api/httpbody.proto"; option go_package = "pkg/proto"; @@ -42,6 +43,7 @@ service EveningDetectiveServer { security: { security_requirement: {} } + summary: "Проверить доступность"; }; } @@ -53,6 +55,7 @@ service EveningDetectiveServer { security: { security_requirement: {} } + summary: "Проверить обработку данных"; }; } @@ -65,6 +68,8 @@ service EveningDetectiveServer { security: { security_requirement: {} } + tags : "Регистрация и вход"; + summary: "Зарегистрироваться"; }; } @@ -77,6 +82,8 @@ service EveningDetectiveServer { security: { security_requirement: {} } + tags : "Регистрация и вход"; + summary: "Обновить пароль"; }; } @@ -89,6 +96,8 @@ service EveningDetectiveServer { security: { security_requirement: {} } + tags : "Регистрация и вход"; + summary: "Войти и получить токена доступа"; }; } @@ -101,6 +110,8 @@ service EveningDetectiveServer { security: { security_requirement: {} } + tags : "Регистрация и вход"; + summary: "Обновить токена доступа"; }; } @@ -108,18 +119,30 @@ service EveningDetectiveServer { option (google.api.http) = { get: "/api/users" }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Пользователи"; + summary: "Получить всех пользователей"; + }; } rpc GetUserById(GetUserByIdReq) returns (GetUserByIdRsp) { option (google.api.http) = { get: "/api/users/{id}" }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Пользователи"; + summary: "Получить пользователя по id"; + }; } rpc GetMe(GetMeReq) returns (GetMeRsp) { option (google.api.http) = { get: "/api/users/me" }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Пользователи"; + summary: "Получить информацию о себе"; + }; } rpc AddUserRole(AddUserRoleReq) returns (AddUserRoleRsp) { @@ -127,12 +150,20 @@ service EveningDetectiveServer { post: "/api/users/{id}/role/add" body: "*" }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Пользователи"; + summary: "Добавить пользователю роль"; + }; } rpc DeleteUserRole(DeleteUserRoleReq) returns (DeleteUserRoleRsp) { option (google.api.http) = { post: "/api/users/{id}/role/delete" - body : "*" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Пользователи"; + summary: "Забрать у пользователя роль"; }; } @@ -140,6 +171,31 @@ service EveningDetectiveServer { option (google.api.http) = { get: "/api/ui/permissions" }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Доступы"; + summary: "Получить список доступных элементов интерфейса"; + }; + } + + rpc UploadFile(UploadFileReq) returns (UploadFileRsp) { + option (google.api.http) = { + post: "/api/files/upload" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Файлы"; + summary: "Загрузить файл"; + }; + } + + rpc DownloadFile(DownloadFileReq) returns (google.api.HttpBody) { + option (google.api.http) = { + get: "/api/files/{filename}" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags : "Файлы"; + summary: "Получить файл"; + }; } } @@ -246,6 +302,20 @@ message DeleteUserRoleRsp { message GetPermissionsReq {} message GetPermissionsRsp { - string error = 1; - repeated string permissions = 2; + string error = 1; + repeated string permissions = 2; +} + +message UploadFileReq { + string filename = 1; + bytes data = 2; +} + +message UploadFileRsp { + string error = 1; + string filename = 2; +} + +message DownloadFileReq { + string filename = 1; } diff --git a/cmd/evening_detective_server/main.go b/cmd/evening_detective_server/main.go index 909f2b7..2b9a854 100644 --- a/cmd/evening_detective_server/main.go +++ b/cmd/evening_detective_server/main.go @@ -5,10 +5,12 @@ import ( _ "embed" "evening_detective_server/internal/app" "evening_detective_server/internal/modules/email_sender" + "evening_detective_server/internal/modules/file_storage" "evening_detective_server/internal/modules/password_generator" "evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/repos/refresh_tokens_repo" "evening_detective_server/internal/repos/users_repo" + "evening_detective_server/internal/services/file_service" "evening_detective_server/internal/services/ui_service" "evening_detective_server/internal/services/users_service" proto "evening_detective_server/proto" @@ -47,15 +49,26 @@ func main() { usersRepo := users_repo.NewUserRepo(dbpool) passwordGenerator := password_generator.NewGenerator(8) - smtpHost := os.Getenv("SMTP_HOST") - smtpPort := os.Getenv("SMTP_PORT") - smtpUser := os.Getenv("SMTP_USER") - smtpPassword := os.Getenv("SMTP_PASSWORD") - emailSender := email_sender.NewSender(smtpHost, smtpPort, smtpUser, smtpPassword) + emailSender := email_sender.NewSender( + os.Getenv("SMTP_HOST"), + os.Getenv("SMTP_PORT"), + os.Getenv("SMTP_USER"), + os.Getenv("SMTP_PASSWORD"), + ) processorJWT := processor_jwt.NewProcessor(os.Getenv("JWT_SECRET")) refreshTokensRepo := refresh_tokens_repo.NewRefreshTokensRepo(dbpool) usersService := users_service.NewUsersService(usersRepo, passwordGenerator, emailSender, processorJWT, refreshTokensRepo) uiService := ui_service.NewUiService() + fileStorage, err := file_storage.NewRustFSStorage( + os.Getenv("S3_HOST"), + os.Getenv("S3_USER"), + os.Getenv("S3_PASSWORD"), + os.Getenv("S3_BUCKET"), + ) + if err != nil { + log.Fatalf("Unable to create connection rustfs: %v\n", err) + } + fileService := file_service.NewFileService(fileStorage) // Create a listener on TCP port lis, err := net.Listen("tcp", ":8080") @@ -74,6 +87,7 @@ func main() { "/crabs.evening_detective_server.EveningDetectiveServer/RefreshPassword": true, "/crabs.evening_detective_server.EveningDetectiveServer/Login": true, "/crabs.evening_detective_server.EveningDetectiveServer/Refresh": true, + "/crabs.evening_detective_server.EveningDetectiveServer/DownloadFile": true, }, processorJWT, ), @@ -85,6 +99,7 @@ func main() { app.NewServer( usersService, uiService, + fileService, ), ) // Serve gRPC server diff --git a/cmd/evening_detective_server/main.swagger.json b/cmd/evening_detective_server/main.swagger.json index d3c9d48..50c0527 100644 --- a/cmd/evening_detective_server/main.swagger.json +++ b/cmd/evening_detective_server/main.swagger.json @@ -18,6 +18,7 @@ "paths": { "/api/auth/login": { "post": { + "summary": "Войти и получить токена доступа", "operationId": "EveningDetectiveServer_Login", "responses": { "200": { @@ -44,7 +45,7 @@ } ], "tags": [ - "EveningDetectiveServer" + "Регистрация и вход" ], "security": [ { @@ -55,6 +56,7 @@ }, "/api/auth/refresh": { "post": { + "summary": "Обновить токена доступа", "operationId": "EveningDetectiveServer_Refresh", "responses": { "200": { @@ -81,7 +83,7 @@ } ], "tags": [ - "EveningDetectiveServer" + "Регистрация и вход" ], "security": [ { @@ -92,6 +94,7 @@ }, "/api/auth/refresh-password": { "post": { + "summary": "Обновить пароль", "operationId": "EveningDetectiveServer_RefreshPassword", "responses": { "200": { @@ -118,7 +121,7 @@ } ], "tags": [ - "EveningDetectiveServer" + "Регистрация и вход" ], "security": [ { @@ -129,6 +132,7 @@ }, "/api/auth/signup": { "post": { + "summary": "Зарегистрироваться", "operationId": "EveningDetectiveServer_Signup", "responses": { "200": { @@ -155,7 +159,7 @@ } ], "tags": [ - "EveningDetectiveServer" + "Регистрация и вход" ], "security": [ { @@ -164,8 +168,73 @@ ] } }, + "/api/files/upload": { + "post": { + "summary": "Загрузить файл", + "operationId": "EveningDetectiveServer_UploadFile", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/evening_detective_serverUploadFileRsp" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/evening_detective_serverUploadFileReq" + } + } + ], + "tags": [ + "Файлы" + ] + } + }, + "/api/files/{filename}": { + "get": { + "summary": "Получить файл", + "operationId": "EveningDetectiveServer_DownloadFile", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/apiHttpBody" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "filename", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "Файлы" + ] + } + }, "/api/test/echo": { "post": { + "summary": "Проверить обработку данных", "operationId": "EveningDetectiveServer_Echo", "responses": { "200": { @@ -201,6 +270,7 @@ }, "/api/test/ping": { "get": { + "summary": "Проверить доступность", "operationId": "EveningDetectiveServer_Ping", "responses": { "200": { @@ -228,6 +298,7 @@ }, "/api/ui/permissions": { "get": { + "summary": "Получить список доступных элементов интерфейса", "operationId": "EveningDetectiveServer_GetPermissions", "responses": { "200": { @@ -244,12 +315,13 @@ } }, "tags": [ - "EveningDetectiveServer" + "Доступы" ] } }, "/api/users": { "get": { + "summary": "Получить всех пользователей", "operationId": "EveningDetectiveServer_GetUsers", "responses": { "200": { @@ -266,12 +338,13 @@ } }, "tags": [ - "EveningDetectiveServer" + "Пользователи" ] } }, "/api/users/me": { "get": { + "summary": "Получить информацию о себе", "operationId": "EveningDetectiveServer_GetMe", "responses": { "200": { @@ -288,12 +361,13 @@ } }, "tags": [ - "EveningDetectiveServer" + "Пользователи" ] } }, "/api/users/{id}": { "get": { + "summary": "Получить пользователя по id", "operationId": "EveningDetectiveServer_GetUserById", "responses": { "200": { @@ -319,12 +393,13 @@ } ], "tags": [ - "EveningDetectiveServer" + "Пользователи" ] } }, "/api/users/{id}/role/add": { "post": { + "summary": "Добавить пользователю роль", "operationId": "EveningDetectiveServer_AddUserRole", "responses": { "200": { @@ -358,12 +433,13 @@ } ], "tags": [ - "EveningDetectiveServer" + "Пользователи" ] } }, "/api/users/{id}/role/delete": { "post": { + "summary": "Забрать у пользователя роль", "operationId": "EveningDetectiveServer_DeleteUserRole", "responses": { "200": { @@ -397,7 +473,7 @@ } ], "tags": [ - "EveningDetectiveServer" + "Пользователи" ] } } @@ -419,6 +495,29 @@ } } }, + "apiHttpBody": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "description": "The HTTP Content-Type header value specifying the content type of the body." + }, + "data": { + "type": "string", + "format": "byte", + "description": "The HTTP request/response body as raw binary." + }, + "extensions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + }, + "description": "Application specific response metadata. Must be set in the first response\nfor streaming APIs." + } + }, + "description": "Message that represents an arbitrary HTTP body. It should only be used for\npayload formats that can't be represented as JSON, such as raw binary or\nan HTML page.\n\n\nThis message can be used both in streaming and non-streaming API methods in\nthe request as well as the response.\n\nIt can be used as a top-level request field, which is convenient if one\nwants to extract parameters from either the URL or HTTP template into the\nrequest fields and also want access to the raw HTTP body.\n\nExample:\n\n message GetResourceRequest {\n // A unique request id.\n string request_id = 1;\n\n // The raw HTTP body is bound to this field.\n google.api.HttpBody http_body = 2;\n\n }\n\n service ResourceService {\n rpc GetResource(GetResourceRequest)\n returns (google.api.HttpBody);\n rpc UpdateResource(google.api.HttpBody)\n returns (google.protobuf.Empty);\n\n }\n\nExample with streaming methods:\n\n service CaldavService {\n rpc GetCalendar(stream google.api.HttpBody)\n returns (stream google.api.HttpBody);\n rpc UpdateCalendar(stream google.api.HttpBody)\n returns (stream google.api.HttpBody);\n\n }\n\nUse of this type only changes how the request and response bodies are\nhandled, all other features will continue to work unchanged." + }, "evening_detective_serverAddUserRoleRsp": { "type": "object", "properties": { @@ -579,6 +678,29 @@ } } }, + "evening_detective_serverUploadFileReq": { + "type": "object", + "properties": { + "filename": { + "type": "string" + }, + "data": { + "type": "string", + "format": "byte" + } + } + }, + "evening_detective_serverUploadFileRsp": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "filename": { + "type": "string" + } + } + }, "evening_detective_serverUser": { "type": "object", "properties": { @@ -611,10 +733,12 @@ "type": "object", "properties": { "@type": { - "type": "string" + "type": "string", + "description": "Identifies the type of the serialized Protobuf message with a URI reference\nconsisting of a prefix ending in a slash and the fully-qualified type name.\n\nExample: type.googleapis.com/google.protobuf.StringValue\n\nThis string must contain at least one `/` character, and the content after\nthe last `/` must be the fully-qualified name of the type in canonical\nform, without a leading dot. Do not write a scheme on these URI references\nso that clients do not attempt to contact them.\n\nThe prefix is arbitrary and Protobuf implementations are expected to\nsimply strip off everything up to and including the last `/` to identify\nthe type. `type.googleapis.com/` is a common default prefix that some\nlegacy implementations require. This prefix does not indicate the origin of\nthe type, and URIs containing it are not expected to respond to any\nrequests.\n\nAll type URL strings must be legal URI references with the additional\nrestriction (for the text format) that the content of the reference\nmust consist only of alphanumeric characters, percent-encoded escapes, and\ncharacters in the following set (not including the outer backticks):\n`/-.~_!$\u0026()*+,;=`. Despite our allowing percent encodings, implementations\nshould not unescape them to prevent confusion with existing parsers. For\nexample, `type.googleapis.com%2FFoo` should be rejected.\n\nIn the original design of `Any`, the possibility of launching a type\nresolution service at these type URLs was considered but Protobuf never\nimplemented one and considers contacting these URLs to be problematic and\na potential security issue. Do not attempt to contact type URLs." } }, - "additionalProperties": {} + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nIn its binary encoding, an `Any` is an ordinary message; but in other wire\nforms like JSON, it has a special encoding. The format of the type URL is\ndescribed on the `type_url` field.\n\nProtobuf APIs provide utilities to interact with `Any` values:\n\n- A 'pack' operation accepts a message and constructs a generic `Any` wrapper\n around it.\n- An 'unpack' operation reads the content of an `Any` message, either into an\n existing message or a new one. Unpack operations must check the type of the\n value they unpack against the declared `type_url`.\n- An 'is' operation decides whether an `Any` contains a message of the given\n type, i.e. whether it can 'unpack' that type.\n\nThe JSON format representation of an `Any` follows one of these cases:\n\n- For types without special-cased JSON encodings, the JSON format\n representation of the `Any` is the same as that of the message, with an\n additional `@type` field which contains the type URL.\n- For types with special-cased JSON encodings (typically called 'well-known'\n types, listed in https://protobuf.dev/programming-guides/json/#any), the\n JSON format representation has a key `@type` which contains the type URL\n and a key `value` which contains the JSON-serialized value.\n\nThe text format representation of an `Any` is like a message with one field\nwhose name is the type URL in brackets. For example, an `Any` containing a\n`foo.Bar` message may be written `[type.googleapis.com/foo.Bar] { a: 2 }`." }, "rpcStatus": { "type": "object", diff --git a/docker-compose.yml b/docker-compose.yml index c01ab78..51dcb8b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,10 @@ services: SMTP_USER: evening_detective@crabs-games.art SMTP_PASSWORD: your_password JWT_SECRET: your_secret + S3_HOST: http://0.0.0.0:9000 + S3_USER: rustfs + S3_PASSWORD: your_password + S3_BUCKET: evening-detective depends_on: - postgres restart: unless-stopped diff --git a/internal/app/server.go b/internal/app/server.go index d32653f..5579bf1 100644 --- a/internal/app/server.go +++ b/internal/app/server.go @@ -2,12 +2,15 @@ package app import ( "context" + "evening_detective_server/internal/modules/file_storage" "evening_detective_server/internal/modules/processor_jwt" "evening_detective_server/internal/modules/roles" + "evening_detective_server/internal/services/file_service" "evening_detective_server/internal/services/ui_service" "evening_detective_server/internal/services/users_service" proto "evening_detective_server/proto" + "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -17,15 +20,18 @@ type server struct { usersService *users_service.UsersService uiService *ui_service.UiService + fileService *file_service.FileService } func NewServer( usersService *users_service.UsersService, uiService *ui_service.UiService, + fileService *file_service.FileService, ) proto.EveningDetectiveServerServer { return &server{ usersService: usersService, uiService: uiService, + fileService: fileService, } } @@ -167,3 +173,32 @@ func (s *server) GetPermissions( Permissions: permissions, }, nil } + +func (s *server) UploadFile(ctx context.Context, req *proto.UploadFileReq) (*proto.UploadFileRsp, error) { + filename, err := s.fileService.UploadFile( + ctx, + &file_storage.File{ + Name: req.Filename, + Data: req.Data, + }, + ) + if err != nil { + return &proto.UploadFileRsp{ + Error: err.Error(), + }, nil + } + return &proto.UploadFileRsp{ + Filename: filename, + }, nil +} + +func (s *server) DownloadFile(ctx context.Context, req *proto.DownloadFileReq) (*httpbody.HttpBody, error) { + file, err := s.fileService.DownloadFile(ctx, req.Filename) + if err != nil { + return &httpbody.HttpBody{}, nil + } + return &httpbody.HttpBody{ + Data: file.Data, + ContentType: file.Mime, + }, nil +} diff --git a/internal/modules/file_storage/storage.go b/internal/modules/file_storage/storage.go index 492c5a7..dfa12c5 100644 --- a/internal/modules/file_storage/storage.go +++ b/internal/modules/file_storage/storage.go @@ -4,6 +4,7 @@ import ( "context" "mime" "path/filepath" + "time" "github.com/kzzan/s3kit" ) @@ -28,6 +29,17 @@ func NewRustFSStorage( if err != nil { return nil, err } + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + err = client.CreateBucket( + ctx, + bucket, + ) + if err != nil { + return nil, err + } + return &storage{ client: client, bucket: bucket, @@ -35,7 +47,8 @@ func NewRustFSStorage( } func (s *storage) Put(ctx context.Context, file *File) error { - return s.client.PutObjectBytes(ctx, s.bucket, file.Name, file.Data, file.Mime) + mime := s.getMimeType(file.Name) + return s.client.PutObjectBytes(ctx, s.bucket, file.Name, file.Data, mime) } func (s *storage) Get(ctx context.Context, filename string) (*File, error) { diff --git a/internal/services/file_service/service.go b/internal/services/file_service/service.go new file mode 100644 index 0000000..8028d0b --- /dev/null +++ b/internal/services/file_service/service.go @@ -0,0 +1,39 @@ +package file_service + +import ( + "context" + "evening_detective_server/internal/modules/file_storage" +) + +type FileService struct { + fileStorage file_storage.IFileStorage +} + +func NewFileService( + fileStorage file_storage.IFileStorage, +) *FileService { + return &FileService{ + fileStorage: fileStorage, + } +} + +func (s *FileService) UploadFile( + ctx context.Context, + file *file_storage.File, +) (string, error) { + if err := s.fileStorage.Put(ctx, file); err != nil { + return "", err + } + return file.Name, nil +} + +func (s *FileService) DownloadFile( + ctx context.Context, + filename string, +) (*file_storage.File, error) { + file, err := s.fileStorage.Get(ctx, filename) + if err != nil { + return nil, err + } + return file, nil +} diff --git a/proto/main.pb.go b/proto/main.pb.go index f1b2db8..0db87c4 100644 --- a/proto/main.pb.go +++ b/proto/main.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.35.0 +// protoc v7.35.1 // source: main.proto package proto @@ -9,6 +9,7 @@ package proto import ( _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" _ "google.golang.org/genproto/googleapis/api/annotations" + httpbody "google.golang.org/genproto/googleapis/api/httpbody" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" @@ -1220,12 +1221,160 @@ func (x *GetPermissionsRsp) GetPermissions() []string { return nil } +type UploadFileReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadFileReq) Reset() { + *x = UploadFileReq{} + mi := &file_main_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadFileReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadFileReq) ProtoMessage() {} + +func (x *UploadFileReq) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadFileReq.ProtoReflect.Descriptor instead. +func (*UploadFileReq) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{25} +} + +func (x *UploadFileReq) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +func (x *UploadFileReq) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type UploadFileRsp struct { + state protoimpl.MessageState `protogen:"open.v1"` + Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + Filename string `protobuf:"bytes,2,opt,name=filename,proto3" json:"filename,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadFileRsp) Reset() { + *x = UploadFileRsp{} + mi := &file_main_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadFileRsp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadFileRsp) ProtoMessage() {} + +func (x *UploadFileRsp) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadFileRsp.ProtoReflect.Descriptor instead. +func (*UploadFileRsp) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{26} +} + +func (x *UploadFileRsp) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *UploadFileRsp) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + +type DownloadFileReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DownloadFileReq) Reset() { + *x = DownloadFileReq{} + mi := &file_main_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DownloadFileReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DownloadFileReq) ProtoMessage() {} + +func (x *DownloadFileReq) ProtoReflect() protoreflect.Message { + mi := &file_main_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DownloadFileReq.ProtoReflect.Descriptor instead. +func (*DownloadFileReq) Descriptor() ([]byte, []int) { + return file_main_proto_rawDescGZIP(), []int{27} +} + +func (x *DownloadFileReq) GetFilename() string { + if x != nil { + return x.Filename + } + return "" +} + var File_main_proto protoreflect.FileDescriptor const file_main_proto_rawDesc = "" + "\n" + "\n" + - "main.proto\x12\x1ecrabs.evening_detective_server\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\t\n" + + "main.proto\x12\x1ecrabs.evening_detective_server\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\x1a\x19google/api/httpbody.proto\"\t\n" + "\aPingReq\"\t\n" + "\aPingRsp\"\x1d\n" + "\aEchoReq\x12\x12\n" + @@ -1291,33 +1440,58 @@ const file_main_proto_rawDesc = "" + "\x11GetPermissionsReq\"K\n" + "\x11GetPermissionsRsp\x12\x14\n" + "\x05error\x18\x01 \x01(\tR\x05error\x12 \n" + - "\vpermissions\x18\x02 \x03(\tR\vpermissions2\x9e\r\n" + - "\x16EveningDetectiveServer\x12{\n" + - "\x04Ping\x12'.crabs.evening_detective_server.PingReq\x1a'.crabs.evening_detective_server.PingRsp\"!\x92A\bb\x06\n" + + "\vpermissions\x18\x02 \x03(\tR\vpermissions\"?\n" + + "\rUploadFileReq\x12\x1a\n" + + "\bfilename\x18\x01 \x01(\tR\bfilename\x12\x12\n" + + "\x04data\x18\x02 \x01(\fR\x04data\"A\n" + + "\rUploadFileRsp\x12\x14\n" + + "\x05error\x18\x01 \x01(\tR\x05error\x12\x1a\n" + + "\bfilename\x18\x02 \x01(\tR\bfilename\"-\n" + + "\x0fDownloadFileReq\x12\x1a\n" + + "\bfilename\x18\x01 \x01(\tR\bfilename2\x9d\x17\n" + + "\x16EveningDetectiveServer\x12\xa6\x01\n" + + "\x04Ping\x12'.crabs.evening_detective_server.PingReq\x1a'.crabs.evening_detective_server.PingRsp\"L\x92A3\x12)Проверить доступностьb\x06\n" + "\x04\n" + - "\x00\x12\x00\x82\xd3\xe4\x93\x02\x10\x12\x0e/api/test/ping\x12{\n" + - "\x04Echo\x12'.crabs.evening_detective_server.EchoReq\x1a'.crabs.evening_detective_server.EchoRsp\"!\x92A\bb\x06\n" + + "\x00\x12\x00\x82\xd3\xe4\x93\x02\x10\x12\x0e/api/test/ping\x12\xaf\x01\n" + + "\x04Echo\x12'.crabs.evening_detective_server.EchoReq\x1a'.crabs.evening_detective_server.EchoRsp\"U\x92A<\x122Проверить обработку данныхb\x06\n" + "\x04\n" + - "\x00\x12\x00\x82\xd3\xe4\x93\x02\x10\"\x0e/api/test/echo\x12\x86\x01\n" + - "\x06Signup\x12).crabs.evening_detective_server.SignupReq\x1a).crabs.evening_detective_server.SignupRsp\"&\x92A\bb\x06\n" + + "\x00\x12\x00\x82\xd3\xe4\x93\x02\x10\"\x0e/api/test/echo\x12\xd0\x01\n" + + "\x06Signup\x12).crabs.evening_detective_server.SignupReq\x1a).crabs.evening_detective_server.SignupRsp\"p\x92AR\n" + + "\"Регистрация и вход\x12$Зарегистрироватьсяb\x06\n" + "\x04\n" + - "\x00\x12\x00\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/api/auth/signup\x12\xab\x01\n" + - "\x0fRefreshPassword\x122.crabs.evening_detective_server.RefreshPasswordReq\x1a2.crabs.evening_detective_server.RefreshPasswordRsp\"0\x92A\bb\x06\n" + + "\x00\x12\x00\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/api/auth/signup\x12\xee\x01\n" + + "\x0fRefreshPassword\x122.crabs.evening_detective_server.RefreshPasswordReq\x1a2.crabs.evening_detective_server.RefreshPasswordRsp\"s\x92AK\n" + + "\"Регистрация и вход\x12\x1dОбновить парольb\x06\n" + "\x04\n" + - "\x00\x12\x00\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/api/auth/refresh-password\x12\x82\x01\n" + - "\x05Login\x12(.crabs.evening_detective_server.LoginReq\x1a(.crabs.evening_detective_server.LoginRsp\"%\x92A\bb\x06\n" + + "\x00\x12\x00\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/api/auth/refresh-password\x12\xe3\x01\n" + + "\x05Login\x12(.crabs.evening_detective_server.LoginReq\x1a(.crabs.evening_detective_server.LoginRsp\"\x85\x01\x92Ah\n" + + "\"Регистрация и вход\x12:Войти и получить токена доступаb\x06\n" + "\x04\n" + - "\x00\x12\x00\x82\xd3\xe4\x93\x02\x14:\x01*\"\x0f/api/auth/login\x12\x8a\x01\n" + - "\aRefresh\x12*.crabs.evening_detective_server.RefreshReq\x1a*.crabs.evening_detective_server.RefreshRsp\"'\x92A\bb\x06\n" + + "\x00\x12\x00\x82\xd3\xe4\x93\x02\x14:\x01*\"\x0f/api/auth/login\x12\xdc\x01\n" + + "\aRefresh\x12*.crabs.evening_detective_server.RefreshReq\x1a*.crabs.evening_detective_server.RefreshRsp\"y\x92AZ\n" + + "\"Регистрация и вход\x12,Обновить токена доступаb\x06\n" + "\x04\n" + - "\x00\x12\x00\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/api/auth/refresh\x12x\n" + - "\bGetUsers\x12+.crabs.evening_detective_server.GetUsersReq\x1a+.crabs.evening_detective_server.GetUsersRsp\"\x12\x82\xd3\xe4\x93\x02\f\x12\n" + - "/api/users\x12\x86\x01\n" + - "\vGetUserById\x12..crabs.evening_detective_server.GetUserByIdReq\x1a..crabs.evening_detective_server.GetUserByIdRsp\"\x17\x82\xd3\xe4\x93\x02\x11\x12\x0f/api/users/{id}\x12r\n" + - "\x05GetMe\x12(.crabs.evening_detective_server.GetMeReq\x1a(.crabs.evening_detective_server.GetMeRsp\"\x15\x82\xd3\xe4\x93\x02\x0f\x12\r/api/users/me\x12\x92\x01\n" + - "\vAddUserRole\x12..crabs.evening_detective_server.AddUserRoleReq\x1a..crabs.evening_detective_server.AddUserRoleRsp\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/api/users/{id}/role/add\x12\x9e\x01\n" + - "\x0eDeleteUserRole\x121.crabs.evening_detective_server.DeleteUserRoleReq\x1a1.crabs.evening_detective_server.DeleteUserRoleRsp\"&\x82\xd3\xe4\x93\x02 :\x01*\"\x1b/api/users/{id}/role/delete\x12\x93\x01\n" + - "\x0eGetPermissions\x121.crabs.evening_detective_server.GetPermissionsReq\x1a1.crabs.evening_detective_server.GetPermissionsRsp\"\x1b\x82\xd3\xe4\x93\x02\x15\x12\x13/api/ui/permissionsB\xd7\x01\x92A\xc8\x01\x12U\n" + + "\x00\x12\x00\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/api/auth/refresh\x12\xcb\x01\n" + + "\bGetUsers\x12+.crabs.evening_detective_server.GetUsersReq\x1a+.crabs.evening_detective_server.GetUsersRsp\"e\x92AP\n" + + "\x18Пользователи\x124Получить всех пользователей\x82\xd3\xe4\x93\x02\f\x12\n" + + "/api/users\x12\xd6\x01\n" + + "\vGetUserById\x12..crabs.evening_detective_server.GetUserByIdReq\x1a..crabs.evening_detective_server.GetUserByIdRsp\"g\x92AM\n" + + "\x18Пользователи\x121Получить пользователя по id\x82\xd3\xe4\x93\x02\x11\x12\x0f/api/users/{id}\x12\xc2\x01\n" + + "\x05GetMe\x12(.crabs.evening_detective_server.GetMeReq\x1a(.crabs.evening_detective_server.GetMeRsp\"e\x92AM\n" + + "\x18Пользователи\x121Получить информацию о себе\x82\xd3\xe4\x93\x02\x0f\x12\r/api/users/me\x12\xe3\x01\n" + + "\vAddUserRole\x12..crabs.evening_detective_server.AddUserRoleReq\x1a..crabs.evening_detective_server.AddUserRoleRsp\"t\x92AN\n" + + "\x18Пользователи\x122Добавить пользователю роль\x82\xd3\xe4\x93\x02\x1d:\x01*\"\x18/api/users/{id}/role/add\x12\xf0\x01\n" + + "\x0eDeleteUserRole\x121.crabs.evening_detective_server.DeleteUserRoleReq\x1a1.crabs.evening_detective_server.DeleteUserRoleRsp\"x\x92AO\n" + + "\x18Пользователи\x123Забрать у пользователя роль\x82\xd3\xe4\x93\x02 :\x01*\"\x1b/api/users/{id}/role/delete\x12\x81\x02\n" + + "\x0eGetPermissions\x121.crabs.evening_detective_server.GetPermissionsReq\x1a1.crabs.evening_detective_server.GetPermissionsRsp\"\x88\x01\x92Aj\n" + + "\x0eДоступы\x12XПолучить список доступных элементов интерфейса\x82\xd3\xe4\x93\x02\x15\x12\x13/api/ui/permissions\x12\xb4\x01\n" + + "\n" + + "UploadFile\x12-.crabs.evening_detective_server.UploadFileReq\x1a-.crabs.evening_detective_server.UploadFileRsp\"H\x92A)\n" + + "\n" + + "Файлы\x12\x1bЗагрузить файл\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/api/files/upload\x12\x9e\x01\n" + + "\fDownloadFile\x12/.crabs.evening_detective_server.DownloadFileReq\x1a\x14.google.api.HttpBody\"G\x92A'\n" + + "\n" + + "Файлы\x12\x19Получить файл\x82\xd3\xe4\x93\x02\x17\x12\x15/api/files/{filename}B\xd7\x01\x92A\xc8\x01\x12U\n" + "KДокументация сервиса \"Вечерний детектив\"2\x06v0.1.0Z]\n" + "[\n" + "\n" + @@ -1338,7 +1512,7 @@ func file_main_proto_rawDescGZIP() []byte { return file_main_proto_rawDescData } -var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_main_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_main_proto_goTypes = []any{ (*PingReq)(nil), // 0: crabs.evening_detective_server.PingReq (*PingRsp)(nil), // 1: crabs.evening_detective_server.PingRsp @@ -1365,11 +1539,15 @@ var file_main_proto_goTypes = []any{ (*DeleteUserRoleRsp)(nil), // 22: crabs.evening_detective_server.DeleteUserRoleRsp (*GetPermissionsReq)(nil), // 23: crabs.evening_detective_server.GetPermissionsReq (*GetPermissionsRsp)(nil), // 24: crabs.evening_detective_server.GetPermissionsRsp - (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp + (*UploadFileReq)(nil), // 25: crabs.evening_detective_server.UploadFileReq + (*UploadFileRsp)(nil), // 26: crabs.evening_detective_server.UploadFileRsp + (*DownloadFileReq)(nil), // 27: crabs.evening_detective_server.DownloadFileReq + (*timestamppb.Timestamp)(nil), // 28: google.protobuf.Timestamp + (*httpbody.HttpBody)(nil), // 29: google.api.HttpBody } var file_main_proto_depIdxs = []int32{ 14, // 0: crabs.evening_detective_server.GetUsersRsp.users:type_name -> crabs.evening_detective_server.User - 25, // 1: crabs.evening_detective_server.User.created_at:type_name -> google.protobuf.Timestamp + 28, // 1: crabs.evening_detective_server.User.created_at:type_name -> google.protobuf.Timestamp 14, // 2: crabs.evening_detective_server.GetUserByIdRsp.user:type_name -> crabs.evening_detective_server.User 14, // 3: crabs.evening_detective_server.GetMeRsp.user:type_name -> crabs.evening_detective_server.User 0, // 4: crabs.evening_detective_server.EveningDetectiveServer.Ping:input_type -> crabs.evening_detective_server.PingReq @@ -1384,20 +1562,24 @@ var file_main_proto_depIdxs = []int32{ 19, // 13: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:input_type -> crabs.evening_detective_server.AddUserRoleReq 21, // 14: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:input_type -> crabs.evening_detective_server.DeleteUserRoleReq 23, // 15: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:input_type -> crabs.evening_detective_server.GetPermissionsReq - 1, // 16: crabs.evening_detective_server.EveningDetectiveServer.Ping:output_type -> crabs.evening_detective_server.PingRsp - 3, // 17: crabs.evening_detective_server.EveningDetectiveServer.Echo:output_type -> crabs.evening_detective_server.EchoRsp - 5, // 18: crabs.evening_detective_server.EveningDetectiveServer.Signup:output_type -> crabs.evening_detective_server.SignupRsp - 7, // 19: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:output_type -> crabs.evening_detective_server.RefreshPasswordRsp - 9, // 20: crabs.evening_detective_server.EveningDetectiveServer.Login:output_type -> crabs.evening_detective_server.LoginRsp - 11, // 21: crabs.evening_detective_server.EveningDetectiveServer.Refresh:output_type -> crabs.evening_detective_server.RefreshRsp - 13, // 22: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:output_type -> crabs.evening_detective_server.GetUsersRsp - 16, // 23: crabs.evening_detective_server.EveningDetectiveServer.GetUserById:output_type -> crabs.evening_detective_server.GetUserByIdRsp - 18, // 24: crabs.evening_detective_server.EveningDetectiveServer.GetMe:output_type -> crabs.evening_detective_server.GetMeRsp - 20, // 25: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:output_type -> crabs.evening_detective_server.AddUserRoleRsp - 22, // 26: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:output_type -> crabs.evening_detective_server.DeleteUserRoleRsp - 24, // 27: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:output_type -> crabs.evening_detective_server.GetPermissionsRsp - 16, // [16:28] is the sub-list for method output_type - 4, // [4:16] is the sub-list for method input_type + 25, // 16: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:input_type -> crabs.evening_detective_server.UploadFileReq + 27, // 17: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:input_type -> crabs.evening_detective_server.DownloadFileReq + 1, // 18: crabs.evening_detective_server.EveningDetectiveServer.Ping:output_type -> crabs.evening_detective_server.PingRsp + 3, // 19: crabs.evening_detective_server.EveningDetectiveServer.Echo:output_type -> crabs.evening_detective_server.EchoRsp + 5, // 20: crabs.evening_detective_server.EveningDetectiveServer.Signup:output_type -> crabs.evening_detective_server.SignupRsp + 7, // 21: crabs.evening_detective_server.EveningDetectiveServer.RefreshPassword:output_type -> crabs.evening_detective_server.RefreshPasswordRsp + 9, // 22: crabs.evening_detective_server.EveningDetectiveServer.Login:output_type -> crabs.evening_detective_server.LoginRsp + 11, // 23: crabs.evening_detective_server.EveningDetectiveServer.Refresh:output_type -> crabs.evening_detective_server.RefreshRsp + 13, // 24: crabs.evening_detective_server.EveningDetectiveServer.GetUsers:output_type -> crabs.evening_detective_server.GetUsersRsp + 16, // 25: crabs.evening_detective_server.EveningDetectiveServer.GetUserById:output_type -> crabs.evening_detective_server.GetUserByIdRsp + 18, // 26: crabs.evening_detective_server.EveningDetectiveServer.GetMe:output_type -> crabs.evening_detective_server.GetMeRsp + 20, // 27: crabs.evening_detective_server.EveningDetectiveServer.AddUserRole:output_type -> crabs.evening_detective_server.AddUserRoleRsp + 22, // 28: crabs.evening_detective_server.EveningDetectiveServer.DeleteUserRole:output_type -> crabs.evening_detective_server.DeleteUserRoleRsp + 24, // 29: crabs.evening_detective_server.EveningDetectiveServer.GetPermissions:output_type -> crabs.evening_detective_server.GetPermissionsRsp + 26, // 30: crabs.evening_detective_server.EveningDetectiveServer.UploadFile:output_type -> crabs.evening_detective_server.UploadFileRsp + 29, // 31: crabs.evening_detective_server.EveningDetectiveServer.DownloadFile:output_type -> google.api.HttpBody + 18, // [18:32] is the sub-list for method output_type + 4, // [4:18] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension extendee 0, // [0:4] is the sub-list for field type_name @@ -1414,7 +1596,7 @@ func file_main_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_main_proto_rawDesc), len(file_main_proto_rawDesc)), NumEnums: 0, - NumMessages: 25, + NumMessages: 28, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/main.pb.gw.go b/proto/main.pb.gw.go index 8e1eae6..9de99dd 100644 --- a/proto/main.pb.gw.go +++ b/proto/main.pb.gw.go @@ -391,6 +391,72 @@ func local_request_EveningDetectiveServer_GetPermissions_0(ctx context.Context, return msg, metadata, err } +func request_EveningDetectiveServer_UploadFile_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UploadFileReq + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.UploadFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_EveningDetectiveServer_UploadFile_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UploadFileReq + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.UploadFile(ctx, &protoReq) + return msg, metadata, err +} + +func request_EveningDetectiveServer_DownloadFile_0(ctx context.Context, marshaler runtime.Marshaler, client EveningDetectiveServerClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DownloadFileReq + metadata runtime.ServerMetadata + err error + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["filename"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "filename") + } + protoReq.Filename, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "filename", err) + } + msg, err := client.DownloadFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_EveningDetectiveServer_DownloadFile_0(ctx context.Context, marshaler runtime.Marshaler, server EveningDetectiveServerServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DownloadFileReq + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["filename"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "filename") + } + protoReq.Filename, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "filename", err) + } + msg, err := server.DownloadFile(ctx, &protoReq) + return msg, metadata, err +} + // RegisterEveningDetectiveServerHandlerServer registers the http handlers for service EveningDetectiveServer to "mux". // UnaryRPC :call EveningDetectiveServerServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -637,6 +703,46 @@ func RegisterEveningDetectiveServerHandlerServer(ctx context.Context, mux *runti } forward_EveningDetectiveServer_GetPermissions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_UploadFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/UploadFile", runtime.WithHTTPPathPattern("/api/files/upload")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EveningDetectiveServer_UploadFile_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_UploadFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/DownloadFile", runtime.WithHTTPPathPattern("/api/files/{filename}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_EveningDetectiveServer_DownloadFile_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_DownloadFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) return nil } @@ -881,6 +987,40 @@ func RegisterEveningDetectiveServerHandlerClient(ctx context.Context, mux *runti } forward_EveningDetectiveServer_GetPermissions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_EveningDetectiveServer_UploadFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/UploadFile", runtime.WithHTTPPathPattern("/api/files/upload")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EveningDetectiveServer_UploadFile_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_UploadFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodGet, pattern_EveningDetectiveServer_DownloadFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/crabs.evening_detective_server.EveningDetectiveServer/DownloadFile", runtime.WithHTTPPathPattern("/api/files/{filename}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_EveningDetectiveServer_DownloadFile_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_EveningDetectiveServer_DownloadFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) return nil } @@ -897,6 +1037,8 @@ var ( pattern_EveningDetectiveServer_AddUserRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"api", "users", "id", "role", "add"}, "")) pattern_EveningDetectiveServer_DeleteUserRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3, 2, 4}, []string{"api", "users", "id", "role", "delete"}, "")) pattern_EveningDetectiveServer_GetPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "ui", "permissions"}, "")) + pattern_EveningDetectiveServer_UploadFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "files", "upload"}, "")) + pattern_EveningDetectiveServer_DownloadFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"api", "files", "filename"}, "")) ) var ( @@ -912,4 +1054,6 @@ var ( forward_EveningDetectiveServer_AddUserRole_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_DeleteUserRole_0 = runtime.ForwardResponseMessage forward_EveningDetectiveServer_GetPermissions_0 = runtime.ForwardResponseMessage + forward_EveningDetectiveServer_UploadFile_0 = runtime.ForwardResponseMessage + forward_EveningDetectiveServer_DownloadFile_0 = runtime.ForwardResponseMessage ) diff --git a/proto/main_grpc.pb.go b/proto/main_grpc.pb.go index 6e7bfac..1e5eb7f 100644 --- a/proto/main_grpc.pb.go +++ b/proto/main_grpc.pb.go @@ -1,13 +1,14 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.6.2 -// - protoc v7.35.0 +// - protoc v7.35.1 // source: main.proto package proto import ( context "context" + httpbody "google.golang.org/genproto/googleapis/api/httpbody" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -31,6 +32,8 @@ const ( EveningDetectiveServer_AddUserRole_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/AddUserRole" EveningDetectiveServer_DeleteUserRole_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DeleteUserRole" EveningDetectiveServer_GetPermissions_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/GetPermissions" + EveningDetectiveServer_UploadFile_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/UploadFile" + EveningDetectiveServer_DownloadFile_FullMethodName = "/crabs.evening_detective_server.EveningDetectiveServer/DownloadFile" ) // EveningDetectiveServerClient is the client API for EveningDetectiveServer service. @@ -49,6 +52,8 @@ type EveningDetectiveServerClient interface { AddUserRole(ctx context.Context, in *AddUserRoleReq, opts ...grpc.CallOption) (*AddUserRoleRsp, error) DeleteUserRole(ctx context.Context, in *DeleteUserRoleReq, opts ...grpc.CallOption) (*DeleteUserRoleRsp, error) GetPermissions(ctx context.Context, in *GetPermissionsReq, opts ...grpc.CallOption) (*GetPermissionsRsp, error) + UploadFile(ctx context.Context, in *UploadFileReq, opts ...grpc.CallOption) (*UploadFileRsp, error) + DownloadFile(ctx context.Context, in *DownloadFileReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error) } type eveningDetectiveServerClient struct { @@ -179,6 +184,26 @@ func (c *eveningDetectiveServerClient) GetPermissions(ctx context.Context, in *G return out, nil } +func (c *eveningDetectiveServerClient) UploadFile(ctx context.Context, in *UploadFileReq, opts ...grpc.CallOption) (*UploadFileRsp, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UploadFileRsp) + err := c.cc.Invoke(ctx, EveningDetectiveServer_UploadFile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *eveningDetectiveServerClient) DownloadFile(ctx context.Context, in *DownloadFileReq, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(httpbody.HttpBody) + err := c.cc.Invoke(ctx, EveningDetectiveServer_DownloadFile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // EveningDetectiveServerServer is the server API for EveningDetectiveServer service. // All implementations must embed UnimplementedEveningDetectiveServerServer // for forward compatibility. @@ -195,6 +220,8 @@ type EveningDetectiveServerServer interface { AddUserRole(context.Context, *AddUserRoleReq) (*AddUserRoleRsp, error) DeleteUserRole(context.Context, *DeleteUserRoleReq) (*DeleteUserRoleRsp, error) GetPermissions(context.Context, *GetPermissionsReq) (*GetPermissionsRsp, error) + UploadFile(context.Context, *UploadFileReq) (*UploadFileRsp, error) + DownloadFile(context.Context, *DownloadFileReq) (*httpbody.HttpBody, error) mustEmbedUnimplementedEveningDetectiveServerServer() } @@ -241,6 +268,12 @@ func (UnimplementedEveningDetectiveServerServer) DeleteUserRole(context.Context, func (UnimplementedEveningDetectiveServerServer) GetPermissions(context.Context, *GetPermissionsReq) (*GetPermissionsRsp, error) { return nil, status.Error(codes.Unimplemented, "method GetPermissions not implemented") } +func (UnimplementedEveningDetectiveServerServer) UploadFile(context.Context, *UploadFileReq) (*UploadFileRsp, error) { + return nil, status.Error(codes.Unimplemented, "method UploadFile not implemented") +} +func (UnimplementedEveningDetectiveServerServer) DownloadFile(context.Context, *DownloadFileReq) (*httpbody.HttpBody, error) { + return nil, status.Error(codes.Unimplemented, "method DownloadFile not implemented") +} func (UnimplementedEveningDetectiveServerServer) mustEmbedUnimplementedEveningDetectiveServerServer() { } func (UnimplementedEveningDetectiveServerServer) testEmbeddedByValue() {} @@ -479,6 +512,42 @@ func _EveningDetectiveServer_GetPermissions_Handler(srv interface{}, ctx context return interceptor(ctx, in, info, handler) } +func _EveningDetectiveServer_UploadFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadFileReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EveningDetectiveServerServer).UploadFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EveningDetectiveServer_UploadFile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EveningDetectiveServerServer).UploadFile(ctx, req.(*UploadFileReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _EveningDetectiveServer_DownloadFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DownloadFileReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EveningDetectiveServerServer).DownloadFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EveningDetectiveServer_DownloadFile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EveningDetectiveServerServer).DownloadFile(ctx, req.(*DownloadFileReq)) + } + return interceptor(ctx, in, info, handler) +} + // EveningDetectiveServer_ServiceDesc is the grpc.ServiceDesc for EveningDetectiveServer service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -534,6 +603,14 @@ var EveningDetectiveServer_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetPermissions", Handler: _EveningDetectiveServer_GetPermissions_Handler, }, + { + MethodName: "UploadFile", + Handler: _EveningDetectiveServer_UploadFile_Handler, + }, + { + MethodName: "DownloadFile", + Handler: _EveningDetectiveServer_DownloadFile_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "main.proto",