From 23174ccf82215be75e1374b8424114814e5a3f0e Mon Sep 17 00:00:00 2001 From: Hamza Ali Date: Sun, 19 Dec 2021 22:30:21 +0700 Subject: [PATCH] feat: transition to grpc --- api/api.go | 77 +- api/auth.go | 183 +-- api/interceptors.go | 77 ++ api/md.go | 30 + api/routes.gen.go | 450 -------- api/types.gen.go | 115 -- api/user.go | 240 ++-- api/v1/.gunkconfig | 19 + api/v1/all.pb.go | 1135 +++++++++++++++++++ api/v1/all.pb.gw.go | 913 +++++++++++++++ api/v1/all_grpc.pb.go | 440 +++++++ api/v1/auth.gunk | 50 + api/v1/codequest.gunk | 28 + api/v1/gen/json/codequest/all.swagger.json | 410 +++++++ api/v1/gen/ts-gateway/codequest/all.pb.ts | 102 ++ api/v1/gen/ts-gateway/codequest/fetch.pb.ts | 232 ++++ api/v1/gen/ts/codequest/all_pb.d.ts | 318 ++++++ api/v1/users.gunk | 75 ++ cmd/hackathon/main.go | 48 +- db/oauth.go | 8 +- db/token.go | 2 +- db/user.go | 61 +- go.mod | 33 +- go.sum | 103 +- question/prompts/q_01.md.tmpl | 67 ++ question/q_01.go | 13 + question/q_02.go | 13 + question/q_03.go | 0 question/question.go | 51 + schema/schema.yaml | 67 +- tailwind.config.cjs | 69 +- 31 files changed, 4352 insertions(+), 1077 deletions(-) create mode 100644 api/interceptors.go create mode 100644 api/md.go delete mode 100644 api/routes.gen.go delete mode 100644 api/types.gen.go create mode 100644 api/v1/.gunkconfig create mode 100644 api/v1/all.pb.go create mode 100644 api/v1/all.pb.gw.go create mode 100644 api/v1/all_grpc.pb.go create mode 100644 api/v1/auth.gunk create mode 100644 api/v1/codequest.gunk create mode 100644 api/v1/gen/json/codequest/all.swagger.json create mode 100644 api/v1/gen/ts-gateway/codequest/all.pb.ts create mode 100644 api/v1/gen/ts-gateway/codequest/fetch.pb.ts create mode 100644 api/v1/gen/ts/codequest/all_pb.d.ts create mode 100644 api/v1/users.gunk create mode 100644 question/prompts/q_01.md.tmpl create mode 100644 question/q_01.go create mode 100644 question/q_02.go create mode 100644 question/q_03.go create mode 100644 question/question.go diff --git a/api/api.go b/api/api.go index ac865af..d085580 100644 --- a/api/api.go +++ b/api/api.go @@ -1,35 +1,29 @@ -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.8.2 --package=api --generate types -o types.gen.go ../schema/schema.yaml -//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.8.2 --package=api --generate chi-server -o routes.gen.go ../schema/schema.yaml - package api import ( "context" - "encoding/json" - "fmt" - "net/http" - "github.com/hhhapz/hackathon/models" + codequestpb "github.com/hhhapz/codequest/api/v1" + "github.com/hhhapz/codequest/models" "golang.org/x/oauth2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/reflection" ) // inProd tells the server whether it is in prod. // It should be set using ldflags on build time. var inProd bool -type Server struct { - *AuthService - *UserService -} - type OAuthStore interface { Create(callback string) (code string) Validate(code string) (string, bool) Exchange(ctx context.Context, code string) (*oauth2.Token, error) - Remove(code string) } type UserStore interface { + ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.Token, bool, error) + CreateToken(ctx context.Context, user *models.User) (*models.Token, error) RevokeToken(ctx context.Context, token string) error RevokeUserTokens(ctx context.Context, user *models.User) (int64, error) @@ -37,50 +31,43 @@ type UserStore interface { User(ctx context.Context, email string) (*models.User, error) Users(ctx context.Context) ([]*models.User, error) - DecodeUser(ctx context.Context, buf []byte) (*models.User, error) UserByToken(ctx context.Context, token string) (*models.User, error) UpdateUser(ctx context.Context, user *models.User) error + DeleteUser(ctx context.Context, user *models.User) error } -var _ ServerInterface = (*Server)(nil) +type Server struct { + *AuthService + *UserService +} -func NewServer(oaStore OAuthStore, userStore UserStore) *Server { - return &Server{ +func NewServer(os OAuthStore, us UserStore) (*grpc.Server, error) { + s := &Server{ AuthService: &AuthService{ - oauthStore: oaStore, - userStore: userStore, + oauthStore: os, + userStore: us, }, UserService: &UserService{ - userStore: userStore, + userStore: us, }, } + srv := grpc.NewServer( + grpc.UnaryInterceptor(AuthInterceptor(s.AuthService.defaultAuthFunc)), + ) + reflection.Register(srv) + codequestpb.RegisterAuthServiceServer(srv, s.AuthService) + codequestpb.RegisterUserServiceServer(srv, s.UserService) + return srv, nil } -func serverError(w http.ResponseWriter, code int, message string) { - w.WriteHeader(code) - json.NewEncoder(w).Encode(Error{ - Code: code, - Message: message, - }) -} - -type parseError struct { - typ string - value string - reason string - message string -} - -func newParseError(typ, value, reason string) error { - return parseError{ - typ: typ, - value: value, - reason: reason, - message: "invalid %s(%q): %s", - } -} +// List of commonly used error values +var ( + ErrInvalidArgument = grpc.Errorf( + codes.InvalidArgument, + "Invalid argument", + ) +) -func (err parseError) Error() string { - return fmt.Sprintf(err.message, err.typ, err.value, err.reason) +func err() { } diff --git a/api/auth.go b/api/auth.go index ce409b2..18b6c0e 100644 --- a/api/auth.go +++ b/api/auth.go @@ -2,169 +2,86 @@ package api import ( "context" - "encoding/json" - "errors" - "fmt" - "io" "log" - "net/http" - "strconv" - "strings" - "time" - "github.com/hhhapz/hackathon/models" - "golang.org/x/oauth2" + codequestpb "github.com/hhhapz/codequest/api/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" ) type AuthService struct { + codequestpb.UnimplementedAuthServiceServer + oauthStore OAuthStore userStore UserStore } -func (as *AuthService) GenOauth(w http.ResponseWriter, r *http.Request, params GenOauthParams) { - // We enforce callback field in production. - if inProd && params.Callback != "https://hackathon.teamortix.com" { - serverError(w, http.StatusUnprocessableEntity, "invalid callback provided") - } - - page := as.oauthStore.Create(params.Callback) - w.WriteHeader(http.StatusOK) - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(ConsentPage{page}) -} - -var couldNotValidate = "Unable to authorize. Please try again.\nIf this issue persists, please contact an admin." - -func (as *AuthService) AuthorizeCallback(w http.ResponseWriter, r *http.Request, params AuthorizeCallbackParams) { - callback, ok := as.oauthStore.Validate(params.State) - if !ok { - serverError(w, http.StatusUnprocessableEntity, "Invalid state provided") - return - } - - token, err := as.oauthStore.Exchange(r.Context(), params.Code) - if err != nil { - log.Printf("error: could not perform token exchange: %v", err) - serverError(w, http.StatusInternalServerError, couldNotValidate) - return - } - - accessToken, err := as.consumeToken(r.Context(), token) - - reason := "serverError" - if errors.As(err, &parseError{}) { - reason = "email" - } +const ( + MDHost = "x-forwarded-host" + UIHost = "codequest.teamortix.com" +) - if err != nil { - log.Printf("error: could not consume oauth token: %v", err) - uri := fmt.Sprintf("%s/fail?reason=%s", callback, reason) - http.Redirect(w, r, uri, http.StatusFound) - return +func (as *AuthService) AuthFuncOverride(ctx context.Context, method string) (context.Context, error) { + switch method { + case "DeleteToken": + return BearerAuth(ctx, as.userStore) } - - http.SetCookie(w, &http.Cookie{ - Name: "token", - Value: accessToken, - Path: "/", - Expires: time.Now().Add(time.Hour * 24 * 14), // 2 weeks - SameSite: http.SameSiteNoneMode, // handled via CORS - Secure: inProd, - }) - http.Redirect(w, r, callback+"/success", http.StatusFound) + return ctx, nil } -const userinfoEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" - -func (as *AuthService) consumeToken(ctx context.Context, token *oauth2.Token) (string, error) { - endpoint := userinfoEndpoint + token.AccessToken - client := http.Client{Timeout: time.Second * 5} - - res, err := client.Get(endpoint) - if err != nil { - return "", fmt.Errorf("could not get userinfo: %w", err) - } - defer res.Body.Close() - - buf, err := io.ReadAll(res.Body) - if err != nil { - return "", fmt.Errorf("could not read request body: %w", err) - } +func (as *AuthService) OAuthCode(ctx context.Context, req *codequestpb.OAuthCodeRequest) (*codequestpb.OAuthCodeResponse, error) { + md := RequestMetadata(ctx) + host := md.Get(MDHost) - user := &models.User{ - CreatedAt: models.NewTime(time.Now()), - } - if err := json.Unmarshal(buf, &user); err != nil { - return "", fmt.Errorf("could not decode userinfo json: %w", err) + if host != UIHost && inProd { + return nil, status.Errorf(codes.InvalidArgument, "invalid host: %v", host) } - if u, err := as.userStore.User(ctx, user.Email); err == nil { - var tk *models.Token - if tk, err = as.userStore.CreateToken(ctx, u); err != nil { - return "", fmt.Errorf("could not create user token: %w", err) - } - return tk.Token, nil - } + page := as.oauthStore.Create(host) + return &codequestpb.OAuthCodeResponse{ + RedirectURI: page, + }, nil +} - student, valid := parseEmail(user.Email) - if !valid { - return "", newParseError("email", user.Email, "invalid email domain") +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) } - - user.Teacher = !student - err = as.userStore.UpdateUser(ctx, user) + token, err := as.oauthStore.Exchange(ctx, req.Code) if err != nil { - return "", fmt.Errorf("could not create user: %w", err) + log.Printf("could not perform token exchange: %v", err) + return nil, status.Errorf(codes.InvalidArgument, "invalid code %q: %v", req.Code, err) } - tk, err := as.userStore.CreateToken(ctx, user) + tk, ok, err := as.userStore.ConsumeToken(ctx, token) if err != nil { - return "", fmt.Errorf("could not create user token: %w", err) + if ok { + return nil, status.Errorf(codes.InvalidArgument, "could not authorize: %v", err) + } + log.Printf("could not authorize request: %v", err) + return nil, status.Errorf(codes.Internal, "could not authorize: internal error") } - return tk.Token, nil + return &codequestpb.Token{ + Token: tk.Token, + Expires: nil, + }, nil } -func (as *AuthService) DeleteToken(w http.ResponseWriter, r *http.Request, params DeleteTokenParams) { - var all bool - if params.All != nil { - all = *params.All - } - +func (as *AuthService) DeleteToken(ctx context.Context, req *codequestpb.DeleteTokenRequest) (*emptypb.Empty, error) { + u := UserCtx(ctx) var err error - if all { - user, err := as.userStore.UserByToken(r.Context(), params.Token) - if err != nil { - serverError(w, http.StatusUnauthorized, "Invalid token provided.") - return - } - - _, err = as.userStore.RevokeUserTokens(r.Context(), user) + if req.All { + _, err = as.userStore.RevokeUserTokens(ctx, u) } else { - err = as.userStore.RevokeToken(r.Context(), params.Token) + err = as.userStore.RevokeToken(ctx, TokenCtx(ctx)) } - if err != nil { - log.Printf("Could not revoke user token %#v: %v", params, err) - serverError(w, http.StatusInternalServerError, "Could not revoke token.") - return - } - - w.WriteHeader(http.StatusNoContent) -} - -const domain = "jisedu.or.id" - -// parseEmail parses the provided email, and returns two bools; -// 1. if the email belongs to a student: it conforms to `\d+@[domain]`, and -// 2. if it's a valid internal email (ends with `domain`). -func parseEmail(email string) (bool, bool) { - parts := strings.Split(email, "@") - if len(parts) != 2 || parts[1] != domain { - return false, false + log.Printf("could not revoke token: %v", err) + return nil, status.Errorf(codes.Internal, "could not revoke token") } - _, err := strconv.Atoi(parts[1]) - return err == nil, true + return &emptypb.Empty{}, nil } diff --git a/api/interceptors.go b/api/interceptors.go new file mode 100644 index 0000000..35a1e74 --- /dev/null +++ b/api/interceptors.go @@ -0,0 +1,77 @@ +package api + +import ( + "context" + "strings" + + grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" + "github.com/hhhapz/codequest/models" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + UserKey = "ctxuser" + TokenKey = "ctxtoken" +) + +func AuthInterceptor(authFunc grpc_auth.AuthFunc) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + var newCtx context.Context + var err error + if overrideSrv, ok := info.Server.(grpc_auth.ServiceAuthFuncOverride); ok { + method := strings.LastIndex(info.FullMethod, "/") + newCtx, err = overrideSrv.AuthFuncOverride(ctx, info.FullMethod[method+1:]) + } else { + newCtx, err = authFunc(ctx) + } + if err != nil { + return nil, err + } + return handler(newCtx, req) + } +} + +func (as AuthService) defaultAuthFunc(ctx context.Context) (context.Context, error) { + return BearerAuth(ctx, as.userStore) +} + +func BearerAuth(ctx context.Context, us UserStore) (context.Context, error) { + token, err := grpc_auth.AuthFromMD(ctx, "Bearer") + if err != nil { + return nil, err + } + + u, err := us.UserByToken(ctx, token) + if err != nil { + return nil, status.Errorf(codes.Unauthenticated, "invalid auth token: %v", token) + } + + ctx = context.WithValue(ctx, UserKey, u) + ctx = context.WithValue(ctx, TokenKey, token) + + return ctx, nil +} + +func AdminOnly(ctx context.Context) (context.Context, error) { + u := UserCtx(ctx) + if u == nil { + return nil, status.Errorf(codes.Unauthenticated, "user not found") + } + + if !u.Admin { + return nil, status.Errorf(codes.PermissionDenied, "access denied: user is not admin") + } + return ctx, nil +} + +func UserCtx(ctx context.Context) *models.User { + u, _ := ctx.Value(UserKey).(*models.User) + return u +} + +func TokenCtx(ctx context.Context) string { + t, _ := ctx.Value(TokenKey).(string) + return t +} diff --git a/api/md.go b/api/md.go new file mode 100644 index 0000000..5915bdc --- /dev/null +++ b/api/md.go @@ -0,0 +1,30 @@ +package api + +import ( + "context" + "strings" + + "google.golang.org/grpc/metadata" +) + +type MD metadata.MD + +func RequestMetadata(ctx context.Context) MD { + m, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil + } + return MD(m) +} + +func (md MD) Get(k string) string { + if md == nil { + return "" + } + + k = strings.ToLower(k) + if res := md[k]; len(res) > 0 { + return res[0] + } + return "" +} diff --git a/api/routes.gen.go b/api/routes.gen.go deleted file mode 100644 index 7e056a0..0000000 --- a/api/routes.gen.go +++ /dev/null @@ -1,450 +0,0 @@ -// Package api provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen version v1.8.2 DO NOT EDIT. -package api - -import ( - "fmt" - "net/http" - - "github.com/deepmap/oapi-codegen/pkg/runtime" - "github.com/go-chi/chi/v5" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - - // (GET /auth/authorize) - AuthorizeCallback(w http.ResponseWriter, r *http.Request, params AuthorizeCallbackParams) - - // (GET /auth/code) - GenOauth(w http.ResponseWriter, r *http.Request, params GenOauthParams) - - // (DELETE /auth/token) - DeleteToken(w http.ResponseWriter, r *http.Request, params DeleteTokenParams) - - // (GET /users/all) - GetAllUsers(w http.ResponseWriter, r *http.Request, params GetAllUsersParams) - - // (GET /users/email) - GetUserByEmail(w http.ResponseWriter, r *http.Request, params GetUserByEmailParams) - - // (PATCH /users/email) - ModifyOtherUser(w http.ResponseWriter, r *http.Request, params ModifyOtherUserParams) - - // (GET /users/me) - GetMe(w http.ResponseWriter, r *http.Request, params GetMeParams) - - // (PATCH /users/me) - ModifyUser(w http.ResponseWriter, r *http.Request, params ModifyUserParams) -} - -// ServerInterfaceWrapper converts contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface - HandlerMiddlewares []MiddlewareFunc -} - -type MiddlewareFunc func(http.HandlerFunc) http.HandlerFunc - -// AuthorizeCallback operation middleware -func (siw *ServerInterfaceWrapper) AuthorizeCallback(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params AuthorizeCallbackParams - - // ------------- Required query parameter "state" ------------- - if paramValue := r.URL.Query().Get("state"); paramValue != "" { - - } else { - http.Error(w, "Query argument state is required, but not found", http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", true, true, "state", r.URL.Query(), ¶ms.State) - if err != nil { - http.Error(w, fmt.Sprintf("Invalid format for parameter state: %s", err), http.StatusBadRequest) - return - } - - // ------------- Required query parameter "code" ------------- - if paramValue := r.URL.Query().Get("code"); paramValue != "" { - - } else { - http.Error(w, "Query argument code is required, but not found", http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", true, true, "code", r.URL.Query(), ¶ms.Code) - if err != nil { - http.Error(w, fmt.Sprintf("Invalid format for parameter code: %s", err), http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AuthorizeCallback(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// GenOauth operation middleware -func (siw *ServerInterfaceWrapper) GenOauth(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GenOauthParams - - // ------------- Required query parameter "callback" ------------- - if paramValue := r.URL.Query().Get("callback"); paramValue != "" { - - } else { - http.Error(w, "Query argument callback is required, but not found", http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", true, true, "callback", r.URL.Query(), ¶ms.Callback) - if err != nil { - http.Error(w, fmt.Sprintf("Invalid format for parameter callback: %s", err), http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GenOauth(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// DeleteToken operation middleware -func (siw *ServerInterfaceWrapper) DeleteToken(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params DeleteTokenParams - - // ------------- Optional query parameter "all" ------------- - if paramValue := r.URL.Query().Get("all"); paramValue != "" { - - } - - err = runtime.BindQueryParameter("form", true, false, "all", r.URL.Query(), ¶ms.All) - if err != nil { - http.Error(w, fmt.Sprintf("Invalid format for parameter all: %s", err), http.StatusBadRequest) - return - } - - var cookie *http.Cookie - - if cookie, err = r.Cookie("token"); err == nil { - var value string - err = runtime.BindStyledParameter("simple", true, "token", cookie.Value, &value) - if err != nil { - http.Error(w, "Invalid format for parameter token: %s", http.StatusBadRequest) - return - } - params.Token = value - - } else { - http.Error(w, "Query argument token is required, but not found", http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeleteToken(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// GetAllUsers operation middleware -func (siw *ServerInterfaceWrapper) GetAllUsers(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetAllUsersParams - - var cookie *http.Cookie - - if cookie, err = r.Cookie("token"); err == nil { - var value string - err = runtime.BindStyledParameter("simple", true, "token", cookie.Value, &value) - if err != nil { - http.Error(w, "Invalid format for parameter token: %s", http.StatusBadRequest) - return - } - params.Token = value - - } else { - http.Error(w, "Query argument token is required, but not found", http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetAllUsers(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// GetUserByEmail operation middleware -func (siw *ServerInterfaceWrapper) GetUserByEmail(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetUserByEmailParams - - // ------------- Required query parameter "email" ------------- - if paramValue := r.URL.Query().Get("email"); paramValue != "" { - - } else { - http.Error(w, "Query argument email is required, but not found", http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", true, true, "email", r.URL.Query(), ¶ms.Email) - if err != nil { - http.Error(w, fmt.Sprintf("Invalid format for parameter email: %s", err), http.StatusBadRequest) - return - } - - var cookie *http.Cookie - - if cookie, err = r.Cookie("token"); err == nil { - var value string - err = runtime.BindStyledParameter("simple", true, "token", cookie.Value, &value) - if err != nil { - http.Error(w, "Invalid format for parameter token: %s", http.StatusBadRequest) - return - } - params.Token = value - - } else { - http.Error(w, "Query argument token is required, but not found", http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetUserByEmail(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// ModifyOtherUser operation middleware -func (siw *ServerInterfaceWrapper) ModifyOtherUser(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params ModifyOtherUserParams - - // ------------- Required query parameter "email" ------------- - if paramValue := r.URL.Query().Get("email"); paramValue != "" { - - } else { - http.Error(w, "Query argument email is required, but not found", http.StatusBadRequest) - return - } - - err = runtime.BindQueryParameter("form", true, true, "email", r.URL.Query(), ¶ms.Email) - if err != nil { - http.Error(w, fmt.Sprintf("Invalid format for parameter email: %s", err), http.StatusBadRequest) - return - } - - var cookie *http.Cookie - - if cookie, err = r.Cookie("token"); err == nil { - var value string - err = runtime.BindStyledParameter("simple", true, "token", cookie.Value, &value) - if err != nil { - http.Error(w, "Invalid format for parameter token: %s", http.StatusBadRequest) - return - } - params.Token = value - - } else { - http.Error(w, "Query argument token is required, but not found", http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ModifyOtherUser(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// GetMe operation middleware -func (siw *ServerInterfaceWrapper) GetMe(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params GetMeParams - - var cookie *http.Cookie - - if cookie, err = r.Cookie("token"); err == nil { - var value string - err = runtime.BindStyledParameter("simple", true, "token", cookie.Value, &value) - if err != nil { - http.Error(w, "Invalid format for parameter token: %s", http.StatusBadRequest) - return - } - params.Token = value - - } else { - http.Error(w, "Query argument token is required, but not found", http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetMe(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// ModifyUser operation middleware -func (siw *ServerInterfaceWrapper) ModifyUser(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params ModifyUserParams - - var cookie *http.Cookie - - if cookie, err = r.Cookie("token"); err == nil { - var value string - err = runtime.BindStyledParameter("simple", true, "token", cookie.Value, &value) - if err != nil { - http.Error(w, "Invalid format for parameter token: %s", http.StatusBadRequest) - return - } - params.Token = value - - } else { - http.Error(w, "Query argument token is required, but not found", http.StatusBadRequest) - return - } - - var handler = func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ModifyUser(w, r, params) - } - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler(w, r.WithContext(ctx)) -} - -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{}) -} - -type ChiServerOptions struct { - BaseURL string - BaseRouter chi.Router - Middlewares []MiddlewareFunc -} - -// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{ - BaseRouter: r, - }) -} - -func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler { - return HandlerWithOptions(si, ChiServerOptions{ - BaseURL: baseURL, - BaseRouter: r, - }) -} - -// HandlerWithOptions creates http.Handler with additional options -func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler { - r := options.BaseRouter - - if r == nil { - r = chi.NewRouter() - } - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - } - - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/auth/authorize", wrapper.AuthorizeCallback) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/auth/code", wrapper.GenOauth) - }) - r.Group(func(r chi.Router) { - r.Delete(options.BaseURL+"/auth/token", wrapper.DeleteToken) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/users/all", wrapper.GetAllUsers) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/users/email", wrapper.GetUserByEmail) - }) - r.Group(func(r chi.Router) { - r.Patch(options.BaseURL+"/users/email", wrapper.ModifyOtherUser) - }) - r.Group(func(r chi.Router) { - r.Get(options.BaseURL+"/users/me", wrapper.GetMe) - }) - r.Group(func(r chi.Router) { - r.Patch(options.BaseURL+"/users/me", wrapper.ModifyUser) - }) - - return r -} diff --git a/api/types.gen.go b/api/types.gen.go deleted file mode 100644 index a4ec406..0000000 --- a/api/types.gen.go +++ /dev/null @@ -1,115 +0,0 @@ -// Package api provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen version v1.8.2 DO NOT EDIT. -package api - -import ( - "time" - - openapi_types "github.com/deepmap/oapi-codegen/pkg/types" -) - -// ConsentPage defines model for ConsentPage. -type ConsentPage struct { - Url string `json:"url"` -} - -// Error defines model for Error. -type Error struct { - Code int `json:"code"` - Message string `json:"message"` -} - -// User defines model for User. -type User struct { - Admin bool `json:"admin"` - CreatedAt time.Time `json:"created_at"` - Email openapi_types.Email `json:"email"` - - // GradeLevel is only present if teacher is false. - GradeLevel *int `json:"grade_level,omitempty"` - Id string `json:"id"` - Name string `json:"name"` - Picture string `json:"picture"` - Teacher bool `json:"teacher"` -} - -// DefaultResponse defines model for DefaultResponse. -type DefaultResponse Error - -// AuthorizeCallbackParams defines parameters for AuthorizeCallback. -type AuthorizeCallbackParams struct { - State string `json:"state"` - Code string `json:"code"` -} - -// GenOauthParams defines parameters for GenOauth. -type GenOauthParams struct { - Callback string `json:"callback"` -} - -// DeleteTokenParams defines parameters for DeleteToken. -type DeleteTokenParams struct { - All *bool `json:"all,omitempty"` - - // User authentication token. - Token string `json:"token"` -} - -// GetAllUsersParams defines parameters for GetAllUsers. -type GetAllUsersParams struct { - // User authentication token. - Token string `json:"token"` -} - -// GetUserByEmailParams defines parameters for GetUserByEmail. -type GetUserByEmailParams struct { - // User email. - Email openapi_types.Email `json:"email"` - - // User authentication token. - Token string `json:"token"` -} - -// ModifyOtherUserJSONBody defines parameters for ModifyOtherUser. -type ModifyOtherUserJSONBody struct { - Admin bool `json:"admin"` - GradeLevel int `json:"grade_level"` - Name string `json:"name"` - NewEmail *openapi_types.Email `json:"new_email,omitempty"` - Picture string `json:"picture"` - Teacher bool `json:"teacher"` -} - -// ModifyOtherUserParams defines parameters for ModifyOtherUser. -type ModifyOtherUserParams struct { - // User email. - Email openapi_types.Email `json:"email"` - - // User authentication token. - Token string `json:"token"` -} - -// GetMeParams defines parameters for GetMe. -type GetMeParams struct { - // User authentication token. - Token string `json:"token"` -} - -// ModifyUserJSONBody defines parameters for ModifyUser. -type ModifyUserJSONBody struct { - GradeLevel int `json:"grade_level"` - Name string `json:"name"` -} - -// ModifyUserParams defines parameters for ModifyUser. -type ModifyUserParams struct { - // User authentication token. - Token string `json:"token"` -} - -// ModifyOtherUserJSONRequestBody defines body for ModifyOtherUser for application/json ContentType. -type ModifyOtherUserJSONRequestBody ModifyOtherUserJSONBody - -// ModifyUserJSONRequestBody defines body for ModifyUser for application/json ContentType. -type ModifyUserJSONRequestBody ModifyUserJSONBody diff --git a/api/user.go b/api/user.go index 0cfbe8e..0398a6d 100644 --- a/api/user.go +++ b/api/user.go @@ -1,210 +1,150 @@ package api import ( + "context" "database/sql" - "encoding/json" "log" - "net/http" - "strings" - "github.com/deepmap/oapi-codegen/pkg/types" - "github.com/hhhapz/hackathon/models" + 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/timestamppb" ) type UserService struct { + codequestpb.UnimplementedUserServiceServer + userStore UserStore } -func (us *UserService) GetMe(w http.ResponseWriter, r *http.Request, params GetMeParams) { - u, err := us.userStore.UserByToken(r.Context(), params.Token) - if err != nil { - serverError(w, http.StatusUnauthorized, "Invalid token provided") - return - } - - writeUser(w, u) +func (us *UserService) User(ctx context.Context, req *codequestpb.UserRequest) (*codequestpb.User, error) { + u := UserCtx(ctx) + return convertUser(u), nil } -func (us *UserService) ModifyUser(w http.ResponseWriter, r *http.Request, params ModifyUserParams) { - u, err := us.userStore.UserByToken(r.Context(), params.Token) - if err != nil { - serverError(w, http.StatusUnauthorized, "Invalid token provided") - return +func (us *UserService) UserByEmail(ctx context.Context, req *codequestpb.UserByEmailRequest) (*codequestpb.User, error) { + u := UserCtx(ctx) + if u.Email == req.Email { + return convertUser(u), nil } - var body ModifyUserJSONBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - serverError(w, http.StatusBadRequest, "Invalid JSON body for ModifyUser") - return + var err error + if ctx, err = AdminOnly(ctx); err != nil { + return nil, err } - u.Name = strings.TrimSpace(body.Name) - if len(u.Name) < 3 || len(u.Name) > 30 { - serverError(w, http.StatusUnprocessableEntity, "Name must be between 3 and 30 characters long") - return + user, err := us.userStore.User(ctx, req.Email) + if err != nil { + log.Printf("Could not fetch user(%q): %v", req.Email, err) + return nil, status.Errorf(codes.NotFound, "email not found: %q", req.Email) } - if !u.Teacher { - if body.GradeLevel < 9 || body.GradeLevel > 12 { - serverError(w, http.StatusUnprocessableEntity, "Grade Level must be between 9 and 12") - return - } - u.GradeLevel = sql.NullInt64{Int64: int64(body.GradeLevel), Valid: true} + + return convertUser(user), nil +} + +func (us *UserService) AllUsers(ctx context.Context, req *codequestpb.AllUsersRequest) (*codequestpb.AllUsersResponse, error) { + var err error + if ctx, err = AdminOnly(ctx); err != nil { + return nil, err } - err = us.userStore.UpdateUser(r.Context(), u) + users, err := us.userStore.Users(ctx) if err != nil { - log.Printf("Could not modify user %s: %v", u.Email, err) - serverError(w, http.StatusInternalServerError, "Could not update user") - return + log.Printf("Could not fetch all users: %v", err) + return nil, status.Errorf(codes.Internal, "unable to fetch users") } - writeUser(w, u) + var userList []*codequestpb.User + for _, u := range users { + userList = append(userList, convertUser(u)) + } + return &codequestpb.AllUsersResponse{Users: userList}, nil } -func (us *UserService) GetUserByEmail(w http.ResponseWriter, r *http.Request, params GetUserByEmailParams) { - u, err := us.userStore.UserByToken(r.Context(), params.Token) - if err != nil { - serverError(w, http.StatusUnauthorized, "Invalid token provided") - return - } +func (us *UserService) UpdateUser(ctx context.Context, req *codequestpb.UpdateUserRequest) (*codequestpb.User, error) { + u := UserCtx(ctx) - email := string(params.Email) - if u.Email == email { - writeUser(w, u) - return + u.Name = req.Body.Name + if len(u.Name) < 3 || len(u.Name) > 20 { + return nil, status.Errorf(codes.InvalidArgument, "name must be between 3 and 20 characters") } - if !u.Admin { - log.Printf("user accessing unauthorized endpoint: %s", u.Email) - serverError(w, http.StatusForbidden, "You are not authorized to do this") - return + gl := req.Body.GradeLevel + u.GradeLevel = sql.NullInt64{Int64: int64(gl), Valid: true} + if gl < 9 || gl > 12 { + return nil, status.Errorf(codes.InvalidArgument, "grade level must be between 9 and 12") } - user, err := us.userStore.User(r.Context(), email) - if err != nil { - log.Printf("Could not fetch user(%q): %v", email, err) - serverError(w, http.StatusNotFound, "Could not find user with the specified email") - return + if err := us.userStore.UpdateUser(ctx, u); err != nil { + log.Printf("could not update user: %v", err) + return nil, status.Errorf(codes.Internal, "unable to update user") } - writeUser(w, user) + return convertUser(u), nil } -func (us *UserService) ModifyOtherUser(w http.ResponseWriter, r *http.Request, params ModifyOtherUserParams) { - u, err := us.userStore.UserByToken(r.Context(), params.Token) - if err != nil { - serverError(w, http.StatusUnauthorized, "Invalid token provided") - return +func (us *UserService) AdminUpdateUser(ctx context.Context, req *codequestpb.UpdateUserRequest) (*codequestpb.User, error) { + var err error + if ctx, err = AdminOnly(ctx); err != nil { + return nil, err } - if !u.Admin { - log.Printf("user accessing unauthorized endpoint: %s", u.Email) - serverError(w, http.StatusForbidden, "You are not authorized to do this") - return + user, err := us.userStore.User(ctx, req.Email) + if err != nil { + log.Printf("Could not fetch user(%q): %v", req.Email, err) + return nil, status.Errorf(codes.NotFound, "email not found: %q", req.Email) } - user, err := us.userStore.User(r.Context(), string(params.Email)) - if err != nil { - log.Printf("Could not fetch user(%q): %v", params.Email, err) - serverError(w, http.StatusNotFound, "Could not find user with the specified email") - return + user.Name = req.Body.Name + if len(user.Name) < 3 || len(user.Name) > 20 { + return nil, status.Errorf(codes.InvalidArgument, "name must be between 3 and 20 characters") } - var body ModifyOtherUserJSONBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - serverError(w, http.StatusBadRequest, "Invalid JSON body for ModifyOtherUser") - return + gl := req.Body.GradeLevel + user.GradeLevel = sql.NullInt64{Int64: int64(gl), Valid: true} + if gl < 9 || gl > 12 { + return nil, status.Errorf(codes.InvalidArgument, "grade level must be between 9 and 12") } - user.Name = strings.TrimSpace(body.Name) - user.Email = string(*body.NewEmail) - user.Picture = body.Picture - user.Teacher = body.Teacher - user.Admin = body.Admin + user.Admin = req.Body.Admin - if len(user.Name) < 3 || len(user.Name) > 30 { - serverError(w, http.StatusUnprocessableEntity, "Name must be between 3 and 30 characters long") - return - } - user.GradeLevel = sql.NullInt64{} - if !user.Teacher { - if body.GradeLevel < 9 || body.GradeLevel > 12 { - serverError(w, http.StatusUnprocessableEntity, "Grade Level must be between 9 and 12") - return - } - user.GradeLevel = sql.NullInt64{Int64: int64(body.GradeLevel), Valid: true} + if err := us.userStore.UpdateUser(ctx, user); err != nil { + log.Printf("could not update user: %v", err) + return nil, status.Errorf(codes.Internal, "unable to update user") } - writeUser(w, user) + return convertUser(user), nil } -func (us *UserService) GetAllUsers(w http.ResponseWriter, r *http.Request, params GetAllUsersParams) { - u, err := us.userStore.UserByToken(r.Context(), params.Token) - if err != nil { - serverError(w, http.StatusUnauthorized, "Invalid token provided") - return +func (us *UserService) DeleteUser(ctx context.Context, req *codequestpb.DeleteUserRequest) (*codequestpb.User, error) { + var err error + if ctx, err = AdminOnly(ctx); err != nil { + return nil, err } - if !u.Admin { - log.Printf("user accessing unauthorized endpoint: %s", u.Email) - serverError(w, http.StatusForbidden, "You are not authorized to do this") - return + user, err := us.userStore.User(ctx, req.Email) + if err != nil { + log.Printf("Could not fetch user(%q): %v", req.Email, err) + return nil, status.Errorf(codes.NotFound, "email not found: %q", req.Email) } - users, err := us.userStore.Users(r.Context()) - if err != nil { - log.Printf("user accessing unauthorized endpoint: %s", u.Email) - serverError(w, http.StatusInternalServerError, "Could not fetch users") - return + if err := us.userStore.DeleteUser(ctx, user); err != nil { + log.Printf("could not delete user: %v", err) + return nil, status.Errorf(codes.Internal, "unable to delete user") } - writeUsers(w, users) + return convertUser(user), nil } -func writeUser(w http.ResponseWriter, u *models.User) { - var grade *int - if u.GradeLevel.Valid { - g := int(u.GradeLevel.Int64) - grade = &g - } - - w.WriteHeader(200) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(User{ +func convertUser(u *models.User) *codequestpb.User { + return &codequestpb.User{ Admin: u.Admin, - CreatedAt: u.CreatedAt.Time(), - Email: types.Email(u.Email), - GradeLevel: grade, - Id: u.ID, + Email: u.Email, + GradeLevel: int32(u.GradeLevel.Int64), + ID: u.ID, Name: u.Name, Picture: u.Picture, - Teacher: u.Teacher, - }) -} - -func writeUsers(w http.ResponseWriter, us []*models.User) { - var users []User - - for _, u := range us { - var grade *int - if u.GradeLevel.Valid { - g := int(u.GradeLevel.Int64) - grade = &g - } - - users = append(users, User{ - Admin: u.Admin, - CreatedAt: u.CreatedAt.Time(), - Email: types.Email(u.Email), - GradeLevel: grade, - Id: u.ID, - Name: u.Name, - Picture: u.Picture, - Teacher: u.Teacher, - }) - } - - w.WriteHeader(200) - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(users) + CreatedAt: timestamppb.New(u.CreatedAt.Time()), + } } diff --git a/api/v1/.gunkconfig b/api/v1/.gunkconfig new file mode 100644 index 0000000..468ee29 --- /dev/null +++ b/api/v1/.gunkconfig @@ -0,0 +1,19 @@ +; pin protoc version +[protoc] + version=v3.19.1 + +; go +[generate go] + json_tag_postproc=true +[generate go-grpc] +[generate grpc-gateway] + +; swagger/openapiv2 +[generate openapiv2] + out=./gen/json/{{ .Package }} + +[generate ts] ; typescript + out=./gen/ts/{{ .Package }} + +[generate grpc-gateway-ts] ; typescript + out=./gen/ts-gateway/{{ .Package }} diff --git a/api/v1/all.pb.go b/api/v1/all.pb.go new file mode 100644 index 0000000..11e419d --- /dev/null +++ b/api/v1/all.pb.go @@ -0,0 +1,1135 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc (unknown) +// source: github.com/hhhapz/codequest/api/v1/all.proto + +package codequest + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Token struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Token string `protobuf:"bytes,1,opt,name=Token,json=token,proto3" json:"token,omitempty"` + Expires *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=Expires,json=expires,proto3" json:"expires,omitempty"` +} + +func (x *Token) Reset() { + *x = Token{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Token) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Token) ProtoMessage() {} + +func (x *Token) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[0] + 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 Token.ProtoReflect.Descriptor instead. +func (*Token) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{0} +} + +func (x *Token) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *Token) GetExpires() *timestamppb.Timestamp { + if x != nil { + return x.Expires + } + return nil +} + +type OAuthCodeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *OAuthCodeRequest) Reset() { + *x = OAuthCodeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OAuthCodeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OAuthCodeRequest) ProtoMessage() {} + +func (x *OAuthCodeRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[1] + 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 OAuthCodeRequest.ProtoReflect.Descriptor instead. +func (*OAuthCodeRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{1} +} + +type OAuthCodeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RedirectURI string `protobuf:"bytes,1,opt,name=RedirectURI,json=redirect_uri,proto3" json:"redirect_uri,omitempty"` +} + +func (x *OAuthCodeResponse) Reset() { + *x = OAuthCodeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OAuthCodeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OAuthCodeResponse) ProtoMessage() {} + +func (x *OAuthCodeResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[2] + 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 OAuthCodeResponse.ProtoReflect.Descriptor instead. +func (*OAuthCodeResponse) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{2} +} + +func (x *OAuthCodeResponse) GetRedirectURI() string { + if x != nil { + return x.RedirectURI + } + return "" +} + +type TokenRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=Code,json=code,proto3" json:"code,omitempty"` + State string `protobuf:"bytes,2,opt,name=State,json=state,proto3" json:"state,omitempty"` +} + +func (x *TokenRequest) Reset() { + *x = TokenRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TokenRequest) ProtoMessage() {} + +func (x *TokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[3] + 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 TokenRequest.ProtoReflect.Descriptor instead. +func (*TokenRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{3} +} + +func (x *TokenRequest) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *TokenRequest) GetState() string { + if x != nil { + return x.State + } + return "" +} + +type DeleteTokenRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + All bool `protobuf:"varint,1,opt,name=All,json=all,proto3" json:"all,omitempty"` + Token *Token `protobuf:"bytes,2,opt,name=Token,json=token,proto3" json:"token,omitempty"` +} + +func (x *DeleteTokenRequest) Reset() { + *x = DeleteTokenRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteTokenRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteTokenRequest) ProtoMessage() {} + +func (x *DeleteTokenRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[4] + 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 DeleteTokenRequest.ProtoReflect.Descriptor instead. +func (*DeleteTokenRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{4} +} + +func (x *DeleteTokenRequest) GetAll() bool { + if x != nil { + return x.All + } + return false +} + +func (x *DeleteTokenRequest) GetToken() *Token { + if x != nil { + return x.Token + } + return nil +} + +// User is a contestant in the competition. +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // ID of the user. Received via Google's OAuth2 API. + ID string `protobuf:"bytes,1,opt,name=ID,json=id,proto3" json:"id,omitempty"` + // Name of the user. + Name string `protobuf:"bytes,2,opt,name=Name,json=name,proto3" json:"name,omitempty"` + // Email of the user. + Email string `protobuf:"bytes,3,opt,name=Email,json=email,proto3" json:"email,omitempty"` + // Picture is the URL of the user's profile picture. + Picture string `protobuf:"bytes,4,opt,name=Picture,json=picture,proto3" json:"picture,omitempty"` + // GradeLevel of the user. + GradeLevel int32 `protobuf:"varint,5,opt,name=GradeLevel,json=grade_level,proto3" json:"grade_level,omitempty"` + // Admin is true if the user is an administrator. + Admin bool `protobuf:"varint,6,opt,name=Admin,json=admin,proto3" json:"admin,omitempty"` + // CreatedAt is the time the user was created. + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=CreatedAt,json=created_at,proto3" json:"created_at,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[5] + 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 User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{5} +} + +func (x *User) GetID() string { + if x != nil { + return x.ID + } + return "" +} + +func (x *User) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *User) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *User) GetPicture() string { + if x != nil { + return x.Picture + } + return "" +} + +func (x *User) GetGradeLevel() int32 { + if x != nil { + return x.GradeLevel + } + return 0 +} + +func (x *User) GetAdmin() bool { + if x != nil { + return x.Admin + } + return false +} + +func (x *User) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +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"` +} + +func (x *UpdateFields) Reset() { + *x = UpdateFields{} + 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 *UpdateFields) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateFields) ProtoMessage() {} + +func (x *UpdateFields) 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 UpdateFields.ProtoReflect.Descriptor instead. +func (*UpdateFields) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateFields) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateFields) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *UpdateFields) GetGradeLevel() int32 { + if x != nil { + return x.GradeLevel + } + return 0 +} + +func (x *UpdateFields) GetAdmin() bool { + if x != nil { + return x.Admin + } + return false +} + +type UserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UserRequest) Reset() { + *x = UserRequest{} + 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 *UserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserRequest) ProtoMessage() {} + +func (x *UserRequest) 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 UserRequest.ProtoReflect.Descriptor instead. +func (*UserRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{7} +} + +type AllUsersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *AllUsersRequest) Reset() { + *x = AllUsersRequest{} + 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 *AllUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllUsersRequest) ProtoMessage() {} + +func (x *AllUsersRequest) 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 AllUsersRequest.ProtoReflect.Descriptor instead. +func (*AllUsersRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{8} +} + +type UpdateUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=Email,json=email,proto3" json:"email,omitempty"` + Body *UpdateFields `protobuf:"bytes,2,opt,name=Body,json=fields,proto3" json:"fields,omitempty"` +} + +func (x *UpdateUserRequest) Reset() { + *x = UpdateUserRequest{} + 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 *UpdateUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserRequest) ProtoMessage() {} + +func (x *UpdateUserRequest) 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 UpdateUserRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateUserRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *UpdateUserRequest) GetBody() *UpdateFields { + if x != nil { + return x.Body + } + return nil +} + +type UserByEmailRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=Email,json=email,proto3" json:"email,omitempty"` +} + +func (x *UserByEmailRequest) Reset() { + *x = UserByEmailRequest{} + 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 *UserByEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserByEmailRequest) ProtoMessage() {} + +func (x *UserByEmailRequest) 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 UserByEmailRequest.ProtoReflect.Descriptor instead. +func (*UserByEmailRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{10} +} + +func (x *UserByEmailRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type DeleteUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=Email,json=email,proto3" json:"email,omitempty"` +} + +func (x *DeleteUserRequest) Reset() { + *x = DeleteUserRequest{} + 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 *DeleteUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserRequest) ProtoMessage() {} + +func (x *DeleteUserRequest) 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 DeleteUserRequest.ProtoReflect.Descriptor instead. +func (*DeleteUserRequest) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{11} +} + +func (x *DeleteUserRequest) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +type AllUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Users []*User `protobuf:"bytes,1,rep,name=Users,json=users,proto3" json:"users,omitempty"` +} + +func (x *AllUsersResponse) Reset() { + *x = AllUsersResponse{} + 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 *AllUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllUsersResponse) ProtoMessage() {} + +func (x *AllUsersResponse) 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 AllUsersResponse.ProtoReflect.Descriptor instead. +func (*AllUsersResponse) Descriptor() ([]byte, []int) { + return file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP(), []int{12} +} + +func (x *AllUsersResponse) GetUsers() []*User { + if x != nil { + return x.Users + } + return nil +} + +var File_github_com_hhhapz_codequest_api_v1_all_proto protoreflect.FileDescriptor + +var file_github_com_hhhapz_codequest_api_v1_all_proto_rawDesc = []byte{ + 0x0a, 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, 0x2f, 0x61, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, + 0x68, 0x68, 0x68, 0x61, 0x70, 0x7a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x73, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, + 0x00, 0x50, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x40, 0x0a, 0x07, 0x45, 0x78, + 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, + 0x00, 0x50, 0x00, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x3a, 0x06, 0x08, 0x00, + 0x10, 0x00, 0x18, 0x00, 0x22, 0x1a, 0x0a, 0x10, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, + 0x22, 0x4a, 0x0a, 0x11, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x0b, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x55, 0x52, 0x49, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, + 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x5f, 0x75, 0x72, 0x69, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x58, 0x0a, 0x0c, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x04, + 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, + 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x05, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, + 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x06, + 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x22, 0x78, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x03, + 0x41, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x3c, 0x0a, 0x05, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, + 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x3a, 0x06, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, + 0x22, 0xa8, 0x02, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 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, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 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, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, 0x30, 0x00, 0x50, 0x00, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x24, 0x0a, 0x07, 0x50, 0x69, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, 0x00, + 0x30, 0x00, 0x50, 0x00, 0x52, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x2b, 0x0a, + 0x0a, 0x47, 0x72, 0x61, 0x64, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x05, 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, 0x06, 0x20, 0x01, 0x28, 0x08, 0x42, 0x0a, 0x08, 0x00, 0x18, 0x00, 0x28, + 0x00, 0x30, 0x00, 0x50, 0x00, 0x52, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x12, 0x45, 0x0a, 0x09, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 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, + 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, + 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, + 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 ( + file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescOnce sync.Once + file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescData = file_github_com_hhhapz_codequest_api_v1_all_proto_rawDesc +) + +func file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescGZIP() []byte { + file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescOnce.Do(func() { + file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_hhhapz_codequest_api_v1_all_proto_rawDescData) + }) + 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_goTypes = []interface{}{ + (*Token)(nil), // 0: hhhapz.codequest.v1.Token + (*OAuthCodeRequest)(nil), // 1: hhhapz.codequest.v1.OAuthCodeRequest + (*OAuthCodeResponse)(nil), // 2: hhhapz.codequest.v1.OAuthCodeResponse + (*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 +} +var file_github_com_hhhapz_codequest_api_v1_all_proto_depIdxs = []int32{ + 13, // 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 +} + +func init() { file_github_com_hhhapz_codequest_api_v1_all_proto_init() } +func file_github_com_hhhapz_codequest_api_v1_all_proto_init() { + if File_github_com_hhhapz_codequest_api_v1_all_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Token); 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[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OAuthCodeRequest); 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[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OAuthCodeResponse); 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[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TokenRequest); 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[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteTokenRequest); 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[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); 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[6].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[7].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[8].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[9].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[10].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[11].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[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AllUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_hhhapz_codequest_api_v1_all_proto_rawDesc, + NumEnums: 0, + NumMessages: 13, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_github_com_hhhapz_codequest_api_v1_all_proto_goTypes, + DependencyIndexes: file_github_com_hhhapz_codequest_api_v1_all_proto_depIdxs, + MessageInfos: file_github_com_hhhapz_codequest_api_v1_all_proto_msgTypes, + }.Build() + File_github_com_hhhapz_codequest_api_v1_all_proto = out.File + file_github_com_hhhapz_codequest_api_v1_all_proto_rawDesc = nil + file_github_com_hhhapz_codequest_api_v1_all_proto_goTypes = nil + file_github_com_hhhapz_codequest_api_v1_all_proto_depIdxs = nil +} diff --git a/api/v1/all.pb.gw.go b/api/v1/all.pb.gw.go new file mode 100644 index 0000000..3f77145 --- /dev/null +++ b/api/v1/all.pb.gw.go @@ -0,0 +1,913 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: github.com/hhhapz/codequest/api/v1/all.proto + +/* +Package codequest is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package codequest + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_AuthService_OAuthCode_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq OAuthCodeRequest + var metadata runtime.ServerMetadata + + msg, err := client.OAuthCode(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_OAuthCode_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq OAuthCodeRequest + var metadata runtime.ServerMetadata + + msg, err := server.OAuthCode(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AuthService_Token_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_Token_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq TokenRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_Token_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Token(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_Token_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq TokenRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_Token_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Token(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AuthService_DeleteToken_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_DeleteToken_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteTokenRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_DeleteToken_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.DeleteToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_DeleteToken_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteTokenRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_DeleteToken_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.DeleteToken(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 + + msg, err := client.User(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_User_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UserRequest + var metadata runtime.ServerMetadata + + msg, err := server.User(ctx, &protoReq) + return msg, metadata, err + +} + +func request_UserService_UserByEmail_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UserByEmailRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["Email"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "Email") + } + + protoReq.Email, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "Email", err) + } + + msg, err := client.UserByEmail(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_UserByEmail_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UserByEmailRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["Email"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "Email") + } + + protoReq.Email, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "Email", err) + } + + msg, err := server.UserByEmail(ctx, &protoReq) + return msg, metadata, err + +} + +func request_UserService_AllUsers_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AllUsersRequest + var metadata runtime.ServerMetadata + + msg, err := client.AllUsers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_AllUsers_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AllUsersRequest + var metadata runtime.ServerMetadata + + msg, err := server.AllUsers(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_UserService_UpdateUser_0 = &utilities.DoubleArray{Encoding: map[string]int{"Body": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_UserService_UpdateUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateUserRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_UpdateUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_UpdateUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateUserRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_UpdateUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateUser(ctx, &protoReq) + return msg, metadata, err + +} + +func request_UserService_AdminUpdateUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateUserRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["Email"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "Email") + } + + protoReq.Email, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "Email", err) + } + + msg, err := client.AdminUpdateUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_AdminUpdateUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateUserRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Body); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["Email"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "Email") + } + + protoReq.Email, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "Email", err) + } + + msg, err := server.AdminUpdateUser(ctx, &protoReq) + return msg, metadata, err + +} + +func request_UserService_DeleteUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteUserRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["Email"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "Email") + } + + protoReq.Email, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "Email", err) + } + + msg, err := client.DeleteUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_UserService_DeleteUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteUserRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["Email"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "Email") + } + + protoReq.Email, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "Email", err) + } + + msg, err := server.DeleteUser(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterAuthServiceHandlerServer registers the http handlers for service AuthService to "mux". +// UnaryRPC :call AuthServiceServer 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 RegisterAuthServiceHandlerFromEndpoint instead. +func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthServiceServer) error { + + mux.Handle("GET", pattern_AuthService_OAuthCode_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.AuthService/OAuthCode", runtime.WithHTTPPathPattern("/v1/auth/code")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_OAuthCode_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_AuthService_OAuthCode_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AuthService_Token_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.AuthService/Token", runtime.WithHTTPPathPattern("/v1/auth/token")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_Token_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_AuthService_Token_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AuthService_DeleteToken_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.AuthService/DeleteToken", runtime.WithHTTPPathPattern("/v1/auth/token")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_DeleteToken_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_AuthService_DeleteToken_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. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterUserServiceHandlerFromEndpoint instead. +func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServiceServer) error { + + mux.Handle("GET", pattern_UserService_User_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.UserService/User", runtime.WithHTTPPathPattern("/v1/users/me")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_UserService_User_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_UserService_User_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_UserService_UserByEmail_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.UserService/UserByEmail", runtime.WithHTTPPathPattern("/v1/admin/users/{Email}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_UserService_UserByEmail_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_UserService_UserByEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_UserService_AllUsers_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.UserService/AllUsers", runtime.WithHTTPPathPattern("/v1/admin/users")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_UserService_AllUsers_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_UserService_AllUsers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_UserService_UpdateUser_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.UserService/UpdateUser", runtime.WithHTTPPathPattern("/v1/users/me")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_UserService_UpdateUser_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_UserService_UpdateUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_UserService_AdminUpdateUser_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.UserService/AdminUpdateUser", runtime.WithHTTPPathPattern("/v1/admin/users/{Email}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_UserService_AdminUpdateUser_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_UserService_AdminUpdateUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_UserService_DeleteUser_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.UserService/DeleteUser", runtime.WithHTTPPathPattern("/v1/admin/users/{Email}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_UserService_DeleteUser_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_UserService_DeleteUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterAuthServiceHandlerFromEndpoint is same as RegisterAuthServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterAuthServiceHandlerFromEndpoint(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 RegisterAuthServiceHandler(ctx, mux, conn) +} + +// RegisterAuthServiceHandler registers the http handlers for service AuthService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterAuthServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn grpc.ClientConnInterface) error { + return RegisterAuthServiceHandlerClient(ctx, mux, NewAuthServiceClient(conn)) +} + +// RegisterAuthServiceHandlerClient registers the http handlers for service AuthService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AuthServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AuthServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "AuthServiceClient" to call the correct interceptors. +func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AuthServiceClient) error { + + mux.Handle("GET", pattern_AuthService_OAuthCode_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.AuthService/OAuthCode", runtime.WithHTTPPathPattern("/v1/auth/code")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_OAuthCode_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_OAuthCode_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AuthService_Token_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.AuthService/Token", runtime.WithHTTPPathPattern("/v1/auth/token")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_Token_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_Token_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AuthService_DeleteToken_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.AuthService/DeleteToken", runtime.WithHTTPPathPattern("/v1/auth/token")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_DeleteToken_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_DeleteToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_AuthService_OAuthCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "auth", "code"}, "")) + + pattern_AuthService_Token_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "auth", "token"}, "")) + + pattern_AuthService_DeleteToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "auth", "token"}, "")) +) + +var ( + forward_AuthService_OAuthCode_0 = runtime.ForwardResponseMessage + + forward_AuthService_Token_0 = runtime.ForwardResponseMessage + + forward_AuthService_DeleteToken_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) { + 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 RegisterUserServiceHandler(ctx, mux, conn) +} + +// RegisterUserServiceHandler registers the http handlers for service UserService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterUserServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn grpc.ClientConnInterface) error { + return RegisterUserServiceHandlerClient(ctx, mux, NewUserServiceClient(conn)) +} + +// RegisterUserServiceHandlerClient registers the http handlers for service UserService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "UserServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "UserServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "UserServiceClient" to call the correct interceptors. +func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserServiceClient) error { + + mux.Handle("GET", pattern_UserService_User_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.UserService/User", runtime.WithHTTPPathPattern("/v1/users/me")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_UserService_User_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_User_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_UserService_UserByEmail_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.UserService/UserByEmail", runtime.WithHTTPPathPattern("/v1/admin/users/{Email}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_UserService_UserByEmail_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_UserByEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_UserService_AllUsers_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.UserService/AllUsers", runtime.WithHTTPPathPattern("/v1/admin/users")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_UserService_AllUsers_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_AllUsers_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_UserService_UpdateUser_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.UserService/UpdateUser", runtime.WithHTTPPathPattern("/v1/users/me")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_UserService_UpdateUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_UpdateUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PUT", pattern_UserService_AdminUpdateUser_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.UserService/AdminUpdateUser", runtime.WithHTTPPathPattern("/v1/admin/users/{Email}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_UserService_AdminUpdateUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_AdminUpdateUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_UserService_DeleteUser_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.UserService/DeleteUser", runtime.WithHTTPPathPattern("/v1/admin/users/{Email}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_UserService_DeleteUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_UserService_DeleteUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_UserService_User_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "users", "me"}, "")) + + pattern_UserService_UserByEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "admin", "users", "Email"}, "")) + + pattern_UserService_AllUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "admin", "users"}, "")) + + pattern_UserService_UpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "users", "me"}, "")) + + pattern_UserService_AdminUpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "admin", "users", "Email"}, "")) + + pattern_UserService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "admin", "users", "Email"}, "")) +) + +var ( + forward_UserService_User_0 = runtime.ForwardResponseMessage + + forward_UserService_UserByEmail_0 = runtime.ForwardResponseMessage + + forward_UserService_AllUsers_0 = runtime.ForwardResponseMessage + + forward_UserService_UpdateUser_0 = runtime.ForwardResponseMessage + + forward_UserService_AdminUpdateUser_0 = runtime.ForwardResponseMessage + + forward_UserService_DeleteUser_0 = runtime.ForwardResponseMessage +) diff --git a/api/v1/all_grpc.pb.go b/api/v1/all_grpc.pb.go new file mode 100644 index 0000000..404102f --- /dev/null +++ b/api/v1/all_grpc.pb.go @@ -0,0 +1,440 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package codequest + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// AuthServiceClient is the client API for AuthService 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 AuthServiceClient interface { + OAuthCode(ctx context.Context, in *OAuthCodeRequest, opts ...grpc.CallOption) (*OAuthCodeResponse, error) + Token(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*Token, error) + DeleteToken(ctx context.Context, in *DeleteTokenRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) +} + +type authServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { + return &authServiceClient{cc} +} + +func (c *authServiceClient) OAuthCode(ctx context.Context, in *OAuthCodeRequest, opts ...grpc.CallOption) (*OAuthCodeResponse, error) { + out := new(OAuthCodeResponse) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.AuthService/OAuthCode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) Token(ctx context.Context, in *TokenRequest, opts ...grpc.CallOption) (*Token, error) { + out := new(Token) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.AuthService/Token", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeleteToken(ctx context.Context, in *DeleteTokenRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.AuthService/DeleteToken", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AuthServiceServer is the server API for AuthService service. +// All implementations must embed UnimplementedAuthServiceServer +// for forward compatibility +type AuthServiceServer interface { + OAuthCode(context.Context, *OAuthCodeRequest) (*OAuthCodeResponse, error) + Token(context.Context, *TokenRequest) (*Token, error) + DeleteToken(context.Context, *DeleteTokenRequest) (*emptypb.Empty, error) + mustEmbedUnimplementedAuthServiceServer() +} + +// UnimplementedAuthServiceServer must be embedded to have forward compatible implementations. +type UnimplementedAuthServiceServer struct { +} + +func (UnimplementedAuthServiceServer) OAuthCode(context.Context, *OAuthCodeRequest) (*OAuthCodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OAuthCode not implemented") +} +func (UnimplementedAuthServiceServer) Token(context.Context, *TokenRequest) (*Token, error) { + return nil, status.Errorf(codes.Unimplemented, "method Token not implemented") +} +func (UnimplementedAuthServiceServer) DeleteToken(context.Context, *DeleteTokenRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteToken not implemented") +} +func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} + +// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AuthServiceServer will +// result in compilation errors. +type UnsafeAuthServiceServer interface { + mustEmbedUnimplementedAuthServiceServer() +} + +func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) { + s.RegisterService(&AuthService_ServiceDesc, srv) +} + +func _AuthService_OAuthCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(OAuthCodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).OAuthCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.AuthService/OAuthCode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).OAuthCode(ctx, req.(*OAuthCodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_Token_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).Token(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.AuthService/Token", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).Token(ctx, req.(*TokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeleteToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteTokenRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeleteToken(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.AuthService/DeleteToken", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeleteToken(ctx, req.(*DeleteTokenRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AuthService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hhhapz.codequest.v1.AuthService", + HandlerType: (*AuthServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "OAuthCode", + Handler: _AuthService_OAuthCode_Handler, + }, + { + MethodName: "Token", + Handler: _AuthService_Token_Handler, + }, + { + MethodName: "DeleteToken", + Handler: _AuthService_DeleteToken_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. +type UserServiceClient interface { + User(ctx context.Context, in *UserRequest, opts ...grpc.CallOption) (*User, error) + UserByEmail(ctx context.Context, in *UserByEmailRequest, opts ...grpc.CallOption) (*User, error) + AllUsers(ctx context.Context, in *AllUsersRequest, opts ...grpc.CallOption) (*AllUsersResponse, error) + UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error) + AdminUpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error) + DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*User, error) +} + +type userServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient { + return &userServiceClient{cc} +} + +func (c *userServiceClient) User(ctx context.Context, in *UserRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.UserService/User", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) UserByEmail(ctx context.Context, in *UserByEmailRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.UserService/UserByEmail", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) AllUsers(ctx context.Context, in *AllUsersRequest, opts ...grpc.CallOption) (*AllUsersResponse, error) { + out := new(AllUsersResponse) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.UserService/AllUsers", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.UserService/UpdateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) AdminUpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.UserService/AdminUpdateUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*User, error) { + out := new(User) + err := c.cc.Invoke(ctx, "/hhhapz.codequest.v1.UserService/DeleteUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServiceServer is the server API for UserService service. +// All implementations must embed UnimplementedUserServiceServer +// for forward compatibility +type UserServiceServer interface { + User(context.Context, *UserRequest) (*User, error) + UserByEmail(context.Context, *UserByEmailRequest) (*User, error) + AllUsers(context.Context, *AllUsersRequest) (*AllUsersResponse, error) + UpdateUser(context.Context, *UpdateUserRequest) (*User, error) + AdminUpdateUser(context.Context, *UpdateUserRequest) (*User, error) + DeleteUser(context.Context, *DeleteUserRequest) (*User, error) + mustEmbedUnimplementedUserServiceServer() +} + +// UnimplementedUserServiceServer must be embedded to have forward compatible implementations. +type UnimplementedUserServiceServer struct { +} + +func (UnimplementedUserServiceServer) User(context.Context, *UserRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method User not implemented") +} +func (UnimplementedUserServiceServer) UserByEmail(context.Context, *UserByEmailRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method UserByEmail not implemented") +} +func (UnimplementedUserServiceServer) AllUsers(context.Context, *AllUsersRequest) (*AllUsersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllUsers not implemented") +} +func (UnimplementedUserServiceServer) UpdateUser(context.Context, *UpdateUserRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUser not implemented") +} +func (UnimplementedUserServiceServer) AdminUpdateUser(context.Context, *UpdateUserRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method AdminUpdateUser not implemented") +} +func (UnimplementedUserServiceServer) DeleteUser(context.Context, *DeleteUserRequest) (*User, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteUser not implemented") +} +func (UnimplementedUserServiceServer) mustEmbedUnimplementedUserServiceServer() {} + +// UnsafeUserServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserServiceServer will +// result in compilation errors. +type UnsafeUserServiceServer interface { + mustEmbedUnimplementedUserServiceServer() +} + +func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) { + s.RegisterService(&UserService_ServiceDesc, srv) +} + +func _UserService_User_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).User(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.UserService/User", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).User(ctx, req.(*UserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_UserByEmail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserByEmailRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).UserByEmail(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.UserService/UserByEmail", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).UserByEmail(ctx, req.(*UserByEmailRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_AllUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AllUsersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).AllUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.UserService/AllUsers", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).AllUsers(ctx, req.(*AllUsersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).UpdateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.UserService/UpdateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).UpdateUser(ctx, req.(*UpdateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_AdminUpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).AdminUpdateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.UserService/AdminUpdateUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).AdminUpdateUser(ctx, req.(*UpdateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServiceServer).DeleteUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hhhapz.codequest.v1.UserService/DeleteUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServiceServer).DeleteUser(ctx, req.(*DeleteUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UserService_ServiceDesc is the grpc.ServiceDesc for UserService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UserService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "hhhapz.codequest.v1.UserService", + HandlerType: (*UserServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "User", + Handler: _UserService_User_Handler, + }, + { + MethodName: "UserByEmail", + Handler: _UserService_UserByEmail_Handler, + }, + { + MethodName: "AllUsers", + Handler: _UserService_AllUsers_Handler, + }, + { + MethodName: "UpdateUser", + Handler: _UserService_UpdateUser_Handler, + }, + { + MethodName: "AdminUpdateUser", + Handler: _UserService_AdminUpdateUser_Handler, + }, + { + MethodName: "DeleteUser", + Handler: _UserService_DeleteUser_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "github.com/hhhapz/codequest/api/v1/all.proto", +} diff --git a/api/v1/auth.gunk b/api/v1/auth.gunk new file mode 100644 index 0000000..56dbe9c --- /dev/null +++ b/api/v1/auth.gunk @@ -0,0 +1,50 @@ +package codequest + +import ( + "github.com/gunk/opt/file/java" + "github.com/gunk/opt/http" + "github.com/gunk/opt/openapiv2" + "github.com/gunk/opt/proto" + "time" +) + +type AuthService interface { + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/auth/code", + // } + OAuthCode(OAuthCodeRequest) OAuthCodeResponse + + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/auth/token", + // } + Token(TokenRequest) Token + + // +gunk http.Match{ + // Method: "DELETE", + // Path: "/v1/auth/token", + // } + DeleteToken(DeleteTokenRequest) +} + +type Token struct { + Token string `pb:"1" json:"token"` + Expires time.Time `pb:"2" json:"expires"` +} + +type OAuthCodeRequest struct{} + +type OAuthCodeResponse struct { + RedirectURI string `pb:"1" json:"redirect_uri"` +} + +type TokenRequest struct { + Code string `pb:"1" json:"code"` + State string `pb:"2" json:"state"` +} + +type DeleteTokenRequest struct { + All bool `pb:"1" json:"all"` + Token Token `pb:"2" json:"token"` +} diff --git a/api/v1/codequest.gunk b/api/v1/codequest.gunk new file mode 100644 index 0000000..bae9213 --- /dev/null +++ b/api/v1/codequest.gunk @@ -0,0 +1,28 @@ +// +gunk proto.Package("hhhapz.codequest.v1") +package codequest + +import ( + "github.com/gunk/opt/file/java" + "github.com/gunk/opt/http" + "github.com/gunk/opt/openapiv2" + "github.com/gunk/opt/proto" + "time" +) + +// User is a contestant in the competition. +type User struct { + // ID of the user. Received via Google's OAuth2 API. + ID string `pb:"1" json:"id"` + // Name of the user. + Name string `pb:"2" json:"name"` + // Email of the user. + Email string `pb:"3" json:"email"` + // Picture is the URL of the user's profile picture. + Picture string `pb:"4" json:"picture"` + // GradeLevel of the user. + GradeLevel int `pb:"5" json:"grade_level"` + // Admin is true if the user is an administrator. + Admin bool `pb:"6" json:"admin"` + // CreatedAt is the time the user was created. + CreatedAt time.Time `pb:"7" json:"created_at"` +} diff --git a/api/v1/gen/json/codequest/all.swagger.json b/api/v1/gen/json/codequest/all.swagger.json new file mode 100644 index 0000000..32f2e40 --- /dev/null +++ b/api/v1/gen/json/codequest/all.swagger.json @@ -0,0 +1,410 @@ +{ + "swagger": "2.0", + "info": { + "title": "github.com/hhhapz/codequest/api/v1/all.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AuthService" + }, + { + "name": "UserService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/admin/users": { + "get": { + "operationId": "UserService_AllUsers", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AllUsersResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "UserService" + ] + } + }, + "/v1/admin/users/{email}": { + "get": { + "operationId": "UserService_UserByEmail", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1User" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "email", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "UserService" + ] + }, + "delete": { + "operationId": "UserService_DeleteUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1User" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "email", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "UserService" + ] + }, + "put": { + "operationId": "UserService_AdminUpdateUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1User" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "email", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UpdateFields" + } + } + ], + "tags": [ + "UserService" + ] + } + }, + "/v1/auth/code": { + "get": { + "operationId": "AuthService_OAuthCode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1OAuthCodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "AuthService" + ] + } + }, + "/v1/auth/token": { + "get": { + "operationId": "AuthService_Token", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1Token" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "code", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "AuthService" + ] + }, + "delete": { + "operationId": "AuthService_DeleteToken", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "properties": {} + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "all", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "token.token", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "token.expires", + "in": "query", + "required": false, + "type": "string", + "format": "date-time" + } + ], + "tags": [ + "AuthService" + ] + } + }, + "/v1/users/me": { + "get": { + "operationId": "UserService_User", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1User" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "UserService" + ] + }, + "put": { + "operationId": "UserService_UpdateUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1User" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UpdateFields" + } + }, + { + "name": "email", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "UserService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1AllUsersResponse": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "$ref": "#/definitions/v1User" + } + } + } + }, + "v1OAuthCodeResponse": { + "type": "object", + "properties": { + "redirect_uri": { + "type": "string" + } + } + }, + "v1Token": { + "type": "object", + "properties": { + "token": { + "type": "string" + }, + "expires": { + "type": "string", + "format": "date-time" + } + } + }, + "v1UpdateFields": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "grade_level": { + "type": "integer", + "format": "int32" + }, + "admin": { + "type": "boolean" + } + } + }, + "v1User": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "ID of the user. Received via Google's OAuth2 API." + }, + "name": { + "type": "string", + "description": "Name of the user." + }, + "email": { + "type": "string", + "description": "Email of the user." + }, + "picture": { + "type": "string", + "description": "Picture is the URL of the user's profile picture." + }, + "grade_level": { + "type": "integer", + "format": "int32", + "description": "GradeLevel of the user." + }, + "admin": { + "type": "boolean", + "description": "Admin is true if the user is an administrator." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "CreatedAt is the time the user was created." + } + }, + "description": "User is a contestant in the competition." + } + } +} diff --git a/api/v1/gen/ts-gateway/codequest/all.pb.ts b/api/v1/gen/ts-gateway/codequest/all.pb.ts new file mode 100644 index 0000000..48eb605 --- /dev/null +++ b/api/v1/gen/ts-gateway/codequest/all.pb.ts @@ -0,0 +1,102 @@ +/* eslint-disable */ +// @ts-nocheck +/* +* This file is a generated Typescript file for GRPC Gateway, DO NOT MODIFY +*/ + +import * as fm from "../../../../../fetch.pb" +import * as GoogleProtobufEmpty from "../../../../../google/protobuf/empty.pb" +import * as GoogleProtobufTimestamp from "../../../../../google/protobuf/timestamp.pb" +export type Token = { + token?: string + expires?: GoogleProtobufTimestamp.Timestamp +} + +export type OAuthCodeRequest = { +} + +export type OAuthCodeResponse = { + redirectURI?: string +} + +export type TokenRequest = { + code?: string + state?: string +} + +export type DeleteTokenRequest = { + all?: boolean + token?: Token +} + +export type User = { + id?: string + name?: string + email?: string + picture?: string + gradeLevel?: number + admin?: boolean + createdAt?: GoogleProtobufTimestamp.Timestamp +} + +export type UpdateFields = { + name?: string + email?: string + gradeLevel?: number + admin?: boolean +} + +export type UserRequest = { +} + +export type AllUsersRequest = { +} + +export type UpdateUserRequest = { + email?: string + body?: UpdateFields +} + +export type UserByEmailRequest = { + email?: string +} + +export type DeleteUserRequest = { + email?: string +} + +export type AllUsersResponse = { + users?: User[] +} + +export class AuthService { + static OAuthCode(req: OAuthCodeRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/auth/code?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"}) + } + static Token(req: TokenRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/auth/token?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"}) + } + static DeleteToken(req: DeleteTokenRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/auth/token`, {...initReq, method: "DELETE"}) + } +} +export class UserService { + static User(req: UserRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/users/me?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"}) + } + static UserByEmail(req: UserByEmailRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/admin/users/${req["email"]}?${fm.renderURLSearchParams(req, ["email"])}`, {...initReq, method: "GET"}) + } + static AllUsers(req: AllUsersRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/admin/users?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"}) + } + static UpdateUser(req: UpdateUserRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/users/me`, {...initReq, method: "PUT", body: JSON.stringify(req["Body"])}) + } + static AdminUpdateUser(req: UpdateUserRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/admin/users/${req["email"]}`, {...initReq, method: "PUT", body: JSON.stringify(req["Body"])}) + } + static DeleteUser(req: DeleteUserRequest, initReq?: fm.InitReq): Promise { + return fm.fetchReq(`/v1/admin/users/${req["email"]}`, {...initReq, method: "DELETE"}) + } +} \ No newline at end of file diff --git a/api/v1/gen/ts-gateway/codequest/fetch.pb.ts b/api/v1/gen/ts-gateway/codequest/fetch.pb.ts new file mode 100644 index 0000000..fe02010 --- /dev/null +++ b/api/v1/gen/ts-gateway/codequest/fetch.pb.ts @@ -0,0 +1,232 @@ +/* eslint-disable */ +// @ts-nocheck +/* +* This file is a generated Typescript file for GRPC Gateway, DO NOT MODIFY +*/ + +export interface InitReq extends RequestInit { + pathPrefix?: string +} + +export function fetchReq(path: string, init?: InitReq): Promise { + const {pathPrefix, ...req} = init || {} + + const url = pathPrefix ? `${pathPrefix}${path}` : path + + return fetch(url, req).then(r => r.json().then((body: O) => { + if (!r.ok) { throw body; } + return body; + })) as Promise +} + +// NotifyStreamEntityArrival is a callback that will be called on streaming entity arrival +export type NotifyStreamEntityArrival = (resp: T) => void + +/** + * fetchStreamingRequest is able to handle grpc-gateway server side streaming call + * it takes NotifyStreamEntityArrival that lets users respond to entity arrival during the call + * all entities will be returned as an array after the call finishes. + **/ +export async function fetchStreamingRequest(path: string, callback?: NotifyStreamEntityArrival, init?: InitReq) { + const {pathPrefix, ...req} = init || {} + const url = pathPrefix ?`${pathPrefix}${path}` : path + const result = await fetch(url, req) + // needs to use the .ok to check the status of HTTP status code + // http other than 200 will not throw an error, instead the .ok will become false. + // see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch# + if (!result.ok) { + const resp = await result.json() + const errMsg = resp.error && resp.error.message ? resp.error.message : "" + throw new Error(errMsg) + } + + if (!result.body) { + throw new Error("response doesnt have a body") + } + + await result.body + .pipeThrough(new TextDecoderStream()) + .pipeThrough(getNewLineDelimitedJSONDecodingStream()) + .pipeTo(getNotifyEntityArrivalSink((e: R) => { + if (callback) { + callback(e) + } + })) + + // wait for the streaming to finish and return the success respond + return +} + +/** + * JSONStringStreamController represents the transform controller that's able to transform the incoming + * new line delimited json content stream into entities and able to push the entity to the down stream + */ +interface JSONStringStreamController extends TransformStreamDefaultController { + buf?: string + pos?: number + enqueue: (s: T) => void +} + +/** + * getNewLineDelimitedJSONDecodingStream returns a TransformStream that's able to handle new line delimited json stream content into parsed entities + */ +function getNewLineDelimitedJSONDecodingStream(): TransformStream { + return new TransformStream({ + start(controller: JSONStringStreamController) { + controller.buf = '' + controller.pos = 0 + }, + + transform(chunk: string, controller: JSONStringStreamController) { + if (controller.buf === undefined) { + controller.buf = '' + } + if (controller.pos === undefined) { + controller.pos = 0 + } + controller.buf += chunk + while (controller.pos < controller.buf.length) { + if (controller.buf[controller.pos] === '\n') { + const line = controller.buf.substring(0, controller.pos) + const response = JSON.parse(line) + controller.enqueue(response.result) + controller.buf = controller.buf.substring(controller.pos + 1) + controller.pos = 0 + } else { + ++controller.pos + } + } + } + }) + +} + +/** + * getNotifyEntityArrivalSink takes the NotifyStreamEntityArrival callback and return + * a sink that will call the callback on entity arrival + * @param notifyCallback + */ +function getNotifyEntityArrivalSink(notifyCallback: NotifyStreamEntityArrival) { + return new WritableStream({ + write(entity: T) { + notifyCallback(entity) + } + }) +} + +type Primitive = string | boolean | number; +type RequestPayload = Record; +type FlattenedRequestPayload = Record>; + +/** + * Checks if given value is a plain object + * Logic copied and adapted from below source: + * https://github.com/char0n/ramda-adjunct/blob/master/src/isPlainObj.js + * @param {unknown} value + * @return {boolean} + */ +function isPlainObject(value: unknown): boolean { + const isObject = + Object.prototype.toString.call(value).slice(8, -1) === "Object"; + const isObjLike = value !== null && isObject; + + if (!isObjLike || !isObject) { + return false; + } + + const proto = Object.getPrototypeOf(value); + + const hasObjectConstructor = + typeof proto === "object" && + proto.constructor === Object.prototype.constructor; + + return hasObjectConstructor; +} + +/** + * Checks if given value is of a primitive type + * @param {unknown} value + * @return {boolean} + */ +function isPrimitive(value: unknown): boolean { + return ["string", "number", "boolean"].some(t => typeof value === t); +} + +/** + * Checks if given primitive is zero-value + * @param {Primitive} value + * @return {boolean} + */ +function isZeroValuePrimitive(value: Primitive): boolean { + return value === false || value === 0 || value === ""; +} + +/** + * Flattens a deeply nested request payload and returns an object + * with only primitive values and non-empty array of primitive values + * as per https://github.com/googleapis/googleapis/blob/master/google/api/http.proto + * @param {RequestPayload} requestPayload + * @param {String} path + * @return {FlattenedRequestPayload>} + */ +function flattenRequestPayload( + requestPayload: T, + path: string = "" +): FlattenedRequestPayload { + return Object.keys(requestPayload).reduce( + (acc: T, key: string): T => { + const value = requestPayload[key]; + const newPath = path ? [path, key].join(".") : key; + + const isNonEmptyPrimitiveArray = + Array.isArray(value) && + value.every(v => isPrimitive(v)) && + value.length > 0; + + const isNonZeroValuePrimitive = + isPrimitive(value) && !isZeroValuePrimitive(value as Primitive); + + let objectToMerge = {}; + + if (isPlainObject(value)) { + objectToMerge = flattenRequestPayload(value as RequestPayload, newPath); + } else if (isNonZeroValuePrimitive || isNonEmptyPrimitiveArray) { + objectToMerge = { [newPath]: value }; + } + + return { ...acc, ...objectToMerge }; + }, + {} as T + ) as FlattenedRequestPayload; +} + +/** + * Renders a deeply nested request payload into a string of URL search + * parameters by first flattening the request payload and then removing keys + * which are already present in the URL path. + * @param {RequestPayload} requestPayload + * @param {string[]} urlPathParams + * @return {string} + */ +export function renderURLSearchParams( + requestPayload: T, + urlPathParams: string[] = [] +): string { + const flattenedRequestPayload = flattenRequestPayload(requestPayload); + + const urlSearchParams = Object.keys(flattenedRequestPayload).reduce( + (acc: string[][], key: string): string[][] => { + // key should not be present in the url path as a parameter + const value = flattenedRequestPayload[key]; + if (urlPathParams.find(f => f === key)) { + return acc; + } + return Array.isArray(value) + ? [...acc, ...value.map(m => [key, m.toString()])] + : (acc = [...acc, [key, value.toString()]]); + }, + [] as string[][] + ); + + return new URLSearchParams(urlSearchParams).toString(); +} \ No newline at end of file diff --git a/api/v1/gen/ts/codequest/all_pb.d.ts b/api/v1/gen/ts/codequest/all_pb.d.ts new file mode 100644 index 0000000..c44634d --- /dev/null +++ b/api/v1/gen/ts/codequest/all_pb.d.ts @@ -0,0 +1,318 @@ +// package: hhhapz.codequest.v1 +// file: github.com/hhhapz/codequest/api/v1/all.proto + +import * as jspb from "google-protobuf"; +import * as google_api_annotations_pb from "../../../../../google/api/annotations_pb"; +import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb"; +import * as google_protobuf_timestamp_pb from "google-protobuf/google/protobuf/timestamp_pb"; + +export class Token extends jspb.Message { + getToken(): string; + setToken(value: string): void; + + hasExpires(): boolean; + clearExpires(): void; + getExpires(): google_protobuf_timestamp_pb.Timestamp | undefined; + setExpires(value?: google_protobuf_timestamp_pb.Timestamp): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): Token.AsObject; + static toObject(includeInstance: boolean, msg: Token): Token.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: Token, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): Token; + static deserializeBinaryFromReader(message: Token, reader: jspb.BinaryReader): Token; +} + +export namespace Token { + export type AsObject = { + token: string, + expires?: google_protobuf_timestamp_pb.Timestamp.AsObject, + } +} + +export class OAuthCodeRequest extends jspb.Message { + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): OAuthCodeRequest.AsObject; + static toObject(includeInstance: boolean, msg: OAuthCodeRequest): OAuthCodeRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: OAuthCodeRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): OAuthCodeRequest; + static deserializeBinaryFromReader(message: OAuthCodeRequest, reader: jspb.BinaryReader): OAuthCodeRequest; +} + +export namespace OAuthCodeRequest { + export type AsObject = { + } +} + +export class OAuthCodeResponse extends jspb.Message { + getRedirecturi(): string; + setRedirecturi(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): OAuthCodeResponse.AsObject; + static toObject(includeInstance: boolean, msg: OAuthCodeResponse): OAuthCodeResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: OAuthCodeResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): OAuthCodeResponse; + static deserializeBinaryFromReader(message: OAuthCodeResponse, reader: jspb.BinaryReader): OAuthCodeResponse; +} + +export namespace OAuthCodeResponse { + export type AsObject = { + redirecturi: string, + } +} + +export class TokenRequest extends jspb.Message { + getCode(): string; + setCode(value: string): void; + + getState(): string; + setState(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): TokenRequest.AsObject; + static toObject(includeInstance: boolean, msg: TokenRequest): TokenRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: TokenRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): TokenRequest; + static deserializeBinaryFromReader(message: TokenRequest, reader: jspb.BinaryReader): TokenRequest; +} + +export namespace TokenRequest { + export type AsObject = { + code: string, + state: string, + } +} + +export class DeleteTokenRequest extends jspb.Message { + getAll(): boolean; + setAll(value: boolean): void; + + hasToken(): boolean; + clearToken(): void; + getToken(): Token | undefined; + setToken(value?: Token): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): DeleteTokenRequest.AsObject; + static toObject(includeInstance: boolean, msg: DeleteTokenRequest): DeleteTokenRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: DeleteTokenRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): DeleteTokenRequest; + static deserializeBinaryFromReader(message: DeleteTokenRequest, reader: jspb.BinaryReader): DeleteTokenRequest; +} + +export namespace DeleteTokenRequest { + export type AsObject = { + all: boolean, + token?: Token.AsObject, + } +} + +export class User extends jspb.Message { + getId(): string; + setId(value: string): void; + + getName(): string; + setName(value: string): void; + + getEmail(): string; + setEmail(value: string): void; + + getPicture(): string; + setPicture(value: string): void; + + getGradelevel(): number; + setGradelevel(value: number): void; + + getAdmin(): boolean; + setAdmin(value: boolean): void; + + hasCreatedat(): boolean; + clearCreatedat(): void; + getCreatedat(): google_protobuf_timestamp_pb.Timestamp | undefined; + setCreatedat(value?: google_protobuf_timestamp_pb.Timestamp): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): User.AsObject; + static toObject(includeInstance: boolean, msg: User): User.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: User, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): User; + static deserializeBinaryFromReader(message: User, reader: jspb.BinaryReader): User; +} + +export namespace User { + export type AsObject = { + id: string, + name: string, + email: string, + picture: string, + gradelevel: number, + admin: boolean, + createdat?: google_protobuf_timestamp_pb.Timestamp.AsObject, + } +} + +export class UpdateFields extends jspb.Message { + getName(): string; + setName(value: string): void; + + getEmail(): string; + setEmail(value: string): void; + + getGradelevel(): number; + setGradelevel(value: number): void; + + getAdmin(): boolean; + setAdmin(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): UpdateFields.AsObject; + static toObject(includeInstance: boolean, msg: UpdateFields): UpdateFields.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: UpdateFields, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): UpdateFields; + static deserializeBinaryFromReader(message: UpdateFields, reader: jspb.BinaryReader): UpdateFields; +} + +export namespace UpdateFields { + export type AsObject = { + name: string, + email: string, + gradelevel: number, + admin: boolean, + } +} + +export class UserRequest extends jspb.Message { + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): UserRequest.AsObject; + static toObject(includeInstance: boolean, msg: UserRequest): UserRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: UserRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): UserRequest; + static deserializeBinaryFromReader(message: UserRequest, reader: jspb.BinaryReader): UserRequest; +} + +export namespace UserRequest { + export type AsObject = { + } +} + +export class AllUsersRequest extends jspb.Message { + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): AllUsersRequest.AsObject; + static toObject(includeInstance: boolean, msg: AllUsersRequest): AllUsersRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: AllUsersRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): AllUsersRequest; + static deserializeBinaryFromReader(message: AllUsersRequest, reader: jspb.BinaryReader): AllUsersRequest; +} + +export namespace AllUsersRequest { + export type AsObject = { + } +} + +export class UpdateUserRequest extends jspb.Message { + getEmail(): string; + setEmail(value: string): void; + + hasBody(): boolean; + clearBody(): void; + getBody(): UpdateFields | undefined; + setBody(value?: UpdateFields): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): UpdateUserRequest.AsObject; + static toObject(includeInstance: boolean, msg: UpdateUserRequest): UpdateUserRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: UpdateUserRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): UpdateUserRequest; + static deserializeBinaryFromReader(message: UpdateUserRequest, reader: jspb.BinaryReader): UpdateUserRequest; +} + +export namespace UpdateUserRequest { + export type AsObject = { + email: string, + body?: UpdateFields.AsObject, + } +} + +export class UserByEmailRequest extends jspb.Message { + getEmail(): string; + setEmail(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): UserByEmailRequest.AsObject; + static toObject(includeInstance: boolean, msg: UserByEmailRequest): UserByEmailRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: UserByEmailRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): UserByEmailRequest; + static deserializeBinaryFromReader(message: UserByEmailRequest, reader: jspb.BinaryReader): UserByEmailRequest; +} + +export namespace UserByEmailRequest { + export type AsObject = { + email: string, + } +} + +export class DeleteUserRequest extends jspb.Message { + getEmail(): string; + setEmail(value: string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): DeleteUserRequest.AsObject; + static toObject(includeInstance: boolean, msg: DeleteUserRequest): DeleteUserRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: DeleteUserRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): DeleteUserRequest; + static deserializeBinaryFromReader(message: DeleteUserRequest, reader: jspb.BinaryReader): DeleteUserRequest; +} + +export namespace DeleteUserRequest { + export type AsObject = { + email: string, + } +} + +export class AllUsersResponse extends jspb.Message { + clearUsersList(): void; + getUsersList(): Array; + setUsersList(value: Array): void; + addUsers(value?: User, index?: number): User; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): AllUsersResponse.AsObject; + static toObject(includeInstance: boolean, msg: AllUsersResponse): AllUsersResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: AllUsersResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): AllUsersResponse; + static deserializeBinaryFromReader(message: AllUsersResponse, reader: jspb.BinaryReader): AllUsersResponse; +} + +export namespace AllUsersResponse { + export type AsObject = { + usersList: Array, + } +} + diff --git a/api/v1/users.gunk b/api/v1/users.gunk new file mode 100644 index 0000000..d803585 --- /dev/null +++ b/api/v1/users.gunk @@ -0,0 +1,75 @@ +package codequest + +import ( + "github.com/gunk/opt/file/java" + "github.com/gunk/opt/http" + "github.com/gunk/opt/openapiv2" + "github.com/gunk/opt/proto" + "time" +) + +type UserService interface { + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/users/me", + // } + User(UserRequest) User + + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/admin/users/{Email}", + // } + UserByEmail(UserByEmailRequest) User + + // +gunk http.Match{ + // Method: "GET", + // Path: "/v1/admin/users", + // } + AllUsers(AllUsersRequest) AllUsersResponse + + // +gunk http.Match{ + // Method: "PUT", + // Path: "/v1/users/me", + // Body: "Body", + // } + UpdateUser(UpdateUserRequest) User + + // +gunk http.Match{ + // Method: "PUT", + // Path: "/v1/admin/users/{Email}", + // Body: "Body", + // } + AdminUpdateUser(UpdateUserRequest) User + + // +gunk http.Match{ + // Method: "DELETE", + // Path: "/v1/admin/users/{Email}", + // } + DeleteUser(DeleteUserRequest) User +} + +type UpdateFields struct { + Name string `pb:"1" json:"name"` + GradeLevel int `pb:"3" json:"grade_level"` + Admin bool `pb:"4" json:"admin"` +} + +type UserRequest struct{} +type AllUsersRequest struct{} + +type UpdateUserRequest struct { + Email string `pb:"1" json:"email"` + Body UpdateFields `pb:"2" json:"fields"` +} + +type UserByEmailRequest struct { + Email string `pb:"1" json:"email"` +} + +type DeleteUserRequest struct { + Email string `pb:"1" json:"email"` +} + +type AllUsersResponse struct { + Users []User `pb:"1" json:"users"` +} diff --git a/cmd/hackathon/main.go b/cmd/hackathon/main.go index 693f0a6..e7d2528 100644 --- a/cmd/hackathon/main.go +++ b/cmd/hackathon/main.go @@ -3,21 +3,19 @@ package main import ( "flag" "fmt" - "log" - "net/http" + "io" + "net" "os" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "github.com/go-chi/cors" - "github.com/hhhapz/hackathon/api" - "github.com/hhhapz/hackathon/db" + "github.com/hhhapz/codequest/api" + "github.com/hhhapz/codequest/db" "github.com/peterbourgon/ff/v3" + "google.golang.org/grpc/grpclog" ) func run() error { - fs := flag.NewFlagSet("hackathon", flag.ExitOnError) - port := fs.Int("port", 8080, "HTTP Server Port") + fs := flag.NewFlagSet("codequest", flag.ExitOnError) + port := fs.Int("port", 10000, "GRPC Server Port") secretFile := fs.String("secret", "client.secret.json", "Path to google oauth2 secret credentials JSON file.") dbFile := fs.String("db", "db.sqlite", "Path to sqlite3 database file") if err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("HK")); err != nil { @@ -38,33 +36,19 @@ func run() error { return fmt.Errorf("could not create oauth config: %w", err) } - server := api.NewServer(oaStore, database) + server, err := api.NewServer(oaStore, database) - r := chi.NewRouter() - r.Use(middleware.Logger) - r.Use(middleware.RealIP) - r.Use(middleware.CleanPath) + log := grpclog.NewLoggerV2(os.Stderr, io.Discard, os.Stderr) + grpclog.SetLoggerV2(log) - r.Route("/api", func(r chi.Router) { - r.Use(cors.Handler(cors.Options{ - AllowedOrigins: []string{"https://hackathon.teamortix.com", "http://localhost:8081"}, - - AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"}, - AllowedHeaders: []string{"Authorization", "Content-Type", "*"}, - AllowCredentials: true, - MaxAge: 300, - })) - - api.HandlerFromMux(server, r) - }) - - s := &http.Server{ - Handler: r, - Addr: fmt.Sprintf("0.0.0.0:%d", *port), + addr := fmt.Sprintf("0.0.0.0:%d", *port) + lis, err := net.Listen("tcp", addr) + if err != nil { + return fmt.Errorf("failed to listen: %v", err) } - log.Println("Starting Web server on", s.Addr) - return s.ListenAndServe() + log.Info("Serving gRPC on http://", addr) + return server.Serve(lis) } func main() { diff --git a/db/oauth.go b/db/oauth.go index c119dc0..17cd5e2 100644 --- a/db/oauth.go +++ b/db/oauth.go @@ -73,6 +73,7 @@ func (o *OAuthState) Validate(state string) (string, bool) { if !ok { return "", false } + delete(o.states, state) return entry.callback, true } @@ -81,13 +82,6 @@ func (o *OAuthState) Exchange(ctx context.Context, code string) (*oauth2.Token, return tk, err } -func (o *OAuthState) Remove(code string) { - o.m.Lock() - defer o.m.Unlock() - - delete(o.states, code) -} - func (o *OAuthState) GarbageCycle(period time.Duration, duration time.Duration) { tick := time.NewTicker(period) diff --git a/db/token.go b/db/token.go index 474ef04..9d92963 100644 --- a/db/token.go +++ b/db/token.go @@ -10,7 +10,7 @@ import ( "log" "time" - "github.com/hhhapz/hackathon/models" + "github.com/hhhapz/codequest/models" "github.com/mattn/go-sqlite3" ) diff --git a/db/user.go b/db/user.go index 94867dc..e4a2e51 100644 --- a/db/user.go +++ b/db/user.go @@ -2,9 +2,14 @@ package db import ( "context" + "encoding/json" "fmt" + "net/http" + "strings" + "time" - "github.com/hhhapz/hackathon/models" + "github.com/hhhapz/codequest/models" + "golang.org/x/oauth2" ) func (db *DB) Users(ctx context.Context) ([]*models.User, error) { @@ -21,3 +26,57 @@ func (db *DB) UpdateUser(ctx context.Context, user *models.User) error { } return nil } + +func (db *DB) DeleteUser(ctx context.Context, user *models.User) error { + if err := user.Delete(ctx, db.DB); err != nil { + return fmt.Errorf("could not delete user: %w", err) + } + return nil +} + +const ( + userinfoEndpoint = "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + emailDomain = "@jisedu.or.id" +) + +func (db *DB) ConsumeToken(ctx context.Context, token *oauth2.Token) (*models.Token, bool, error) { + endpoint := userinfoEndpoint + token.AccessToken + client := http.Client{Timeout: time.Second * 5} + + res, err := client.Get(endpoint) + if err != nil { + return nil, false, fmt.Errorf("could not get userinfo: %w", err) + } + defer res.Body.Close() + + user := &models.User{ + 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) + } + + 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) + } + 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) + } + + tk, err := db.CreateToken(ctx, user) + if err != nil { + return nil, false, fmt.Errorf("could not create user token: %w", err) + } + + return tk, true, nil +} diff --git a/go.mod b/go.mod index 3188790..d7fff2d 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,27 @@ -module github.com/hhhapz/hackathon +module github.com/hhhapz/codequest go 1.17 require ( - github.com/deepmap/oapi-codegen v1.8.2 - github.com/getkin/kin-openapi v0.61.0 - github.com/go-chi/chi/v5 v5.0.4 - github.com/go-chi/cors v1.2.0 - github.com/k0kubun/pp v3.0.1+incompatible + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 github.com/mattn/go-sqlite3 v1.14.8 github.com/peterbourgon/ff/v3 v3.1.0 - golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f + golang.org/x/oauth2 v0.0.0-20211028175245-ba495a64dcb5 + google.golang.org/genproto v0.0.0-20211116182654-e63d96a377c4 + google.golang.org/grpc v1.40.0 + google.golang.org/protobuf v1.27.1 ) require ( cloud.google.com/go v0.94.1 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/swag v0.19.5 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/googleapis/gax-go/v2 v2.1.0 // indirect - github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect - github.com/pkg/errors v0.8.1 // indirect - golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 // indirect - golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365 // indirect - golang.org/x/text v0.3.6 // indirect + github.com/stretchr/testify v1.7.0 // indirect + golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect + golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c // indirect + golang.org/x/text v0.3.7 // indirect google.golang.org/api v0.57.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 // indirect - google.golang.org/grpc v1.40.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 19d6940..11b3f5b 100644 --- a/go.sum +++ b/go.sum @@ -57,15 +57,9 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deepmap/oapi-codegen v1.7.1 h1:fBWh5YlHQbH0lCY+CPVlEV1fmqqPU0kBBVN71QiOyCI= -github.com/deepmap/oapi-codegen v1.7.1/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= -github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= -github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -74,23 +68,17 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/getkin/kin-openapi v0.61.0 h1:6awGqF5nG5zkVpMsAih1QH4VgzS8phTxECUWIFo7zko= -github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-chi/chi/v5 v5.0.4 h1:5e494iHzsYBiyXQAHHuI4tyJS9M3V84OuX3ufIIGHFo= -github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= -github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -122,7 +110,6 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -162,58 +149,47 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= 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/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= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= -github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU= github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/peterbourgon/ff/v3 v3.1.0 h1:5JAeDK5j/zhKFjyHEZQXwXBoDijERaos10RE+xamOsY= github.com/peterbourgon/ff/v3 v3.1.0/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -227,13 +203,14 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -303,8 +280,9 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 h1:a8jGStKg0XqKDlKqjLrXn0ioF5MH36pT7Z0BRTqLhbk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -319,8 +297,9 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211028175245-ba495a64dcb5 h1:v79phzBz03tsVCUTbvTBmmC3CUXF5mKYt7DA4ZVldpM= +golang.org/x/oauth2 v0.0.0-20211028175245-ba495a64dcb5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -334,21 +313,18 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -361,14 +337,12 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -382,9 +356,9 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365 h1:6wSTsvPddg9gc/mVEEyk9oOAoxn+bT4Z9q1zx+4RwA4= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c h1:DHcbWVXeY+0Y8HHKR+rbLwnoh2F4tNCY7rTiHJ30RmA= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -393,13 +367,12 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -437,6 +410,7 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -445,6 +419,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -514,6 +489,7 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -546,8 +522,9 @@ google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwy google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 h1:3V2dxSZpz4zozWWUq36vUxXEKnSYitEH2LdsAx+RUmg= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20211116182654-e63d96a377c4 h1:nPiLDJ9/wsay2NDshdJ1B24frx+butTxmaVaCxDBChY= +google.golang.org/genproto v0.0.0-20211116182654-e63d96a377c4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -590,16 +567,14 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/question/prompts/q_01.md.tmpl b/question/prompts/q_01.md.tmpl new file mode 100644 index 0000000..47d3323 --- /dev/null +++ b/question/prompts/q_01.md.tmpl @@ -0,0 +1,67 @@ +# No Time For Directions! + +__Hermes__ is the Greek god, and amongst others, he is the god of 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 of Hermes. After years of training, **You** are now +set out on a quest. You must steal a key from __Hecate__, hidden near Mount +Cyllene. + +Unfortunately, "near", is as close as you know where you are. The instructions +on the parchment Hermes gave begin from here, however, he never had the time to +tell you how to follow them, or where they lead to. + +The document has different markings that appear to tell you which direction to +travel in. They indicade a direction, (`N`, `S`, `E` or `W`), and the number of +steps you must take to find the hiding location. + +The problem is, that there's over a 100 different directions, and there's no +time following these directions one by one. It will take far too long! You take +a moment and work out the final destination, so you can get more quickly. Given +that you can only walk in the cardinal directions, what is the shortest path to +the destination? + +### Example + +- Given the following input + + ``` + N5 + E2 + S9 + W3 + ``` + + Instructs you to to travel `5` steps North, `2` steps East, `9` steps South, + and `3` steps West. Simplifying it, means `4` steps South, and `1` step West, + or `5` steps away. + +- Given the following input + + ``` + N6 + E5 + N5 + W3 + N4 + S9 + E4 + S1 + W6 + E3 + ``` + + Leaves you `5` steps North, and `3` steps East, or `8` steps away. + +Each line will have 2 characters of input, the first being the direction, and +the second being the number of steps. The number of steps on each line will +always be between 1 and 9, inclusive, steps. + +**How many steps away** is the key? + +{{ if ge .Step 2 }} + +## Part 2 + +{{ end }} diff --git a/question/q_01.go b/question/q_01.go new file mode 100644 index 0000000..c69e8b8 --- /dev/null +++ b/question/q_01.go @@ -0,0 +1,13 @@ +package question + +import "github.com/hhhapz/codequest/models" + +func init() { + Register(&Question{ + ID: "directions", + Text: ``, + Level: 0, + Generate: func(*models.User) string { panic("not implemented") }, + Validate: func(*models.User, string) bool { panic("not implemented") }, + }) +} diff --git a/question/q_02.go b/question/q_02.go new file mode 100644 index 0000000..ee393d0 --- /dev/null +++ b/question/q_02.go @@ -0,0 +1,13 @@ +package question + +import "github.com/hhhapz/codequest/models" + +func init() { + Register(&Question{ + ID: "", + Text: "", + Level: 0, + Generate: func(*models.User) string { panic("not implemented") }, + Validate: func(*models.User, string) bool { panic("not implemented") }, + }) +} diff --git a/question/q_03.go b/question/q_03.go new file mode 100644 index 0000000..e69de29 diff --git a/question/question.go b/question/question.go new file mode 100644 index 0000000..a9590a9 --- /dev/null +++ b/question/question.go @@ -0,0 +1,51 @@ +package question + +import ( + "math/rand" + + "github.com/hhhapz/codequest/models" +) + +var bank Bank + +// Bank is a map of different questions registered. +// The key of the map is the ID of the question. +// +// A custom type was created for convenience for picking random questions based +// on difficulties, and for registration. +type Bank [][]*Question + +func Register(q *Question) { + bank[q.Level] = append(bank[q.Level], q) +} + +func Questions(user *models.User, level Level) []*Question { + qs := make([]*Question, len(bank)) + r := rand.New(rand.NewSource(user.CreatedAt.Time().Unix())) + for level := range bank { + idx := r.Intn(len(bank[level])) + qs[level] = bank[level][idx] + } + + return qs +} + +type Question struct { + ID string + Text string + Level Level + + Generate func(user *models.User) string + Validate func(user *models.User, solution string) bool +} + +// Level represents the difficulty of each question. +// As the level gets higher, the difficulty also gets higher. +type Level int + +// Allowed difficulty levels. +const ( + Level1 Level = iota + Level2 + Level3 +) diff --git a/schema/schema.yaml b/schema/schema.yaml index f4beb27..991b97a 100644 --- a/schema/schema.yaml +++ b/schema/schema.yaml @@ -64,19 +64,14 @@ paths: delete: tags: ["Auth"] operationId: delete token + x-go-middlewares: ["token"] parameters: + - $ref: "#/components/parameters/Token" - name: all in: query - required: false - schema: - type: boolean - default: false - - name: token - in: cookie - description: User authentication token. required: true schema: - type: string + type: boolean responses: '204': description: User successfully logged out. @@ -88,13 +83,9 @@ paths: description: Get self user information. tags: ["Users"] operationId: get me + x-go-middlewares: ["token"] parameters: - - name: token - in: cookie - description: User authentication token. - required: true - schema: - type: string + - $ref: "#/components/parameters/Token" responses: '200': description: User information. @@ -104,17 +95,13 @@ paths: $ref: "#/components/schemas/User" default: $ref: "#/components/responses/DefaultResponse" - patch: + put: description: Update self user. tags: ["Users"] operationId: modify user + x-go-middlewares: ["token"] parameters: - - name: token - in: cookie - description: User authentication token. - required: true - schema: - type: string + - $ref: "#/components/parameters/Token" requestBody: description: Modified user information. content: @@ -146,13 +133,9 @@ paths: Requires admin to get user info not equal to the owner of the token. tags: ["Users"] operationId: get user by email + x-go-middlewares: ["token"] parameters: - - name: token - in: cookie - description: User authentication token. - required: true - schema: - type: string + - $ref: "#/components/parameters/Token" - name: email in: query description: User email. @@ -169,10 +152,11 @@ paths: $ref: "#/components/schemas/User" default: $ref: "#/components/responses/DefaultResponse" - patch: + put: description: Update another user. Requires admin. tags: ["Users"] operationId: modify other user + x-go-middlewares: ["token", "admin_token"] parameters: - name: token in: cookie @@ -228,27 +212,34 @@ paths: /users/all: get: - description: Get all users. Requires admin. + description: Get all users. Requires admin. tags: ["Users"] operationId: get all users + x-go-middlewares: ["token", "admin_token"] parameters: - - name: token - in: cookie - description: User authentication token. - required: true - schema: - type: string + - $ref: "#/components/parameters/Token" responses: '200': description: All user information. content: application/json: schema: - $ref: "#/components/schemas/User" + type: array + items: + $ref: "#/components/schemas/User" default: $ref: "#/components/responses/DefaultResponse" components: + parameters: + Token: + name: token + in: cookie + description: User authentication token. + required: true + schema: + type: string + responses: DefaultResponse: description: Unexpected server error or invalid user input. @@ -301,11 +292,7 @@ components: Error: type: object required: - - code - message properties: - code: - type: integer - default: 400 message: type: string diff --git a/tailwind.config.cjs b/tailwind.config.cjs index 1b570d4..7b15ee1 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -7,31 +7,30 @@ const config = { plugins: [ require('daisyui'), ], + + + + daisyui: { themes: [ { 'hackathon': { - 'neutral': '#9C6B91', - 'neutral-focus': '#702860', - 'neutral-content': '#EAE7E4', - - 'secondary': '#703529', - 'secondary-focus': '#A8351E', + 'primary': '#9BA77A', + 'primary-focus': '#5E6536', + 'primary-content': '#EAE7E4', + 'secondary': '#A8351E', + 'secondary-focus': '#703529', 'secondary-content': '#EAE7E4', - + 'accent': '#283D70', + 'accent-focus': '#2E3546', + 'accent-content': '#EAE7E4', 'neutral': '#1F1B12', - 'neutral-focus': '#221F17', + 'neutral-focus': '#4F4630', 'neutral-content': '#EAE7E4', - - 'primary': '#283D70', - 'primary-focus': '#2E3546', - 'primary-content': '#EAE7E4', - - 'base-100': '#FFEBC4', - 'base-200': '#FAF2DE', - 'base-300': '#B98976', + 'base-100': '#EBDCB3', + 'base-200': '#E0C98A', + 'base-300': '#B89876', 'base-content': '#3F270E', - 'info': '#2094f3', 'success': '#009485', 'warning': '#ff9900', @@ -39,7 +38,41 @@ const config = { }, }, ], - } + }, + + // daisyui: { + // themes: [ + // { + // 'hackathon': { + // 'primary': '#8B4D96', + // 'primary-focus': '#702860', + // 'primary-content': '#EAE7E4', + + // 'neutral': '#972812', + // 'neutral-focus': '#A8351E', + // 'neutral-content': '#EAE7E4', + + // 'neutral': '#1F1B12', + // 'neutral-focus': '#221F17', + // 'neutral-content': '#EAE7E4', + + // 'secondary': '#283D70', + // 'secondary-focus': '#2E3546', + // 'secondary-content': '#EAE7E4', + + // 'base-100': '#967E74', + // 'base-200': '#E4E0D2', + // 'base-300': '#B98976', + // 'base-content': '#D1AA59', + + // 'info': '#2094f3', + // 'success': '#009485', + // 'warning': '#ff9900', + // 'error': '#ff5724', + // }, + // }, + // ], + // } }; module.exports = config;