From 6fe1b54a7fc63256c40ec671e150b8b5854bfbe9 Mon Sep 17 00:00:00 2001 From: mateuszpiorowski Date: Sun, 10 Mar 2024 00:22:09 +0100 Subject: [PATCH 1/8] update --- client/src/hooks.server.js | 56 +++- .../src/lib/proto/{user.proto => auth.proto} | 17 +- client/src/lib/proto/{user.ts => auth.ts} | 0 client/src/lib/proto/main.proto | 15 +- client/src/lib/proto/main.ts | 1 + client/src/lib/proto/note.proto | 2 +- client/src/lib/proto/profile.proto | 2 +- client/src/lib/proto/proto/AuthResponse.ts | 6 +- client/src/lib/proto/proto/Empty.ts | 2 +- client/src/lib/proto/proto/Id.ts | 2 +- client/src/lib/proto/proto/Note.ts | 10 +- client/src/lib/proto/proto/Profile.ts | 22 +- client/src/lib/proto/proto/Service.ts | 39 ++- .../src/lib/proto/proto/StripeUrlResponse.ts | 10 + client/src/lib/proto/proto/User.ts | 24 +- client/src/lib/proto/proto/UserRole.ts | 10 +- client/src/lib/safe.d.ts | 20 -- client/src/lib/safe.js | 102 ------ client/src/lib/server/api.js | 11 +- client/src/lib/server/grpc.js | 57 +++- client/src/lib/server/logger.js | 47 +-- client/src/lib/server/metadata.js | 6 +- client/src/lib/server/private.key | 52 +-- client/src/lib/server/safe.d.ts | 27 ++ client/src/lib/server/safe.js | 51 +++ client/src/routes/(app)/+error.svelte | 30 ++ client/src/routes/(app)/notes/+page.server.js | 31 +- .../(app)/notes/[noteId]/+page.server.js | 38 ++- .../src/routes/(app)/profile/+page.server.js | 61 ++-- client/src/routes/(app)/profile/+page.svelte | 16 +- client/src/routes/auth/+page.svelte | 74 +++-- docker-compose.yml | 17 +- proto.sh | 23 +- proto/{user.proto => auth.proto} | 17 +- proto/main.proto | 14 +- proto/note.proto | 2 +- proto/profile.proto | 2 +- server/Dockerfile | 4 +- server/auth/auth_db.go | 184 +++++++++++ server/auth/auth_oauth.go | 140 ++++++++ server/auth/auth_service.go | 287 ++++++++++++++++ server/auth/auth_stripe.go | 95 ++++++ .../{users/user_test.go => auth/auth_test.go} | 58 ++-- server/db/db_service.go | 28 -- server/go.mod | 41 ++- server/go.sum | 126 +++---- server/main.go | 59 ++-- server/main_grpc.go | 64 ++-- server/notes/note_db.go | 122 ++++--- server/notes/note_service.go | 104 +++--- server/notes/note_validation.go | 28 +- server/profiles/profile_db.go | 115 +++---- server/profiles/profile_service.go | 60 ++-- server/profiles/profile_validation.go | 30 +- server/proto/auth.pb.go | 308 ++++++++++++++++++ server/proto/main.pb.go | 206 ++++++++---- server/proto/main_grpc.pb.go | 100 ++++-- server/proto/note.pb.go | 40 ++- server/proto/profile.pb.go | 58 ++-- server/proto/user.pb.go | 290 ----------------- server/public.key | 14 +- .../util_env.go => system/system_env.go} | 17 +- server/system/system_jwt.go | 62 ++++ server/system/system_logger.go | 30 ++ .../system_migrations.go} | 49 ++- server/system/system_storage.go | 27 ++ .../system_string.go} | 9 +- .../system_string_test.go} | 7 +- server/system/system_task.go | 30 ++ server/system/system_validate.go | 21 ++ server/users/token_db.go | 69 ---- server/users/token_service.go | 74 ----- server/users/token_test.go | 80 ----- server/users/user_db.go | 62 ---- server/users/user_oauth.go | 129 -------- server/users/user_service.go | 219 ------------- server/utils/util_storage.go | 36 -- server/utils/util_storage_test.go | 70 ---- server/utils/util_validate.go | 44 --- server/utils/util_validate_test.go | 38 --- 80 files changed, 2441 insertions(+), 2109 deletions(-) rename client/src/lib/proto/{user.proto => auth.proto} (60%) rename client/src/lib/proto/{user.ts => auth.ts} (100%) create mode 100644 client/src/lib/proto/proto/StripeUrlResponse.ts delete mode 100644 client/src/lib/safe.d.ts delete mode 100644 client/src/lib/safe.js create mode 100644 client/src/lib/server/safe.d.ts create mode 100644 client/src/lib/server/safe.js create mode 100644 client/src/routes/(app)/+error.svelte rename proto/{user.proto => auth.proto} (60%) create mode 100644 server/auth/auth_db.go create mode 100644 server/auth/auth_oauth.go create mode 100644 server/auth/auth_service.go create mode 100644 server/auth/auth_stripe.go rename server/{users/user_test.go => auth/auth_test.go} (64%) delete mode 100644 server/db/db_service.go create mode 100644 server/proto/auth.pb.go delete mode 100644 server/proto/user.pb.go rename server/{utils/util_env.go => system/system_env.go} (71%) create mode 100644 server/system/system_jwt.go create mode 100644 server/system/system_logger.go rename server/{db/db_migrations.go => system/system_migrations.go} (53%) mode change 100644 => 100755 create mode 100755 server/system/system_storage.go rename server/{utils/util_string.go => system/system_string.go} (87%) rename server/{utils/util_string_test.go => system/system_string_test.go} (90%) create mode 100644 server/system/system_task.go create mode 100644 server/system/system_validate.go delete mode 100644 server/users/token_db.go delete mode 100644 server/users/token_service.go delete mode 100644 server/users/token_test.go delete mode 100644 server/users/user_db.go delete mode 100644 server/users/user_oauth.go delete mode 100644 server/users/user_service.go delete mode 100644 server/utils/util_storage.go delete mode 100644 server/utils/util_storage_test.go delete mode 100644 server/utils/util_validate.go delete mode 100644 server/utils/util_validate_test.go diff --git a/client/src/hooks.server.js b/client/src/hooks.server.js index 43b3b6d..8935140 100644 --- a/client/src/hooks.server.js +++ b/client/src/hooks.server.js @@ -1,13 +1,17 @@ -import { COOKIE_DOMAIN } from "$env/static/private"; -import { grpcSafe } from "$lib/safe"; -import { server } from "$lib/server/grpc"; +import { UserRole } from "$lib/proto/proto/UserRole"; +import { grpcSafe, server } from "$lib/server/grpc"; import { logger, perf } from "$lib/server/logger"; import { createMetadata } from "$lib/server/metadata"; import { redirect } from "@sveltejs/kit"; +import { building } from "$app/environment"; /** @type {import('@sveltejs/kit').Handle} */ export async function handle({ event, resolve }) { - const end = perf("Auth"); + if (building) { + return await resolve(event); + } + + const end = perf("auth"); event.locals.user = { id: "", created: "", @@ -15,48 +19,64 @@ export async function handle({ event, resolve }) { deleted: "", email: "", avatar: "", - role: 0, + role: UserRole.ROLE_UNSET, sub: "", - subscriptionId: "", - subscriptionEnd: "", - _deleted: "deleted", - _subscriptionEnd: "subscriptionEnd", + subscription_id: "", + subscription_end: "", + subscription_check: "", + subscription_active: false, }; if (event.url.pathname === "/auth") { event.cookies.set("token", "", { - domain: COOKIE_DOMAIN, path: "/", maxAge: 0, }); return await resolve(event); } - const token = event.cookies.get("token"); + /** + * Check if the user is coming from the oauth flow + * If so, set a temporary cookie with the token + * On the next request, the new token will be used + */ + let token = event.url.pathname.includes("/token/") + ? event.url.pathname.split("/token/")[1] + : ""; + if (token) { + event.cookies.set("token", token, { + path: "/", + maxAge: 10, + }); + throw redirect(302, "/"); + } + + token = event.cookies.get("token") ?? ""; if (!token) { logger.info("No token"); - throw redirect(302, "/auth"); + throw redirect(302, "/auth?error=1"); } const metadata = createMetadata(token); - /** @type {import("$lib/safe").Safe} */ + /** @type {import("$lib/server/safe").Safe} */ const auth = await new Promise((res) => { server.Auth({}, metadata, grpcSafe(res)); }); - if (auth.error || !auth.data.tokenId || !auth.data.user) { + if (!auth.success || !auth.data.token || !auth.data.user) { logger.error("Error during auth"); - throw redirect(302, "/auth"); + throw redirect(302, "/auth?error=1"); } event.locals.user = auth.data.user; - event.locals.token = auth.data.tokenId; + event.locals.token = auth.data.token; + // logger.debug(event.locals.user, "user"); end(); const response = await resolve(event); - // max age is 30 days + // max age is 7 days response.headers.append( "set-cookie", - `token=${auth.data.tokenId}; HttpOnly; SameSite=Lax; Secure; Max-Age=2592000; Path=/; Domain=${COOKIE_DOMAIN}`, + `token=${auth.data.token}; HttpOnly; SameSite=Lax; Secure; Max-Age=604800; Path=/`, ); return response; } diff --git a/client/src/lib/proto/user.proto b/client/src/lib/proto/auth.proto similarity index 60% rename from client/src/lib/proto/user.proto rename to client/src/lib/proto/auth.proto index 1da4643..9b56dc7 100644 --- a/client/src/lib/proto/user.proto +++ b/client/src/lib/proto/auth.proto @@ -1,11 +1,9 @@ syntax = "proto3"; - -package proto; - option go_package = "sgsg/proto"; +package proto; enum UserRole { - ROLE_UNSPECIFIED = 0; + ROLE_UNSET = 0; ROLE_USER = 1; ROLE_ADMIN = 2; } @@ -14,12 +12,15 @@ message User { string id = 1; string created = 2; string updated = 3; - optional string deleted = 4; + string deleted = 4; string email = 5; - UserRole role = 6; - string sub = 7; + string sub = 6; + UserRole role = 7; string avatar = 8; + string subscription_id = 9; - optional string subscription_end = 10; + string subscription_end = 10; + string subscription_check = 11; + bool subscription_active = 12; } diff --git a/client/src/lib/proto/user.ts b/client/src/lib/proto/auth.ts similarity index 100% rename from client/src/lib/proto/user.ts rename to client/src/lib/proto/auth.ts diff --git a/client/src/lib/proto/main.proto b/client/src/lib/proto/main.proto index 19c4a29..a03e030 100644 --- a/client/src/lib/proto/main.proto +++ b/client/src/lib/proto/main.proto @@ -1,10 +1,9 @@ syntax = "proto3"; - +option go_package = "sgsg/proto"; package proto; -option go_package = "sgsg/proto"; -import "user.proto"; +import "auth.proto"; import "profile.proto"; import "note.proto"; @@ -15,16 +14,22 @@ message Id { } message AuthResponse { - string tokenId = 1; + string token = 1; User user = 2; } +message StripeUrlResponse { + string url = 1; +} + service Service { rpc Auth(Empty) returns (AuthResponse) {} + rpc CreateStripeCheckout(Empty) returns (StripeUrlResponse) {} + rpc CreateStripePortal(Empty) returns (StripeUrlResponse) {} + rpc GetProfileByUserId(Empty) returns (Profile) {} rpc CreateProfile(Profile) returns (Profile) {} - rpc DeleteProfileById(Id) returns (Empty) {} rpc GetNotesByUserId(Empty) returns (stream Note) {} rpc GetNoteById(Id) returns (Note) {} diff --git a/client/src/lib/proto/main.ts b/client/src/lib/proto/main.ts index 165b194..4d5f498 100644 --- a/client/src/lib/proto/main.ts +++ b/client/src/lib/proto/main.ts @@ -15,6 +15,7 @@ export interface ProtoGrpcType { Note: MessageTypeDefinition Profile: MessageTypeDefinition Service: SubtypeConstructor & { service: _proto_ServiceDefinition } + StripeUrlResponse: MessageTypeDefinition User: MessageTypeDefinition UserRole: EnumTypeDefinition } diff --git a/client/src/lib/proto/note.proto b/client/src/lib/proto/note.proto index e263e5c..284cf8b 100644 --- a/client/src/lib/proto/note.proto +++ b/client/src/lib/proto/note.proto @@ -8,7 +8,7 @@ message Note { string id = 1; string created = 2; string updated = 3; - optional string deleted = 4; + string deleted = 4; string user_id = 5; string title = 6; diff --git a/client/src/lib/proto/profile.proto b/client/src/lib/proto/profile.proto index f225d5a..0c66455 100644 --- a/client/src/lib/proto/profile.proto +++ b/client/src/lib/proto/profile.proto @@ -8,7 +8,7 @@ message Profile { string id = 1; string created = 2; string updated = 3; - optional string deleted = 4; + string deleted = 4; string user_id = 5; string username = 6; diff --git a/client/src/lib/proto/proto/AuthResponse.ts b/client/src/lib/proto/proto/AuthResponse.ts index d3ed09d..9b5c9fc 100644 --- a/client/src/lib/proto/proto/AuthResponse.ts +++ b/client/src/lib/proto/proto/AuthResponse.ts @@ -1,13 +1,13 @@ -// Original file: ../proto/main.proto +// Original file: proto/main.proto import type { User as _proto_User, User__Output as _proto_User__Output } from '../proto/User'; export interface AuthResponse { - 'tokenId'?: (string); + 'token'?: (string); 'user'?: (_proto_User | null); } export interface AuthResponse__Output { - 'tokenId': (string); + 'token': (string); 'user': (_proto_User__Output | null); } diff --git a/client/src/lib/proto/proto/Empty.ts b/client/src/lib/proto/proto/Empty.ts index 00bff7f..6f320f0 100644 --- a/client/src/lib/proto/proto/Empty.ts +++ b/client/src/lib/proto/proto/Empty.ts @@ -1,4 +1,4 @@ -// Original file: ../proto/main.proto +// Original file: proto/main.proto export interface Empty { diff --git a/client/src/lib/proto/proto/Id.ts b/client/src/lib/proto/proto/Id.ts index e3f3afe..3c9b2ce 100644 --- a/client/src/lib/proto/proto/Id.ts +++ b/client/src/lib/proto/proto/Id.ts @@ -1,4 +1,4 @@ -// Original file: ../proto/main.proto +// Original file: proto/main.proto export interface Id { diff --git a/client/src/lib/proto/proto/Note.ts b/client/src/lib/proto/proto/Note.ts index b769da2..7c62f05 100644 --- a/client/src/lib/proto/proto/Note.ts +++ b/client/src/lib/proto/proto/Note.ts @@ -1,4 +1,4 @@ -// Original file: ../proto/note.proto +// Original file: proto/note.proto export interface Note { @@ -6,19 +6,17 @@ export interface Note { 'created'?: (string); 'updated'?: (string); 'deleted'?: (string); - 'userId'?: (string); + 'user_id'?: (string); 'title'?: (string); 'content'?: (string); - '_deleted'?: "deleted"; } export interface Note__Output { 'id': (string); 'created': (string); 'updated': (string); - 'deleted'?: (string); - 'userId': (string); + 'deleted': (string); + 'user_id': (string); 'title': (string); 'content': (string); - '_deleted': "deleted"; } diff --git a/client/src/lib/proto/proto/Profile.ts b/client/src/lib/proto/proto/Profile.ts index b6a31e3..a64dcd9 100644 --- a/client/src/lib/proto/proto/Profile.ts +++ b/client/src/lib/proto/proto/Profile.ts @@ -1,4 +1,4 @@ -// Original file: ../proto/profile.proto +// Original file: proto/profile.proto export interface Profile { @@ -6,25 +6,23 @@ export interface Profile { 'created'?: (string); 'updated'?: (string); 'deleted'?: (string); - 'userId'?: (string); + 'user_id'?: (string); 'username'?: (string); 'about'?: (string); - 'resumeId'?: (string); - 'coverId'?: (string); - 'coverUrl'?: (string); - '_deleted'?: "deleted"; + 'resume_id'?: (string); + 'cover_id'?: (string); + 'cover_url'?: (string); } export interface Profile__Output { 'id': (string); 'created': (string); 'updated': (string); - 'deleted'?: (string); - 'userId': (string); + 'deleted': (string); + 'user_id': (string); 'username': (string); 'about': (string); - 'resumeId': (string); - 'coverId': (string); - 'coverUrl': (string); - '_deleted': "deleted"; + 'resume_id': (string); + 'cover_id': (string); + 'cover_url': (string); } diff --git a/client/src/lib/proto/proto/Service.ts b/client/src/lib/proto/proto/Service.ts index 09f23af..83e5b14 100644 --- a/client/src/lib/proto/proto/Service.ts +++ b/client/src/lib/proto/proto/Service.ts @@ -1,4 +1,4 @@ -// Original file: ../proto/main.proto +// Original file: proto/main.proto import type * as grpc from '@grpc/grpc-js' import type { MethodDefinition } from '@grpc/proto-loader' @@ -7,6 +7,7 @@ import type { Empty as _proto_Empty, Empty__Output as _proto_Empty__Output } fro import type { Id as _proto_Id, Id__Output as _proto_Id__Output } from '../proto/Id'; import type { Note as _proto_Note, Note__Output as _proto_Note__Output } from '../proto/Note'; import type { Profile as _proto_Profile, Profile__Output as _proto_Profile__Output } from '../proto/Profile'; +import type { StripeUrlResponse as _proto_StripeUrlResponse, StripeUrlResponse__Output as _proto_StripeUrlResponse__Output } from '../proto/StripeUrlResponse'; export interface ServiceClient extends grpc.Client { Auth(argument: _proto_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_AuthResponse__Output>): grpc.ClientUnaryCall; @@ -36,6 +37,24 @@ export interface ServiceClient extends grpc.Client { createProfile(argument: _proto_Profile, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Profile__Output>): grpc.ClientUnaryCall; createProfile(argument: _proto_Profile, callback: grpc.requestCallback<_proto_Profile__Output>): grpc.ClientUnaryCall; + CreateStripeCheckout(argument: _proto_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + CreateStripeCheckout(argument: _proto_Empty, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + CreateStripeCheckout(argument: _proto_Empty, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + CreateStripeCheckout(argument: _proto_Empty, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripeCheckout(argument: _proto_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripeCheckout(argument: _proto_Empty, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripeCheckout(argument: _proto_Empty, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripeCheckout(argument: _proto_Empty, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + + CreateStripePortal(argument: _proto_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + CreateStripePortal(argument: _proto_Empty, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + CreateStripePortal(argument: _proto_Empty, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + CreateStripePortal(argument: _proto_Empty, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripePortal(argument: _proto_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripePortal(argument: _proto_Empty, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripePortal(argument: _proto_Empty, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + createStripePortal(argument: _proto_Empty, callback: grpc.requestCallback<_proto_StripeUrlResponse__Output>): grpc.ClientUnaryCall; + DeleteNoteById(argument: _proto_Id, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; DeleteNoteById(argument: _proto_Id, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; DeleteNoteById(argument: _proto_Id, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; @@ -45,15 +64,6 @@ export interface ServiceClient extends grpc.Client { deleteNoteById(argument: _proto_Id, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; deleteNoteById(argument: _proto_Id, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - DeleteProfileById(argument: _proto_Id, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - DeleteProfileById(argument: _proto_Id, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - DeleteProfileById(argument: _proto_Id, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - DeleteProfileById(argument: _proto_Id, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - deleteProfileById(argument: _proto_Id, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - deleteProfileById(argument: _proto_Id, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - deleteProfileById(argument: _proto_Id, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - deleteProfileById(argument: _proto_Id, callback: grpc.requestCallback<_proto_Empty__Output>): grpc.ClientUnaryCall; - GetNoteById(argument: _proto_Id, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Note__Output>): grpc.ClientUnaryCall; GetNoteById(argument: _proto_Id, metadata: grpc.Metadata, callback: grpc.requestCallback<_proto_Note__Output>): grpc.ClientUnaryCall; GetNoteById(argument: _proto_Id, options: grpc.CallOptions, callback: grpc.requestCallback<_proto_Note__Output>): grpc.ClientUnaryCall; @@ -86,9 +96,11 @@ export interface ServiceHandlers extends grpc.UntypedServiceImplementation { CreateProfile: grpc.handleUnaryCall<_proto_Profile__Output, _proto_Profile>; - DeleteNoteById: grpc.handleUnaryCall<_proto_Id__Output, _proto_Empty>; + CreateStripeCheckout: grpc.handleUnaryCall<_proto_Empty__Output, _proto_StripeUrlResponse>; - DeleteProfileById: grpc.handleUnaryCall<_proto_Id__Output, _proto_Empty>; + CreateStripePortal: grpc.handleUnaryCall<_proto_Empty__Output, _proto_StripeUrlResponse>; + + DeleteNoteById: grpc.handleUnaryCall<_proto_Id__Output, _proto_Empty>; GetNoteById: grpc.handleUnaryCall<_proto_Id__Output, _proto_Note>; @@ -102,8 +114,9 @@ export interface ServiceDefinition extends grpc.ServiceDefinition { Auth: MethodDefinition<_proto_Empty, _proto_AuthResponse, _proto_Empty__Output, _proto_AuthResponse__Output> CreateNote: MethodDefinition<_proto_Note, _proto_Note, _proto_Note__Output, _proto_Note__Output> CreateProfile: MethodDefinition<_proto_Profile, _proto_Profile, _proto_Profile__Output, _proto_Profile__Output> + CreateStripeCheckout: MethodDefinition<_proto_Empty, _proto_StripeUrlResponse, _proto_Empty__Output, _proto_StripeUrlResponse__Output> + CreateStripePortal: MethodDefinition<_proto_Empty, _proto_StripeUrlResponse, _proto_Empty__Output, _proto_StripeUrlResponse__Output> DeleteNoteById: MethodDefinition<_proto_Id, _proto_Empty, _proto_Id__Output, _proto_Empty__Output> - DeleteProfileById: MethodDefinition<_proto_Id, _proto_Empty, _proto_Id__Output, _proto_Empty__Output> GetNoteById: MethodDefinition<_proto_Id, _proto_Note, _proto_Id__Output, _proto_Note__Output> GetNotesByUserId: MethodDefinition<_proto_Empty, _proto_Note, _proto_Empty__Output, _proto_Note__Output> GetProfileByUserId: MethodDefinition<_proto_Empty, _proto_Profile, _proto_Empty__Output, _proto_Profile__Output> diff --git a/client/src/lib/proto/proto/StripeUrlResponse.ts b/client/src/lib/proto/proto/StripeUrlResponse.ts new file mode 100644 index 0000000..6158586 --- /dev/null +++ b/client/src/lib/proto/proto/StripeUrlResponse.ts @@ -0,0 +1,10 @@ +// Original file: proto/main.proto + + +export interface StripeUrlResponse { + 'url'?: (string); +} + +export interface StripeUrlResponse__Output { + 'url': (string); +} diff --git a/client/src/lib/proto/proto/User.ts b/client/src/lib/proto/proto/User.ts index 73abb7f..8bfe22a 100644 --- a/client/src/lib/proto/proto/User.ts +++ b/client/src/lib/proto/proto/User.ts @@ -1,4 +1,4 @@ -// Original file: ../proto/user.proto +// Original file: proto/auth.proto import type { UserRole as _proto_UserRole, UserRole__Output as _proto_UserRole__Output } from '../proto/UserRole'; @@ -8,26 +8,26 @@ export interface User { 'updated'?: (string); 'deleted'?: (string); 'email'?: (string); - 'role'?: (_proto_UserRole); 'sub'?: (string); + 'role'?: (_proto_UserRole); 'avatar'?: (string); - 'subscriptionId'?: (string); - 'subscriptionEnd'?: (string); - '_deleted'?: "deleted"; - '_subscriptionEnd'?: "subscriptionEnd"; + 'subscription_id'?: (string); + 'subscription_end'?: (string); + 'subscription_check'?: (string); + 'subscription_active'?: (boolean); } export interface User__Output { 'id': (string); 'created': (string); 'updated': (string); - 'deleted'?: (string); + 'deleted': (string); 'email': (string); - 'role': (_proto_UserRole__Output); 'sub': (string); + 'role': (_proto_UserRole__Output); 'avatar': (string); - 'subscriptionId': (string); - 'subscriptionEnd'?: (string); - '_deleted': "deleted"; - '_subscriptionEnd': "subscriptionEnd"; + 'subscription_id': (string); + 'subscription_end': (string); + 'subscription_check': (string); + 'subscription_active': (boolean); } diff --git a/client/src/lib/proto/proto/UserRole.ts b/client/src/lib/proto/proto/UserRole.ts index 76c41a6..57b3bca 100644 --- a/client/src/lib/proto/proto/UserRole.ts +++ b/client/src/lib/proto/proto/UserRole.ts @@ -1,13 +1,13 @@ -// Original file: ../proto/user.proto +// Original file: proto/auth.proto export const UserRole = { - ROLE_UNSPECIFIED: 0, - ROLE_USER: 1, - ROLE_ADMIN: 2, + ROLE_UNSET: 'ROLE_UNSET', + ROLE_USER: 'ROLE_USER', + ROLE_ADMIN: 'ROLE_ADMIN', } as const; export type UserRole = - | 'ROLE_UNSPECIFIED' + | 'ROLE_UNSET' | 0 | 'ROLE_USER' | 1 diff --git a/client/src/lib/safe.d.ts b/client/src/lib/safe.d.ts deleted file mode 100644 index 5765c6c..0000000 --- a/client/src/lib/safe.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -export type Safe = - | { - error: false; - data: T; - } - | { - error: true; - msg: string; - fields?: { - field: string; - tag: string; - }[]; - }; - -export declare function safe(promise: Promise): Promise>; -export declare function safe(fn: () => T): Safe; - -export declare function grpcSafe( - res: (value: Safe) => void, -): (err: ServiceError | null, data: T | undefined) => void; diff --git a/client/src/lib/safe.js b/client/src/lib/safe.js deleted file mode 100644 index 1c88eec..0000000 --- a/client/src/lib/safe.js +++ /dev/null @@ -1,102 +0,0 @@ -import { logger } from "$lib/server/logger"; - -/** - * @param {Promise | Function} promiseOrFunc - * @returns {Promise> | import("./safe").Safe} - * @template T - */ -export function safe(promiseOrFunc) { - if (promiseOrFunc instanceof Promise) { - return safeAsync(promiseOrFunc); - } - return safeSync(promiseOrFunc); -} - -/** - * @param {Promise} promise - * @returns {Promise>} - * @template T - * @private - */ -async function safeAsync(promise) { - try { - const data = await promise; - return { data, error: false }; - } catch (e) { - logger.error(e); - if (e instanceof Error) { - return { error: true, msg: e.message }; - } - return { error: true, msg: "Something went wrong" }; - } -} - -/** - * @param {Function} func - * @returns {import("./safe").Safe} - * @template T - * @private - */ -function safeSync(func) { - try { - const data = func(); - return { data, error: false }; - } catch (e) { - logger.error(e); - if (e instanceof Error) { - return { error: true, msg: e.message }; - } - return { error: true, msg: "Something went wrong" }; - } -} - -/** - * Callback function for handling gRPC responses safely. - * - * @template T - The type of data expected in the response. - * - * @param {(value: import("./safe").Safe) => void} res - The callback function to handle the response. - * @returns {(err: import("@grpc/grpc-js").ServiceError | null, data: T | undefined) => void} - A callback function to be used with gRPC response handling. - */ -export function grpcSafe(res) { - /** - * Handles the gRPC response and calls the provided callback function safely. - * - * @param {import("@grpc/grpc-js").ServiceError | null} err - The error, if any, returned in the response. - * @param {T | undefined} data - The data returned in the response. - */ - return (err, data) => { - if (err) { - logger.error(err); - if (err.code === 3) { - let fields = []; - try { - fields = JSON.parse(err.details); - } catch (e) { - return res({ - error: true, - msg: err?.message || "Something went wrong", - }); - } - - return res({ - error: true, - msg: "Invalid argument", - fields: fields, - }); - } - return res({ - error: true, - msg: err?.message || "Something went wrong", - }); - } - if (!data) { - logger.error("No data returned"); - return res({ - error: true, - msg: "No data returned", - }); - } - res({ data, error: false }); - }; -} diff --git a/client/src/lib/server/api.js b/client/src/lib/server/api.js index 38bb506..53a81c4 100644 --- a/client/src/lib/server/api.js +++ b/client/src/lib/server/api.js @@ -9,7 +9,7 @@ import { logger } from "./logger"; * file?: File, * email?: import("$lib/types").UpsendEmail, * }} options - * @returns {Promise>} + * @returns {Promise>} * @template T */ export async function upsendApi({ method = "GET", url, file, email }) { @@ -35,16 +35,17 @@ export async function upsendApi({ method = "GET", url, file, email }) { } if (response.status === 204) { const empty = /** @type {T} */ (""); - return { error: false, data: empty }; + return { success: true, data: empty }; } const data = await response.json(); - return { error: false, data }; + return { success: true, data }; } catch (error) { logger.error(error); return { - error: true, - msg: "Error using Upsend API", + success: false, + error: + error instanceof Error ? error.message : "Something went wrong", }; } } diff --git a/client/src/lib/server/grpc.js b/client/src/lib/server/grpc.js index cecfcfd..60fc225 100644 --- a/client/src/lib/server/grpc.js +++ b/client/src/lib/server/grpc.js @@ -5,11 +5,11 @@ import { ENV, SERVER_GRPC } from "$env/static/private"; export const packageDefinition = protoLoader.loadSync( "./src/lib/proto/main.proto", { - keepCase: false, + keepCase: true, longs: String, + enums: String, defaults: true, oneofs: true, - arrays: true, }, ); @@ -24,3 +24,56 @@ const cr = : credentials.createInsecure(); export const server = new proto.proto.Service(SERVER_GRPC, cr); + +/** + * Callback function for handling gRPC responses safely. + * + * @template T - The type of data expected in the response. + * + * @param {(value: import("./safe").GrpcSafe) => void} res - The callback function to handle the response. + * @returns {(err: import("@grpc/grpc-js").ServiceError | null, data: T | undefined) => void} - A callback function to be used with gRPC response handling. + */ +export function grpcSafe(res) { + /** + * Handles the gRPC response and calls the provided callback function safely. + * + * @param {import("@grpc/grpc-js").ServiceError | null} err - The error, if any, returned in the response. + * @param {T | undefined} data - The data returned in the response. + */ + return (err, data) => { + if (err) { + if (err.code === 3) { + let fields = []; + try { + fields = JSON.parse(err.details); + } catch (e) { + return res({ + success: false, + error: err?.message || "Something went wrong", + code: err.code, + }); + } + + return res({ + success: false, + error: "Invalid argument", + fields: fields, + code: err.code, + }); + } + return res({ + success: false, + code: err.code, + error: err?.message || "Something went wrong", + }); + } + if (!data) { + return res({ + success: false, + error: "No data returned", + code: 0, + }); + } + return res({ data, success: true }); + }; +} diff --git a/client/src/lib/server/logger.js b/client/src/lib/server/logger.js index f0d6e10..84c0e47 100644 --- a/client/src/lib/server/logger.js +++ b/client/src/lib/server/logger.js @@ -1,22 +1,25 @@ +import { ENV } from "$env/static/private"; import pino from "pino"; -export const logger = pino({ - transport: { - target: "pino-pretty", - options: { - colorize: true, - }, - }, - // transport: - // ENV === "production" - // ? undefined - // : { - // target: "pino-pretty", - // options: { - // colorize: true, - // }, - // }, -}); +function get_pino_config() { + if (ENV === "development") { + return { + transport: { + target: "pino-pretty", + options: { + colorize: true, + }, + }, + level: "debug", + }; + } else { + return { + level: "info", + }; + } +} + +export const logger = pino(get_pino_config()); /** * Measure the performance @@ -24,11 +27,11 @@ export const logger = pino({ * @returns {() => void} - The end function */ export function perf(name) { - // if (ENV === "production") { - // return () => { - // // do nothing - // }; - // } + if (ENV === "productionn") { + return () => { + // do nothing + }; + } const start = performance.now(); /** diff --git a/client/src/lib/server/metadata.js b/client/src/lib/server/metadata.js index d34dbcc..a07e8e1 100644 --- a/client/src/lib/server/metadata.js +++ b/client/src/lib/server/metadata.js @@ -9,14 +9,14 @@ const key = fs.readFileSync("./src/lib/server/private.key"); /** * Create a Metadata object with the correct authorization headers - * @param {string} tokenId - The token id to use for the authorization + * @param {string} id - The token id or user id * @returns {Metadata} - Metadata object with the correct authorization headers */ -export function createMetadata(tokenId) { +export function createMetadata(id) { const metadata = new Metadata(); const tokenPayload = { - tokenId: tokenId, + id: id, }; // Generate and sign the token diff --git a/client/src/lib/server/private.key b/client/src/lib/server/private.key index d6ffadf..a8d4833 100644 --- a/client/src/lib/server/private.key +++ b/client/src/lib/server/private.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwd1e3P4ylu9OE -A3OtlihdVpIS678mZzmL8/qvIKCW22D2xyFCMX/G7eBPItBmtqEQMuF7A6UDafPQ -SDdvs5D0Rla6K2JICdJKwzvwo+HT/62rGyNPcwG6Uj0kdhUcaAQBkU6jTk5xLgM8 -k1uG1FIcqduLFLtFtRQsFq28g9fu8ML+EoNCX9kidnwP4GT6vL8L/NNNjt5+w2FC -ukP+SvLRWh1C3R85H17tZk4efiVedlnRpGm9emg9PXuY1NO4x34vtshBNNXAer2a -Swu9qbnPGcKViWVfY6cL0bgb0aG6ePcH0IHEZyW5qH70c9PPhjVq7yHSioJZW6fk -nz6WHHQ1AgMBAAECggEAKk5yWRyDO7isHRo2wYceZkI7Aw5B5ZMZ2NPFZfcMiR5P -QNq8voHfgHHHNTHDhNyEAL4yEKvvA8KDEYw+vijut6GlaTy9c0fngsULucWQfqLt -n/gBnyqTX3gX8IXeydCmJToRAFXluHyvifZKGykMBpMyb0WpIC0piOhm/qsdOctY -+Fgbi4vxYQK9TWuNmBoJ06JgQ3SC1BAdDeiVcbIuM/MMl4kluHWAmZKXYSndDq5W -0+PqJo/2+Fzld57uKl5RXwKxrq7UEQ5FHvul6VDOtR27UgjBBDv+e3rjlLXJ57FK -jS+lI7l+H0bs+rCszUfDeMBI2Au6koI+pGbUA5zkgQKBgQDcm1ybaa8Z46i7jF2A -3/vrIDJvWJPDwaKgt17sruBJGKKpo4WdP0iYYGsxACtf9RnEc1be58zZbicwRjHH -usFsT3Pg2B1dxoJp11jayhl+4/4OAXBZfb/+OmkRuakNm6+KKHgvm/BWmmg1caRz -n4Pttme7vmCBAqlW0+PS+zk9ywKBgQDMxw9CggS9eFmCuhzH4+IqP4jkpN7Y55Ko -Ek26/Onh7mYbVf5lRgn8AfrWaNxyHIhKQKtsbHQ+5r9CH/2sbWWNfN8MJU2l3DaI -NJhu6lRmnkMQFds2bGBbRUOlm55vJJmul30KaajU+aEQp1hgvgMMx8JKDIeNGTmY -6H8QMUrV/wKBgQDJxRtVVbr+Pdfk+YPHzJTXv5IBfw1fPOpmfnDGn0ep82tLJrGd -WfUm0QEZRyNk14Mix69Lns0gjPwwzfLXz7r7Okws+N0bGOXMslalfbUF9rc1ziEY -6MfCWWAiAyJYvO03ur36JXETdJQdVXxo+ButPmjwMTaIqIuDS7eTD42SMwKBgApB -RcBc5oPejQ0A6QQRo3feKqrYnthZ8Hw+PmpI1CWeXLqtucm0kjdumfM22SNVznV5 -e5w4ajHkOFvFYlzKNbW6NSlUjOjreEel6qRTU9q3vkAF+C5niwPHGjYm7u499PxL -VdW5qNzRi4FcAA8INPrk3hP7QKaORtYjfol/DnJdAoGBAIHQqlPWqmMjhRwe/Ogf -GQ+FjyqEXFWlIGyY0shfd+e4UBuxD/X/N1VgqEFC4/1JRDQ84W3T69aFkvt/1+/U -5pp/u0cXsrlwJ2cUqcYSldmeS0RF+Aci3Yygt7pbSHCayqReEGpYEhwDJteUN93x -wh3Rai1zJBeaYgGEVEKu2ILw +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBUBOyiIbiDXPv +HHdIae7AfBVHBBbbMGDDjFKhGFs/Zt8BA9D/hg0KHSyLsiIUisvEkcErqzV7dwb3 +J30cTXV5TJtki0KcmqmHzo/C8H5dzbcvQN5wrkU+O98X/Z4C2RLsyT5FoTH6x2Fq +Rz+oV2oJ+Pq3iZIiV81vIiA3PvMNjH/p7e4RhCD5GVI8a6pLeT8swrZwTXgr11w0 +N1h/h+uUNQv/Ex6V3nx1D84wYp1s7nlpG3/ojd8nZtlHRUf6ywYvkBcOWqf9KlQZ +UazkJCCYd3Ibj30kKEwo77mK0VRfBc2dLguBRYX9+RTQeyCXSKYY1WF5AyjaqCqS +by+k99xtAgMBAAECggEAHOdDArB8xmNvivgCcmklrFGr1sHq7vE6o+ehBSWAoygC +Pi3FZnyIX5OWxk5R39NpfdBd2xB5adE/+91Dd2Nc0KWecvfgHk0rqDq/bky0qtl9 +bbXGbH+fVRubktk18m66xdJIcB3BZ3cUftD8rh1fz/I8/mCLNnz9TNlZNW7BOtby +ZtMEdBrOcEj5Z5QG6MMRe+7pLTFNpevbg5r7ZPIe18Tn+g/+FpiUuLswKPOPGzBF +vgaz1QG5tXl/D2jhZLBHeTyIosXCyVudQNF0p80SmzrP7dSzjv8xMOyS4PJ7/s3l +Bq1fsmk9yBe9Sgy5s8RWDmEwUyXJtgL1vU1utd0QewKBgQDzMgszg9S6KZsuy0O4 +6AlsGOraNm7YYaK6uCt6kL40eEszxkN5bAXhWYA3/I+1qW4Glw6HrH6oTLYjGgm+ +mV9wU/ukr6nmTIgmxox5eUay/dTXT42nZa5BD7TH7W0nfmz1SQXUqE0vXX0bdtSo +1VY1wvjKs0JqbTyYfMXRBjON6wKBgQDLfa4WUPil2EF6iNhRIG8d92UsxdZ8YkTu +NAbparW1Z7FeJ8lpCH4POSeglFAY9dlP4x7tDT/oHGdc+2z9H6l9cWfIuodins0R +ZZjXIGWUXdEm5DfBsjr4qfe2/0mQRe/GB78uAnjd4znPTWEsAJzO5mHCNv/5y1ZN +XzR1F+8xBwKBgAXK5ltmw3VfslOOAeHwnPDXMxjZfRBoWvDpnBeCRRWI2/myuj61 +JPq2IAi1WlLwYy+C/5SZtjaaBSiW4S6KBqztQywsBvb2UbPivMvT6KwwwZYTTgNz +t4/TKPIuJJBxQXUiNSJYk+YR6v3xeaU/15rWNwjU9jsEuRHEvw14gVfbAoGBAIgY +7q4OSb7h/CkwDT11K9wm8owXZXSbZO7L7TOAIzfIul/2zEZrX6Re3ZoQl+GZzFYZ +2T1Cd1OOa7NMlYBWBM3ZY0hlONdEznKsOKTpDgdFF/Wi/YeW5MobI4pJA7JylAMm +ez8SeDQvHSMA5dTANCBNBWUX0+wFixsEadlGwLtRAoGBAImCP2MPhhygOWECut9k +j3U3sf3w8CQDW42TkoEP2cS6ZfcFLZnMOtLpeivDfYsZeK0mK3XySLlCinwk2vYF +W/Mo/Y3YSLLTzgjvZgm1NTJqeJUSucther6TNU0Ta4amXpsr02v3vPmlAVAkreFl +CsE1tWCcisxZTmnDwogTgLc/ -----END PRIVATE KEY----- diff --git a/client/src/lib/server/safe.d.ts b/client/src/lib/server/safe.d.ts new file mode 100644 index 0000000..5622470 --- /dev/null +++ b/client/src/lib/server/safe.d.ts @@ -0,0 +1,27 @@ +export type Safe = + | { + success: true; + data: T; + } + | { + success: false; + error: string; + }; + +export type GrpcSafe = + | { + success: true; + data: T; + } + | { + success: false; + error: string; + fields?: { + field: string; + tag: string; + }[]; + code: number; + }; + +export declare function safe(promise: Promise): Promise>; +export declare function safe(fn: () => T): Safe; diff --git a/client/src/lib/server/safe.js b/client/src/lib/server/safe.js new file mode 100644 index 0000000..5efeb18 --- /dev/null +++ b/client/src/lib/server/safe.js @@ -0,0 +1,51 @@ +import { logger } from "$lib/server/logger"; + +/** + * @param {Promise | Function} promiseOrFunc + * @returns {Promise> | import("./safe").Safe} + * @template T + */ +export function safe(promiseOrFunc) { + if (promiseOrFunc instanceof Promise) { + return safeAsync(promiseOrFunc); + } + return safeSync(promiseOrFunc); +} + +/** + * @param {Promise} promise + * @returns {Promise>} + * @template T + * @private + */ +async function safeAsync(promise) { + try { + const data = await promise; + return { data, success: true }; + } catch (e) { + logger.error(e); + if (e instanceof Error) { + return { success: false, error: e.message }; + } + return { success: false, error: "Something went wrong" }; + } +} + +/** + * @param {Function} func + * @returns {import("./safe").Safe} + * @template T + * @private + */ +function safeSync(func) { + try { + const data = func(); + return { data, success: true }; + } catch (e) { + logger.error(e); + if (e instanceof Error) { + return { success: false, error: e.message }; + } + return { success: false, error: "Something went wrong" }; + } +} diff --git a/client/src/routes/(app)/+error.svelte b/client/src/routes/(app)/+error.svelte new file mode 100644 index 0000000..148b917 --- /dev/null +++ b/client/src/routes/(app)/+error.svelte @@ -0,0 +1,30 @@ + + +
+
+

{$page.status}

+

+ {$page.status === 404 ? "Page not found" : "Something went wrong"} +

+

+ {$page.error?.message ?? "Unknown error"} +

+
+ + + Contact support + +
+
+
diff --git a/client/src/routes/(app)/notes/+page.server.js b/client/src/routes/(app)/notes/+page.server.js index 29179d9..8a4eb90 100644 --- a/client/src/routes/(app)/notes/+page.server.js +++ b/client/src/routes/(app)/notes/+page.server.js @@ -1,14 +1,16 @@ import { getFormValue } from "$lib/helpers"; -import { grpcSafe, safe } from "$lib/safe"; -import { server } from "$lib/server/grpc"; +import { safe } from "$lib/server/safe"; +import { grpcSafe, server } from "$lib/server/grpc"; import { createMetadata } from "$lib/server/metadata"; -import { fail } from "@sveltejs/kit"; +import { error, fail } from "@sveltejs/kit"; +import { perf } from "$lib/server/logger"; /** @type {import('./$types').PageServerLoad} */ export async function load({ locals }) { + const end = perf("load_notes"); /** @type {import("$lib/proto/proto/Note").Note__Output[]} */ const notes = []; - const metadata = createMetadata(locals.token); + const metadata = createMetadata(locals.user.id); const notesStream = server.GetNotesByUserId({}, metadata); /** @type {Promise} */ @@ -19,12 +21,10 @@ export async function load({ locals }) { }); const r = await safe(p); - if (r.error) { - return { - error: r.msg, - notes: [], - }; + if (!r.success) { + throw error(500, r.error); } + end(); return { notes: notes, }; @@ -33,6 +33,7 @@ export async function load({ locals }) { /** @type {import('./$types').Actions} */ export const actions = { insert: async ({ locals, request }) => { + const end = perf("insert_note"); const form = await request.formData(); /** @type {import("$lib/proto/proto/Note").Note} */ @@ -40,19 +41,17 @@ export const actions = { title: getFormValue(form, "title"), content: getFormValue(form, "content"), }; - const metadata = createMetadata(locals.token); - /** @type {import("$lib/safe").Safe} */ + const metadata = createMetadata(locals.user.id); + /** @type {import("$lib/server/safe").GrpcSafe} */ const req = await new Promise((r) => { server.CreateNote(data, metadata, grpcSafe(r)); }); - if (req.error) { - if (req.fields) { - return fail(400, { fields: req.fields }); - } - return fail(500, { error: req.msg }); + if (!req.success) { + return fail(500, { error: req.error, fields: req.fields }); } + end(); return { note: req.data }; }, }; diff --git a/client/src/routes/(app)/notes/[noteId]/+page.server.js b/client/src/routes/(app)/notes/[noteId]/+page.server.js index 4878724..9e1888c 100644 --- a/client/src/routes/(app)/notes/[noteId]/+page.server.js +++ b/client/src/routes/(app)/notes/[noteId]/+page.server.js @@ -1,27 +1,29 @@ import { error, fail } from "@sveltejs/kit"; import { getFormValue } from "$lib/helpers"; import { createMetadata } from "$lib/server/metadata"; -import { server } from "$lib/server/grpc"; -import { grpcSafe } from "$lib/safe"; +import { grpcSafe, server } from "$lib/server/grpc"; import { schema } from "./note"; +import { perf } from "$lib/server/logger"; /** @type {import('./$types').PageServerLoad} */ export async function load({ locals, params }) { + const end = perf("load_note"); const id = params.noteId; if (!id) { throw error(409, "Missing note id"); } - const metadata = createMetadata(locals.token); - /** @type {import("$lib/safe").Safe} */ + const metadata = createMetadata(locals.user.id); + /** @type {import("$lib/server/safe").GrpcSafe} */ const req = await new Promise((r) => { server.GetNoteById({ id }, metadata, grpcSafe(r)); }); - if (req.error) { - throw error(404, req.msg); + if (!req.success) { + throw error(404, req.error); } + end(); return { note: req.data, }; @@ -30,6 +32,7 @@ export async function load({ locals, params }) { /** @type {import('./$types').Actions} */ export const actions = { update: async ({ locals, request }) => { + const end = perf("update_note"); const form = await request.formData(); const validation = schema.safeParse({ @@ -54,37 +57,36 @@ export const actions = { content: validation.data.content, }; - const metadata = createMetadata(locals.token); - /** @type {import("$lib/safe").Safe} */ + const metadata = createMetadata(locals.user.id); + /** @type {import("$lib/server/safe").GrpcSafe} */ const req = await new Promise((r) => { server.CreateNote(data, metadata, grpcSafe(r)); }); - if (req.error) { - if (req.fields) { - return fail(400, { fields: req.fields }); - } - return fail(500, { error: req.msg }); + if (!req.success) { + return fail(500, { error: req.error, fields: req.fields }); } - + end(); return { note: req.data }; }, delete: async ({ locals, request }) => { + const end = perf("delete_note"); const form = await request.formData(); /** @type {import("$lib/proto/proto/Id").Id} */ const data = { id: getFormValue(form, "id"), }; - const metadata = createMetadata(locals.token); - /** @type {import("$lib/safe").Safe} */ + const metadata = createMetadata(locals.user.id); + /** @type {import("$lib/server/safe").GrpcSafe} */ const req = await new Promise((r) => { server.DeleteNoteById(data, metadata, grpcSafe(r)); }); - if (req.error) { - return fail(400, { error: req.msg }); + if (!req.success) { + return fail(400, { error: req.error }); } + end(); return { success: true, }; diff --git a/client/src/routes/(app)/profile/+page.server.js b/client/src/routes/(app)/profile/+page.server.js index 66826d3..5b66d77 100644 --- a/client/src/routes/(app)/profile/+page.server.js +++ b/client/src/routes/(app)/profile/+page.server.js @@ -1,6 +1,6 @@ import { getFormValue } from "$lib/helpers"; -import { safe } from "$lib/safe"; -import { grpcSafe } from "$lib/safe"; +import { safe } from "$lib/server/safe"; +import { grpcSafe } from "$lib/server/grpc"; import { upsendApi } from "$lib/server/api"; import { server } from "$lib/server/grpc"; import { perf } from "$lib/server/logger"; @@ -9,29 +9,29 @@ import { error, fail } from "@sveltejs/kit"; /** @type {import('./$types').PageServerLoad} */ export async function load({ locals }) { - const end = perf("Load profile"); + const end = perf("load_profile"); /** * We return the profile data immediately, and then fetch the resume and stream it to the client as it loads. */ - /** @type {import('$lib/safe').Safe} */ + /** @type {import('$lib/server/safe').Safe} */ const profile = await new Promise((r) => { server.GetProfileByUserId( {}, - createMetadata(locals.token), + createMetadata(locals.user.id), grpcSafe(r), ); }); - if (profile.error) { - throw error(500, profile.msg); + if (!profile.success) { + throw error(500, profile.error); } - /** @type {Promise>} */ - let resumePromise = Promise.resolve({ data: undefined, error: false }); - if (profile.data.resumeId) { - /** @type {Promise>} */ + /** @type {Promise>} */ + let resumePromise = Promise.resolve({ data: undefined, success: true }); + if (profile.data.resume_id) { + /** @type {Promise>} */ resumePromise = upsendApi({ - url: `/files/${profile.data.resumeId}`, + url: `/files/${profile.data.resume_id}`, method: "GET", }); } @@ -46,6 +46,7 @@ export async function load({ locals }) { /** @type {import('./$types').Actions} */ export const actions = { createProfile: async ({ locals, request }) => { + const end = perf("create_profile"); const form = await request.formData(); let resumeId = getFormValue(form, "resumeId"); @@ -69,26 +70,25 @@ export const actions = { url: `/files/${resumeId}`, method: "DELETE", }); - if (resDel.error) { - return fail(400, { error: resDel.msg }); + if (!resDel.success) { + return fail(400, { error: resDel.error }); } } /** * Upload new resume - * @type {import("$lib/safe").Safe} + * @type {import("$lib/server/safe").Safe} */ const file = await upsendApi({ url: "/files", method: "POST", file: resume, }); - if (file.error) { - return fail(400, { error: file.msg }); + if (!file.success) { + return fail(400, { error: file.error }); } resumeId = file.data.id; - console.log(resumeId); } let coverId = getFormValue(form, "coverId"); @@ -114,22 +114,22 @@ export const actions = { url: `/images/${coverId}`, method: "DELETE", }); - if (resDel.error) { - return fail(400, { error: resDel.msg }); + if (!resDel.success) { + return fail(400, { error: resDel.error }); } } /** * Upload new cover - * @type {import("$lib/safe").Safe} + * @type {import("$lib/server/safe").Safe} */ const file = await upsendApi({ url: "/images", method: "POST", file: cover, }); - if (file.error) { - return fail(400, { error: file.msg }); + if (!file.success) { + return fail(400, { error: file.error }); } coverId = file.data.id; @@ -141,25 +141,25 @@ export const actions = { id: getFormValue(form, "id"), username: getFormValue(form, "username"), about: getFormValue(form, "about"), - resumeId: resumeId, - coverId: coverId, - coverUrl: coverUrl, + resume_id: resumeId, + cover_id: coverId, + cover_url: coverUrl, }; - /** @type {import("$lib/safe").Safe} */ + /** @type {import("$lib/server/safe").GrpcSafe} */ const res = await new Promise((r) => { server.CreateProfile( data, - createMetadata(locals.token), + createMetadata(locals.user.id), grpcSafe(r), ); }); - if (res.error) { + if (!res.success) { if (res.fields) { return fail(400, { fields: res.fields }); } - return fail(400, { error: res.msg }); + return fail(400, { error: res.error }); } /** @@ -183,6 +183,7 @@ export const actions = { }), ); + end(); return { profile: res.data, }; diff --git a/client/src/routes/(app)/profile/+page.svelte b/client/src/routes/(app)/profile/+page.svelte index 3e26528..2b5ee6d 100644 --- a/client/src/routes/(app)/profile/+page.svelte +++ b/client/src/routes/(app)/profile/+page.svelte @@ -14,7 +14,7 @@ /** @type {import("./$types").ActionData} */ export let form; $: if (form?.error) { - toast.error("Error", form?.error || "Unknown error"); + toast.error("Error", form.error); } /** @type {boolean} */ @@ -110,7 +110,7 @@ - {#if data.profile.resumeId} + {#if data.profile.resume_id} {#await data.stream.resume}
@@ -126,7 +126,7 @@
{:then r} - {#if !r.error && r.data} + {#if r.success && r.data}
-