diff --git a/api/api.go b/api/api.go index d085580..9e28138 100644 --- a/api/api.go +++ b/api/api.go @@ -17,12 +17,11 @@ var inProd bool type OAuthStore interface { Create(callback string) (code string) - Validate(code string) (string, bool) - Exchange(ctx context.Context, code string) (*oauth2.Token, error) + Validate(ctx context.Context, state, code string) (*oauth2.Token, string, error) } type UserStore interface { - ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.Token, bool, error) + ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.Token, error) CreateToken(ctx context.Context, user *models.User) (*models.Token, error) RevokeToken(ctx context.Context, token string) error diff --git a/api/auth.go b/api/auth.go index 18b6c0e..47e5b71 100644 --- a/api/auth.go +++ b/api/auth.go @@ -2,9 +2,11 @@ package api import ( "context" + "errors" "log" codequestpb "github.com/hhhapz/codequest/api/v1" + "github.com/hhhapz/codequest/models" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" @@ -18,8 +20,8 @@ type AuthService struct { } const ( - MDHost = "x-forwarded-host" - UIHost = "codequest.teamortix.com" + forwardedHostKey = "x-forwarded-host" + uiHost = "codequest.teamortix.com" ) func (as *AuthService) AuthFuncOverride(ctx context.Context, method string) (context.Context, error) { @@ -32,9 +34,9 @@ func (as *AuthService) AuthFuncOverride(ctx context.Context, method string) (con func (as *AuthService) OAuthCode(ctx context.Context, req *codequestpb.OAuthCodeRequest) (*codequestpb.OAuthCodeResponse, error) { md := RequestMetadata(ctx) - host := md.Get(MDHost) + host := md.Get(forwardedHostKey) - if host != UIHost && inProd { + if host != uiHost && inProd { return nil, status.Errorf(codes.InvalidArgument, "invalid host: %v", host) } @@ -45,19 +47,18 @@ func (as *AuthService) OAuthCode(ctx context.Context, req *codequestpb.OAuthCode } func (as *AuthService) Token(ctx context.Context, req *codequestpb.TokenRequest) (*codequestpb.Token, error) { - _, ok := as.oauthStore.Validate(req.State) - if !ok { - return nil, status.Errorf(codes.InvalidArgument, "invalid state %q", req.State) - } - token, err := as.oauthStore.Exchange(ctx, req.Code) + token, _, err := as.oauthStore.Validate(ctx, req.State, req.Code) if err != nil { + if errors.As(err, &models.UserError{}) { + return nil, status.Errorf(codes.InvalidArgument, err.Error()) + } log.Printf("could not perform token exchange: %v", err) return nil, status.Errorf(codes.InvalidArgument, "invalid code %q: %v", req.Code, err) } - tk, ok, err := as.userStore.ConsumeToken(ctx, token) + tk, err := as.userStore.ConsumeToken(ctx, token) if err != nil { - if ok { + if errors.As(err, &models.UserError{}) { return nil, status.Errorf(codes.InvalidArgument, "could not authorize: %v", err) } log.Printf("could not authorize request: %v", err) diff --git a/api/interceptors.go b/api/interceptors.go index 35a1e74..3ad4613 100644 --- a/api/interceptors.go +++ b/api/interceptors.go @@ -2,6 +2,7 @@ package api import ( "context" + "errors" "strings" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" @@ -45,7 +46,10 @@ func BearerAuth(ctx context.Context, us UserStore) (context.Context, error) { u, err := us.UserByToken(ctx, token) if err != nil { - return nil, status.Errorf(codes.Unauthenticated, "invalid auth token: %v", token) + if errors.As(err, &models.UserError{}) { + return nil, status.Error(codes.Unauthenticated, err.Error()) + } + return nil, status.Errorf(codes.Internal, "could not authenticate your request") } ctx = context.WithValue(ctx, UserKey, u) diff --git a/api/v1/all.pb.go b/api/v1/all.pb.go index 11e419d..3cebe36 100644 --- a/api/v1/all.pb.go +++ b/api/v1/all.pb.go @@ -376,13 +376,500 @@ func (x *User) GetCreatedAt() *timestamppb.Timestamp { return nil } +type PartData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Part int32 `protobuf:"varint,1,opt,name=Part,json=part,proto3" json:"part,omitempty"` + Completed bool `protobuf:"varint,2,opt,name=Completed,json=completed,proto3" json:"completed,omitempty"` + PointsWorth int32 `protobuf:"varint,3,opt,name=PointsWorth,json=points_worth,proto3" json:"points_worth,omitempty"` +} + +func (x *PartData) Reset() { + *x = PartData{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PartData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PartData) ProtoMessage() {} + +func (x *PartData) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PartData.ProtoReflect.Descriptor instead. +func (*PartData) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{6} +} + +func (x *PartData) GetPart() int32 { + if x != nil { + return x.Part + } + return 0 +} + +func (x *PartData) GetCompleted() bool { + if x != nil { + return x.Completed + } + return false +} + +func (x *PartData) GetPointsWorth() int32 { + if x != nil { + return x.PointsWorth + } + return 0 +} + +type Question struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` + Title string `protobuf:"bytes,2,opt,name=Title,json=title,proto3" json:"title,omitempty"` + Content string `protobuf:"bytes,3,opt,name=Content,json=content,proto3" json:"content,omitempty"` + Part1 *PartData `protobuf:"bytes,4,opt,name=Part1,json=part1,proto3" json:"part1,omitempty"` + Part2 *PartData `protobuf:"bytes,5,opt,name=Part2,json=part2,proto3" json:"part2,omitempty"` +} + +func (x *Question) Reset() { + *x = Question{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Question) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Question) ProtoMessage() {} + +func (x *Question) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Question.ProtoReflect.Descriptor instead. +func (*Question) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{7} +} + +func (x *Question) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *Question) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *Question) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *Question) GetPart1() *PartData { + if x != nil { + return x.Part1 + } + return nil +} + +func (x *Question) GetPart2() *PartData { + if x != nil { + return x.Part2 + } + return nil +} + +type QuestionsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Questions []*Question `protobuf:"bytes,1,rep,name=Questions,json=questions,proto3" json:"questions,omitempty"` +} + +func (x *QuestionsResponse) Reset() { + *x = QuestionsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuestionsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuestionsResponse) ProtoMessage() {} + +func (x *QuestionsResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuestionsResponse.ProtoReflect.Descriptor instead. +func (*QuestionsResponse) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{8} +} + +func (x *QuestionsResponse) GetQuestions() []*Question { + if x != nil { + return x.Questions + } + return nil +} + +type QuestionByIDRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` +} + +func (x *QuestionByIDRequest) Reset() { + *x = QuestionByIDRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuestionByIDRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuestionByIDRequest) ProtoMessage() {} + +func (x *QuestionByIDRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuestionByIDRequest.ProtoReflect.Descriptor instead. +func (*QuestionByIDRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{9} +} + +func (x *QuestionByIDRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +type QuestionInputRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` +} + +func (x *QuestionInputRequest) Reset() { + *x = QuestionInputRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuestionInputRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuestionInputRequest) ProtoMessage() {} + +func (x *QuestionInputRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuestionInputRequest.ProtoReflect.Descriptor instead. +func (*QuestionInputRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{10} +} + +func (x *QuestionInputRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +type QuestionInput struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` + Input string `protobuf:"bytes,2,opt,name=Input,json=input,proto3" json:"input,omitempty"` +} + +func (x *QuestionInput) Reset() { + *x = QuestionInput{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuestionInput) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuestionInput) ProtoMessage() {} + +func (x *QuestionInput) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuestionInput.ProtoReflect.Descriptor instead. +func (*QuestionInput) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{11} +} + +func (x *QuestionInput) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *QuestionInput) GetInput() string { + if x != nil { + return x.Input + } + return "" +} + +type SubmitRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` + Answer string `protobuf:"bytes,2,opt,name=Answer,json=content,proto3" json:"content,omitempty"` + Part bool `protobuf:"varint,3,opt,name=Part,json=part,proto3" json:"part,omitempty"` + Code string `protobuf:"bytes,4,opt,name=Code,json=code,proto3" json:"code,omitempty"` +} + +func (x *SubmitRequest) Reset() { + *x = SubmitRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitRequest) ProtoMessage() {} + +func (x *SubmitRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitRequest.ProtoReflect.Descriptor instead. +func (*SubmitRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{12} +} + +func (x *SubmitRequest) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *SubmitRequest) GetAnswer() string { + if x != nil { + return x.Answer + } + return "" +} + +func (x *SubmitRequest) GetPart() bool { + if x != nil { + return x.Part + } + return false +} + +func (x *SubmitRequest) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +type SubmitResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` + Part int32 `protobuf:"varint,2,opt,name=Part,json=part,proto3" json:"part,omitempty"` + Correct bool `protobuf:"varint,3,opt,name=Correct,json=correct,proto3" json:"correct,omitempty"` + Ranking int32 `protobuf:"varint,4,opt,name=Ranking,json=ranking,proto3" json:"ranking,omitempty"` + Points int32 `protobuf:"varint,5,opt,name=Points,json=points,proto3" json:"points,omitempty"` +} + +func (x *SubmitResponse) Reset() { + *x = SubmitResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitResponse) ProtoMessage() {} + +func (x *SubmitResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitResponse.ProtoReflect.Descriptor instead. +func (*SubmitResponse) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{13} +} + +func (x *SubmitResponse) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *SubmitResponse) GetPart() int32 { + if x != nil { + return x.Part + } + return 0 +} + +func (x *SubmitResponse) GetCorrect() bool { + if x != nil { + return x.Correct + } + return false +} + +func (x *SubmitResponse) GetRanking() int32 { + if x != nil { + return x.Ranking + } + return 0 +} + +func (x *SubmitResponse) GetPoints() int32 { + if x != nil { + return x.Points + } + return 0 +} + type UpdateFields struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Name string `protobuf:"bytes,1,opt,name=Name,json=name,proto3" json:"name,omitempty"` - Email string `protobuf:"bytes,2,opt,name=Email,json=email,proto3" json:"email,omitempty"` GradeLevel int32 `protobuf:"varint,3,opt,name=GradeLevel,json=grade_level,proto3" json:"grade_level,omitempty"` Admin bool `protobuf:"varint,4,opt,name=Admin,json=admin,proto3" json:"admin,omitempty"` } @@ -390,7 +877,7 @@ type UpdateFields struct { func (x *UpdateFields) Reset() { *x = UpdateFields{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[6] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -403,7 +890,7 @@ func (x *UpdateFields) String() string { func (*UpdateFields) ProtoMessage() {} func (x *UpdateFields) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[6] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -416,7 +903,7 @@ func (x *UpdateFields) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateFields.ProtoReflect.Descriptor instead. func (*UpdateFields) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{6} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{14} } func (x *UpdateFields) GetName() string { @@ -426,13 +913,6 @@ func (x *UpdateFields) GetName() string { return "" } -func (x *UpdateFields) GetEmail() string { - if x != nil { - return x.Email - } - return "" -} - func (x *UpdateFields) GetGradeLevel() int32 { if x != nil { return x.GradeLevel @@ -456,7 +936,7 @@ type UserRequest struct { func (x *UserRequest) Reset() { *x = UserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[7] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -469,7 +949,7 @@ func (x *UserRequest) String() string { func (*UserRequest) ProtoMessage() {} func (x *UserRequest) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[7] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -482,7 +962,7 @@ func (x *UserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UserRequest.ProtoReflect.Descriptor instead. func (*UserRequest) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{7} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{15} } type AllUsersRequest struct { @@ -494,7 +974,7 @@ type AllUsersRequest struct { func (x *AllUsersRequest) Reset() { *x = AllUsersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[8] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -507,7 +987,7 @@ func (x *AllUsersRequest) String() string { func (*AllUsersRequest) ProtoMessage() {} func (x *AllUsersRequest) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[8] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -520,7 +1000,7 @@ func (x *AllUsersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AllUsersRequest.ProtoReflect.Descriptor instead. func (*AllUsersRequest) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{8} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{16} } type UpdateUserRequest struct { @@ -535,7 +1015,7 @@ type UpdateUserRequest struct { func (x *UpdateUserRequest) Reset() { *x = UpdateUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[9] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -548,7 +1028,7 @@ func (x *UpdateUserRequest) String() string { func (*UpdateUserRequest) ProtoMessage() {} func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[9] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -561,7 +1041,7 @@ func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateUserRequest.ProtoReflect.Descriptor instead. func (*UpdateUserRequest) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{9} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{17} } func (x *UpdateUserRequest) GetEmail() string { @@ -589,7 +1069,7 @@ type UserByEmailRequest struct { func (x *UserByEmailRequest) Reset() { *x = UserByEmailRequest{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[10] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -602,7 +1082,7 @@ func (x *UserByEmailRequest) String() string { func (*UserByEmailRequest) ProtoMessage() {} func (x *UserByEmailRequest) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[10] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -615,7 +1095,7 @@ func (x *UserByEmailRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UserByEmailRequest.ProtoReflect.Descriptor instead. func (*UserByEmailRequest) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{10} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{18} } func (x *UserByEmailRequest) GetEmail() string { @@ -636,7 +1116,7 @@ type DeleteUserRequest struct { func (x *DeleteUserRequest) Reset() { *x = DeleteUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[11] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -649,7 +1129,7 @@ func (x *DeleteUserRequest) String() string { func (*DeleteUserRequest) ProtoMessage() {} func (x *DeleteUserRequest) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[11] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -662,7 +1142,7 @@ func (x *DeleteUserRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteUserRequest.ProtoReflect.Descriptor instead. func (*DeleteUserRequest) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{11} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{19} } func (x *DeleteUserRequest) GetEmail() string { @@ -683,7 +1163,7 @@ type AllUsersResponse struct { func (x *AllUsersResponse) Reset() { *x = AllUsersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[12] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -696,7 +1176,7 @@ func (x *AllUsersResponse) String() string { func (*AllUsersResponse) ProtoMessage() {} func (x *AllUsersResponse) ProtoReflect() protoreflect.Message { - mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[12] + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -709,7 +1189,7 @@ func (x *AllUsersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AllUsersResponse.ProtoReflect.Descriptor instead. func (*AllUsersResponse) Descriptor() ([]byte, []int) { - return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{12} + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{20} } func (x *AllUsersResponse) GetUsers() []*User { @@ -777,117 +1257,214 @@ var file_github_com_hhhapz_codequest_api_v1_all_proto_rawDesc = []byte{ 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, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x5f, 0x61, 0x74, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0xa7, 0x01, 0x0a, 0x0c, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x04, - 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, - 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x05, - 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, - 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2b, - 0x0a, 0x0a, 0x47, 0x72, 0x61, 0x64, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x05, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x0b, - 0x67, 0x72, 0x61, 0x64, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x05, 0x41, - 0x64, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, - 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x3a, 0x06, 0x08, - 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x15, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x19, 0x0a, 0x0f, - 0x41, 0x6c, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, - 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x82, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, - 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, - 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, - 0x43, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, - 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x06, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x73, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x3e, 0x0a, 0x12, - 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x20, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, - 0x6d, 0x61, 0x69, 0x6c, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x3d, 0x0a, 0x11, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x20, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, 0x6d, - 0x61, 0x69, 0x6c, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x57, 0x0a, 0x10, 0x41, - 0x6c, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3b, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, - 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x3a, 0x06, 0x08, 0x00, - 0x10, 0x00, 0x18, 0x00, 0x32, 0xe9, 0x02, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x7b, 0x0a, 0x09, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, - 0x65, 0x12, 0x25, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, - 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4f, - 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1b, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, - 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x00, 0x30, - 0x00, 0x12, 0x68, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x2e, 0x68, 0x68, 0x68, + 0x5f, 0x61, 0x74, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x8b, 0x01, 0x0a, 0x08, + 0x50, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x04, 0x50, 0x61, 0x72, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, + 0x50, 0x00, 0x52, 0x04, 0x70, 0x61, 0x72, 0x74, 0x12, 0x28, 0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, + 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x12, 0x2d, 0x0a, 0x0b, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x57, 0x6f, 0x72, 0x74, + 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, + 0x00, 0x50, 0x00, 0x52, 0x0c, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x74, + 0x68, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0xf8, 0x01, 0x0a, 0x08, 0x51, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x20, 0x0a, 0x05, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, + 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x05, 0x50, 0x61, + 0x72, 0x74, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x68, 0x68, 0x61, + 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, + 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x74, 0x31, 0x12, 0x3f, 0x0a, 0x05, 0x50, + 0x61, 0x72, 0x74, 0x32, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1c, 0x88, 0x02, 0x00, 0x90, 0x02, - 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, - 0x68, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x28, 0x00, 0x30, 0x00, 0x12, 0x6e, 0x0a, 0x0b, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x27, 0x2e, 0x68, 0x68, 0x68, + 0x2e, 0x50, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x74, 0x32, 0x3a, 0x06, 0x08, 0x00, + 0x10, 0x00, 0x18, 0x00, 0x22, 0x64, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x09, 0x51, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, + 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0a, 0x08, 0x00, 0x18, + 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x09, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x39, 0x0a, 0x13, 0x51, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, + 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x02, 0x69, 0x64, 0x3a, 0x06, 0x08, + 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x3a, 0x0a, 0x14, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, + 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x02, 0x69, 0x64, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, + 0x00, 0x22, 0x55, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, + 0x75, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, + 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, + 0x0a, 0x05, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, + 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x98, 0x01, 0x0a, 0x0d, 0x53, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, + 0x50, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x23, 0x0a, 0x06, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, + 0x50, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x0a, 0x04, 0x50, + 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x04, 0x70, 0x61, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x04, 0x43, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x06, 0x08, 0x00, 0x10, + 0x00, 0x18, 0x00, 0x22, 0xc4, 0x01, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x50, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x04, 0x70, 0x61, + 0x72, 0x74, 0x12, 0x24, 0x0a, 0x07, 0x43, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, + 0x07, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x12, 0x24, 0x0a, 0x07, 0x52, 0x61, 0x6e, 0x6b, + 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x07, 0x72, 0x61, 0x6e, 0x6b, 0x69, 0x6e, 0x67, 0x12, 0x22, + 0x0a, 0x06, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0a, + 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x06, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x73, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x85, 0x01, 0x0a, 0x0c, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x04, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x0a, 0x47, + 0x72, 0x61, 0x64, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, + 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x0b, 0x67, 0x72, 0x61, + 0x64, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x05, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, + 0x00, 0x50, 0x00, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, + 0x18, 0x00, 0x22, 0x15, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x19, 0x0a, 0x0f, 0x41, 0x6c, 0x6c, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x06, 0x08, 0x00, + 0x10, 0x00, 0x18, 0x00, 0x22, 0x82, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x05, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x43, 0x0a, 0x04, + 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1c, 0x88, 0x02, 0x00, - 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x2a, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x61, - 0x75, 0x74, 0x68, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x28, 0x00, 0x1a, 0x03, 0x88, 0x02, 0x00, - 0x32, 0xec, 0x05, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x63, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, - 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x42, 0x0a, 0x08, + 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x73, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x3e, 0x0a, 0x12, 0x55, 0x73, 0x65, + 0x72, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x20, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, + 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x3d, 0x0a, 0x11, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, + 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, + 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x57, 0x0a, 0x10, 0x41, 0x6c, 0x6c, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x05, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x68, 0x68, + 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, + 0x50, 0x00, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, + 0x00, 0x32, 0xe9, 0x02, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x7b, 0x0a, 0x09, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, + 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, + 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x41, 0x75, 0x74, + 0x68, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x88, + 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x76, 0x31, + 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x28, 0x00, 0x30, 0x00, 0x12, 0x68, + 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x1a, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, - 0x65, 0x28, 0x00, 0x30, 0x00, 0x12, 0x7c, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x42, 0x79, 0x45, - 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x27, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, - 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, - 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, - 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x25, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x7d, 0x28, - 0x00, 0x30, 0x00, 0x12, 0x7a, 0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, - 0x24, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, - 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x6c, 0x55, - 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x88, 0x02, - 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x76, 0x31, 0x2f, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x28, 0x00, 0x30, 0x00, 0x12, - 0x75, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x26, 0x2e, - 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, - 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, - 0x22, 0x20, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x04, - 0x42, 0x6f, 0x64, 0x79, 0x1a, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, - 0x6d, 0x65, 0x28, 0x00, 0x30, 0x00, 0x12, 0x85, 0x01, 0x0a, 0x0f, 0x41, 0x64, 0x6d, 0x69, 0x6e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x26, 0x2e, 0x68, 0x68, 0x68, + 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1c, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x28, 0x00, 0x30, 0x00, 0x12, 0x6e, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x27, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, + 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1c, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x2a, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, + 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x28, 0x00, 0x1a, 0x03, 0x88, 0x02, 0x00, 0x32, 0x84, 0x04, + 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6a, + 0x0a, 0x09, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x26, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x88, 0x02, 0x00, + 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x12, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x00, 0x12, 0x7d, 0x0a, 0x0c, 0x51, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x49, 0x44, 0x12, 0x28, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x2b, 0x88, - 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x04, 0x42, 0x6f, 0x64, - 0x79, 0x1a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x75, 0x73, 0x65, - 0x72, 0x73, 0x2f, 0x7b, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x7d, 0x28, 0x00, 0x30, 0x00, 0x12, 0x7a, - 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x26, 0x2e, 0x68, + 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x20, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x14, 0x12, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x7b, 0x49, 0x44, 0x7d, 0x28, 0x00, 0x30, 0x00, 0x12, 0x8a, 0x01, 0x0a, 0x0d, 0x51, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x29, 0x2e, 0x68, 0x68, + 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x26, 0x88, 0x02, 0x00, 0x90, + 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x49, 0x44, 0x7d, 0x2f, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x28, 0x00, 0x30, 0x00, 0x12, 0x77, 0x0a, 0x06, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x12, 0x22, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x88, 0x02, 0x00, 0x90, 0x02, + 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x12, 0x2f, 0x76, 0x31, 0x2f, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x49, 0x44, 0x7d, 0x28, 0x00, 0x30, 0x00, 0x1a, + 0x03, 0x88, 0x02, 0x00, 0x32, 0xec, 0x05, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x20, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, - 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, - 0x25, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x2a, 0x17, 0x2f, - 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, - 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x7d, 0x28, 0x00, 0x30, 0x00, 0x1a, 0x03, 0x88, 0x02, 0x00, 0x42, - 0x47, 0x48, 0x01, 0x50, 0x00, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x80, 0x01, 0x00, 0x88, 0x01, 0x00, 0x90, 0x01, 0x00, 0xb8, 0x01, 0x00, 0xd8, - 0x01, 0x00, 0xf8, 0x01, 0x01, 0xd0, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x1a, 0x88, 0x02, 0x00, 0x90, 0x02, + 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x28, 0x00, 0x30, 0x00, 0x12, 0x7c, 0x0a, 0x0b, 0x55, 0x73, 0x65, + 0x72, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x27, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, + 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x42, 0x79, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x22, 0x25, 0x88, 0x02, + 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x45, 0x6d, 0x61, + 0x69, 0x6c, 0x7d, 0x28, 0x00, 0x30, 0x00, 0x12, 0x7a, 0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x12, 0x24, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x6c, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x68, 0x68, 0x61, + 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x6c, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1d, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, + 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x28, + 0x00, 0x30, 0x00, 0x12, 0x75, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x26, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, + 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x22, 0x20, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x14, 0x3a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x1a, 0x0c, 0x2f, 0x76, 0x31, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x28, 0x00, 0x30, 0x00, 0x12, 0x85, 0x01, 0x0a, 0x0f, 0x41, + 0x64, 0x6d, 0x69, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x26, + 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, + 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x22, 0x2b, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, + 0x04, 0x42, 0x6f, 0x64, 0x79, 0x1a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x7d, 0x28, 0x00, + 0x30, 0x00, 0x12, 0x7a, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x12, 0x26, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x68, 0x68, 0x68, 0x61, 0x70, + 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x22, 0x25, 0x88, 0x02, 0x00, 0x90, 0x02, 0x00, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x19, 0x2a, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x7b, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x7d, 0x28, 0x00, 0x30, 0x00, 0x1a, 0x03, + 0x88, 0x02, 0x00, 0x42, 0x47, 0x48, 0x01, 0x50, 0x00, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2f, 0x63, 0x6f, 0x64, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, + 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x80, 0x01, 0x00, 0x88, 0x01, 0x00, 0x90, 0x01, 0x00, + 0xb8, 0x01, 0x00, 0xd8, 0x01, 0x00, 0xf8, 0x01, 0x01, 0xd0, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -902,7 +1479,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP() []byte { return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescData } -var file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_github_com_hhhapz_codequest_api_v1_all_proto_goTypes = []interface{}{ (*Token)(nil), // 0: hhhapz.codequest.v1.Token (*OAuthCodeRequest)(nil), // 1: hhhapz.codequest.v1.OAuthCodeRequest @@ -910,45 +1487,64 @@ var file_github_com_hhhapz_codequest_api_v1_all_proto_goTypes = []interface{}{ (*TokenRequest)(nil), // 3: hhhapz.codequest.v1.TokenRequest (*DeleteTokenRequest)(nil), // 4: hhhapz.codequest.v1.DeleteTokenRequest (*User)(nil), // 5: hhhapz.codequest.v1.User - (*UpdateFields)(nil), // 6: hhhapz.codequest.v1.UpdateFields - (*UserRequest)(nil), // 7: hhhapz.codequest.v1.UserRequest - (*AllUsersRequest)(nil), // 8: hhhapz.codequest.v1.AllUsersRequest - (*UpdateUserRequest)(nil), // 9: hhhapz.codequest.v1.UpdateUserRequest - (*UserByEmailRequest)(nil), // 10: hhhapz.codequest.v1.UserByEmailRequest - (*DeleteUserRequest)(nil), // 11: hhhapz.codequest.v1.DeleteUserRequest - (*AllUsersResponse)(nil), // 12: hhhapz.codequest.v1.AllUsersResponse - (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 14: google.protobuf.Empty + (*PartData)(nil), // 6: hhhapz.codequest.v1.PartData + (*Question)(nil), // 7: hhhapz.codequest.v1.Question + (*QuestionsResponse)(nil), // 8: hhhapz.codequest.v1.QuestionsResponse + (*QuestionByIDRequest)(nil), // 9: hhhapz.codequest.v1.QuestionByIDRequest + (*QuestionInputRequest)(nil), // 10: hhhapz.codequest.v1.QuestionInputRequest + (*QuestionInput)(nil), // 11: hhhapz.codequest.v1.QuestionInput + (*SubmitRequest)(nil), // 12: hhhapz.codequest.v1.SubmitRequest + (*SubmitResponse)(nil), // 13: hhhapz.codequest.v1.SubmitResponse + (*UpdateFields)(nil), // 14: hhhapz.codequest.v1.UpdateFields + (*UserRequest)(nil), // 15: hhhapz.codequest.v1.UserRequest + (*AllUsersRequest)(nil), // 16: hhhapz.codequest.v1.AllUsersRequest + (*UpdateUserRequest)(nil), // 17: hhhapz.codequest.v1.UpdateUserRequest + (*UserByEmailRequest)(nil), // 18: hhhapz.codequest.v1.UserByEmailRequest + (*DeleteUserRequest)(nil), // 19: hhhapz.codequest.v1.DeleteUserRequest + (*AllUsersResponse)(nil), // 20: hhhapz.codequest.v1.AllUsersResponse + (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 22: google.protobuf.Empty } var file_github_com_hhhapz_codequest_api_v1_all_proto_depIdxs = []int32{ - 13, // 0: hhhapz.codequest.v1.Token.Expires:type_name -> google.protobuf.Timestamp + 21, // 0: hhhapz.codequest.v1.Token.Expires:type_name -> google.protobuf.Timestamp 0, // 1: hhhapz.codequest.v1.DeleteTokenRequest.Token:type_name -> hhhapz.codequest.v1.Token - 13, // 2: hhhapz.codequest.v1.User.CreatedAt:type_name -> google.protobuf.Timestamp - 6, // 3: hhhapz.codequest.v1.UpdateUserRequest.Body:type_name -> hhhapz.codequest.v1.UpdateFields - 5, // 4: hhhapz.codequest.v1.AllUsersResponse.Users:type_name -> hhhapz.codequest.v1.User - 1, // 5: hhhapz.codequest.v1.AuthService.OAuthCode:input_type -> hhhapz.codequest.v1.OAuthCodeRequest - 3, // 6: hhhapz.codequest.v1.AuthService.Token:input_type -> hhhapz.codequest.v1.TokenRequest - 4, // 7: hhhapz.codequest.v1.AuthService.DeleteToken:input_type -> hhhapz.codequest.v1.DeleteTokenRequest - 7, // 8: hhhapz.codequest.v1.UserService.User:input_type -> hhhapz.codequest.v1.UserRequest - 10, // 9: hhhapz.codequest.v1.UserService.UserByEmail:input_type -> hhhapz.codequest.v1.UserByEmailRequest - 8, // 10: hhhapz.codequest.v1.UserService.AllUsers:input_type -> hhhapz.codequest.v1.AllUsersRequest - 9, // 11: hhhapz.codequest.v1.UserService.UpdateUser:input_type -> hhhapz.codequest.v1.UpdateUserRequest - 9, // 12: hhhapz.codequest.v1.UserService.AdminUpdateUser:input_type -> hhhapz.codequest.v1.UpdateUserRequest - 11, // 13: hhhapz.codequest.v1.UserService.DeleteUser:input_type -> hhhapz.codequest.v1.DeleteUserRequest - 2, // 14: hhhapz.codequest.v1.AuthService.OAuthCode:output_type -> hhhapz.codequest.v1.OAuthCodeResponse - 0, // 15: hhhapz.codequest.v1.AuthService.Token:output_type -> hhhapz.codequest.v1.Token - 14, // 16: hhhapz.codequest.v1.AuthService.DeleteToken:output_type -> google.protobuf.Empty - 5, // 17: hhhapz.codequest.v1.UserService.User:output_type -> hhhapz.codequest.v1.User - 5, // 18: hhhapz.codequest.v1.UserService.UserByEmail:output_type -> hhhapz.codequest.v1.User - 12, // 19: hhhapz.codequest.v1.UserService.AllUsers:output_type -> hhhapz.codequest.v1.AllUsersResponse - 5, // 20: hhhapz.codequest.v1.UserService.UpdateUser:output_type -> hhhapz.codequest.v1.User - 5, // 21: hhhapz.codequest.v1.UserService.AdminUpdateUser:output_type -> hhhapz.codequest.v1.User - 5, // 22: hhhapz.codequest.v1.UserService.DeleteUser:output_type -> hhhapz.codequest.v1.User - 14, // [14:23] is the sub-list for method output_type - 5, // [5:14] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 21, // 2: hhhapz.codequest.v1.User.CreatedAt:type_name -> google.protobuf.Timestamp + 6, // 3: hhhapz.codequest.v1.Question.Part1:type_name -> hhhapz.codequest.v1.PartData + 6, // 4: hhhapz.codequest.v1.Question.Part2:type_name -> hhhapz.codequest.v1.PartData + 7, // 5: hhhapz.codequest.v1.QuestionsResponse.Questions:type_name -> hhhapz.codequest.v1.Question + 14, // 6: hhhapz.codequest.v1.UpdateUserRequest.Body:type_name -> hhhapz.codequest.v1.UpdateFields + 5, // 7: hhhapz.codequest.v1.AllUsersResponse.Users:type_name -> hhhapz.codequest.v1.User + 1, // 8: hhhapz.codequest.v1.AuthService.OAuthCode:input_type -> hhhapz.codequest.v1.OAuthCodeRequest + 3, // 9: hhhapz.codequest.v1.AuthService.Token:input_type -> hhhapz.codequest.v1.TokenRequest + 4, // 10: hhhapz.codequest.v1.AuthService.DeleteToken:input_type -> hhhapz.codequest.v1.DeleteTokenRequest + 22, // 11: hhhapz.codequest.v1.QuestService.Questions:input_type -> google.protobuf.Empty + 9, // 12: hhhapz.codequest.v1.QuestService.QuestionByID:input_type -> hhhapz.codequest.v1.QuestionByIDRequest + 10, // 13: hhhapz.codequest.v1.QuestService.QuestionInput:input_type -> hhhapz.codequest.v1.QuestionInputRequest + 12, // 14: hhhapz.codequest.v1.QuestService.Submit:input_type -> hhhapz.codequest.v1.SubmitRequest + 15, // 15: hhhapz.codequest.v1.UserService.User:input_type -> hhhapz.codequest.v1.UserRequest + 18, // 16: hhhapz.codequest.v1.UserService.UserByEmail:input_type -> hhhapz.codequest.v1.UserByEmailRequest + 16, // 17: hhhapz.codequest.v1.UserService.AllUsers:input_type -> hhhapz.codequest.v1.AllUsersRequest + 17, // 18: hhhapz.codequest.v1.UserService.UpdateUser:input_type -> hhhapz.codequest.v1.UpdateUserRequest + 17, // 19: hhhapz.codequest.v1.UserService.AdminUpdateUser:input_type -> hhhapz.codequest.v1.UpdateUserRequest + 19, // 20: hhhapz.codequest.v1.UserService.DeleteUser:input_type -> hhhapz.codequest.v1.DeleteUserRequest + 2, // 21: hhhapz.codequest.v1.AuthService.OAuthCode:output_type -> hhhapz.codequest.v1.OAuthCodeResponse + 0, // 22: hhhapz.codequest.v1.AuthService.Token:output_type -> hhhapz.codequest.v1.Token + 22, // 23: hhhapz.codequest.v1.AuthService.DeleteToken:output_type -> google.protobuf.Empty + 8, // 24: hhhapz.codequest.v1.QuestService.Questions:output_type -> hhhapz.codequest.v1.QuestionsResponse + 7, // 25: hhhapz.codequest.v1.QuestService.QuestionByID:output_type -> hhhapz.codequest.v1.Question + 11, // 26: hhhapz.codequest.v1.QuestService.QuestionInput:output_type -> hhhapz.codequest.v1.QuestionInput + 13, // 27: hhhapz.codequest.v1.QuestService.Submit:output_type -> hhhapz.codequest.v1.SubmitResponse + 5, // 28: hhhapz.codequest.v1.UserService.User:output_type -> hhhapz.codequest.v1.User + 5, // 29: hhhapz.codequest.v1.UserService.UserByEmail:output_type -> hhhapz.codequest.v1.User + 20, // 30: hhhapz.codequest.v1.UserService.AllUsers:output_type -> hhhapz.codequest.v1.AllUsersResponse + 5, // 31: hhhapz.codequest.v1.UserService.UpdateUser:output_type -> hhhapz.codequest.v1.User + 5, // 32: hhhapz.codequest.v1.UserService.AdminUpdateUser:output_type -> hhhapz.codequest.v1.User + 5, // 33: hhhapz.codequest.v1.UserService.DeleteUser:output_type -> hhhapz.codequest.v1.User + 21, // [21:34] is the sub-list for method output_type + 8, // [8:21] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_github_com_hhhapz_codequest_api_v1_all_proto_init() } @@ -1030,7 +1626,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateFields); i { + switch v := v.(*PartData); i { case 0: return &v.state case 1: @@ -1042,7 +1638,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserRequest); i { + switch v := v.(*Question); i { case 0: return &v.state case 1: @@ -1054,7 +1650,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AllUsersRequest); i { + switch v := v.(*QuestionsResponse); i { case 0: return &v.state case 1: @@ -1066,7 +1662,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUserRequest); i { + switch v := v.(*QuestionByIDRequest); i { case 0: return &v.state case 1: @@ -1078,7 +1674,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserByEmailRequest); i { + switch v := v.(*QuestionInputRequest); i { case 0: return &v.state case 1: @@ -1090,7 +1686,7 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteUserRequest); i { + switch v := v.(*QuestionInput); i { case 0: return &v.state case 1: @@ -1102,6 +1698,102 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { } } file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateFields); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AllUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserByEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AllUsersResponse); i { case 0: return &v.state @@ -1120,9 +1812,9 @@ func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_github_com_hhhapz_codequest_api_v1_all_proto_rawDesc, NumEnums: 0, - NumMessages: 13, + NumMessages: 21, NumExtensions: 0, - NumServices: 2, + NumServices: 3, }, GoTypes: file_github_com_hhhapz_codequest_api_v1_all_proto_goTypes, DependencyIndexes: file_github_com_hhhapz_codequest_api_v1_all_proto_depIdxs, diff --git a/api/v1/all.pb.gw.go b/api/v1/all.pb.gw.go index 3f77145..14dbe94 100644 --- a/api/v1/all.pb.gw.go +++ b/api/v1/all.pb.gw.go @@ -21,6 +21,7 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/emptypb" ) // Suppress "imported and not used" errors @@ -121,6 +122,198 @@ func local_request_AuthService_DeleteToken_0(ctx context.Context, marshaler runt } +func request_QuestService_Questions_0(ctx context.Context, marshaler runtime.Marshaler, client QuestServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := client.Questions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_QuestService_Questions_0(ctx context.Context, marshaler runtime.Marshaler, server QuestServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq emptypb.Empty + var metadata runtime.ServerMetadata + + msg, err := server.Questions(ctx, &protoReq) + return msg, metadata, err + +} + +func request_QuestService_QuestionByID_0(ctx context.Context, marshaler runtime.Marshaler, client QuestServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuestionByIDRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + + protoReq.ID, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + + msg, err := client.QuestionByID(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_QuestService_QuestionByID_0(ctx context.Context, marshaler runtime.Marshaler, server QuestServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuestionByIDRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + + protoReq.ID, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + + msg, err := server.QuestionByID(ctx, &protoReq) + return msg, metadata, err + +} + +func request_QuestService_QuestionInput_0(ctx context.Context, marshaler runtime.Marshaler, client QuestServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuestionInputRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + + protoReq.ID, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + + msg, err := client.QuestionInput(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_QuestService_QuestionInput_0(ctx context.Context, marshaler runtime.Marshaler, server QuestServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuestionInputRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + + protoReq.ID, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + + msg, err := server.QuestionInput(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_QuestService_Submit_0 = &utilities.DoubleArray{Encoding: map[string]int{"ID": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_QuestService_Submit_0(ctx context.Context, marshaler runtime.Marshaler, client QuestServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SubmitRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + + protoReq.ID, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_QuestService_Submit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Submit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_QuestService_Submit_0(ctx context.Context, marshaler runtime.Marshaler, server QuestServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SubmitRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["ID"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "ID") + } + + protoReq.ID, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "ID", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_QuestService_Submit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Submit(ctx, &protoReq) + return msg, metadata, err + +} + func request_UserService_User_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UserRequest var metadata runtime.ServerMetadata @@ -459,6 +652,107 @@ func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux return nil } +// RegisterQuestServiceHandlerServer registers the http handlers for service QuestService to "mux". +// UnaryRPC :call QuestServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQuestServiceHandlerFromEndpoint instead. +func RegisterQuestServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QuestServiceServer) error { + + mux.Handle("GET", pattern_QuestService_Questions_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) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/Questions", runtime.WithHTTPPathPattern("/v1/questions")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_QuestService_Questions_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_Questions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_QuestService_QuestionByID_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) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/QuestionByID", runtime.WithHTTPPathPattern("/v1/questions/{ID}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_QuestService_QuestionByID_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_QuestionByID_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_QuestService_QuestionInput_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) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/QuestionInput", runtime.WithHTTPPathPattern("/v1/questions/{ID}/input")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_QuestService_QuestionInput_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_QuestionInput_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_QuestService_Submit_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) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/Submit", runtime.WithHTTPPathPattern("/v1/questions/{ID}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_QuestService_Submit_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_Submit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + // RegisterUserServiceHandlerServer registers the http handlers for service UserService to "mux". // UnaryRPC :call UserServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -723,6 +1017,147 @@ var ( forward_AuthService_DeleteToken_0 = runtime.ForwardResponseMessage ) +// RegisterQuestServiceHandlerFromEndpoint is same as RegisterQuestServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQuestServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQuestServiceHandler(ctx, mux, conn) +} + +// RegisterQuestServiceHandler registers the http handlers for service QuestService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQuestServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn grpc.ClientConnInterface) error { + return RegisterQuestServiceHandlerClient(ctx, mux, NewQuestServiceClient(conn)) +} + +// RegisterQuestServiceHandlerClient registers the http handlers for service QuestService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QuestServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QuestServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QuestServiceClient" to call the correct interceptors. +func RegisterQuestServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QuestServiceClient) error { + + mux.Handle("GET", pattern_QuestService_Questions_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/Questions", runtime.WithHTTPPathPattern("/v1/questions")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_QuestService_Questions_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_Questions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_QuestService_QuestionByID_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/QuestionByID", runtime.WithHTTPPathPattern("/v1/questions/{ID}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_QuestService_QuestionByID_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_QuestionByID_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_QuestService_QuestionInput_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/QuestionInput", runtime.WithHTTPPathPattern("/v1/questions/{ID}/input")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_QuestService_QuestionInput_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_QuestionInput_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_QuestService_Submit_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/hhhapz.codequest.v1.QuestService/Submit", runtime.WithHTTPPathPattern("/v1/questions/{ID}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_QuestService_Submit_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_QuestService_Submit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_QuestService_Questions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "questions"}, "")) + + pattern_QuestService_QuestionByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "questions", "ID"}, "")) + + pattern_QuestService_QuestionInput_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "questions", "ID", "input"}, "")) + + pattern_QuestService_Submit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "questions", "ID"}, "")) +) + +var ( + forward_QuestService_Questions_0 = runtime.ForwardResponseMessage + + forward_QuestService_QuestionByID_0 = runtime.ForwardResponseMessage + + forward_QuestService_QuestionInput_0 = runtime.ForwardResponseMessage + + forward_QuestService_Submit_0 = runtime.ForwardResponseMessage +) + // RegisterUserServiceHandlerFromEndpoint is same as RegisterUserServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterUserServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { diff --git a/api/v1/all_grpc.pb.go b/api/v1/all_grpc.pb.go index 404102f..8c781a3 100644 --- a/api/v1/all_grpc.pb.go +++ b/api/v1/all_grpc.pb.go @@ -173,6 +173,200 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{ Metadata: "github.com/hhhapz/codequest/api/v1/all.proto", } +// QuestServiceClient is the client API for QuestService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QuestServiceClient interface { + Questions(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*QuestionsResponse, error) + QuestionByID(ctx context.Context, in *QuestionByIDRequest, opts ...grpc.CallOption) (*Question, error) + QuestionInput(ctx context.Context, in *QuestionInputRequest, opts ...grpc.CallOption) (*QuestionInput, error) + Submit(ctx context.Context, in *SubmitRequest, opts ...grpc.CallOption) (*SubmitResponse, error) +} + +type questServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewQuestServiceClient(cc grpc.ClientConnInterface) QuestServiceClient { + return &questServiceClient{cc} +} + +func (c *questServiceClient) Questions(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*QuestionsResponse, error) { + out := new(QuestionsResponse) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.QuestService/Questions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *questServiceClient) QuestionByID(ctx context.Context, in *QuestionByIDRequest, opts ...grpc.CallOption) (*Question, error) { + out := new(Question) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.QuestService/QuestionByID", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *questServiceClient) QuestionInput(ctx context.Context, in *QuestionInputRequest, opts ...grpc.CallOption) (*QuestionInput, error) { + out := new(QuestionInput) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.QuestService/QuestionInput", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *questServiceClient) Submit(ctx context.Context, in *SubmitRequest, opts ...grpc.CallOption) (*SubmitResponse, error) { + out := new(SubmitResponse) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.QuestService/Submit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QuestServiceServer is the server API for QuestService service. +// All implementations must embed UnimplementedQuestServiceServer +// for forward compatibility +type QuestServiceServer interface { + Questions(context.Context, *emptypb.Empty) (*QuestionsResponse, error) + QuestionByID(context.Context, *QuestionByIDRequest) (*Question, error) + QuestionInput(context.Context, *QuestionInputRequest) (*QuestionInput, error) + Submit(context.Context, *SubmitRequest) (*SubmitResponse, error) + mustEmbedUnimplementedQuestServiceServer() +} + +// UnimplementedQuestServiceServer must be embedded to have forward compatible implementations. +type UnimplementedQuestServiceServer struct { +} + +func (UnimplementedQuestServiceServer) Questions(context.Context, *emptypb.Empty) (*QuestionsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Questions not implemented") +} +func (UnimplementedQuestServiceServer) QuestionByID(context.Context, *QuestionByIDRequest) (*Question, error) { + return nil, status.Errorf(codes.Unimplemented, "method QuestionByID not implemented") +} +func (UnimplementedQuestServiceServer) QuestionInput(context.Context, *QuestionInputRequest) (*QuestionInput, error) { + return nil, status.Errorf(codes.Unimplemented, "method QuestionInput not implemented") +} +func (UnimplementedQuestServiceServer) Submit(context.Context, *SubmitRequest) (*SubmitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Submit not implemented") +} +func (UnimplementedQuestServiceServer) mustEmbedUnimplementedQuestServiceServer() {} + +// UnsafeQuestServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QuestServiceServer will +// result in compilation errors. +type UnsafeQuestServiceServer interface { + mustEmbedUnimplementedQuestServiceServer() +} + +func RegisterQuestServiceServer(s grpc.ServiceRegistrar, srv QuestServiceServer) { + s.RegisterService(&QuestService_ServiceDesc, srv) +} + +func _QuestService_Questions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuestServiceServer).Questions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.QuestService/Questions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuestServiceServer).Questions(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _QuestService_QuestionByID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuestionByIDRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuestServiceServer).QuestionByID(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.QuestService/QuestionByID", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuestServiceServer).QuestionByID(ctx, req.(*QuestionByIDRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _QuestService_QuestionInput_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuestionInputRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuestServiceServer).QuestionInput(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.QuestService/QuestionInput", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuestServiceServer).QuestionInput(ctx, req.(*QuestionInputRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _QuestService_Submit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuestServiceServer).Submit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.QuestService/Submit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuestServiceServer).Submit(ctx, req.(*SubmitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// QuestService_ServiceDesc is the grpc.ServiceDesc for QuestService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var QuestService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hhhapz.codequest.v1.QuestService", + HandlerType: (*QuestServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Questions", + Handler: _QuestService_Questions_Handler, + }, + { + MethodName: "QuestionByID", + Handler: _QuestService_QuestionByID_Handler, + }, + { + MethodName: "QuestionInput", + Handler: _QuestService_QuestionInput_Handler, + }, + { + MethodName: "Submit", + Handler: _QuestService_Submit_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/hhhapz/codequest/api/v1/all.proto", +} + // UserServiceClient is the client API for UserService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. diff --git a/api/v1/auth.gunk b/api/v1/auth.gunk index 56dbe9c..abb34e1 100644 --- a/api/v1/auth.gunk +++ b/api/v1/auth.gunk @@ -1,7 +1,6 @@ package codequest import ( - "github.com/gunk/opt/file/java" "github.com/gunk/opt/http" "github.com/gunk/opt/openapiv2" "github.com/gunk/opt/proto" diff --git a/api/v1/codequest.gunk b/api/v1/codequest.gunk index bae9213..bbf9417 100644 --- a/api/v1/codequest.gunk +++ b/api/v1/codequest.gunk @@ -2,7 +2,6 @@ package codequest import ( - "github.com/gunk/opt/file/java" "github.com/gunk/opt/http" "github.com/gunk/opt/openapiv2" "github.com/gunk/opt/proto" diff --git a/api/v1/gen/json/codequest/all.swagger.json b/api/v1/gen/json/codequest/all.swagger.json index 32f2e40..706f30b 100644 --- a/api/v1/gen/json/codequest/all.swagger.json +++ b/api/v1/gen/json/codequest/all.swagger.json @@ -8,6 +8,9 @@ { "name": "AuthService" }, + { + "name": "QuestService" + }, { "name": "UserService" } @@ -234,6 +237,134 @@ ] } }, + "/v1/questions": { + "get": { + "operationId": "QuestService_Questions", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1QuestionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "QuestService" + ] + } + }, + "/v1/questions/{id}": { + "get": { + "operationId": "QuestService_QuestionByID", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1Question" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "QuestService" + ] + }, + "post": { + "operationId": "QuestService_Submit", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1SubmitResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "content", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "part", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "code", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "QuestService" + ] + } + }, + "/v1/questions/{id}/input": { + "get": { + "operationId": "QuestService_QuestionInput", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1QuestionInput" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "QuestService" + ] + } + }, "/v1/users/me": { "get": { "operationId": "UserService_User", @@ -340,6 +471,87 @@ } } }, + "v1PartData": { + "type": "object", + "properties": { + "part": { + "type": "integer", + "format": "int32" + }, + "completed": { + "type": "boolean" + }, + "points_worth": { + "type": "integer", + "format": "int32" + } + } + }, + "v1Question": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "content": { + "type": "string" + }, + "part1": { + "$ref": "#/definitions/v1PartData" + }, + "part2": { + "$ref": "#/definitions/v1PartData" + } + } + }, + "v1QuestionInput": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "input": { + "type": "string" + } + } + }, + "v1QuestionsResponse": { + "type": "object", + "properties": { + "questions": { + "type": "array", + "items": { + "$ref": "#/definitions/v1Question" + } + } + } + }, + "v1SubmitResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "part": { + "type": "integer", + "format": "int32" + }, + "correct": { + "type": "boolean" + }, + "ranking": { + "type": "integer", + "format": "int32" + }, + "points": { + "type": "integer", + "format": "int32" + } + } + }, "v1Token": { "type": "object", "properties": { @@ -358,9 +570,6 @@ "name": { "type": "string" }, - "email": { - "type": "string" - }, "grade_level": { "type": "integer", "format": "int32" diff --git a/api/v1/gen/ts-gateway/codequest/all.pb.ts b/api/v1/gen/ts-gateway/codequest/all.pb.ts index 48eb605..67d4e4b 100644 --- a/api/v1/gen/ts-gateway/codequest/all.pb.ts +++ b/api/v1/gen/ts-gateway/codequest/all.pb.ts @@ -39,9 +39,54 @@ export type User = { createdAt?: GoogleProtobufTimestamp.Timestamp } +export type PartData = { + part?: number + completed?: boolean + pointsWorth?: number +} + +export type Question = { + id?: string + title?: string + content?: string + part1?: PartData + part2?: PartData +} + +export type QuestionsResponse = { + questions?: Question[] +} + +export type QuestionByIDRequest = { + id?: string +} + +export type QuestionInputRequest = { + id?: string +} + +export type QuestionInput = { + id?: string + input?: string +} + +export type SubmitRequest = { + id?: string + answer?: string + part?: boolean + code?: string +} + +export type SubmitResponse = { + id?: string + part?: number + correct?: boolean + ranking?: number + points?: number +} + export type UpdateFields = { name?: string - email?: string gradeLevel?: number admin?: boolean } @@ -80,6 +125,20 @@ export class AuthService { return fm.fetchReq(`/v1/auth/token`, {...initReq, method: "DELETE"}) } } +export class QuestService { + static Questions(req: GoogleProtobufEmpty.Empty, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/questions?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"}) + } + static QuestionByID(req: QuestionByIDRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/questions/${req["id"]}?${fm.renderURLSearchParams(req, ["id"])}`, {...initReq, method: "GET"}) + } + static QuestionInput(req: QuestionInputRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/questions/${req["id"]}/input?${fm.renderURLSearchParams(req, ["id"])}`, {...initReq, method: "GET"}) + } + static Submit(req: SubmitRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/questions/${req["id"]}`, {...initReq, method: "POST"}) + } +} export class UserService { static User(req: UserRequest, initReq?: fm.InitReq): Promise { return fm.fetchReq(`/v1/users/me?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"}) diff --git a/api/v1/gen/ts/codequest/all_pb.d.ts b/api/v1/gen/ts/codequest/all_pb.d.ts index c44634d..0bcc797 100644 --- a/api/v1/gen/ts/codequest/all_pb.d.ts +++ b/api/v1/gen/ts/codequest/all_pb.d.ts @@ -164,13 +164,232 @@ export namespace User { } } +export class PartData extends jspb.Message { + getPart(): number; + setPart(value: number): void; + + getCompleted(): boolean; + setCompleted(value: boolean): void; + + getPointsworth(): number; + setPointsworth(value: number): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): PartData.AsObject; + static toObject(includeInstance: boolean, msg: PartData): PartData.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: PartData, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): PartData; + static deserializeBinaryFromReader(message: PartData, reader: jspb.BinaryReader): PartData; +} + +export namespace PartData { + export type AsObject = { + part: number, + completed: boolean, + pointsworth: number, + } +} + +export class Question extends jspb.Message { + getId(): string; + setId(value: string): void; + + getTitle(): string; + setTitle(value: string): void; + + getContent(): string; + setContent(value: string): void; + + hasPart1(): boolean; + clearPart1(): void; + getPart1(): PartData | undefined; + setPart1(value?: PartData): void; + + hasPart2(): boolean; + clearPart2(): void; + getPart2(): PartData | undefined; + setPart2(value?: PartData): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): Question.AsObject; + static toObject(includeInstance: boolean, msg: Question): Question.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: Question, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): Question; + static deserializeBinaryFromReader(message: Question, reader: jspb.BinaryReader): Question; +} + +export namespace Question { + export type AsObject = { + id: string, + title: string, + content: string, + part1?: PartData.AsObject, + part2?: PartData.AsObject, + } +} + +export class QuestionsResponse extends jspb.Message { + clearQuestionsList(): void; + getQuestionsList(): Array; + setQuestionsList(value: Array): void; + addQuestions(value?: Question, index?: number): Question; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): QuestionsResponse.AsObject; + static toObject(includeInstance: boolean, msg: QuestionsResponse): QuestionsResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: QuestionsResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): QuestionsResponse; + static deserializeBinaryFromReader(message: QuestionsResponse, reader: jspb.BinaryReader): QuestionsResponse; +} + +export namespace QuestionsResponse { + export type AsObject = { + questionsList: Array, + } +} + +export class QuestionByIDRequest extends jspb.Message { + getId(): string; + setId(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): QuestionByIDRequest.AsObject; + static toObject(includeInstance: boolean, msg: QuestionByIDRequest): QuestionByIDRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: QuestionByIDRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): QuestionByIDRequest; + static deserializeBinaryFromReader(message: QuestionByIDRequest, reader: jspb.BinaryReader): QuestionByIDRequest; +} + +export namespace QuestionByIDRequest { + export type AsObject = { + id: string, + } +} + +export class QuestionInputRequest extends jspb.Message { + getId(): string; + setId(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): QuestionInputRequest.AsObject; + static toObject(includeInstance: boolean, msg: QuestionInputRequest): QuestionInputRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: QuestionInputRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): QuestionInputRequest; + static deserializeBinaryFromReader(message: QuestionInputRequest, reader: jspb.BinaryReader): QuestionInputRequest; +} + +export namespace QuestionInputRequest { + export type AsObject = { + id: string, + } +} + +export class QuestionInput extends jspb.Message { + getId(): string; + setId(value: string): void; + + getInput(): string; + setInput(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): QuestionInput.AsObject; + static toObject(includeInstance: boolean, msg: QuestionInput): QuestionInput.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: QuestionInput, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): QuestionInput; + static deserializeBinaryFromReader(message: QuestionInput, reader: jspb.BinaryReader): QuestionInput; +} + +export namespace QuestionInput { + export type AsObject = { + id: string, + input: string, + } +} + +export class SubmitRequest extends jspb.Message { + getId(): string; + setId(value: string): void; + + getAnswer(): string; + setAnswer(value: string): void; + + getPart(): boolean; + setPart(value: boolean): void; + + getCode(): string; + setCode(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): SubmitRequest.AsObject; + static toObject(includeInstance: boolean, msg: SubmitRequest): SubmitRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: SubmitRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): SubmitRequest; + static deserializeBinaryFromReader(message: SubmitRequest, reader: jspb.BinaryReader): SubmitRequest; +} + +export namespace SubmitRequest { + export type AsObject = { + id: string, + answer: string, + part: boolean, + code: string, + } +} + +export class SubmitResponse extends jspb.Message { + getId(): string; + setId(value: string): void; + + getPart(): number; + setPart(value: number): void; + + getCorrect(): boolean; + setCorrect(value: boolean): void; + + getRanking(): number; + setRanking(value: number): void; + + getPoints(): number; + setPoints(value: number): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): SubmitResponse.AsObject; + static toObject(includeInstance: boolean, msg: SubmitResponse): SubmitResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: SubmitResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): SubmitResponse; + static deserializeBinaryFromReader(message: SubmitResponse, reader: jspb.BinaryReader): SubmitResponse; +} + +export namespace SubmitResponse { + export type AsObject = { + id: string, + part: number, + correct: boolean, + ranking: number, + points: number, + } +} + export class UpdateFields extends jspb.Message { getName(): string; setName(value: string): void; - getEmail(): string; - setEmail(value: string): void; - getGradelevel(): number; setGradelevel(value: number): void; @@ -190,7 +409,6 @@ export class UpdateFields extends jspb.Message { export namespace UpdateFields { export type AsObject = { name: string, - email: string, gradelevel: number, admin: boolean, } diff --git a/api/v1/quest.gunk b/api/v1/quest.gunk new file mode 100644 index 0000000..3582912 --- /dev/null +++ b/api/v1/quest.gunk @@ -0,0 +1,80 @@ +package codequest + +import ( + "github.com/gunk/opt/http" + "github.com/gunk/opt/openapiv2" + "github.com/gunk/opt/proto" + "time" +) + +type QuestService interface { + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/questions", + // } + Questions() QuestionsResponse + + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/questions/{ID}", + // } + QuestionByID(QuestionByIDRequest) Question + + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/questions/{ID}/input", + // } + QuestionInput(QuestionInputRequest) QuestionInput + + // +gunk http.Match{ + // Method: "POST", + // Path: "/v1/questions/{ID}", + // } + Submit(SubmitRequest) SubmitResponse +} + +type PartData struct { + Part int `pb:"1" json:"part"` + Completed bool `pb:"2" json:"completed"` + PointsWorth int `pb:"3" json:"points_worth"` +} + +type Question struct { + ID string `pb:"1" json:"id"` + Title string `pb:"2" json:"title"` + Content string `pb:"3" json:"content"` + Part1 PartData `pb:"4" json:"part1"` + Part2 PartData `pb:"5" json:"part2"` +} + +type QuestionsResponse struct { + Questions []Question `pb:"1" json:"questions"` +} + +type QuestionByIDRequest struct { + ID string `pb:"1" json:"id"` +} + +type QuestionInputRequest struct { + ID string `pb:"1" json:"id"` +} + +type QuestionInput struct { + ID string `pb:"1" json:"id"` + Input string `pb:"2" json:"input"` +} + +type SubmitRequest struct { + ID string `pb:"1" json:"id"` + Answer string `pb:"2" json:"content"` + Part bool `pb:"3" json:"part"` + Code string `pb:"4" json:"code"` +} + +type SubmitResponse struct { + ID string `pb:"1" json:"id"` + Part int `pb:"2" json:"part"` + Correct bool `pb:"3" json:"correct"` + Ranking int `pb:"4" json:"ranking"` + Points int `pb:"5" json:"points"` +} diff --git a/api/v1/users.gunk b/api/v1/users.gunk index d803585..b4654b4 100644 --- a/api/v1/users.gunk +++ b/api/v1/users.gunk @@ -1,7 +1,6 @@ package codequest import ( - "github.com/gunk/opt/file/java" "github.com/gunk/opt/http" "github.com/gunk/opt/openapiv2" "github.com/gunk/opt/proto" diff --git a/db/oauth.go b/db/oauth.go index 17cd5e2..44d3ea4 100644 --- a/db/oauth.go +++ b/db/oauth.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/hhhapz/codequest/models" "golang.org/x/oauth2" "golang.org/x/oauth2/google" ) @@ -18,7 +19,7 @@ const ( ) type OAuthState struct { - *oauth2.Config + config *oauth2.Config states map[string]oauthEntry m sync.Mutex } @@ -40,7 +41,7 @@ func NewOAuthState(path string) (*OAuthState, error) { } return &OAuthState{ - Config: config, + config: config, states: make(map[string]oauthEntry), m: sync.Mutex{}, }, nil @@ -62,32 +63,28 @@ func (o *OAuthState) Create(callback string) string { created: time.Now(), callback: callback, } - return o.Config.AuthCodeURL(state, oauth2.AccessTypeOffline) + return o.config.AuthCodeURL(state, oauth2.AccessTypeOffline) } -func (o *OAuthState) Validate(state string) (string, bool) { +func (o *OAuthState) Validate(ctx context.Context, state string, code string) (*oauth2.Token, string, error) { o.m.Lock() defer o.m.Unlock() entry, ok := o.states[state] if !ok { - return "", false + return nil, "", models.NewUserError("invalid state: %q", state) } delete(o.states, state) - return entry.callback, true -} -func (o *OAuthState) Exchange(ctx context.Context, code string) (*oauth2.Token, error) { - tk, err := o.Config.Exchange(ctx, code, oauth2.AccessTypeOffline) - return tk, err + tk, err := o.config.Exchange(ctx, code, oauth2.AccessTypeOffline) + return tk, entry.callback, err } func (o *OAuthState) GarbageCycle(period time.Duration, duration time.Duration) { tick := time.NewTicker(period) - clean := func() { + for range tick.C { o.m.Lock() - defer o.m.Unlock() now := time.Now() for state, entry := range o.states { @@ -95,12 +92,7 @@ func (o *OAuthState) GarbageCycle(period time.Duration, duration time.Duration) delete(o.states, state) } } - } - for { - select { - case <-tick.C: - clean() - } + o.m.Unlock() } } diff --git a/db/token.go b/db/token.go index 9d92963..63ddde5 100644 --- a/db/token.go +++ b/db/token.go @@ -7,7 +7,6 @@ import ( "encoding/base64" "errors" "fmt" - "log" "time" "github.com/hhhapz/codequest/models" @@ -32,7 +31,6 @@ func (db *DB) CreateToken(ctx context.Context, user *models.User) (*models.Token var e sqlite3.Error if errors.As(err, &e) && e.ExtendedCode == sqlite3.ErrConstraintUnique { - log.Printf("Duplicate token string generated: %s, recreating", tokenString) token.Token = createToken(48) continue } @@ -45,7 +43,10 @@ var ErrInvalidToken = errors.New("no results found") func (db *DB) UserByToken(ctx context.Context, token string) (*models.User, error) { user, err := models.UserByToken(ctx, db.DB, token) if err == sql.ErrNoRows { - return nil, ErrInvalidToken + return nil, models.NewUserError("the provided token(%q) does not exist", token) + } + if err != nil { + return nil, err } return user, nil diff --git a/db/user.go b/db/user.go index e4a2e51..763c91b 100644 --- a/db/user.go +++ b/db/user.go @@ -39,13 +39,21 @@ const ( emailDomain = "@jisedu.or.id" ) -func (db *DB) ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.Token, bool, error) { +func (db *DB) ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.Token, error) { endpoint := userinfoEndpoint + token.AccessToken - client := http.Client{Timeout: time.Second * 5} - res, err := client.Get(endpoint) + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, time.Second*5) + defer cancel() + + r, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil) if err != nil { - return nil, false, fmt.Errorf("could not get userinfo: %w", err) + return nil, fmt.Errorf("could not create request: %w", err) + } + + res, err := http.DefaultClient.Do(r) + if err != nil { + return nil, fmt.Errorf("could not get userinfo: %w", err) } defer res.Body.Close() @@ -53,30 +61,25 @@ func (db *DB) ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.To CreatedAt: models.NewTime(time.Now()), } if err := json.NewDecoder(res.Body).Decode(&user); err != nil { - return nil, false, fmt.Errorf("could not decode userinfo json: %w", err) + return nil, fmt.Errorf("could not decode userinfo json: %w", err) } - if u, err := db.User(ctx, user.Email); err == nil { - var tk *models.Token - if tk, err = db.CreateToken(ctx, u); err != nil { - return nil, false, fmt.Errorf("could not create user token: %w", err) + // register new user + if _, err := db.User(ctx, user.Email); err != nil { + if !strings.HasSuffix(user.Email, emailDomain) { + return nil, models.NewUserError("invalid registration email: %s", user.Email) } - return tk, true, nil - } - if !strings.HasSuffix(user.Email, emailDomain) { - return nil, true, fmt.Errorf("invalid registration email %q: must end with %q", user.Email, emailDomain) - } - - err = db.UpdateUser(ctx, user) - if err != nil { - return nil, false, fmt.Errorf("could not create user: %w", err) + err = db.UpdateUser(ctx, user) + if err != nil { + return nil, fmt.Errorf("could not create user: %w", err) + } } + // gen new token tk, err := db.CreateToken(ctx, user) if err != nil { - return nil, false, fmt.Errorf("could not create user token: %w", err) + return nil, fmt.Errorf("could not create user token: %w", err) } - - return tk, true, nil + return tk, nil } diff --git a/go.mod b/go.mod index 3d050f8..c3b7004 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/googleapis/gax-go/v2 v2.1.1 // indirect github.com/gorilla/css v1.0.0 // indirect + github.com/gunk/opt v0.2.0 // indirect github.com/kenshaw/diskcache v0.5.1 // indirect github.com/kenshaw/httplog v0.4.0 // indirect github.com/kenshaw/redoc v0.1.3 // indirect diff --git a/go.sum b/go.sum index 827e39b..1eab587 100644 --- a/go.sum +++ b/go.sum @@ -177,6 +177,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 h1:rgxjzoDmDXw5q8HONgyHhBas4to0/XWRo/gPpJhsUNQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0/go.mod h1:qrJPVzv9YlhsrxJc3P/Q85nr0w1lIRikTl4JlhdDH5w= +github.com/gunk/opt v0.2.0 h1:TAfvX5vrEuMEVXs/XnaJMam9q27d9noVsXbQ4V9LAnA= +github.com/gunk/opt v0.2.0/go.mod h1:Pp/fgnNbbjanUyvaIZ+4eMPAcZNHuro8QjpVSNxwJJU= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= diff --git a/models/codequest.go b/models/codequest.go new file mode 100644 index 0000000..b3689c7 --- /dev/null +++ b/models/codequest.go @@ -0,0 +1,15 @@ +package models + +import "fmt" + +type UserError struct { + reason string +} + +func NewUserError(message string, args ...interface{}) UserError { + return UserError{fmt.Sprintf(message, args...)} +} + +func (e UserError) Error() string { + return e.reason +} diff --git a/question/q01.go b/question/q01.go deleted file mode 100644 index bc80dc3..0000000 --- a/question/q01.go +++ /dev/null @@ -1,150 +0,0 @@ -package question - -import ( - _ "embed" - "fmt" - "math" - "math/rand" - "strconv" - "strings" - - "github.com/hhhapz/codequest/models" -) - -func move(x, y int, dir byte, step int) (int, int) { - switch dir { - case 'N': - return x, y + step - case 'S': - return x, y - step - case 'E': - return x + step, y - case 'W': - return x - step, y - } - return x, y -} - -func q1P1(steps []string) (x int, y int) { - for _, step := range steps { - dir := step[0] - amt, _ := strconv.Atoi(step[1:]) - x, y = move(x, y, dir, amt) - } - return -} - -func q1P2(steps []string) (x int, y int) { - known := make(map[int]map[int]bool) - - for _, step := range steps { - dir := step[0] - amt, _ := strconv.Atoi(step[1:]) - x, y = move(x, y, dir, amt) - - if known[x] == nil { - known[x] = make(map[int]bool) - } - if known[x][y] { - return - } - known[x][y] = true - } - return -} - -func q1Total(a, b int) int { - if a < 0 { - a = -a - } - if b < 0 { - b = -b - } - return a + b -} - -const ( - q1Entries = 100 - q1Range = 20 - directions = "NSWE" -) - -func init() { - var q *Question - q = &Question{ - ID: "directions", - Text: q01Text, - Level: Level1, - Generate: func(u *models.User) string { - res := make([]string, 0, 100) - - r := userRandom(u) - - known := make(map[int]map[int]bool) - var x, y int - for i := 0; i < q1Entries; i++ { - dir := directions[r.Intn(4)] - steps := r.Intn(30) + 1 - newX, newY := move(x, y, dir, steps) - - if known[newX] == nil { - known[newX] = make(map[int]bool) - } - if known[newX][newY] { - i-- - continue - } - - known[newX][newY] = true - x, y = newX, newY - - res = append(res, fmt.Sprintf("%c%d", dir, steps)) - } - - n := rand.Intn(q1Range) + 10 - locX, locY := q1P1(res[:n]) - - n = rand.Intn(q1Range) + 35 - lastX, lastY := q1P1(res[:n]) - - dX := math.Max(float64(locX), float64(lastX)) - math.Min(float64(locX), float64(lastX)) - dY := math.Max(float64(locY), float64(lastY)) - math.Min(float64(locY), float64(lastY)) - - if locX > lastX { - res[n] = fmt.Sprintf("E%d", int(dX)) - n++ - } else if locX < lastX { - res[n] = fmt.Sprintf("W%d", int(dX)) - n++ - } - - if locY > lastY { - res[n] = fmt.Sprintf("N%d", int(dY)) - } else if locY < lastY { - res[n] = fmt.Sprintf("S%d", int(dY)) - } - - return strings.Join(res, "\n") - }, - - Validate: func(u *models.User, level Part, input string) bool { - raw := q.Generate(u) - inp := strings.Split(raw, "\n") - - switch level { - case Part1: - x, y := q1P1(inp) - return q1Total(x, y) == 0 - case Part2: - x, y := q1P2(inp) - return q1Total(x, y) == 0 - } - return false - }, - } - - Register(q) -} - -//go:embed prompts/q01.md -var q01Text string diff --git a/question/q01/part1.go b/question/q01/part1.go new file mode 100644 index 0000000..24c60fd --- /dev/null +++ b/question/q01/part1.go @@ -0,0 +1,26 @@ +package q01 + +import "strconv" + +func move(x, y int, dir byte, step int) (int, int) { + switch dir { + case 'N': + return x, y + step + case 'S': + return x, y - step + case 'E': + return x + step, y + case 'W': + return x - step, y + } + return x, y +} + +func solveP1(steps []string) (x int, y int) { + for _, step := range steps { + dir := step[0] + amt, _ := strconv.Atoi(step[1:]) + x, y = move(x, y, dir, amt) + } + return +} diff --git a/question/q01/part2.go b/question/q01/part2.go new file mode 100644 index 0000000..720620d --- /dev/null +++ b/question/q01/part2.go @@ -0,0 +1,22 @@ +package q01 + +import "strconv" + +func solveP2(steps []string) (x int, y int) { + known := make(map[int]map[int]bool) + + for _, step := range steps { + dir := step[0] + amt, _ := strconv.Atoi(step[1:]) + x, y = move(x, y, dir, amt) + + if known[x] == nil { + known[x] = make(map[int]bool) + } + if known[x][y] { + return + } + known[x][y] = true + } + return +} diff --git a/question/q01/q01.go b/question/q01/q01.go new file mode 100644 index 0000000..0b287c2 --- /dev/null +++ b/question/q01/q01.go @@ -0,0 +1,131 @@ +package q01 + +import ( + _ "embed" + "fmt" + "strconv" + "strings" + + "github.com/hhhapz/codequest/models" + "github.com/hhhapz/codequest/question" +) + +func init() { + question.Register( + &question.Question{ + ID: "directions", + Name: "No Time for Directions!", + Text: q01Text, + Level: question.Level1, + Generate: func(u *models.User) string { + return strings.Join(generate(u), "\n") + }, + Validate: func(u *models.User, part question.Part, solution string) bool { + return Validate(u, part, solution) + }, + }) +} + +func total(a, b int) int { + if a < 0 { + a = -a + } + if b < 0 { + b = -b + } + return a + b +} + +const ( + // totalSteps in the input + totalSteps = 100 + + // stepRange is the range of steps within each step + stepRange = 30 + + // randRage is the range of steps between where the duplicate will be + // present + randRange = 20 + + // earliestCandidate the earliest step where the duplicate candidate is + earliestCandidate = 10 + + // earliestDupe is the earliest step where the candidate is visited + earliestDupe = 35 + + // directions for a step + directions = "NSWE" +) + +func generate(u *models.User) []string { + res := make([]string, 0, totalSteps) + + r := question.UserRandom(u) + + // known is used to disallow duplicate steps before the chosen dupe + known := make(map[int]map[int]bool) + var x, y int + + for len(res) != cap(res) { + dir := directions[r.Intn(4)] + steps := r.Intn(stepRange) + 1 + + newX, newY := move(x, y, dir, steps) + if known[newX] == nil { + known[newX] = make(map[int]bool) + } + if known[newX][newY] { + continue + } + + known[newX][newY] = true + x, y = newX, newY + + res = append(res, fmt.Sprintf("%c%d", dir, steps)) + } + + // the location of the candidate for the duplicate + n := r.Intn(randRange) + earliestCandidate + locX, locY := solveP1(res[:n]) + + // the location where the candidate is revisited + n = r.Intn(randRange) + earliestDupe + lastX, lastY := solveP2(res[:n]) + + // jump to the candidate + if locX > lastX { + res[n] = fmt.Sprintf("E%d", locX-lastX) + n++ + } else if locX < lastX { + res[n] = fmt.Sprintf("W%d", lastX-locX) + n++ + } + + if locY > lastY { + res[n] = fmt.Sprintf("N%d", locY-lastY) + } else if locY < lastY { + res[n] = fmt.Sprintf("S%d", lastY-locY) + } + + return res +} + +func Validate(u *models.User, p question.Part, sol string) bool { + inp := generate(u) + + var t int + switch p { + case question.Part1: + t = total(solveP1(inp)) + case question.Part2: + t = total(solveP2(inp)) + + default: + return false + } + + return strconv.Itoa(t) == sol +} + +//go:embed q01.md +var q01Text string diff --git a/question/prompts/q01.md b/question/q01/q01.md similarity index 96% rename from question/prompts/q01.md rename to question/q01/q01.md index 16737fc..6f9fbea 100644 --- a/question/prompts/q01.md +++ b/question/q01/q01.md @@ -1,6 +1,6 @@ # No Time For Directions! -**Hermes** is the Greek god, and amongst others, he is the god of travel, trade, and athletes. +**Hermes** is the Greek god of, amongst others, travel, trade, and athletes. Hermes has placed his hope in you. You're dropped to a random location near Mount Cyllene in Arcadia, widely considered the birthplace diff --git a/question/q01/q01_test.go b/question/q01/q01_test.go new file mode 100644 index 0000000..8e28e76 --- /dev/null +++ b/question/q01/q01_test.go @@ -0,0 +1,54 @@ +package q01 + +import ( + "strconv" + "strings" + "testing" + + "github.com/hhhapz/codequest/models" + "github.com/hhhapz/codequest/question" +) + +func TestQ01(t *testing.T) { + u := &models.User{ + ID: "12031209571980516", + } + + q := question.QuestionByID("directions") + + raw := q.Generate(u) + input := strings.Split(raw, "\n") + + res := total(solveP1(input)) + if !q.Validate(u, question.Part1, strconv.Itoa(res)) { + t.Errorf("Expected question 1 part 1(%v) to be correct!", res) + } + + res = total(solveP2(input)) + if !q.Validate(u, question.Part2, strconv.Itoa(res)) { + t.Errorf("Expected question 2 part 2(%v) to be correct!", res) + } + + if q.Validate(u, question.Part1, "") { + t.Errorf("Expected bad input to be invalid") + } + + if t.Failed() { + t.Logf("Input:\n%v", raw) + } +} + +func TestQ01Idempotent(t *testing.T) { + q := question.QuestionByID("directions") + + u1 := &models.User{ID: "1"} + raw1 := q.Generate(u1) + + u2 := &models.User{ID: "2"} + _ = q.Generate(u2) + + raw2 := q.Generate(u1) + if raw1 != raw2 { + t.Errorf("Expected raw1 and raw2 to be the same") + } +} diff --git a/question/q01_test.go b/question/q01_test.go deleted file mode 100644 index 7c02db0..0000000 --- a/question/q01_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package question - -import ( - "fmt" - "strings" - "testing" - - "github.com/hhhapz/codequest/models" -) - -func TestQ01(t *testing.T) { - u := &models.User{ - ID: "0", - } - - q := QuestionByID("directions") - - input := q.Generate(u) - - fmt.Println("STAAART") - x, y := q1P1(strings.Split(input, "\n")) - fmt.Println("STAAART") - - t.Logf("SOLUTION (P1): (%d, %d): %d", x, y, q1Total(x, y)) - x, y = q1P2(strings.Split(input, "\n")) - t.Logf("SOLUTION (P2): (%d, %d): %d", x, y, q1Total(x, y)) - - fmt.Printf("INPUT: %v", input) -} diff --git a/question/q02.go b/question/q02.go deleted file mode 100644 index dbb1a3a..0000000 --- a/question/q02.go +++ /dev/null @@ -1,11 +0,0 @@ -package question - -func init() { - Register(&Question{ - ID: "", - Text: "", - Level: 0, - Generate: nil, - Validate: nil, - }) -} diff --git a/question/q02/part1.go b/question/q02/part1.go new file mode 100644 index 0000000..335bdd9 --- /dev/null +++ b/question/q02/part1.go @@ -0,0 +1,21 @@ +package q02 + +func gcd(a, b int64) int64 { + for b != 0 { + a, b = b, a%b + } + return a +} + +func lcm(nums []int) int64 { + result := int64(nums[0]) + for i := range nums { + n := int64(nums[i]) + result = result * n / gcd(result, n) + } + return result +} + +func solveP1(ships []int) int64 { + return lcm(ships) +} diff --git a/question/q02/part2.go b/question/q02/part2.go new file mode 100644 index 0000000..a45e279 --- /dev/null +++ b/question/q02/part2.go @@ -0,0 +1,12 @@ +package q02 + +func solveP2(ships []int) int64 { + lcm := solveP1(ships) + var res int64 + + for _, v := range ships { + res += lcm / int64(v) + } + + return res +} diff --git a/question/q02/q02.go b/question/q02/q02.go new file mode 100644 index 0000000..7cbbba0 --- /dev/null +++ b/question/q02/q02.go @@ -0,0 +1,87 @@ +package q02 + +import ( + _ "embed" + "math" + "math/big" + "strconv" + "strings" + + "github.com/hhhapz/codequest/models" + "github.com/hhhapz/codequest/question" +) + +func init() { + question.Register( + &question.Question{ + ID: "saturnalia", + Name: "Saturnalia's Problem", + Text: q02Text, + Level: question.Level1, + Generate: func(u *models.User) string { + inp := generate(u) + var res []string + + for _, n := range inp { + res = append(res, strconv.Itoa(n)) + } + return strings.Join(res, "\n") + }, + Validate: func(u *models.User, part question.Part, solution string) bool { + return Validate(u, part, solution) + }, + }) +} + +func bigLCM(a, b *big.Int) *big.Int { + return big.NewInt(0).Div(big.NewInt(0).Mul(a, b), big.NewInt(0).GCD(nil, nil, a, b)) +} + +const ( + ships = 25 + + minNum = 3 + maxNum = 100 +) + +var maxLCM = big.NewInt(math.MaxInt64 / 100) + +func generate(u *models.User) []int { + res := make([]int, 0, ships) + + r := question.UserRandom(u) + + lcm := big.NewInt(1) + for len(res) != cap(res) { + n := r.Intn(maxNum-minNum) + minNum + + nLcm := bigLCM(lcm, big.NewInt(int64(n))) + if nLcm.Cmp(maxLCM) > 0 { + continue + } + lcm = nLcm + + res = append(res, n) + } + return res +} + +func Validate(u *models.User, p question.Part, sol string) bool { + inp := generate(u) + + var t int64 + switch p { + case question.Part1: + t = solveP1(inp) + case question.Part2: + t = solveP2(inp) + + default: + return false + } + + return strconv.FormatInt(t, 10) == sol +} + +//go:embed q02.md +var q02Text string diff --git a/question/q02/q02.md b/question/q02/q02.md new file mode 100644 index 0000000..6e1d159 --- /dev/null +++ b/question/q02/q02.md @@ -0,0 +1,88 @@ +# Saturnalia's Problem + +**Kronos** is the father of the Olympian gods, and is the king of the Titans. He is the Titan god of +Time, Justice, and Evil. + +After the Olympians defeated the titans, Kronos was given a new fate: he now rules over the Isles of +the Blessed and the region of Latium near the Roman Empire. Next month, the festival **Saturnalia**. + +You've been given the task to schedule and organize the arrival of the citizens of Isles of the +Blessed and Latium to reach Mount Othrys by ship. + +Unfortunately, there are far too many ships to calculate this all by hand. Each ship takes a +different amount of time to return back to Mount Othrys, and you need to make sure everyone arrives +at the same time. + +You have been given the shipping planner, that tells you how long it takes for each ship to reach +either Isles of the Blessed or Latium, in minutes, and return back. + +Each ship initially departs at the same time, and continues to do as many rounds as needed, such +that **each ship returns back to Mount Othrys at the same time**. + +Your task is to determine for the given ships, what is the fewest number of minutes until each ship +returns back at the same time after the leave? + +### Example + +- Given the following input + + +``` +3 +5 +9 +``` + + Says that there are 3 different ships. The first one takes `3` minutes to complete a cycle, the + second takes `5`, and `9` minutes for last ship. After `45` minutes, all of them will return back + to Mount Othrys **at the same time**. + +- Given the following input + +``` +3 +12 +15 +9 +5 +73 +19 +49 +10 +13 +``` + + Says that there are a total of 10 ships, and all of them will return back after `159,033,420` + minutes. + + +**How many minutes** will your ships take to all return back at the same time? + +Hint: The numbers might get a bit large here! + +{{ if eq .Part 2 }} + +**Congratulations! You got Part 1 correct. Your answer was `{{ .Answer1 }}`.** + +## Part 2 + +To continue planning for the journey, Kronos needs figure out what the total number of journeys will +be for each ship, summed all together. + +### Example + +Given the following input: + +``` +3 +5 +9 +``` + +The total duration will still be `45` minutes before all the ships return again to the same +position. In this time, the first ship will complete `15` trips, the second ship will complete `9` +trips, and the last ship will complete `5` trips, for a total of `29` trips. + +With these new instructions, **how many steps total trips will all the ships complete?** + +{{ end }} diff --git a/question/q02/q02_test.go b/question/q02/q02_test.go new file mode 100644 index 0000000..b1a2fc3 --- /dev/null +++ b/question/q02/q02_test.go @@ -0,0 +1,58 @@ +package q02 + +import ( + "strconv" + "strings" + "testing" + + "github.com/hhhapz/codequest/models" + "github.com/hhhapz/codequest/question" +) + +func TestQ02(t *testing.T) { + u := &models.User{ + ID: "1203120957198056", + } + + q := question.QuestionByID("saturnalia") + + raw := q.Generate(u) + var input []int + + for _, s := range strings.Split(raw, "\n") { + i, _ := strconv.Atoi(s) + input = append(input, i) + } + + res := solveP1(input) + t.Logf("part 1 result: %d", res) + if !q.Validate(u, question.Part1, strconv.FormatInt(res, 10)) { + t.Errorf("Expected question 1 part 1(%v) to be correct!", res) + } + + res = solveP2(input) + if !q.Validate(u, question.Part2, strconv.FormatInt(res, 10)) { + t.Errorf("Expected question 2 part 2(%v) to be correct!", res) + } + + if q.Validate(u, question.Part1, "") { + t.Errorf("Expected bad input to be invalid") + } + + t.Logf("Input:\n%v", raw) +} + +func TestQ02Idempotent(t *testing.T) { + q := question.QuestionByID("saturnalia") + + u1 := &models.User{ID: "1"} + raw1 := q.Generate(u1) + + u2 := &models.User{ID: "2"} + _ = q.Generate(u2) + + raw2 := q.Generate(u1) + if raw1 != raw2 { + t.Errorf("Expected raw1 and raw2 to be the same") + } +} diff --git a/question/question.go b/question/question.go index f9b0316..83cb773 100644 --- a/question/question.go +++ b/question/question.go @@ -36,6 +36,7 @@ func Questions(user *models.User, level Level) []*Question { type Question struct { ID string + Name string Text string Level Level @@ -57,12 +58,12 @@ const ( Part2 ) -func userRandom(u *models.User) *rand.Rand { +// TODO: Internal autoincrement id +func UserRandom(u *models.User) *rand.Rand { id := u.ID if len(id) > 17 { id = id[:17] } seed, _ := strconv.ParseInt(id, 10, 64) - return rand.New(rand.NewSource(seed)) }