diff --git a/proto/api/v1/shared.proto b/proto/api/v1/shared.proto index 6a0d663d..29ce279c 100644 --- a/proto/api/v1/shared.proto +++ b/proto/api/v1/shared.proto @@ -32,7 +32,8 @@ message User { string id = 1 [(buf.validate.field).string.uuid = true]; string first_name = 2 [(buf.validate.field).string.min_len = 1]; string last_name = 3 [(buf.validate.field).string.min_len = 1]; - bool followed = 4; + string email = 4; + bool followed = 5; } message PaginationRequest { diff --git a/server/pkg/proto/api/v1/shared.pb.go b/server/pkg/proto/api/v1/shared.pb.go index 65e5c322..b56687f3 100644 --- a/server/pkg/proto/api/v1/shared.pb.go +++ b/server/pkg/proto/api/v1/shared.pb.go @@ -267,7 +267,8 @@ type User struct { Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` FirstName string `protobuf:"bytes,2,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` LastName string `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` - Followed bool `protobuf:"varint,4,opt,name=followed,proto3" json:"followed,omitempty"` + Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` + Followed bool `protobuf:"varint,5,opt,name=followed,proto3" json:"followed,omitempty"` } func (x *User) Reset() { @@ -321,6 +322,13 @@ func (x *User) GetLastName() string { return "" } +func (x *User) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + func (x *User) GetFollowed() bool { if x != nil { return x.Followed @@ -462,35 +470,36 @@ var file_api_v1_shared_proto_rawDesc = []byte{ 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x8a, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x18, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xa0, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x08, 0x6c, 0x61, - 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, - 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, - 0x65, 0x64, 0x22, 0x5c, 0x0a, 0x11, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x42, 0x09, 0xba, 0x48, 0x06, - 0x1a, 0x04, 0x18, 0x64, 0x28, 0x01, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0x3c, 0x0a, 0x12, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, - 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x8f, - 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x53, - 0x68, 0x61, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3b, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x73, 0x6e, 0x2f, - 0x67, 0x65, 0x74, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, - 0x02, 0x06, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x06, 0x41, 0x70, 0x69, 0x5c, 0x56, - 0x31, 0xe2, 0x02, 0x12, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x1a, 0x0a, 0x08, + 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x22, 0x5c, 0x0a, 0x11, 0x50, 0x61, 0x67, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, + 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x42, 0x09, 0xba, 0x48, 0x06, 0x1a, 0x04, 0x18, 0x64, 0x28, 0x01, 0x52, 0x09, 0x70, 0x61, + 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x61, 0x67, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x3c, 0x0a, 0x12, 0x50, 0x61, 0x67, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x0f, + 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x8f, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x72, 0x6c, 0x73, 0x73, 0x6e, 0x2f, 0x67, 0x65, 0x74, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x65, + 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, + 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x06, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, + 0x06, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x12, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x41, + 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/server/pkg/repo/repo.go b/server/pkg/repo/repo.go index cc304d2c..dc06c733 100644 --- a/server/pkg/repo/repo.go +++ b/server/pkg/repo/repo.go @@ -1165,6 +1165,12 @@ func (r *Repo) IsUserFollowedByUserID(ctx context.Context, user *orm.User, userI type GetAuthOpt func() qm.QueryMod +func GetAuthByID(id string) GetAuthOpt { + return func() qm.QueryMod { + return orm.AuthWhere.ID.EQ(id) + } +} + func GetAuthByEmail(email string) GetAuthOpt { return func() qm.QueryMod { return orm.AuthWhere.Email.EQ(email) diff --git a/server/rpc/v1/user.go b/server/rpc/v1/user.go index e5a1978a..e1c2d915 100644 --- a/server/rpc/v1/user.go +++ b/server/rpc/v1/user.go @@ -38,15 +38,25 @@ func (h *userHandler) GetUser(ctx context.Context, req *connect.Request[v1.GetUs return nil, connect.NewError(connect.CodeInternal, nil) } + auth, err := h.repo.GetAuth(ctx, repo.GetAuthByID(user.ID)) + if err != nil { + log.Error("failed to get auth", zap.Error(err)) + return nil, connect.NewError(connect.CodeInternal, nil) + } + followed, err := h.repo.IsUserFollowedByUserID(ctx, user, userID) if err != nil { log.Error("failed to check if user is followed", zap.Error(err)) return nil, connect.NewError(connect.CodeInternal, nil) } + // DEBT: Move email to user model. + u := parseUserToPB(user, followed) + u.Email = auth.Email + return &connect.Response[v1.GetUserResponse]{ Msg: &v1.GetUserResponse{ - User: parseUserToPB(user, followed), + User: u, }, }, nil } diff --git a/web/src/proto/api/v1/shared_pb.ts b/web/src/proto/api/v1/shared_pb.ts index 5fb32b89..2347c21e 100644 --- a/web/src/proto/api/v1/shared_pb.ts +++ b/web/src/proto/api/v1/shared_pb.ts @@ -13,7 +13,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file api/v1/shared.proto. */ export const file_api_v1_shared: GenFile = /*@__PURE__*/ - fileDesc("ChNhcGkvdjEvc2hhcmVkLnByb3RvEgZhcGkudjEiXwoMRXhlcmNpc2VTZXRzEioKCGV4ZXJjaXNlGAEgASgLMhAuYXBpLnYxLkV4ZXJjaXNlQga6SAPIAQESIwoEc2V0cxgCIAMoCzILLmFwaS52MS5TZXRCCLpIBZIBAggBIk4KCEV4ZXJjaXNlEhQKAmlkGAEgASgJQgi6SAVyA7ABARIPCgd1c2VyX2lkGAIgASgJEgwKBG5hbWUYAyABKAkSDQoFbGFiZWwYBCABKAkiUwoDU2V0Eg4KBndlaWdodBgBIAEoARIVCgRyZXBzGAIgASgFQge6SAQaAigBEiUKCG1ldGFkYXRhGAMgASgLMhMuYXBpLnYxLk1ldGFkYXRhU2V0IlsKC01ldGFkYXRhU2V0EhwKCndvcmtvdXRfaWQYASABKAlCCLpIBXIDsAEBEi4KCmNyZWF0ZWRfYXQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wImcKBFVzZXISFAoCaWQYASABKAlCCLpIBXIDsAEBEhsKCmZpcnN0X25hbWUYAiABKAlCB7pIBHICEAESGgoJbGFzdF9uYW1lGAMgASgJQge6SARyAhABEhAKCGZvbGxvd2VkGAQgASgIIkYKEVBhZ2luYXRpb25SZXF1ZXN0Eh0KCnBhZ2VfbGltaXQYASABKAVCCbpIBhoEGGQoARISCgpwYWdlX3Rva2VuGAIgASgMIi0KElBhZ2luYXRpb25SZXNwb25zZRIXCg9uZXh0X3BhZ2VfdG9rZW4YASABKAxCjwEKCmNvbS5hcGkudjFCC1NoYXJlZFByb3RvUAFaO2dpdGh1Yi5jb20vY3Jsc3NuL2dldHN0cm9uZ2VyL3NlcnZlci9wa2cvcHJvdG8vYXBpL3YxO2FwaXYxogIDQVhYqgIGQXBpLlYxygIGQXBpXFYx4gISQXBpXFYxXEdQQk1ldGFkYXRh6gIHQXBpOjpWMWIGcHJvdG8z", [file_buf_validate_validate, file_google_protobuf_timestamp]); + fileDesc("ChNhcGkvdjEvc2hhcmVkLnByb3RvEgZhcGkudjEiXwoMRXhlcmNpc2VTZXRzEioKCGV4ZXJjaXNlGAEgASgLMhAuYXBpLnYxLkV4ZXJjaXNlQga6SAPIAQESIwoEc2V0cxgCIAMoCzILLmFwaS52MS5TZXRCCLpIBZIBAggBIk4KCEV4ZXJjaXNlEhQKAmlkGAEgASgJQgi6SAVyA7ABARIPCgd1c2VyX2lkGAIgASgJEgwKBG5hbWUYAyABKAkSDQoFbGFiZWwYBCABKAkiUwoDU2V0Eg4KBndlaWdodBgBIAEoARIVCgRyZXBzGAIgASgFQge6SAQaAigBEiUKCG1ldGFkYXRhGAMgASgLMhMuYXBpLnYxLk1ldGFkYXRhU2V0IlsKC01ldGFkYXRhU2V0EhwKCndvcmtvdXRfaWQYASABKAlCCLpIBXIDsAEBEi4KCmNyZWF0ZWRfYXQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wInYKBFVzZXISFAoCaWQYASABKAlCCLpIBXIDsAEBEhsKCmZpcnN0X25hbWUYAiABKAlCB7pIBHICEAESGgoJbGFzdF9uYW1lGAMgASgJQge6SARyAhABEg0KBWVtYWlsGAQgASgJEhAKCGZvbGxvd2VkGAUgASgIIkYKEVBhZ2luYXRpb25SZXF1ZXN0Eh0KCnBhZ2VfbGltaXQYASABKAVCCbpIBhoEGGQoARISCgpwYWdlX3Rva2VuGAIgASgMIi0KElBhZ2luYXRpb25SZXNwb25zZRIXCg9uZXh0X3BhZ2VfdG9rZW4YASABKAxCjwEKCmNvbS5hcGkudjFCC1NoYXJlZFByb3RvUAFaO2dpdGh1Yi5jb20vY3Jsc3NuL2dldHN0cm9uZ2VyL3NlcnZlci9wa2cvcHJvdG8vYXBpL3YxO2FwaXYxogIDQVhYqgIGQXBpLlYxygIGQXBpXFYx4gISQXBpXFYxXEdQQk1ldGFkYXRh6gIHQXBpOjpWMWIGcHJvdG8z", [file_buf_validate_validate, file_google_protobuf_timestamp]); /** * @generated from message api.v1.ExerciseSets @@ -140,7 +140,12 @@ export type User = Message<"api.v1.User"> & { lastName: string; /** - * @generated from field: bool followed = 4; + * @generated from field: string email = 4; + */ + email: string; + + /** + * @generated from field: bool followed = 5; */ followed: boolean; }; diff --git a/web/src/stores/auth.ts b/web/src/stores/auth.ts index 9b45f310..5181fa10 100644 --- a/web/src/stores/auth.ts +++ b/web/src/stores/auth.ts @@ -7,21 +7,21 @@ import { jwtDecode } from 'jwt-decode' export const useAuthStore = defineStore( 'auth', () => { - const userID = ref('') + const userId = ref('') const accessToken = ref('') const accessTokenRefreshInterval = ref(0) const setAccessToken = (token: string) => { console.log('setting access token', token) - if (userID.value === '') { + if (userId.value === '') { const claims = jwtDecode(token) as AccessToken - userID.value = claims.userId + userId.value = claims.userId } accessToken.value = token } const logout = () => { - userID.value = '' + userId.value = '' accessToken.value = '' clearInterval(accessTokenRefreshInterval.value) } @@ -30,7 +30,7 @@ export const useAuthStore = defineStore( accessTokenRefreshInterval.value = interval } - return { accessToken, logout, setAccessToken, setAccessTokenRefreshInterval, userID } + return { accessToken, logout, setAccessToken, setAccessTokenRefreshInterval, userId } }, { persist: true, diff --git a/web/src/ui/components/CardWorkout.vue b/web/src/ui/components/CardWorkout.vue index f6e41ccb..9d58b95e 100644 --- a/web/src/ui/components/CardWorkout.vue +++ b/web/src/ui/components/CardWorkout.vue @@ -73,7 +73,7 @@ const formatComment = computed(() => { {{ formatToRelativeDateTime(props.workout.finishedAt) }} - +
diff --git a/web/src/ui/components/NotificationWorkoutComment.vue b/web/src/ui/components/NotificationWorkoutComment.vue index 971a9b91..4d3816ce 100644 --- a/web/src/ui/components/NotificationWorkoutComment.vue +++ b/web/src/ui/components/NotificationWorkoutComment.vue @@ -16,7 +16,7 @@ const props = defineProps<{ }>() const workoutOwnership = computed(() => { - if (authStore.userID === props.workout?.user?.id) { + if (authStore.userId === props.workout?.user?.id) { return 'your' } diff --git a/web/src/ui/exercises/ViewExercise.vue b/web/src/ui/exercises/ViewExercise.vue index 9c7af0a7..4688aca5 100644 --- a/web/src/ui/exercises/ViewExercise.vue +++ b/web/src/ui/exercises/ViewExercise.vue @@ -82,7 +82,7 @@ const onDeleteExercise = async () => { -
+
Admin
diff --git a/web/src/ui/profile/ProfileView.vue b/web/src/ui/profile/ProfileView.vue index 86e6d9be..ca8ae0d7 100644 --- a/web/src/ui/profile/ProfileView.vue +++ b/web/src/ui/profile/ProfileView.vue @@ -1,9 +1,40 @@ - + diff --git a/web/src/ui/users/UserView.vue b/web/src/ui/users/UserView.vue index 2e40eb41..f062593f 100644 --- a/web/src/ui/users/UserView.vue +++ b/web/src/ui/users/UserView.vue @@ -60,7 +60,7 @@ const updateTab = (event: Event) => {