mirror of
https://github.com/aykhans/slash-e.git
synced 2025-07-06 13:12:36 +00:00
Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
8612715371 | |||
e91050c803 | |||
ec2ec74e31 | |||
bfb640f201 | |||
34f8a97309 | |||
1c58702716 | |||
bd31c19a15 | |||
7e0ada6161 | |||
b5d6036fcf | |||
0fcee9baf2 | |||
f6fefdb8e6 | |||
0ec06423e5 | |||
8f028e4054 | |||
ae3b632f53 | |||
bafb17015c | |||
d939bb8250 | |||
946548b33a | |||
d97a7e736d | |||
e5d5ba5cbc | |||
ce4232c9f5 | |||
bc6a72561c | |||
b9e5e7f2af | |||
96ab5b226d | |||
9c6f85e938 | |||
f1e3eace1a | |||
6f26523a11 | |||
304a29a18c | |||
3e5fa5573e | |||
93ed3c81ff | |||
0efd495f56 | |||
ae56f6df8c | |||
df51720310 | |||
1194099667 | |||
e936aaced1 | |||
0ee999a30a | |||
1211136037 | |||
73061034b2 |
13
README.md
13
README.md
@ -17,6 +17,7 @@
|
|||||||
- Create customizable `/s/` short links for any URL.
|
- Create customizable `/s/` short links for any URL.
|
||||||
- Share short links privately or with teammates.
|
- Share short links privately or with teammates.
|
||||||
- View analytics on link traffic and sources.
|
- View analytics on link traffic and sources.
|
||||||
|
- Easy access to your shortcuts with browser extension.
|
||||||
- Open source self-hosted solution.
|
- Open source self-hosted solution.
|
||||||
|
|
||||||
## Deploy with Docker in seconds
|
## Deploy with Docker in seconds
|
||||||
@ -26,3 +27,15 @@ docker run -d --name slash -p 5231:5231 -v ~/.slash/:/var/opt/slash yourselfhost
|
|||||||
```
|
```
|
||||||
|
|
||||||
Learn more in [Self-hosting Slash with Docker](https://github.com/boojack/slash/blob/main/docs/install.md).
|
Learn more in [Self-hosting Slash with Docker](https://github.com/boojack/slash/blob/main/docs/install.md).
|
||||||
|
|
||||||
|
## Browser Extension
|
||||||
|
|
||||||
|
Slash provides a browser extension to help you use your shortcuts in the search bar to go to the corresponding URL.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Chromium based browsers
|
||||||
|
|
||||||
|
For Chromium based browsers(Chrome, Edge, Arc, ...), you can install the extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg).
|
||||||
|
|
||||||
|
Learn more in [The Browser Extension of Slash](https://github.com/boojack/slash/blob/main/docs/install-browser-extension.md).
|
||||||
|
@ -71,7 +71,7 @@ func JWTMiddleware(s *APIV1Service, next echo.HandlerFunc, secret string) echo.H
|
|||||||
token := findAccessToken(c)
|
token := findAccessToken(c)
|
||||||
if token == "" {
|
if token == "" {
|
||||||
// When the request is not authenticated, we allow the user to access the shortcut endpoints for those public shortcuts.
|
// When the request is not authenticated, we allow the user to access the shortcut endpoints for those public shortcuts.
|
||||||
if util.HasPrefixes(path, "/s/*") && method == http.MethodGet {
|
if util.HasPrefixes(path, "/s/") && method == http.MethodGet {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
return echo.NewHTTPError(http.StatusUnauthorized, "Missing access token")
|
return echo.NewHTTPError(http.StatusUnauthorized, "Missing access token")
|
||||||
|
@ -90,7 +90,7 @@ func (s *APIV1Service) registerShortcutRoutes(g *echo.Group) {
|
|||||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("malformatted post shortcut request, err: %s", err)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("malformatted post shortcut request, err: %s", err)).SetInternal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
shortcut, err := s.Store.CreateShortcut(ctx, &storepb.Shortcut{
|
shortcut := &storepb.Shortcut{
|
||||||
CreatorId: userID,
|
CreatorId: userID,
|
||||||
Name: strings.ToLower(create.Name),
|
Name: strings.ToLower(create.Name),
|
||||||
Link: create.Link,
|
Link: create.Link,
|
||||||
@ -98,12 +98,16 @@ func (s *APIV1Service) registerShortcutRoutes(g *echo.Group) {
|
|||||||
Description: create.Description,
|
Description: create.Description,
|
||||||
Visibility: convertVisibilityToStorepb(create.Visibility),
|
Visibility: convertVisibilityToStorepb(create.Visibility),
|
||||||
Tags: create.Tags,
|
Tags: create.Tags,
|
||||||
OgMetadata: &storepb.OpenGraphMetadata{
|
OgMetadata: &storepb.OpenGraphMetadata{},
|
||||||
|
}
|
||||||
|
if create.OpenGraphMetadata != nil {
|
||||||
|
shortcut.OgMetadata = &storepb.OpenGraphMetadata{
|
||||||
Title: create.OpenGraphMetadata.Title,
|
Title: create.OpenGraphMetadata.Title,
|
||||||
Description: create.OpenGraphMetadata.Description,
|
Description: create.OpenGraphMetadata.Description,
|
||||||
Image: create.OpenGraphMetadata.Image,
|
Image: create.OpenGraphMetadata.Image,
|
||||||
},
|
}
|
||||||
})
|
}
|
||||||
|
shortcut, err := s.Store.CreateShortcut(ctx, shortcut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to create shortcut, err: %s", err)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to create shortcut, err: %s", err)).SetInternal(err)
|
||||||
}
|
}
|
||||||
@ -349,6 +353,8 @@ func convertVisibilityToStorepb(visibility Visibility) storepb.Visibility {
|
|||||||
switch visibility {
|
switch visibility {
|
||||||
case VisibilityPublic:
|
case VisibilityPublic:
|
||||||
return storepb.Visibility_PUBLIC
|
return storepb.Visibility_PUBLIC
|
||||||
|
case VisibilityWorkspace:
|
||||||
|
return storepb.Visibility_WORKSPACE
|
||||||
case VisibilityPrivate:
|
case VisibilityPrivate:
|
||||||
return storepb.Visibility_PRIVATE
|
return storepb.Visibility_PRIVATE
|
||||||
default:
|
default:
|
||||||
|
@ -17,16 +17,6 @@ import (
|
|||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
var authenticationAllowlistMethods = map[string]bool{}
|
|
||||||
|
|
||||||
// IsAuthenticationAllowed returns whether the method is exempted from authentication.
|
|
||||||
func IsAuthenticationAllowed(fullMethodName string) bool {
|
|
||||||
if strings.HasPrefix(fullMethodName, "/grpc.reflection") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return authenticationAllowlistMethods[fullMethodName]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContextKey is the key type of context value.
|
// ContextKey is the key type of context value.
|
||||||
type ContextKey int
|
type ContextKey int
|
||||||
|
|
||||||
@ -63,11 +53,23 @@ func (in *GRPCAuthInterceptor) AuthenticationInterceptor(ctx context.Context, re
|
|||||||
|
|
||||||
userID, err := in.authenticate(ctx, accessToken)
|
userID, err := in.authenticate(ctx, accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsAuthenticationAllowed(serverInfo.FullMethod) {
|
if isUnauthorizeAllowedMethod(serverInfo.FullMethod) {
|
||||||
return handler(ctx, request)
|
return handler(ctx, request)
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
user, err := in.Store.GetUser(ctx, &store.FindUser{
|
||||||
|
ID: &userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to get user")
|
||||||
|
}
|
||||||
|
if user == nil {
|
||||||
|
return nil, status.Errorf(codes.Unauthenticated, "user ID %q not exists in the access token", userID)
|
||||||
|
}
|
||||||
|
if isOnlyForAdminAllowedMethod(serverInfo.FullMethod) && user.Role != store.RoleAdmin {
|
||||||
|
return nil, status.Errorf(codes.PermissionDenied, "user ID %q is not admin", userID)
|
||||||
|
}
|
||||||
|
|
||||||
userAccessTokens, err := in.Store.GetUserAccessTokens(ctx, userID)
|
userAccessTokens, err := in.Store.GetUserAccessTokens(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
23
api/v2/acl_config.go
Normal file
23
api/v2/acl_config.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package v2
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
var allowedMethodsWhenUnauthorized = map[string]bool{}
|
||||||
|
|
||||||
|
// isUnauthorizeAllowedMethod returns true if the method is allowed to be called when the user is not authorized.
|
||||||
|
func isUnauthorizeAllowedMethod(methodName string) bool {
|
||||||
|
if strings.HasPrefix(methodName, "/grpc.reflection") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return allowedMethodsWhenUnauthorized[methodName]
|
||||||
|
}
|
||||||
|
|
||||||
|
var allowedMethodsOnlyForAdmin = map[string]bool{
|
||||||
|
"/slash.api.v2.UserService/CreateUser": true,
|
||||||
|
"/slash.api.v2.UserService/DeleteUser": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// isOnlyForAdminAllowedMethod returns true if the method is allowed to be called only by admin.
|
||||||
|
func isOnlyForAdminAllowedMethod(methodName string) bool {
|
||||||
|
return allowedMethodsOnlyForAdmin[methodName]
|
||||||
|
}
|
@ -6,8 +6,10 @@ import (
|
|||||||
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
|
apiv2pb "github.com/boojack/slash/proto/gen/api/v2"
|
||||||
storepb "github.com/boojack/slash/proto/gen/store"
|
storepb "github.com/boojack/slash/proto/gen/store"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ShortcutService struct {
|
type ShortcutService struct {
|
||||||
@ -75,6 +77,91 @@ func (s *ShortcutService) GetShortcut(ctx context.Context, request *apiv2pb.GetS
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ShortcutService) CreateShortcut(ctx context.Context, request *apiv2pb.CreateShortcutRequest) (*apiv2pb.CreateShortcutResponse, error) {
|
||||||
|
userID := ctx.Value(UserIDContextKey).(int32)
|
||||||
|
shortcut := &storepb.Shortcut{
|
||||||
|
CreatorId: userID,
|
||||||
|
Name: request.Shortcut.Name,
|
||||||
|
Link: request.Shortcut.Link,
|
||||||
|
Title: request.Shortcut.Title,
|
||||||
|
Tags: request.Shortcut.Tags,
|
||||||
|
Description: request.Shortcut.Description,
|
||||||
|
Visibility: storepb.Visibility(request.Shortcut.Visibility),
|
||||||
|
OgMetadata: &storepb.OpenGraphMetadata{},
|
||||||
|
}
|
||||||
|
if request.Shortcut.OgMetadata != nil {
|
||||||
|
shortcut.OgMetadata = &storepb.OpenGraphMetadata{
|
||||||
|
Title: request.Shortcut.OgMetadata.Title,
|
||||||
|
Description: request.Shortcut.OgMetadata.Description,
|
||||||
|
Image: request.Shortcut.OgMetadata.Image,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shortcut, err := s.Store.CreateShortcut(ctx, shortcut)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to create shortcut, err: %v", err)
|
||||||
|
}
|
||||||
|
if err := s.createShortcutCreateActivity(ctx, shortcut); err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to create activity, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &apiv2pb.CreateShortcutResponse{
|
||||||
|
Shortcut: convertShortcutFromStorepb(shortcut),
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShortcutService) DeleteShortcut(ctx context.Context, request *apiv2pb.DeleteShortcutRequest) (*apiv2pb.DeleteShortcutResponse, error) {
|
||||||
|
userID := ctx.Value(UserIDContextKey).(int32)
|
||||||
|
currentUser, err := s.Store.GetUser(ctx, &store.FindUser{
|
||||||
|
ID: &userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to get current user, err: %v", err)
|
||||||
|
}
|
||||||
|
shortcut, err := s.Store.GetShortcut(ctx, &store.FindShortcut{
|
||||||
|
Name: &request.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to get shortcut by name: %v", err)
|
||||||
|
}
|
||||||
|
if shortcut == nil {
|
||||||
|
return nil, status.Errorf(codes.NotFound, "shortcut not found")
|
||||||
|
}
|
||||||
|
if shortcut.CreatorId != userID && currentUser.Role != store.RoleAdmin {
|
||||||
|
return nil, status.Errorf(codes.PermissionDenied, "Permission denied")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.Store.DeleteShortcut(ctx, &store.DeleteShortcut{
|
||||||
|
ID: shortcut.Id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to delete shortcut, err: %v", err)
|
||||||
|
}
|
||||||
|
response := &apiv2pb.DeleteShortcutResponse{}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ShortcutService) createShortcutCreateActivity(ctx context.Context, shortcut *storepb.Shortcut) error {
|
||||||
|
payload := &storepb.ActivityShorcutCreatePayload{
|
||||||
|
ShortcutId: shortcut.Id,
|
||||||
|
}
|
||||||
|
payloadStr, err := protojson.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to marshal activity payload")
|
||||||
|
}
|
||||||
|
activity := &store.Activity{
|
||||||
|
CreatorID: shortcut.CreatorId,
|
||||||
|
Type: store.ActivityShortcutCreate,
|
||||||
|
Level: store.ActivityInfo,
|
||||||
|
Payload: string(payloadStr),
|
||||||
|
}
|
||||||
|
_, err = s.Store.CreateActivity(ctx, activity)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to create activity")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func convertShortcutFromStorepb(shortcut *storepb.Shortcut) *apiv2pb.Shortcut {
|
func convertShortcutFromStorepb(shortcut *storepb.Shortcut) *apiv2pb.Shortcut {
|
||||||
return &apiv2pb.Shortcut{
|
return &apiv2pb.Shortcut{
|
||||||
Id: shortcut.Id,
|
Id: shortcut.Id,
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
@ -30,6 +31,22 @@ func NewUserService(secret string, store *store.Store) *UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *UserService) ListUsers(ctx context.Context, _ *apiv2pb.ListUsersRequest) (*apiv2pb.ListUsersResponse, error) {
|
||||||
|
users, err := s.Store.ListUsers(ctx, &store.FindUser{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to list users: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userMessages := []*apiv2pb.User{}
|
||||||
|
for _, user := range users {
|
||||||
|
userMessages = append(userMessages, convertUserFromStore(user))
|
||||||
|
}
|
||||||
|
response := &apiv2pb.ListUsersResponse{
|
||||||
|
Users: userMessages,
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserRequest) (*apiv2pb.GetUserResponse, error) {
|
func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserRequest) (*apiv2pb.GetUserResponse, error) {
|
||||||
user, err := s.Store.GetUser(ctx, &store.FindUser{
|
user, err := s.Store.GetUser(ctx, &store.FindUser{
|
||||||
ID: &request.Id,
|
ID: &request.Id,
|
||||||
@ -48,6 +65,43 @@ func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserReque
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *UserService) CreateUser(ctx context.Context, request *apiv2pb.CreateUserRequest) (*apiv2pb.CreateUserResponse, error) {
|
||||||
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(request.User.Password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to hash password: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := s.Store.CreateUser(ctx, &store.User{
|
||||||
|
Email: request.User.Email,
|
||||||
|
Nickname: request.User.Nickname,
|
||||||
|
Role: store.RoleUser,
|
||||||
|
PasswordHash: string(passwordHash),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to create user: %v", err)
|
||||||
|
}
|
||||||
|
response := &apiv2pb.CreateUserResponse{
|
||||||
|
User: convertUserFromStore(user),
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *UserService) DeleteUser(ctx context.Context, request *apiv2pb.DeleteUserRequest) (*apiv2pb.DeleteUserResponse, error) {
|
||||||
|
userID := ctx.Value(UserIDContextKey).(int32)
|
||||||
|
if userID == request.Id {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "cannot delete yourself")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.Store.DeleteUser(ctx, &store.DeleteUser{
|
||||||
|
ID: request.Id,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to delete user: %v", err)
|
||||||
|
}
|
||||||
|
response := &apiv2pb.DeleteUserResponse{}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *UserService) ListUserAccessTokens(ctx context.Context, request *apiv2pb.ListUserAccessTokensRequest) (*apiv2pb.ListUserAccessTokensResponse, error) {
|
func (s *UserService) ListUserAccessTokens(ctx context.Context, request *apiv2pb.ListUserAccessTokensRequest) (*apiv2pb.ListUserAccessTokensResponse, error) {
|
||||||
userID := ctx.Value(UserIDContextKey).(int32)
|
userID := ctx.Value(UserIDContextKey).(int32)
|
||||||
if userID != request.Id {
|
if userID != request.Id {
|
||||||
|
@ -8,14 +8,15 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/boojack/slash/internal/log"
|
||||||
"github.com/spf13/viper"
|
|
||||||
_ "modernc.org/sqlite"
|
|
||||||
|
|
||||||
"github.com/boojack/slash/server"
|
"github.com/boojack/slash/server"
|
||||||
_profile "github.com/boojack/slash/server/profile"
|
_profile "github.com/boojack/slash/server/profile"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
"github.com/boojack/slash/store/db"
|
"github.com/boojack/slash/store/db"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -36,7 +37,7 @@ var (
|
|||||||
db := db.NewDB(profile)
|
db := db.NewDB(profile)
|
||||||
if err := db.Open(ctx); err != nil {
|
if err := db.Open(ctx); err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
fmt.Printf("failed to open db, error: %+v\n", err)
|
log.Error("failed to open database", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ var (
|
|||||||
s, err := server.NewServer(ctx, profile, storeInstance)
|
s, err := server.NewServer(ctx, profile, storeInstance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
fmt.Printf("failed to create server, error: %+v\n", err)
|
log.Error("failed to create server", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,16 +56,16 @@ var (
|
|||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
go func() {
|
go func() {
|
||||||
sig := <-c
|
sig := <-c
|
||||||
fmt.Printf("%s received.\n", sig.String())
|
log.Info(fmt.Sprintf("%s received.\n", sig.String()))
|
||||||
s.Shutdown(ctx)
|
s.Shutdown(ctx)
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
println(greetingBanner)
|
printGreetings()
|
||||||
fmt.Printf("Version %s has started at :%d\n", profile.Version, profile.Port)
|
|
||||||
if err := s.Start(ctx); err != nil {
|
if err := s.Start(ctx); err != nil {
|
||||||
if err != http.ErrServerClosed {
|
if err != http.ErrServerClosed {
|
||||||
fmt.Printf("failed to start server, error: %+v\n", err)
|
log.Error("failed to start server", zap.Error(err))
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,6 +77,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Execute() error {
|
func Execute() error {
|
||||||
|
defer log.Sync()
|
||||||
return rootCmd.Execute()
|
return rootCmd.Execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +111,7 @@ func initConfig() {
|
|||||||
var err error
|
var err error
|
||||||
profile, err = _profile.GetProfile()
|
profile, err = _profile.GetProfile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to get profile, error: %+v\n", err)
|
log.Error("failed to get profile", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +124,15 @@ func initConfig() {
|
|||||||
println("---")
|
println("---")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printGreetings() {
|
||||||
|
fmt.Println(greetingBanner)
|
||||||
|
fmt.Printf("Version %s has been started on port %d\n", profile.Version, profile.Port)
|
||||||
|
fmt.Println("---")
|
||||||
|
fmt.Println("See more in:")
|
||||||
|
fmt.Printf("👉GitHub: %s\n", "https://github.com/boojack/slash")
|
||||||
|
fmt.Println("---")
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := Execute()
|
err := Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,6 +4,12 @@ Slash provides a browser extension to help you use your shortcuts in the search
|
|||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
|
### Install the extension
|
||||||
|
|
||||||
|
For Chromuim based browsers, you can install the extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg).
|
||||||
|
|
||||||
|
For Firefox, we don't support the Firefox Add-ons platform yet. And we are working on it.
|
||||||
|
|
||||||
### Generate an access token
|
### Generate an access token
|
||||||
|
|
||||||
1. Go to your Slash instance and sign in with your account.
|
1. Go to your Slash instance and sign in with your account.
|
||||||
@ -16,14 +22,6 @@ Slash provides a browser extension to help you use your shortcuts in the search
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Install the extension
|
|
||||||
|
|
||||||
> **Note**: The extension is not published to the Chrome Web Store yet. You can install it from the source code.
|
|
||||||
|
|
||||||
For Chromuim based browsers, you can download the packed extension from the [resources](https://github.com/boojack/slash/tree/main/extension/resources).
|
|
||||||
|
|
||||||
For Firefox, we don't support the Firefox Add-ons platform yet. And we are working on it.
|
|
||||||
|
|
||||||
### Configure the extension
|
### Configure the extension
|
||||||
|
|
||||||
1. Click on the extension icon and click on the "Settings" button.
|
1. Click on the extension icon and click on the "Settings" button.
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "slash-extexnsion",
|
"name": "slash-extension",
|
||||||
"displayName": "Slash",
|
"displayName": "Slash",
|
||||||
"version": "0.1.0",
|
"version": "0.1.4",
|
||||||
"description": "An open source, self-hosted bookmarks and link sharing platform. Save and share your links very easily.",
|
"description": "An open source, self-hosted bookmarks and link sharing platform. Save and share your links very easily.",
|
||||||
"author": "steven",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "plasmo dev",
|
"dev": "plasmo dev",
|
||||||
"build": "plasmo build",
|
"build": "plasmo build",
|
||||||
@ -12,6 +11,7 @@
|
|||||||
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix"
|
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@bufbuild/protobuf": "^1.3.0",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/joy": "5.0.0-beta.0",
|
"@mui/joy": "5.0.0-beta.0",
|
||||||
@ -46,14 +46,11 @@
|
|||||||
"typescript": "5.1.6"
|
"typescript": "5.1.6"
|
||||||
},
|
},
|
||||||
"manifest": {
|
"manifest": {
|
||||||
"host_permissions": [
|
"omnibox": {
|
||||||
"http://*/*",
|
"keyword": "s"
|
||||||
"https://*/*"
|
},
|
||||||
],
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"tabs",
|
"tabs",
|
||||||
"activeTab",
|
|
||||||
"scripting",
|
|
||||||
"storage"
|
"storage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
7
extension/pnpm-lock.yaml
generated
7
extension/pnpm-lock.yaml
generated
@ -5,6 +5,9 @@ settings:
|
|||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@bufbuild/protobuf':
|
||||||
|
specifier: ^1.3.0
|
||||||
|
version: 1.3.0
|
||||||
'@emotion/react':
|
'@emotion/react':
|
||||||
specifier: ^11.11.1
|
specifier: ^11.11.1
|
||||||
version: 11.11.1(@types/react@18.2.15)(react@18.2.0)
|
version: 11.11.1(@types/react@18.2.15)(react@18.2.0)
|
||||||
@ -339,6 +342,10 @@ packages:
|
|||||||
'@babel/helper-validator-identifier': 7.22.5
|
'@babel/helper-validator-identifier': 7.22.5
|
||||||
to-fast-properties: 2.0.0
|
to-fast-properties: 2.0.0
|
||||||
|
|
||||||
|
/@bufbuild/protobuf@1.3.0:
|
||||||
|
resolution: {integrity: sha512-G372ods0pLt46yxVRsnP/e2btVPuuzArcMPFpIDeIwiGPuuglEs9y75iG0HMvZgncsj5TvbYRWqbVyOe3PLCWQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@emotion/babel-plugin@11.11.0:
|
/@emotion/babel-plugin@11.11.0:
|
||||||
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
|
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
Binary file not shown.
@ -20,6 +20,15 @@ chrome.tabs.onUpdated.addListener(async (tabId, _, tab) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
chrome.omnibox.onInputEntered.addListener(async (text) => {
|
||||||
|
const shortcuts = (await storage.getItem<Shortcut[]>("shortcuts")) || [];
|
||||||
|
const shortcut = shortcuts.find((shortcut) => shortcut.name === text);
|
||||||
|
if (!shortcut) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return chrome.tabs.update({ url: shortcut.link });
|
||||||
|
});
|
||||||
|
|
||||||
const getShortcutNameFromUrl = (urlString: string) => {
|
const getShortcutNameFromUrl = (urlString: string) => {
|
||||||
const matchResult = urlRegex.exec(urlString);
|
const matchResult = urlRegex.exec(urlString);
|
||||||
if (matchResult === null) {
|
if (matchResult === null) {
|
||||||
|
173
extension/src/components/CreateShortcutsButton.tsx
Normal file
173
extension/src/components/CreateShortcutsButton.tsx
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
import { Button, IconButton, Input, Modal, ModalDialog } from "@mui/joy";
|
||||||
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { toast } from "react-hot-toast";
|
||||||
|
import { CreateShortcutResponse, OpenGraphMetadata, Visibility } from "@/types/proto/api/v2/shortcut_service_pb";
|
||||||
|
import Icon from "./Icon";
|
||||||
|
|
||||||
|
const generateTempName = (length = 6) => {
|
||||||
|
let result = "";
|
||||||
|
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
const charactersLength = characters.length;
|
||||||
|
let counter = 0;
|
||||||
|
while (counter < length) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
link: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateShortcutsButton = () => {
|
||||||
|
const [domain] = useStorage("domain");
|
||||||
|
const [accessToken] = useStorage("access_token");
|
||||||
|
const [shortcuts, setShortcuts] = useStorage("shortcuts");
|
||||||
|
const [state, setState] = useState<State>({
|
||||||
|
name: "",
|
||||||
|
title: "",
|
||||||
|
link: "",
|
||||||
|
});
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showModal) {
|
||||||
|
document.body.style.height = "384px";
|
||||||
|
} else {
|
||||||
|
document.body.style.height = "auto";
|
||||||
|
}
|
||||||
|
}, [showModal]);
|
||||||
|
|
||||||
|
const handleCreateShortcutButtonClick = async () => {
|
||||||
|
chrome.tabs.query({ active: true, currentWindow: true }, async (tabs) => {
|
||||||
|
if (tabs.length === 0) {
|
||||||
|
toast.error("No active tab found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tab = tabs[0];
|
||||||
|
setState((state) => ({
|
||||||
|
...state,
|
||||||
|
name: generateTempName().toLowerCase() + "-temp",
|
||||||
|
title: tab.title || "",
|
||||||
|
link: tab.url || "",
|
||||||
|
}));
|
||||||
|
setShowModal(true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNameInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setState((state) => ({
|
||||||
|
...state,
|
||||||
|
name: e.target.value,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTitleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setState((state) => ({
|
||||||
|
...state,
|
||||||
|
title: e.target.value,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLinkInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setState((state) => ({
|
||||||
|
...state,
|
||||||
|
link: e.target.value,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveBtnClick = async () => {
|
||||||
|
if (isLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!state.name) {
|
||||||
|
toast.error("Name is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
data: { shortcut },
|
||||||
|
} = await axios.post<CreateShortcutResponse>(
|
||||||
|
`${domain}/api/v2/shortcuts`,
|
||||||
|
{
|
||||||
|
name: state.name,
|
||||||
|
title: state.title,
|
||||||
|
link: state.link,
|
||||||
|
visibility: Visibility.PRIVATE,
|
||||||
|
ogMetadata: OpenGraphMetadata.fromJsonString("{}"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
setShortcuts([shortcut, ...shortcuts]);
|
||||||
|
toast.success("Shortcut created successfully");
|
||||||
|
setShowModal(false);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error);
|
||||||
|
toast.error(error.response.data.message);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IconButton color="primary" variant="solid" size="sm" onClick={() => handleCreateShortcutButtonClick()}>
|
||||||
|
<Icon.Plus className="w-5 h-auto" />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Modal container={() => document.body} open={showModal} onClose={() => setShowModal(false)}>
|
||||||
|
<ModalDialog className="w-3/4">
|
||||||
|
<div className="w-full flex flex-row justify-between items-center mb-2">
|
||||||
|
<span className="text-base font-medium">Create Shortcut</span>
|
||||||
|
<Button size="sm" variant="plain" onClick={() => setShowModal(false)}>
|
||||||
|
<Icon.X className="w-5 h-auto text-gray-600" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="overflow-x-hidden w-full flex flex-col justify-start items-center">
|
||||||
|
<div className="w-full flex flex-row justify-start items-center mb-2">
|
||||||
|
<span className="block w-12 mr-2 shrink-0">Name</span>
|
||||||
|
<Input className="grow" type="text" placeholder="Unique shortcut name" value={state.name} onChange={handleNameInputChange} />
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-row justify-start items-center mb-2">
|
||||||
|
<span className="block w-12 mr-2 shrink-0">Title</span>
|
||||||
|
<Input className="grow" type="text" placeholder="Shortcut title" value={state.title} onChange={handleTitleInputChange} />
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex flex-row justify-start items-center mb-2">
|
||||||
|
<span className="block w-12 mr-2 shrink-0">Link</span>
|
||||||
|
<Input
|
||||||
|
className="grow"
|
||||||
|
type="text"
|
||||||
|
placeholder="https://github.com/boojack/slash"
|
||||||
|
value={state.link}
|
||||||
|
onChange={handleLinkInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-full flex flex-row justify-end items-center mt-2 space-x-2">
|
||||||
|
<Button color="neutral" variant="plain" onClick={() => setShowModal(false)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button color="primary" disabled={isLoading} loading={isLoading} onClick={handleSaveBtnClick}>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalDialog>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CreateShortcutsButton;
|
12
extension/src/components/Logo.tsx
Normal file
12
extension/src/components/Logo.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import LogoBase64 from "data-base64:../..//assets/icon.png";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Logo = ({ className }: Props) => {
|
||||||
|
return <img className={classNames(className)} src={LogoBase64} alt="" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
@ -1,17 +1,15 @@
|
|||||||
import { Button } from "@mui/joy";
|
import { IconButton } from "@mui/joy";
|
||||||
import { useStorage } from "@plasmohq/storage/hook";
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { ListShortcutsResponse } from "@/types/proto/api/v2/shortcut_service_pb";
|
import { ListShortcutsResponse } from "@/types/proto/api/v2/shortcut_service_pb";
|
||||||
import "../style.css";
|
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
const PullShortcutsButton = () => {
|
const PullShortcutsButton = () => {
|
||||||
const [domain] = useStorage("domain");
|
const [domain] = useStorage("domain");
|
||||||
const [accessToken] = useStorage("access_token");
|
const [accessToken] = useStorage("access_token");
|
||||||
const [, setShortcuts] = useStorage("shortcuts");
|
const [, setShortcuts] = useStorage("shortcuts");
|
||||||
const [isPulling, setIsPulling] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (domain && accessToken) {
|
if (domain && accessToken) {
|
||||||
@ -21,7 +19,6 @@ const PullShortcutsButton = () => {
|
|||||||
|
|
||||||
const handlePullShortcuts = async (silence = false) => {
|
const handlePullShortcuts = async (silence = false) => {
|
||||||
try {
|
try {
|
||||||
setIsPulling(true);
|
|
||||||
const {
|
const {
|
||||||
data: { shortcuts },
|
data: { shortcuts },
|
||||||
} = await axios.get<ListShortcutsResponse>(`${domain}/api/v2/shortcuts`, {
|
} = await axios.get<ListShortcutsResponse>(`${domain}/api/v2/shortcuts`, {
|
||||||
@ -36,13 +33,12 @@ const PullShortcutsButton = () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error("Failed to pull shortcuts, error: " + error.message);
|
toast.error("Failed to pull shortcuts, error: " + error.message);
|
||||||
}
|
}
|
||||||
setIsPulling(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button loading={isPulling} color="neutral" variant="plain" size="sm" onClick={() => handlePullShortcuts()}>
|
<IconButton color="neutral" variant="plain" size="sm" onClick={() => handlePullShortcuts()}>
|
||||||
<Icon.RefreshCcw className="w-4 h-auto" />
|
<Icon.RefreshCcw className="w-4 h-auto" />
|
||||||
</Button>
|
</IconButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import { Button, Input } from "@mui/joy";
|
import type { Shortcut } from "./types/proto/api/v2/shortcut_service_pb";
|
||||||
|
import { Button, Divider, Input } from "@mui/joy";
|
||||||
import { useStorage } from "@plasmohq/storage/hook";
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Toaster, toast } from "react-hot-toast";
|
import { Toaster, toast } from "react-hot-toast";
|
||||||
import Icon from "./components/Icon";
|
import Icon from "./components/Icon";
|
||||||
|
import Logo from "./components/Logo";
|
||||||
|
import PullShortcutsButton from "./components/PullShortcutsButton";
|
||||||
|
import ShortcutsContainer from "./components/ShortcutsContainer";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
@ -17,6 +21,8 @@ const IndexOptions = () => {
|
|||||||
domain,
|
domain,
|
||||||
accessToken,
|
accessToken,
|
||||||
});
|
});
|
||||||
|
const [shortcuts] = useStorage<Shortcut[]>("shortcuts", []);
|
||||||
|
const isInitialized = domain && accessToken;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSettingState({
|
setSettingState({
|
||||||
@ -41,16 +47,41 @@ const IndexOptions = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
<div className="w-full flex flex-row justify-center items-center">
|
||||||
|
<a
|
||||||
|
className="bg-yellow-100 mt-12 py-2 px-3 rounded-full border flex flex-row justify-start items-center cursor-pointer shadow hover:underline hover:text-blue-600"
|
||||||
|
href="https://github.com/boojack/slash#browser-extension"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Icon.HelpCircle className="w-4 h-auto" />
|
||||||
|
<span className="mx-1 text-sm">Need help? Check out the docs</span>
|
||||||
|
<Icon.ExternalLink className="w-4 h-auto" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="w-full max-w-lg mx-auto flex flex-col justify-start items-start mt-12">
|
<div className="w-full max-w-lg mx-auto flex flex-col justify-start items-start mt-12">
|
||||||
<h2 className="flex flex-row justify-start items-center mb-6 font-mono">
|
<h2 className="flex flex-row justify-start items-center mb-6 text-2xl">
|
||||||
<Icon.CircleSlash className="w-8 h-auto mr-2 text-gray-500" />
|
<Logo className="w-10 h-auto mr-2" />
|
||||||
<span className="text-lg">Slash</span>
|
<span>Slash</span>
|
||||||
<span className="mx-2 text-gray-400">/</span>
|
<span className="mx-2 text-gray-400">/</span>
|
||||||
<span className="text-lg">Setting</span>
|
<span>Setting</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<div className="w-full flex flex-col justify-start items-start">
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-4">
|
<div className="w-full flex flex-col justify-start items-start mb-4">
|
||||||
<span className="mb-2 text-base">Domain</span>
|
<div className="mb-2 text-base w-full flex flex-row justify-between items-center">
|
||||||
|
<span>Domain</span>
|
||||||
|
{domain !== "" && (
|
||||||
|
<a
|
||||||
|
className="text-sm flex flex-row justify-start items-center hover:underline hover:text-blue-600"
|
||||||
|
href={domain}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span className="mr-1">Go to my Slash</span>
|
||||||
|
<Icon.ExternalLink className="w-4 h-auto" />
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<Input
|
<Input
|
||||||
className="w-full"
|
className="w-full"
|
||||||
@ -79,6 +110,20 @@ const IndexOptions = () => {
|
|||||||
<Button onClick={handleSaveSetting}>Save</Button>
|
<Button onClick={handleSaveSetting}>Save</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{isInitialized && (
|
||||||
|
<>
|
||||||
|
<Divider className="!my-6" />
|
||||||
|
|
||||||
|
<h2 className="flex flex-row justify-start items-center mb-4">
|
||||||
|
<span className="text-lg">Shortcuts</span>
|
||||||
|
<span className="text-gray-500 mr-1">({shortcuts.length})</span>
|
||||||
|
<PullShortcutsButton />
|
||||||
|
</h2>
|
||||||
|
<ShortcutsContainer />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Toaster position="top-center" />
|
<Toaster position="top-center" />
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Button } from "@mui/joy";
|
import { Button, Divider, IconButton } from "@mui/joy";
|
||||||
import { useStorage } from "@plasmohq/storage/hook";
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
|
import CreateShortcutsButton from "@/components/CreateShortcutsButton";
|
||||||
|
import Icon from "@/components/Icon";
|
||||||
|
import Logo from "@/components/Logo";
|
||||||
|
import PullShortcutsButton from "@/components/PullShortcutsButton";
|
||||||
|
import ShortcutsContainer from "@/components/ShortcutsContainer";
|
||||||
import { Shortcut } from "@/types/proto/api/v2/shortcut_service_pb";
|
import { Shortcut } from "@/types/proto/api/v2/shortcut_service_pb";
|
||||||
import Icon from "./components/Icon";
|
|
||||||
import PullShortcutsButton from "./components/PullShortcutsButton";
|
|
||||||
import ShortcutsContainer from "./components/ShortcutsContainer";
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
const IndexPopup = () => {
|
const IndexPopup = () => {
|
||||||
@ -19,40 +21,69 @@ const IndexPopup = () => {
|
|||||||
|
|
||||||
const handleRefreshButtonClick = () => {
|
const handleRefreshButtonClick = () => {
|
||||||
chrome.runtime.reload();
|
chrome.runtime.reload();
|
||||||
|
chrome.browserAction.setPopup({ popup: "" });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full min-w-[480px] p-4">
|
<div className="w-full min-w-[512px] px-4 pt-4">
|
||||||
<div className="w-full flex flex-row justify-between items-center text-sm">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<div className="flex flex-row justify-start items-center font-mono">
|
<div className="flex flex-row justify-start items-center">
|
||||||
<Icon.CircleSlash className="w-5 h-auto mr-1 text-gray-500 -mt-0.5" />
|
<Logo className="w-6 h-auto mr-2" />
|
||||||
<span className="font-mono">Slash</span>
|
<span className="">Slash</span>
|
||||||
{isInitialized && (
|
{isInitialized && (
|
||||||
<>
|
<>
|
||||||
<span className="mx-1 text-gray-400">/</span>
|
<span className="mx-1 text-gray-400">/</span>
|
||||||
<span>Shortcuts</span>
|
<span>Shortcuts</span>
|
||||||
<span className="mr-1 text-gray-500">({shortcuts.length})</span>
|
<span className="text-gray-500 mr-0.5">({shortcuts.length})</span>
|
||||||
<PullShortcutsButton />
|
<PullShortcutsButton />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>{isInitialized && <CreateShortcutsButton />}</div>
|
||||||
<Button size="sm" variant="plain" color="neutral" onClick={handleSettingButtonClick}>
|
|
||||||
<Icon.Settings className="w-5 h-auto" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full mt-4">
|
<div className="w-full mt-4">
|
||||||
{isInitialized ? (
|
{isInitialized ? (
|
||||||
shortcuts.length !== 0 ? (
|
<>
|
||||||
|
{shortcuts.length !== 0 ? (
|
||||||
<ShortcutsContainer />
|
<ShortcutsContainer />
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full flex flex-col justify-center items-center">
|
<div className="w-full flex flex-col justify-center items-center">
|
||||||
<p>No shortcut found.</p>
|
<p>No shortcut found.</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)}
|
||||||
|
|
||||||
|
<Divider className="!mt-4 !mb-2 opacity-40" />
|
||||||
|
|
||||||
|
<div className="w-full flex flex-row justify-between items-center mb-2">
|
||||||
|
<div className="flex flex-row justify-start items-center">
|
||||||
|
<IconButton size="sm" variant="plain" color="neutral" onClick={handleSettingButtonClick}>
|
||||||
|
<Icon.Settings className="w-5 h-auto text-gray-500" />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
size="sm"
|
||||||
|
variant="plain"
|
||||||
|
color="neutral"
|
||||||
|
component="a"
|
||||||
|
href="https://github.com/boojack/slash"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Icon.Github className="w-5 h-auto text-gray-500" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row justify-end items-center">
|
||||||
|
<a
|
||||||
|
className="text-sm flex flex-row justify-start items-center text-gray-500 hover:underline hover:text-blue-600"
|
||||||
|
href={domain}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span className="mr-1">Go to my Slash</span>
|
||||||
|
<Icon.ExternalLink className="w-4 h-auto" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full flex flex-col justify-start items-center">
|
<div className="w-full flex flex-col justify-start items-center">
|
||||||
<p>No domain and access token found.</p>
|
<p>No domain and access token found.</p>
|
||||||
|
@ -236,3 +236,94 @@ export declare class GetShortcutResponse extends Message<GetShortcutResponse> {
|
|||||||
static equals(a: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined, b: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined): boolean;
|
static equals(a: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined, b: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutRequest
|
||||||
|
*/
|
||||||
|
export declare class CreateShortcutRequest extends Message<CreateShortcutRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.Shortcut shortcut = 1;
|
||||||
|
*/
|
||||||
|
shortcut?: Shortcut;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateShortcutRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateShortcutRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateShortcutRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateShortcutRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateShortcutRequest;
|
||||||
|
|
||||||
|
static equals(a: CreateShortcutRequest | PlainMessage<CreateShortcutRequest> | undefined, b: CreateShortcutRequest | PlainMessage<CreateShortcutRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutResponse
|
||||||
|
*/
|
||||||
|
export declare class CreateShortcutResponse extends Message<CreateShortcutResponse> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.Shortcut shortcut = 1;
|
||||||
|
*/
|
||||||
|
shortcut?: Shortcut;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateShortcutResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateShortcutResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateShortcutResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateShortcutResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateShortcutResponse;
|
||||||
|
|
||||||
|
static equals(a: CreateShortcutResponse | PlainMessage<CreateShortcutResponse> | undefined, b: CreateShortcutResponse | PlainMessage<CreateShortcutResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutRequest
|
||||||
|
*/
|
||||||
|
export declare class DeleteShortcutRequest extends Message<DeleteShortcutRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: string name = 1;
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<DeleteShortcutRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteShortcutRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteShortcutRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteShortcutRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteShortcutRequest;
|
||||||
|
|
||||||
|
static equals(a: DeleteShortcutRequest | PlainMessage<DeleteShortcutRequest> | undefined, b: DeleteShortcutRequest | PlainMessage<DeleteShortcutRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutResponse
|
||||||
|
*/
|
||||||
|
export declare class DeleteShortcutResponse extends Message<DeleteShortcutResponse> {
|
||||||
|
constructor(data?: PartialMessage<DeleteShortcutResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteShortcutResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteShortcutResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteShortcutResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteShortcutResponse;
|
||||||
|
|
||||||
|
static equals(a: DeleteShortcutResponse | PlainMessage<DeleteShortcutResponse> | undefined, b: DeleteShortcutResponse | PlainMessage<DeleteShortcutResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -90,3 +90,41 @@ export const GetShortcutResponse = proto3.makeMessageType(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutRequest
|
||||||
|
*/
|
||||||
|
export const CreateShortcutRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateShortcutRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "shortcut", kind: "message", T: Shortcut },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutResponse
|
||||||
|
*/
|
||||||
|
export const CreateShortcutResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateShortcutResponse",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "shortcut", kind: "message", T: Shortcut },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutRequest
|
||||||
|
*/
|
||||||
|
export const DeleteShortcutRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteShortcutRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutResponse
|
||||||
|
*/
|
||||||
|
export const DeleteShortcutResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteShortcutResponse",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
@ -66,6 +66,11 @@ export declare class User extends Message<User> {
|
|||||||
*/
|
*/
|
||||||
nickname: string;
|
nickname: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: string password = 9;
|
||||||
|
*/
|
||||||
|
password: string;
|
||||||
|
|
||||||
constructor(data?: PartialMessage<User>);
|
constructor(data?: PartialMessage<User>);
|
||||||
|
|
||||||
static readonly runtime: typeof proto3;
|
static readonly runtime: typeof proto3;
|
||||||
@ -81,6 +86,49 @@ export declare class User extends Message<User> {
|
|||||||
static equals(a: User | PlainMessage<User> | undefined, b: User | PlainMessage<User> | undefined): boolean;
|
static equals(a: User | PlainMessage<User> | undefined, b: User | PlainMessage<User> | undefined): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersRequest
|
||||||
|
*/
|
||||||
|
export declare class ListUsersRequest extends Message<ListUsersRequest> {
|
||||||
|
constructor(data?: PartialMessage<ListUsersRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.ListUsersRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListUsersRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListUsersRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListUsersRequest;
|
||||||
|
|
||||||
|
static equals(a: ListUsersRequest | PlainMessage<ListUsersRequest> | undefined, b: ListUsersRequest | PlainMessage<ListUsersRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersResponse
|
||||||
|
*/
|
||||||
|
export declare class ListUsersResponse extends Message<ListUsersResponse> {
|
||||||
|
/**
|
||||||
|
* @generated from field: repeated slash.api.v2.User users = 1;
|
||||||
|
*/
|
||||||
|
users: User[];
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<ListUsersResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.ListUsersResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListUsersResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListUsersResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListUsersResponse;
|
||||||
|
|
||||||
|
static equals(a: ListUsersResponse | PlainMessage<ListUsersResponse> | undefined, b: ListUsersResponse | PlainMessage<ListUsersResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message slash.api.v2.GetUserRequest
|
* @generated from message slash.api.v2.GetUserRequest
|
||||||
*/
|
*/
|
||||||
@ -129,6 +177,97 @@ export declare class GetUserResponse extends Message<GetUserResponse> {
|
|||||||
static equals(a: GetUserResponse | PlainMessage<GetUserResponse> | undefined, b: GetUserResponse | PlainMessage<GetUserResponse> | undefined): boolean;
|
static equals(a: GetUserResponse | PlainMessage<GetUserResponse> | undefined, b: GetUserResponse | PlainMessage<GetUserResponse> | undefined): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserRequest
|
||||||
|
*/
|
||||||
|
export declare class CreateUserRequest extends Message<CreateUserRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.User user = 1;
|
||||||
|
*/
|
||||||
|
user?: User;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateUserRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateUserRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateUserRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateUserRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateUserRequest;
|
||||||
|
|
||||||
|
static equals(a: CreateUserRequest | PlainMessage<CreateUserRequest> | undefined, b: CreateUserRequest | PlainMessage<CreateUserRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserResponse
|
||||||
|
*/
|
||||||
|
export declare class CreateUserResponse extends Message<CreateUserResponse> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.User user = 1;
|
||||||
|
*/
|
||||||
|
user?: User;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateUserResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateUserResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateUserResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateUserResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateUserResponse;
|
||||||
|
|
||||||
|
static equals(a: CreateUserResponse | PlainMessage<CreateUserResponse> | undefined, b: CreateUserResponse | PlainMessage<CreateUserResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserRequest
|
||||||
|
*/
|
||||||
|
export declare class DeleteUserRequest extends Message<DeleteUserRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 id = 1;
|
||||||
|
*/
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<DeleteUserRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteUserRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteUserRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteUserRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteUserRequest;
|
||||||
|
|
||||||
|
static equals(a: DeleteUserRequest | PlainMessage<DeleteUserRequest> | undefined, b: DeleteUserRequest | PlainMessage<DeleteUserRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserResponse
|
||||||
|
*/
|
||||||
|
export declare class DeleteUserResponse extends Message<DeleteUserResponse> {
|
||||||
|
constructor(data?: PartialMessage<DeleteUserResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteUserResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteUserResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteUserResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteUserResponse;
|
||||||
|
|
||||||
|
static equals(a: DeleteUserResponse | PlainMessage<DeleteUserResponse> | undefined, b: DeleteUserResponse | PlainMessage<DeleteUserResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
||||||
*/
|
*/
|
||||||
|
@ -31,6 +31,25 @@ export const User = proto3.makeMessageType(
|
|||||||
{ no: 6, name: "role", kind: "enum", T: proto3.getEnumType(Role) },
|
{ no: 6, name: "role", kind: "enum", T: proto3.getEnumType(Role) },
|
||||||
{ no: 7, name: "email", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
{ no: 7, name: "email", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
{ no: 8, name: "nickname", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
{ no: 8, name: "nickname", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
|
{ no: 9, name: "password", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersRequest
|
||||||
|
*/
|
||||||
|
export const ListUsersRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.ListUsersRequest",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersResponse
|
||||||
|
*/
|
||||||
|
export const ListUsersResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.ListUsersResponse",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "users", kind: "message", T: User, repeated: true },
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -54,6 +73,44 @@ export const GetUserResponse = proto3.makeMessageType(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserRequest
|
||||||
|
*/
|
||||||
|
export const CreateUserRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateUserRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "user", kind: "message", T: User },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserResponse
|
||||||
|
*/
|
||||||
|
export const CreateUserResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateUserResponse",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "user", kind: "message", T: User },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserRequest
|
||||||
|
*/
|
||||||
|
export const DeleteUserRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteUserRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "id", kind: "scalar", T: 5 /* ScalarType.INT32 */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserResponse
|
||||||
|
*/
|
||||||
|
export const DeleteUserResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteUserResponse",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
||||||
*/
|
*/
|
||||||
|
32
extension/src/types/proto/store/activity_pb.d.ts
vendored
Normal file
32
extension/src/types/proto/store/activity_pb.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// @generated by protoc-gen-es v1.3.0
|
||||||
|
// @generated from file store/activity.proto (package slash.store, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
|
||||||
|
import { Message, proto3 } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.store.ActivityShorcutCreatePayload
|
||||||
|
*/
|
||||||
|
export declare class ActivityShorcutCreatePayload extends Message<ActivityShorcutCreatePayload> {
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 shortcut_id = 1;
|
||||||
|
*/
|
||||||
|
shortcutId: number;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<ActivityShorcutCreatePayload>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.store.ActivityShorcutCreatePayload";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ActivityShorcutCreatePayload;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ActivityShorcutCreatePayload;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ActivityShorcutCreatePayload;
|
||||||
|
|
||||||
|
static equals(a: ActivityShorcutCreatePayload | PlainMessage<ActivityShorcutCreatePayload> | undefined, b: ActivityShorcutCreatePayload | PlainMessage<ActivityShorcutCreatePayload> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
17
extension/src/types/proto/store/activity_pb.js
Normal file
17
extension/src/types/proto/store/activity_pb.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// @generated by protoc-gen-es v1.3.0
|
||||||
|
// @generated from file store/activity.proto (package slash.store, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { proto3 } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.store.ActivityShorcutCreatePayload
|
||||||
|
*/
|
||||||
|
export const ActivityShorcutCreatePayload = proto3.makeMessageType(
|
||||||
|
"slash.store.ActivityShorcutCreatePayload",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "shortcut_id", kind: "scalar", T: 5 /* ScalarType.INT32 */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
4
go.mod
4
go.mod
@ -50,6 +50,8 @@ require (
|
|||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/subosito/gotenv v1.4.2 // indirect
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.8.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.6.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||||
@ -70,9 +72,11 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2
|
||||||
|
github.com/h2non/filetype v1.1.3
|
||||||
github.com/mssola/useragent v1.0.0
|
github.com/mssola/useragent v1.0.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
go.deanishe.net/favicon v0.1.0
|
go.deanishe.net/favicon v0.1.0
|
||||||
|
go.uber.org/zap v1.21.0
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
||||||
golang.org/x/mod v0.11.0
|
golang.org/x/mod v0.11.0
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e
|
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e
|
||||||
|
22
go.sum
22
go.sum
@ -44,6 +44,8 @@ github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5z
|
|||||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
@ -171,6 +173,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
|||||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y=
|
||||||
|
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
||||||
|
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
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/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
@ -290,6 +294,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||||||
github.com/yuin/goldmark v1.1.27/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=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.deanishe.net/favicon v0.1.0 h1:Afy941gjRik+DjUUcYHUxcztFEeFse2ITBkMMOlgefM=
|
go.deanishe.net/favicon v0.1.0 h1:Afy941gjRik+DjUUcYHUxcztFEeFse2ITBkMMOlgefM=
|
||||||
go.deanishe.net/favicon v0.1.0/go.mod h1:vIKVI+lUh8k3UAzaN4gjC+cpyatLQWmx0hVX4vLE8jU=
|
go.deanishe.net/favicon v0.1.0/go.mod h1:vIKVI+lUh8k3UAzaN4gjC+cpyatLQWmx0hVX4vLE8jU=
|
||||||
go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
||||||
@ -299,6 +304,16 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
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.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||||
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||||
|
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||||
|
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
|
||||||
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
@ -346,6 +361,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -380,6 +396,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
||||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@ -402,6 +419,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -440,7 +458,9 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -515,6 +535,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
|||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -630,6 +651,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
package errorutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Code is the error code.
|
|
||||||
type Code int
|
|
||||||
|
|
||||||
// Application error codes.
|
|
||||||
const (
|
|
||||||
// 0 ~ 99 general error.
|
|
||||||
Ok Code = 0
|
|
||||||
Internal Code = 1
|
|
||||||
NotAuthorized Code = 2
|
|
||||||
Invalid Code = 3
|
|
||||||
NotFound Code = 4
|
|
||||||
Conflict Code = 5
|
|
||||||
NotImplemented Code = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
// Error represents an application-specific error. Application errors can be
|
|
||||||
// unwrapped by the caller to extract out the code & message.
|
|
||||||
//
|
|
||||||
// Any non-application error (such as a disk error) should be reported as an
|
|
||||||
// Internal error and the human user should only see "Internal error" as the
|
|
||||||
// message. These low-level internal error details should only be logged and
|
|
||||||
// reported to the operator of the application (not the end user).
|
|
||||||
type Error struct {
|
|
||||||
// Machine-readable error code.
|
|
||||||
Code Code
|
|
||||||
|
|
||||||
// Embedded error.
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface. Not used by the application otherwise.
|
|
||||||
func (e *Error) Error() string {
|
|
||||||
return e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorCode unwraps an application error and returns its code.
|
|
||||||
// Non-application errors always return EINTERNAL.
|
|
||||||
func ErrorCode(err error) Code {
|
|
||||||
var e *Error
|
|
||||||
if err == nil {
|
|
||||||
return Ok
|
|
||||||
} else if errors.As(err, &e) {
|
|
||||||
return e.Code
|
|
||||||
}
|
|
||||||
return Internal
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorMessage unwraps an application error and returns its message.
|
|
||||||
// Non-application errors always return "Internal error".
|
|
||||||
func ErrorMessage(err error) string {
|
|
||||||
var e *Error
|
|
||||||
if err == nil {
|
|
||||||
return ""
|
|
||||||
} else if errors.As(err, &e) {
|
|
||||||
return e.Err.Error()
|
|
||||||
}
|
|
||||||
return "Internal error."
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf is a helper function to return an Error with a given code and error.
|
|
||||||
func Errorf(code Code, err error) *Error {
|
|
||||||
return &Error{
|
|
||||||
Code: code,
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
66
internal/log/logger.go
Normal file
66
internal/log/logger.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// `gl` is the global logger.
|
||||||
|
// Other packages should use public methods such as Info/Error to do the logging.
|
||||||
|
// For other types of logging, e.g. logging to a separate file, they should use their own loggers.
|
||||||
|
gl *zap.Logger
|
||||||
|
gLevel zap.AtomicLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initializes the global console logger.
|
||||||
|
func init() {
|
||||||
|
gLevel = zap.NewAtomicLevelAt(zap.InfoLevel)
|
||||||
|
gl, _ = zap.Config{
|
||||||
|
Level: gLevel,
|
||||||
|
Development: true,
|
||||||
|
// Use "console" to print readable stacktrace.
|
||||||
|
Encoding: "console",
|
||||||
|
EncoderConfig: zap.NewDevelopmentEncoderConfig(),
|
||||||
|
OutputPaths: []string{"stderr"},
|
||||||
|
ErrorOutputPaths: []string{"stderr"},
|
||||||
|
}.Build(
|
||||||
|
// Skip one caller stack to locate the correct caller.
|
||||||
|
zap.AddCallerSkip(1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLevel wraps the zap Level's SetLevel method.
|
||||||
|
func SetLevel(level zapcore.Level) {
|
||||||
|
gLevel.SetLevel(level)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnabledLevel wraps the zap Level's Enabled method.
|
||||||
|
func EnabledLevel(level zapcore.Level) bool {
|
||||||
|
return gLevel.Enabled(level)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug wraps the zap Logger's Debug method.
|
||||||
|
func Debug(msg string, fields ...zap.Field) {
|
||||||
|
gl.Debug(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info wraps the zap Logger's Info method.
|
||||||
|
func Info(msg string, fields ...zap.Field) {
|
||||||
|
gl.Info(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn wraps the zap Logger's Warn method.
|
||||||
|
func Warn(msg string, fields ...zap.Field) {
|
||||||
|
gl.Warn(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error wraps the zap Logger's Error method.
|
||||||
|
func Error(msg string, fields ...zap.Field) {
|
||||||
|
gl.Error(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync wraps the zap Logger's Sync method.
|
||||||
|
func Sync() {
|
||||||
|
_ = gl.Sync()
|
||||||
|
}
|
@ -9,6 +9,7 @@ import "google/api/client.proto";
|
|||||||
option go_package = "gen/api/v2";
|
option go_package = "gen/api/v2";
|
||||||
|
|
||||||
service ShortcutService {
|
service ShortcutService {
|
||||||
|
// ListShortcuts returns a list of shortcuts.
|
||||||
rpc ListShortcuts(ListShortcutsRequest) returns (ListShortcutsResponse) {
|
rpc ListShortcuts(ListShortcutsRequest) returns (ListShortcutsResponse) {
|
||||||
option (google.api.http) = {get: "/api/v2/shortcuts"};
|
option (google.api.http) = {get: "/api/v2/shortcuts"};
|
||||||
}
|
}
|
||||||
@ -17,6 +18,18 @@ service ShortcutService {
|
|||||||
option (google.api.http) = {get: "/api/v2/shortcuts/{name}"};
|
option (google.api.http) = {get: "/api/v2/shortcuts/{name}"};
|
||||||
option (google.api.method_signature) = "name";
|
option (google.api.method_signature) = "name";
|
||||||
}
|
}
|
||||||
|
// CreateShortcut creates a shortcut.
|
||||||
|
rpc CreateShortcut(CreateShortcutRequest) returns (CreateShortcutResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/api/v2/shortcuts"
|
||||||
|
body: "shortcut"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// DeleteShortcut deletes a shortcut by name.
|
||||||
|
rpc DeleteShortcut(DeleteShortcutRequest) returns (DeleteShortcutResponse) {
|
||||||
|
option (google.api.http) = {delete: "/api/v2/shortcuts/{name}"};
|
||||||
|
option (google.api.method_signature) = "name";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Shortcut {
|
message Shortcut {
|
||||||
@ -76,3 +89,17 @@ message GetShortcutRequest {
|
|||||||
message GetShortcutResponse {
|
message GetShortcutResponse {
|
||||||
Shortcut shortcut = 1;
|
Shortcut shortcut = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CreateShortcutRequest {
|
||||||
|
Shortcut shortcut = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateShortcutResponse {
|
||||||
|
Shortcut shortcut = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteShortcutRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteShortcutResponse {}
|
||||||
|
@ -10,11 +10,27 @@ import "google/protobuf/timestamp.proto";
|
|||||||
option go_package = "gen/api/v2";
|
option go_package = "gen/api/v2";
|
||||||
|
|
||||||
service UserService {
|
service UserService {
|
||||||
|
// ListUsers returns a list of users.
|
||||||
|
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
|
||||||
|
option (google.api.http) = {get: "/api/v2/users"};
|
||||||
|
}
|
||||||
// GetUser returns a user by id.
|
// GetUser returns a user by id.
|
||||||
rpc GetUser(GetUserRequest) returns (GetUserResponse) {
|
rpc GetUser(GetUserRequest) returns (GetUserResponse) {
|
||||||
option (google.api.http) = {get: "/api/v2/users/{id}"};
|
option (google.api.http) = {get: "/api/v2/users/{id}"};
|
||||||
option (google.api.method_signature) = "id";
|
option (google.api.method_signature) = "id";
|
||||||
}
|
}
|
||||||
|
// CreateUser creates a new user.
|
||||||
|
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/api/v2/users"
|
||||||
|
body: "user"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// DeleteUser deletes a user by id.
|
||||||
|
rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse) {
|
||||||
|
option (google.api.http) = {delete: "/api/v2/users/{id}"};
|
||||||
|
option (google.api.method_signature) = "id";
|
||||||
|
}
|
||||||
// ListUserAccessTokens returns a list of access tokens for a user.
|
// ListUserAccessTokens returns a list of access tokens for a user.
|
||||||
rpc ListUserAccessTokens(ListUserAccessTokensRequest) returns (ListUserAccessTokensResponse) {
|
rpc ListUserAccessTokens(ListUserAccessTokensRequest) returns (ListUserAccessTokensResponse) {
|
||||||
option (google.api.http) = {get: "/api/v2/users/{id}/access_tokens"};
|
option (google.api.http) = {get: "/api/v2/users/{id}/access_tokens"};
|
||||||
@ -49,6 +65,8 @@ message User {
|
|||||||
string email = 7;
|
string email = 7;
|
||||||
|
|
||||||
string nickname = 8;
|
string nickname = 8;
|
||||||
|
|
||||||
|
string password = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Role {
|
enum Role {
|
||||||
@ -59,6 +77,12 @@ enum Role {
|
|||||||
USER = 2;
|
USER = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListUsersRequest {}
|
||||||
|
|
||||||
|
message ListUsersResponse {
|
||||||
|
repeated User users = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message GetUserRequest {
|
message GetUserRequest {
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
}
|
}
|
||||||
@ -67,6 +91,20 @@ message GetUserResponse {
|
|||||||
User user = 1;
|
User user = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CreateUserRequest {
|
||||||
|
User user = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CreateUserResponse {
|
||||||
|
User user = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteUserRequest {
|
||||||
|
int32 id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteUserResponse {}
|
||||||
|
|
||||||
message ListUserAccessTokensRequest {
|
message ListUserAccessTokensRequest {
|
||||||
// id is the user id.
|
// id is the user id.
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
- [RowStatus](#slash-api-v2-RowStatus)
|
- [RowStatus](#slash-api-v2-RowStatus)
|
||||||
|
|
||||||
- [api/v2/shortcut_service.proto](#api_v2_shortcut_service-proto)
|
- [api/v2/shortcut_service.proto](#api_v2_shortcut_service-proto)
|
||||||
|
- [CreateShortcutRequest](#slash-api-v2-CreateShortcutRequest)
|
||||||
|
- [CreateShortcutResponse](#slash-api-v2-CreateShortcutResponse)
|
||||||
|
- [DeleteShortcutRequest](#slash-api-v2-DeleteShortcutRequest)
|
||||||
|
- [DeleteShortcutResponse](#slash-api-v2-DeleteShortcutResponse)
|
||||||
- [GetShortcutRequest](#slash-api-v2-GetShortcutRequest)
|
- [GetShortcutRequest](#slash-api-v2-GetShortcutRequest)
|
||||||
- [GetShortcutResponse](#slash-api-v2-GetShortcutResponse)
|
- [GetShortcutResponse](#slash-api-v2-GetShortcutResponse)
|
||||||
- [ListShortcutsRequest](#slash-api-v2-ListShortcutsRequest)
|
- [ListShortcutsRequest](#slash-api-v2-ListShortcutsRequest)
|
||||||
@ -21,12 +25,18 @@
|
|||||||
- [api/v2/user_service.proto](#api_v2_user_service-proto)
|
- [api/v2/user_service.proto](#api_v2_user_service-proto)
|
||||||
- [CreateUserAccessTokenRequest](#slash-api-v2-CreateUserAccessTokenRequest)
|
- [CreateUserAccessTokenRequest](#slash-api-v2-CreateUserAccessTokenRequest)
|
||||||
- [CreateUserAccessTokenResponse](#slash-api-v2-CreateUserAccessTokenResponse)
|
- [CreateUserAccessTokenResponse](#slash-api-v2-CreateUserAccessTokenResponse)
|
||||||
|
- [CreateUserRequest](#slash-api-v2-CreateUserRequest)
|
||||||
|
- [CreateUserResponse](#slash-api-v2-CreateUserResponse)
|
||||||
- [DeleteUserAccessTokenRequest](#slash-api-v2-DeleteUserAccessTokenRequest)
|
- [DeleteUserAccessTokenRequest](#slash-api-v2-DeleteUserAccessTokenRequest)
|
||||||
- [DeleteUserAccessTokenResponse](#slash-api-v2-DeleteUserAccessTokenResponse)
|
- [DeleteUserAccessTokenResponse](#slash-api-v2-DeleteUserAccessTokenResponse)
|
||||||
|
- [DeleteUserRequest](#slash-api-v2-DeleteUserRequest)
|
||||||
|
- [DeleteUserResponse](#slash-api-v2-DeleteUserResponse)
|
||||||
- [GetUserRequest](#slash-api-v2-GetUserRequest)
|
- [GetUserRequest](#slash-api-v2-GetUserRequest)
|
||||||
- [GetUserResponse](#slash-api-v2-GetUserResponse)
|
- [GetUserResponse](#slash-api-v2-GetUserResponse)
|
||||||
- [ListUserAccessTokensRequest](#slash-api-v2-ListUserAccessTokensRequest)
|
- [ListUserAccessTokensRequest](#slash-api-v2-ListUserAccessTokensRequest)
|
||||||
- [ListUserAccessTokensResponse](#slash-api-v2-ListUserAccessTokensResponse)
|
- [ListUserAccessTokensResponse](#slash-api-v2-ListUserAccessTokensResponse)
|
||||||
|
- [ListUsersRequest](#slash-api-v2-ListUsersRequest)
|
||||||
|
- [ListUsersResponse](#slash-api-v2-ListUsersResponse)
|
||||||
- [User](#slash-api-v2-User)
|
- [User](#slash-api-v2-User)
|
||||||
- [UserAccessToken](#slash-api-v2-UserAccessToken)
|
- [UserAccessToken](#slash-api-v2-UserAccessToken)
|
||||||
|
|
||||||
@ -74,6 +84,61 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-CreateShortcutRequest"></a>
|
||||||
|
|
||||||
|
### CreateShortcutRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| shortcut | [Shortcut](#slash-api-v2-Shortcut) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-CreateShortcutResponse"></a>
|
||||||
|
|
||||||
|
### CreateShortcutResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| shortcut | [Shortcut](#slash-api-v2-Shortcut) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-DeleteShortcutRequest"></a>
|
||||||
|
|
||||||
|
### DeleteShortcutRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| name | [string](#string) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-DeleteShortcutResponse"></a>
|
||||||
|
|
||||||
|
### DeleteShortcutResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="slash-api-v2-GetShortcutRequest"></a>
|
<a name="slash-api-v2-GetShortcutRequest"></a>
|
||||||
|
|
||||||
### GetShortcutRequest
|
### GetShortcutRequest
|
||||||
@ -199,8 +264,10 @@
|
|||||||
|
|
||||||
| Method Name | Request Type | Response Type | Description |
|
| Method Name | Request Type | Response Type | Description |
|
||||||
| ----------- | ------------ | ------------- | ------------|
|
| ----------- | ------------ | ------------- | ------------|
|
||||||
| ListShortcuts | [ListShortcutsRequest](#slash-api-v2-ListShortcutsRequest) | [ListShortcutsResponse](#slash-api-v2-ListShortcutsResponse) | |
|
| ListShortcuts | [ListShortcutsRequest](#slash-api-v2-ListShortcutsRequest) | [ListShortcutsResponse](#slash-api-v2-ListShortcutsResponse) | ListShortcuts returns a list of shortcuts. |
|
||||||
| GetShortcut | [GetShortcutRequest](#slash-api-v2-GetShortcutRequest) | [GetShortcutResponse](#slash-api-v2-GetShortcutResponse) | GetShortcut returns a shortcut by name. |
|
| GetShortcut | [GetShortcutRequest](#slash-api-v2-GetShortcutRequest) | [GetShortcutResponse](#slash-api-v2-GetShortcutResponse) | GetShortcut returns a shortcut by name. |
|
||||||
|
| CreateShortcut | [CreateShortcutRequest](#slash-api-v2-CreateShortcutRequest) | [CreateShortcutResponse](#slash-api-v2-CreateShortcutResponse) | CreateShortcut creates a shortcut. |
|
||||||
|
| DeleteShortcut | [DeleteShortcutRequest](#slash-api-v2-DeleteShortcutRequest) | [DeleteShortcutResponse](#slash-api-v2-DeleteShortcutResponse) | DeleteShortcut deletes a shortcut by name. |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -244,6 +311,36 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-CreateUserRequest"></a>
|
||||||
|
|
||||||
|
### CreateUserRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| user | [User](#slash-api-v2-User) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-CreateUserResponse"></a>
|
||||||
|
|
||||||
|
### CreateUserResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| user | [User](#slash-api-v2-User) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="slash-api-v2-DeleteUserAccessTokenRequest"></a>
|
<a name="slash-api-v2-DeleteUserAccessTokenRequest"></a>
|
||||||
|
|
||||||
### DeleteUserAccessTokenRequest
|
### DeleteUserAccessTokenRequest
|
||||||
@ -270,6 +367,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-DeleteUserRequest"></a>
|
||||||
|
|
||||||
|
### DeleteUserRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| id | [int32](#int32) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-DeleteUserResponse"></a>
|
||||||
|
|
||||||
|
### DeleteUserResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="slash-api-v2-GetUserRequest"></a>
|
<a name="slash-api-v2-GetUserRequest"></a>
|
||||||
|
|
||||||
### GetUserRequest
|
### GetUserRequest
|
||||||
@ -330,6 +452,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-ListUsersRequest"></a>
|
||||||
|
|
||||||
|
### ListUsersRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-api-v2-ListUsersResponse"></a>
|
||||||
|
|
||||||
|
### ListUsersResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| users | [User](#slash-api-v2-User) | repeated | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="slash-api-v2-User"></a>
|
<a name="slash-api-v2-User"></a>
|
||||||
|
|
||||||
### User
|
### User
|
||||||
@ -345,6 +492,7 @@
|
|||||||
| role | [Role](#slash-api-v2-Role) | | |
|
| role | [Role](#slash-api-v2-Role) | | |
|
||||||
| email | [string](#string) | | |
|
| email | [string](#string) | | |
|
||||||
| nickname | [string](#string) | | |
|
| nickname | [string](#string) | | |
|
||||||
|
| password | [string](#string) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -395,7 +543,10 @@
|
|||||||
|
|
||||||
| Method Name | Request Type | Response Type | Description |
|
| Method Name | Request Type | Response Type | Description |
|
||||||
| ----------- | ------------ | ------------- | ------------|
|
| ----------- | ------------ | ------------- | ------------|
|
||||||
|
| ListUsers | [ListUsersRequest](#slash-api-v2-ListUsersRequest) | [ListUsersResponse](#slash-api-v2-ListUsersResponse) | ListUsers returns a list of users. |
|
||||||
| GetUser | [GetUserRequest](#slash-api-v2-GetUserRequest) | [GetUserResponse](#slash-api-v2-GetUserResponse) | GetUser returns a user by id. |
|
| GetUser | [GetUserRequest](#slash-api-v2-GetUserRequest) | [GetUserResponse](#slash-api-v2-GetUserResponse) | GetUser returns a user by id. |
|
||||||
|
| CreateUser | [CreateUserRequest](#slash-api-v2-CreateUserRequest) | [CreateUserResponse](#slash-api-v2-CreateUserResponse) | CreateUser creates a new user. |
|
||||||
|
| DeleteUser | [DeleteUserRequest](#slash-api-v2-DeleteUserRequest) | [DeleteUserResponse](#slash-api-v2-DeleteUserResponse) | DeleteUser deletes a user by id. |
|
||||||
| ListUserAccessTokens | [ListUserAccessTokensRequest](#slash-api-v2-ListUserAccessTokensRequest) | [ListUserAccessTokensResponse](#slash-api-v2-ListUserAccessTokensResponse) | ListUserAccessTokens returns a list of access tokens for a user. |
|
| ListUserAccessTokens | [ListUserAccessTokensRequest](#slash-api-v2-ListUserAccessTokensRequest) | [ListUserAccessTokensResponse](#slash-api-v2-ListUserAccessTokensResponse) | ListUserAccessTokens returns a list of access tokens for a user. |
|
||||||
| CreateUserAccessToken | [CreateUserAccessTokenRequest](#slash-api-v2-CreateUserAccessTokenRequest) | [CreateUserAccessTokenResponse](#slash-api-v2-CreateUserAccessTokenResponse) | CreateUserAccessToken creates a new access token for a user. |
|
| CreateUserAccessToken | [CreateUserAccessTokenRequest](#slash-api-v2-CreateUserAccessTokenRequest) | [CreateUserAccessTokenResponse](#slash-api-v2-CreateUserAccessTokenResponse) | CreateUserAccessToken creates a new access token for a user. |
|
||||||
| DeleteUserAccessToken | [DeleteUserAccessTokenRequest](#slash-api-v2-DeleteUserAccessTokenRequest) | [DeleteUserAccessTokenResponse](#slash-api-v2-DeleteUserAccessTokenResponse) | DeleteUserAccessToken deletes an access token for a user. |
|
| DeleteUserAccessToken | [DeleteUserAccessTokenRequest](#slash-api-v2-DeleteUserAccessTokenRequest) | [DeleteUserAccessTokenResponse](#slash-api-v2-DeleteUserAccessTokenResponse) | DeleteUserAccessToken deletes an access token for a user. |
|
||||||
|
@ -450,6 +450,185 @@ func (x *GetShortcutResponse) GetShortcut() *Shortcut {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateShortcutRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Shortcut *Shortcut `protobuf:"bytes,1,opt,name=shortcut,proto3" json:"shortcut,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateShortcutRequest) Reset() {
|
||||||
|
*x = CreateShortcutRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_v2_shortcut_service_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateShortcutRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CreateShortcutRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CreateShortcutRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_v2_shortcut_service_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 CreateShortcutRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CreateShortcutRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_v2_shortcut_service_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateShortcutRequest) GetShortcut() *Shortcut {
|
||||||
|
if x != nil {
|
||||||
|
return x.Shortcut
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateShortcutResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Shortcut *Shortcut `protobuf:"bytes,1,opt,name=shortcut,proto3" json:"shortcut,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateShortcutResponse) Reset() {
|
||||||
|
*x = CreateShortcutResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_v2_shortcut_service_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateShortcutResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CreateShortcutResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CreateShortcutResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_v2_shortcut_service_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 CreateShortcutResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CreateShortcutResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_v2_shortcut_service_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CreateShortcutResponse) GetShortcut() *Shortcut {
|
||||||
|
if x != nil {
|
||||||
|
return x.Shortcut
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteShortcutRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutRequest) Reset() {
|
||||||
|
*x = DeleteShortcutRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_v2_shortcut_service_proto_msgTypes[8]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*DeleteShortcutRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_v2_shortcut_service_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 DeleteShortcutRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*DeleteShortcutRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_v2_shortcut_service_proto_rawDescGZIP(), []int{8}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutRequest) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeleteShortcutResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutResponse) Reset() {
|
||||||
|
*x = DeleteShortcutResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_api_v2_shortcut_service_proto_msgTypes[9]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*DeleteShortcutResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *DeleteShortcutResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_api_v2_shortcut_service_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 DeleteShortcutResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*DeleteShortcutResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_api_v2_shortcut_service_proto_rawDescGZIP(), []int{9}
|
||||||
|
}
|
||||||
|
|
||||||
var File_api_v2_shortcut_service_proto protoreflect.FileDescriptor
|
var File_api_v2_shortcut_service_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_api_v2_shortcut_service_proto_rawDesc = []byte{
|
var file_api_v2_shortcut_service_proto_rawDesc = []byte{
|
||||||
@ -506,40 +685,71 @@ var file_api_v2_shortcut_service_proto_rawDesc = []byte{
|
|||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63,
|
||||||
0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
||||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74,
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74,
|
||||||
0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x2a, 0x50, 0x0a, 0x0a, 0x56, 0x69,
|
0x52, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x22, 0x4b, 0x0a, 0x15, 0x43, 0x72,
|
||||||
0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x49, 0x53, 0x49,
|
0x65, 0x61, 0x74, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75,
|
||||||
0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
|
0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x18,
|
||||||
0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x10,
|
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70,
|
||||||
0x01, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x10, 0x02,
|
0x69, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x08, 0x73,
|
||||||
0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x03, 0x32, 0x83, 0x02, 0x0a,
|
0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x22, 0x4c, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||||
0x0f, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x12, 0x73, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74,
|
0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x18, 0x01, 0x20,
|
||||||
0x73, 0x12, 0x22, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32,
|
0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73, 0x52, 0x65,
|
0x76, 0x32, 0x2e, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x08, 0x73, 0x68, 0x6f,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70,
|
0x72, 0x74, 0x63, 0x75, 0x74, 0x22, 0x2b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53,
|
||||||
0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75,
|
0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,
|
||||||
0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93,
|
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||||
0x02, 0x13, 0x12, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x68, 0x6f, 0x72,
|
0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x68, 0x6f, 0x72,
|
||||||
0x74, 0x63, 0x75, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x72,
|
0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x50, 0x0a, 0x0a,
|
||||||
0x74, 0x63, 0x75, 0x74, 0x12, 0x20, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69,
|
0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x49,
|
||||||
0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52,
|
0x53, 0x49, 0x42, 0x49, 0x4c, 0x49, 0x54, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61,
|
0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54,
|
||||||
|
0x45, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45,
|
||||||
|
0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x03, 0x32, 0x8d,
|
||||||
|
0x04, 0x0a, 0x0f, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
|
||||||
|
0x63, 0x65, 0x12, 0x73, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63,
|
||||||
|
0x75, 0x74, 0x73, 0x12, 0x22, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||||
|
0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e,
|
||||||
|
0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74,
|
||||||
|
0x63, 0x75, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3,
|
||||||
|
0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x68,
|
||||||
|
0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x53, 0x68,
|
||||||
|
0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x12, 0x20, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61,
|
||||||
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75,
|
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75,
|
||||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0xda, 0x41, 0x04, 0x6e, 0x61,
|
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
||||||
0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76,
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x72, 0x74,
|
||||||
0x32, 0x2f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73, 0x2f, 0x7b, 0x6e, 0x61, 0x6d,
|
0x63, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0xda, 0x41, 0x04,
|
||||||
0x65, 0x7d, 0x42, 0xab, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x61, 0x70, 0x69,
|
||||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x14, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75,
|
0x2f, 0x76, 0x32, 0x2f, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73, 0x2f, 0x7b, 0x6e,
|
||||||
0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
|
0x61, 0x6d, 0x65, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53,
|
||||||
0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a,
|
0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x12, 0x23, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e,
|
||||||
0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x68, 0x6f,
|
||||||
0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32,
|
0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73,
|
||||||
0xa2, 0x02, 0x03, 0x53, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x41,
|
0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61,
|
||||||
0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70,
|
0x74, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||||
0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69,
|
0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x08, 0x73, 0x68, 0x6f, 0x72,
|
||||||
0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea,
|
0x74, 0x63, 0x75, 0x74, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x68,
|
||||||
0x02, 0x0e, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32,
|
0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73, 0x12, 0x84, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65,
|
||||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x74, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x12, 0x23, 0x2e, 0x73, 0x6c, 0x61,
|
||||||
|
0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||||
|
0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
|
0x24, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x44,
|
||||||
|
0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x52, 0x65, 0x73,
|
||||||
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x82, 0xd3,
|
||||||
|
0xe4, 0x93, 0x02, 0x1a, 0x2a, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x68,
|
||||||
|
0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x73, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x42, 0xab,
|
||||||
|
0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69,
|
||||||
|
0x2e, 0x76, 0x32, 0x42, 0x14, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x53, 0x65, 0x72,
|
||||||
|
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74,
|
||||||
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f,
|
||||||
|
0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f,
|
||||||
|
0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x53,
|
||||||
|
0x41, 0x58, 0xaa, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56,
|
||||||
|
0x32, 0xca, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32,
|
||||||
|
0xe2, 0x02, 0x18, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c,
|
||||||
|
0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x53, 0x6c,
|
||||||
|
0x61, 0x73, 0x68, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72,
|
||||||
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -555,7 +765,7 @@ func file_api_v2_shortcut_service_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_api_v2_shortcut_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_api_v2_shortcut_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_api_v2_shortcut_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
var file_api_v2_shortcut_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||||
var file_api_v2_shortcut_service_proto_goTypes = []interface{}{
|
var file_api_v2_shortcut_service_proto_goTypes = []interface{}{
|
||||||
(Visibility)(0), // 0: slash.api.v2.Visibility
|
(Visibility)(0), // 0: slash.api.v2.Visibility
|
||||||
(*Shortcut)(nil), // 1: slash.api.v2.Shortcut
|
(*Shortcut)(nil), // 1: slash.api.v2.Shortcut
|
||||||
@ -564,23 +774,33 @@ var file_api_v2_shortcut_service_proto_goTypes = []interface{}{
|
|||||||
(*ListShortcutsResponse)(nil), // 4: slash.api.v2.ListShortcutsResponse
|
(*ListShortcutsResponse)(nil), // 4: slash.api.v2.ListShortcutsResponse
|
||||||
(*GetShortcutRequest)(nil), // 5: slash.api.v2.GetShortcutRequest
|
(*GetShortcutRequest)(nil), // 5: slash.api.v2.GetShortcutRequest
|
||||||
(*GetShortcutResponse)(nil), // 6: slash.api.v2.GetShortcutResponse
|
(*GetShortcutResponse)(nil), // 6: slash.api.v2.GetShortcutResponse
|
||||||
(RowStatus)(0), // 7: slash.api.v2.RowStatus
|
(*CreateShortcutRequest)(nil), // 7: slash.api.v2.CreateShortcutRequest
|
||||||
|
(*CreateShortcutResponse)(nil), // 8: slash.api.v2.CreateShortcutResponse
|
||||||
|
(*DeleteShortcutRequest)(nil), // 9: slash.api.v2.DeleteShortcutRequest
|
||||||
|
(*DeleteShortcutResponse)(nil), // 10: slash.api.v2.DeleteShortcutResponse
|
||||||
|
(RowStatus)(0), // 11: slash.api.v2.RowStatus
|
||||||
}
|
}
|
||||||
var file_api_v2_shortcut_service_proto_depIdxs = []int32{
|
var file_api_v2_shortcut_service_proto_depIdxs = []int32{
|
||||||
7, // 0: slash.api.v2.Shortcut.row_status:type_name -> slash.api.v2.RowStatus
|
11, // 0: slash.api.v2.Shortcut.row_status:type_name -> slash.api.v2.RowStatus
|
||||||
0, // 1: slash.api.v2.Shortcut.visibility:type_name -> slash.api.v2.Visibility
|
0, // 1: slash.api.v2.Shortcut.visibility:type_name -> slash.api.v2.Visibility
|
||||||
2, // 2: slash.api.v2.Shortcut.og_metadata:type_name -> slash.api.v2.OpenGraphMetadata
|
2, // 2: slash.api.v2.Shortcut.og_metadata:type_name -> slash.api.v2.OpenGraphMetadata
|
||||||
1, // 3: slash.api.v2.ListShortcutsResponse.shortcuts:type_name -> slash.api.v2.Shortcut
|
1, // 3: slash.api.v2.ListShortcutsResponse.shortcuts:type_name -> slash.api.v2.Shortcut
|
||||||
1, // 4: slash.api.v2.GetShortcutResponse.shortcut:type_name -> slash.api.v2.Shortcut
|
1, // 4: slash.api.v2.GetShortcutResponse.shortcut:type_name -> slash.api.v2.Shortcut
|
||||||
3, // 5: slash.api.v2.ShortcutService.ListShortcuts:input_type -> slash.api.v2.ListShortcutsRequest
|
1, // 5: slash.api.v2.CreateShortcutRequest.shortcut:type_name -> slash.api.v2.Shortcut
|
||||||
5, // 6: slash.api.v2.ShortcutService.GetShortcut:input_type -> slash.api.v2.GetShortcutRequest
|
1, // 6: slash.api.v2.CreateShortcutResponse.shortcut:type_name -> slash.api.v2.Shortcut
|
||||||
4, // 7: slash.api.v2.ShortcutService.ListShortcuts:output_type -> slash.api.v2.ListShortcutsResponse
|
3, // 7: slash.api.v2.ShortcutService.ListShortcuts:input_type -> slash.api.v2.ListShortcutsRequest
|
||||||
6, // 8: slash.api.v2.ShortcutService.GetShortcut:output_type -> slash.api.v2.GetShortcutResponse
|
5, // 8: slash.api.v2.ShortcutService.GetShortcut:input_type -> slash.api.v2.GetShortcutRequest
|
||||||
7, // [7:9] is the sub-list for method output_type
|
7, // 9: slash.api.v2.ShortcutService.CreateShortcut:input_type -> slash.api.v2.CreateShortcutRequest
|
||||||
5, // [5:7] is the sub-list for method input_type
|
9, // 10: slash.api.v2.ShortcutService.DeleteShortcut:input_type -> slash.api.v2.DeleteShortcutRequest
|
||||||
5, // [5:5] is the sub-list for extension type_name
|
4, // 11: slash.api.v2.ShortcutService.ListShortcuts:output_type -> slash.api.v2.ListShortcutsResponse
|
||||||
5, // [5:5] is the sub-list for extension extendee
|
6, // 12: slash.api.v2.ShortcutService.GetShortcut:output_type -> slash.api.v2.GetShortcutResponse
|
||||||
0, // [0:5] is the sub-list for field type_name
|
8, // 13: slash.api.v2.ShortcutService.CreateShortcut:output_type -> slash.api.v2.CreateShortcutResponse
|
||||||
|
10, // 14: slash.api.v2.ShortcutService.DeleteShortcut:output_type -> slash.api.v2.DeleteShortcutResponse
|
||||||
|
11, // [11:15] is the sub-list for method output_type
|
||||||
|
7, // [7:11] is the sub-list for method input_type
|
||||||
|
7, // [7:7] is the sub-list for extension type_name
|
||||||
|
7, // [7:7] is the sub-list for extension extendee
|
||||||
|
0, // [0:7] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_api_v2_shortcut_service_proto_init() }
|
func init() { file_api_v2_shortcut_service_proto_init() }
|
||||||
@ -662,6 +882,54 @@ func file_api_v2_shortcut_service_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_api_v2_shortcut_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CreateShortcutRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_v2_shortcut_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*CreateShortcutResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_v2_shortcut_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*DeleteShortcutRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_api_v2_shortcut_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*DeleteShortcutResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
@ -669,7 +937,7 @@ func file_api_v2_shortcut_service_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_api_v2_shortcut_service_proto_rawDesc,
|
RawDescriptor: file_api_v2_shortcut_service_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 1,
|
||||||
NumMessages: 6,
|
NumMessages: 10,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
@ -101,6 +101,92 @@ func local_request_ShortcutService_GetShortcut_0(ctx context.Context, marshaler
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func request_ShortcutService_CreateShortcut_0(ctx context.Context, marshaler runtime.Marshaler, client ShortcutServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq CreateShortcutRequest
|
||||||
|
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.Shortcut); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.CreateShortcut(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_ShortcutService_CreateShortcut_0(ctx context.Context, marshaler runtime.Marshaler, server ShortcutServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq CreateShortcutRequest
|
||||||
|
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.Shortcut); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.CreateShortcut(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func request_ShortcutService_DeleteShortcut_0(ctx context.Context, marshaler runtime.Marshaler, client ShortcutServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq DeleteShortcutRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
var (
|
||||||
|
val string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
_ = err
|
||||||
|
)
|
||||||
|
|
||||||
|
val, ok = pathParams["name"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.Name, err = runtime.String(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.DeleteShortcut(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_ShortcutService_DeleteShortcut_0(ctx context.Context, marshaler runtime.Marshaler, server ShortcutServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq DeleteShortcutRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
var (
|
||||||
|
val string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
_ = err
|
||||||
|
)
|
||||||
|
|
||||||
|
val, ok = pathParams["name"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.Name, err = runtime.String(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.DeleteShortcut(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterShortcutServiceHandlerServer registers the http handlers for service ShortcutService to "mux".
|
// RegisterShortcutServiceHandlerServer registers the http handlers for service ShortcutService to "mux".
|
||||||
// UnaryRPC :call ShortcutServiceServer directly.
|
// UnaryRPC :call ShortcutServiceServer directly.
|
||||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||||
@ -157,6 +243,56 @@ func RegisterShortcutServiceHandlerServer(ctx context.Context, mux *runtime.Serv
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_ShortcutService_CreateShortcut_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/slash.api.v2.ShortcutService/CreateShortcut", runtime.WithHTTPPathPattern("/api/v2/shortcuts"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_ShortcutService_CreateShortcut_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ShortcutService_CreateShortcut_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("DELETE", pattern_ShortcutService_DeleteShortcut_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/slash.api.v2.ShortcutService/DeleteShortcut", runtime.WithHTTPPathPattern("/api/v2/shortcuts/{name}"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_ShortcutService_DeleteShortcut_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ShortcutService_DeleteShortcut_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +378,50 @@ func RegisterShortcutServiceHandlerClient(ctx context.Context, mux *runtime.Serv
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_ShortcutService_CreateShortcut_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/slash.api.v2.ShortcutService/CreateShortcut", runtime.WithHTTPPathPattern("/api/v2/shortcuts"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_ShortcutService_CreateShortcut_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ShortcutService_CreateShortcut_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.Handle("DELETE", pattern_ShortcutService_DeleteShortcut_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/slash.api.v2.ShortcutService/DeleteShortcut", runtime.WithHTTPPathPattern("/api/v2/shortcuts/{name}"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_ShortcutService_DeleteShortcut_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_ShortcutService_DeleteShortcut_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,10 +429,18 @@ var (
|
|||||||
pattern_ShortcutService_ListShortcuts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "shortcuts"}, ""))
|
pattern_ShortcutService_ListShortcuts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "shortcuts"}, ""))
|
||||||
|
|
||||||
pattern_ShortcutService_GetShortcut_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "shortcuts", "name"}, ""))
|
pattern_ShortcutService_GetShortcut_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "shortcuts", "name"}, ""))
|
||||||
|
|
||||||
|
pattern_ShortcutService_CreateShortcut_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "shortcuts"}, ""))
|
||||||
|
|
||||||
|
pattern_ShortcutService_DeleteShortcut_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "shortcuts", "name"}, ""))
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
forward_ShortcutService_ListShortcuts_0 = runtime.ForwardResponseMessage
|
forward_ShortcutService_ListShortcuts_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_ShortcutService_GetShortcut_0 = runtime.ForwardResponseMessage
|
forward_ShortcutService_GetShortcut_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_ShortcutService_CreateShortcut_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_ShortcutService_DeleteShortcut_0 = runtime.ForwardResponseMessage
|
||||||
)
|
)
|
||||||
|
@ -21,15 +21,22 @@ const _ = grpc.SupportPackageIsVersion7
|
|||||||
const (
|
const (
|
||||||
ShortcutService_ListShortcuts_FullMethodName = "/slash.api.v2.ShortcutService/ListShortcuts"
|
ShortcutService_ListShortcuts_FullMethodName = "/slash.api.v2.ShortcutService/ListShortcuts"
|
||||||
ShortcutService_GetShortcut_FullMethodName = "/slash.api.v2.ShortcutService/GetShortcut"
|
ShortcutService_GetShortcut_FullMethodName = "/slash.api.v2.ShortcutService/GetShortcut"
|
||||||
|
ShortcutService_CreateShortcut_FullMethodName = "/slash.api.v2.ShortcutService/CreateShortcut"
|
||||||
|
ShortcutService_DeleteShortcut_FullMethodName = "/slash.api.v2.ShortcutService/DeleteShortcut"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShortcutServiceClient is the client API for ShortcutService service.
|
// ShortcutServiceClient is the client API for ShortcutService 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.
|
// 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 ShortcutServiceClient interface {
|
type ShortcutServiceClient interface {
|
||||||
|
// ListShortcuts returns a list of shortcuts.
|
||||||
ListShortcuts(ctx context.Context, in *ListShortcutsRequest, opts ...grpc.CallOption) (*ListShortcutsResponse, error)
|
ListShortcuts(ctx context.Context, in *ListShortcutsRequest, opts ...grpc.CallOption) (*ListShortcutsResponse, error)
|
||||||
// GetShortcut returns a shortcut by name.
|
// GetShortcut returns a shortcut by name.
|
||||||
GetShortcut(ctx context.Context, in *GetShortcutRequest, opts ...grpc.CallOption) (*GetShortcutResponse, error)
|
GetShortcut(ctx context.Context, in *GetShortcutRequest, opts ...grpc.CallOption) (*GetShortcutResponse, error)
|
||||||
|
// CreateShortcut creates a shortcut.
|
||||||
|
CreateShortcut(ctx context.Context, in *CreateShortcutRequest, opts ...grpc.CallOption) (*CreateShortcutResponse, error)
|
||||||
|
// DeleteShortcut deletes a shortcut by name.
|
||||||
|
DeleteShortcut(ctx context.Context, in *DeleteShortcutRequest, opts ...grpc.CallOption) (*DeleteShortcutResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type shortcutServiceClient struct {
|
type shortcutServiceClient struct {
|
||||||
@ -58,13 +65,36 @@ func (c *shortcutServiceClient) GetShortcut(ctx context.Context, in *GetShortcut
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *shortcutServiceClient) CreateShortcut(ctx context.Context, in *CreateShortcutRequest, opts ...grpc.CallOption) (*CreateShortcutResponse, error) {
|
||||||
|
out := new(CreateShortcutResponse)
|
||||||
|
err := c.cc.Invoke(ctx, ShortcutService_CreateShortcut_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *shortcutServiceClient) DeleteShortcut(ctx context.Context, in *DeleteShortcutRequest, opts ...grpc.CallOption) (*DeleteShortcutResponse, error) {
|
||||||
|
out := new(DeleteShortcutResponse)
|
||||||
|
err := c.cc.Invoke(ctx, ShortcutService_DeleteShortcut_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ShortcutServiceServer is the server API for ShortcutService service.
|
// ShortcutServiceServer is the server API for ShortcutService service.
|
||||||
// All implementations must embed UnimplementedShortcutServiceServer
|
// All implementations must embed UnimplementedShortcutServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
type ShortcutServiceServer interface {
|
type ShortcutServiceServer interface {
|
||||||
|
// ListShortcuts returns a list of shortcuts.
|
||||||
ListShortcuts(context.Context, *ListShortcutsRequest) (*ListShortcutsResponse, error)
|
ListShortcuts(context.Context, *ListShortcutsRequest) (*ListShortcutsResponse, error)
|
||||||
// GetShortcut returns a shortcut by name.
|
// GetShortcut returns a shortcut by name.
|
||||||
GetShortcut(context.Context, *GetShortcutRequest) (*GetShortcutResponse, error)
|
GetShortcut(context.Context, *GetShortcutRequest) (*GetShortcutResponse, error)
|
||||||
|
// CreateShortcut creates a shortcut.
|
||||||
|
CreateShortcut(context.Context, *CreateShortcutRequest) (*CreateShortcutResponse, error)
|
||||||
|
// DeleteShortcut deletes a shortcut by name.
|
||||||
|
DeleteShortcut(context.Context, *DeleteShortcutRequest) (*DeleteShortcutResponse, error)
|
||||||
mustEmbedUnimplementedShortcutServiceServer()
|
mustEmbedUnimplementedShortcutServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +108,12 @@ func (UnimplementedShortcutServiceServer) ListShortcuts(context.Context, *ListSh
|
|||||||
func (UnimplementedShortcutServiceServer) GetShortcut(context.Context, *GetShortcutRequest) (*GetShortcutResponse, error) {
|
func (UnimplementedShortcutServiceServer) GetShortcut(context.Context, *GetShortcutRequest) (*GetShortcutResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetShortcut not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetShortcut not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedShortcutServiceServer) CreateShortcut(context.Context, *CreateShortcutRequest) (*CreateShortcutResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CreateShortcut not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedShortcutServiceServer) DeleteShortcut(context.Context, *DeleteShortcutRequest) (*DeleteShortcutResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method DeleteShortcut not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedShortcutServiceServer) mustEmbedUnimplementedShortcutServiceServer() {}
|
func (UnimplementedShortcutServiceServer) mustEmbedUnimplementedShortcutServiceServer() {}
|
||||||
|
|
||||||
// UnsafeShortcutServiceServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeShortcutServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
@ -127,6 +163,42 @@ func _ShortcutService_GetShortcut_Handler(srv interface{}, ctx context.Context,
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _ShortcutService_CreateShortcut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CreateShortcutRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ShortcutServiceServer).CreateShortcut(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: ShortcutService_CreateShortcut_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ShortcutServiceServer).CreateShortcut(ctx, req.(*CreateShortcutRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _ShortcutService_DeleteShortcut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(DeleteShortcutRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ShortcutServiceServer).DeleteShortcut(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: ShortcutService_DeleteShortcut_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ShortcutServiceServer).DeleteShortcut(ctx, req.(*DeleteShortcutRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
// ShortcutService_ServiceDesc is the grpc.ServiceDesc for ShortcutService service.
|
// ShortcutService_ServiceDesc is the grpc.ServiceDesc for ShortcutService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@ -142,6 +214,14 @@ var ShortcutService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "GetShortcut",
|
MethodName: "GetShortcut",
|
||||||
Handler: _ShortcutService_GetShortcut_Handler,
|
Handler: _ShortcutService_GetShortcut_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "CreateShortcut",
|
||||||
|
Handler: _ShortcutService_CreateShortcut_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "DeleteShortcut",
|
||||||
|
Handler: _ShortcutService_DeleteShortcut_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "api/v2/shortcut_service.proto",
|
Metadata: "api/v2/shortcut_service.proto",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,24 @@ var _ = runtime.String
|
|||||||
var _ = utilities.NewDoubleArray
|
var _ = utilities.NewDoubleArray
|
||||||
var _ = metadata.Join
|
var _ = metadata.Join
|
||||||
|
|
||||||
|
func request_UserService_ListUsers_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ListUsersRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
msg, err := client.ListUsers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_UserService_ListUsers_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ListUsersRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
msg, err := server.ListUsers(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq GetUserRequest
|
var protoReq GetUserRequest
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@ -83,6 +101,92 @@ func local_request_UserService_GetUser_0(ctx context.Context, marshaler runtime.
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func request_UserService_CreateUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq CreateUserRequest
|
||||||
|
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.User); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.CreateUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_UserService_CreateUser_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq CreateUserRequest
|
||||||
|
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.User); err != nil && err != io.EOF {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.CreateUser(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["id"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.Id, err = runtime.Int32(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", 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["id"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.Id, err = runtime.Int32(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.DeleteUser(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func request_UserService_ListUserAccessTokens_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_UserService_ListUserAccessTokens_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq ListUserAccessTokensRequest
|
var protoReq ListUserAccessTokensRequest
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@ -281,6 +385,31 @@ func local_request_UserService_DeleteUserAccessToken_0(ctx context.Context, mars
|
|||||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterUserServiceHandlerFromEndpoint instead.
|
// 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 {
|
func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServiceServer) error {
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_UserService_ListUsers_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/slash.api.v2.UserService/ListUsers", runtime.WithHTTPPathPattern("/api/v2/users"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_UserService_ListUsers_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_UserService_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -306,6 +435,56 @@ func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_UserService_CreateUser_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/slash.api.v2.UserService/CreateUser", runtime.WithHTTPPathPattern("/api/v2/users"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_UserService_CreateUser_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_UserService_CreateUser_0(annotatedContext, 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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/slash.api.v2.UserService/DeleteUser", runtime.WithHTTPPathPattern("/api/v2/users/{id}"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_UserService_DeleteUser_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_UserService_DeleteUser_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_UserService_ListUserAccessTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_UserService_ListUserAccessTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -422,6 +601,28 @@ func RegisterUserServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn
|
|||||||
// "UserServiceClient" to call the correct interceptors.
|
// "UserServiceClient" to call the correct interceptors.
|
||||||
func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserServiceClient) error {
|
func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserServiceClient) error {
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_UserService_ListUsers_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/slash.api.v2.UserService/ListUsers", runtime.WithHTTPPathPattern("/api/v2/users"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_UserService_ListUsers_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_UserService_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -444,6 +645,50 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("POST", pattern_UserService_CreateUser_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/slash.api.v2.UserService/CreateUser", runtime.WithHTTPPathPattern("/api/v2/users"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_UserService_CreateUser_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_UserService_CreateUser_0(annotatedContext, 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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/slash.api.v2.UserService/DeleteUser", runtime.WithHTTPPathPattern("/api/v2/users/{id}"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_UserService_DeleteUser_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_UserService_DeleteUser_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_UserService_ListUserAccessTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_UserService_ListUserAccessTokens_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -514,8 +759,14 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
pattern_UserService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "users"}, ""))
|
||||||
|
|
||||||
pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "users", "id"}, ""))
|
pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "users", "id"}, ""))
|
||||||
|
|
||||||
|
pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v2", "users"}, ""))
|
||||||
|
|
||||||
|
pattern_UserService_DeleteUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "users", "id"}, ""))
|
||||||
|
|
||||||
pattern_UserService_ListUserAccessTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v2", "users", "id", "access_tokens"}, ""))
|
pattern_UserService_ListUserAccessTokens_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v2", "users", "id", "access_tokens"}, ""))
|
||||||
|
|
||||||
pattern_UserService_CreateUserAccessToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v2", "users", "id", "access_tokens"}, ""))
|
pattern_UserService_CreateUserAccessToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v2", "users", "id", "access_tokens"}, ""))
|
||||||
@ -524,8 +775,14 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
|
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_UserService_DeleteUser_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_UserService_ListUserAccessTokens_0 = runtime.ForwardResponseMessage
|
forward_UserService_ListUserAccessTokens_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_UserService_CreateUserAccessToken_0 = runtime.ForwardResponseMessage
|
forward_UserService_CreateUserAccessToken_0 = runtime.ForwardResponseMessage
|
||||||
|
@ -19,7 +19,10 @@ import (
|
|||||||
const _ = grpc.SupportPackageIsVersion7
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
UserService_ListUsers_FullMethodName = "/slash.api.v2.UserService/ListUsers"
|
||||||
UserService_GetUser_FullMethodName = "/slash.api.v2.UserService/GetUser"
|
UserService_GetUser_FullMethodName = "/slash.api.v2.UserService/GetUser"
|
||||||
|
UserService_CreateUser_FullMethodName = "/slash.api.v2.UserService/CreateUser"
|
||||||
|
UserService_DeleteUser_FullMethodName = "/slash.api.v2.UserService/DeleteUser"
|
||||||
UserService_ListUserAccessTokens_FullMethodName = "/slash.api.v2.UserService/ListUserAccessTokens"
|
UserService_ListUserAccessTokens_FullMethodName = "/slash.api.v2.UserService/ListUserAccessTokens"
|
||||||
UserService_CreateUserAccessToken_FullMethodName = "/slash.api.v2.UserService/CreateUserAccessToken"
|
UserService_CreateUserAccessToken_FullMethodName = "/slash.api.v2.UserService/CreateUserAccessToken"
|
||||||
UserService_DeleteUserAccessToken_FullMethodName = "/slash.api.v2.UserService/DeleteUserAccessToken"
|
UserService_DeleteUserAccessToken_FullMethodName = "/slash.api.v2.UserService/DeleteUserAccessToken"
|
||||||
@ -29,8 +32,14 @@ const (
|
|||||||
//
|
//
|
||||||
// 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.
|
// 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 {
|
type UserServiceClient interface {
|
||||||
|
// ListUsers returns a list of users.
|
||||||
|
ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error)
|
||||||
// GetUser returns a user by id.
|
// GetUser returns a user by id.
|
||||||
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error)
|
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error)
|
||||||
|
// CreateUser creates a new user.
|
||||||
|
CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error)
|
||||||
|
// DeleteUser deletes a user by id.
|
||||||
|
DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error)
|
||||||
// ListUserAccessTokens returns a list of access tokens for a user.
|
// ListUserAccessTokens returns a list of access tokens for a user.
|
||||||
ListUserAccessTokens(ctx context.Context, in *ListUserAccessTokensRequest, opts ...grpc.CallOption) (*ListUserAccessTokensResponse, error)
|
ListUserAccessTokens(ctx context.Context, in *ListUserAccessTokensRequest, opts ...grpc.CallOption) (*ListUserAccessTokensResponse, error)
|
||||||
// CreateUserAccessToken creates a new access token for a user.
|
// CreateUserAccessToken creates a new access token for a user.
|
||||||
@ -47,6 +56,15 @@ func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient {
|
|||||||
return &userServiceClient{cc}
|
return &userServiceClient{cc}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *userServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) {
|
||||||
|
out := new(ListUsersResponse)
|
||||||
|
err := c.cc.Invoke(ctx, UserService_ListUsers_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) {
|
func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) {
|
||||||
out := new(GetUserResponse)
|
out := new(GetUserResponse)
|
||||||
err := c.cc.Invoke(ctx, UserService_GetUser_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, UserService_GetUser_FullMethodName, in, out, opts...)
|
||||||
@ -56,6 +74,24 @@ func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opt
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *userServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) {
|
||||||
|
out := new(CreateUserResponse)
|
||||||
|
err := c.cc.Invoke(ctx, UserService_CreateUser_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *userServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) {
|
||||||
|
out := new(DeleteUserResponse)
|
||||||
|
err := c.cc.Invoke(ctx, UserService_DeleteUser_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *userServiceClient) ListUserAccessTokens(ctx context.Context, in *ListUserAccessTokensRequest, opts ...grpc.CallOption) (*ListUserAccessTokensResponse, error) {
|
func (c *userServiceClient) ListUserAccessTokens(ctx context.Context, in *ListUserAccessTokensRequest, opts ...grpc.CallOption) (*ListUserAccessTokensResponse, error) {
|
||||||
out := new(ListUserAccessTokensResponse)
|
out := new(ListUserAccessTokensResponse)
|
||||||
err := c.cc.Invoke(ctx, UserService_ListUserAccessTokens_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, UserService_ListUserAccessTokens_FullMethodName, in, out, opts...)
|
||||||
@ -87,8 +123,14 @@ func (c *userServiceClient) DeleteUserAccessToken(ctx context.Context, in *Delet
|
|||||||
// All implementations must embed UnimplementedUserServiceServer
|
// All implementations must embed UnimplementedUserServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
type UserServiceServer interface {
|
type UserServiceServer interface {
|
||||||
|
// ListUsers returns a list of users.
|
||||||
|
ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error)
|
||||||
// GetUser returns a user by id.
|
// GetUser returns a user by id.
|
||||||
GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error)
|
GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error)
|
||||||
|
// CreateUser creates a new user.
|
||||||
|
CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error)
|
||||||
|
// DeleteUser deletes a user by id.
|
||||||
|
DeleteUser(context.Context, *DeleteUserRequest) (*DeleteUserResponse, error)
|
||||||
// ListUserAccessTokens returns a list of access tokens for a user.
|
// ListUserAccessTokens returns a list of access tokens for a user.
|
||||||
ListUserAccessTokens(context.Context, *ListUserAccessTokensRequest) (*ListUserAccessTokensResponse, error)
|
ListUserAccessTokens(context.Context, *ListUserAccessTokensRequest) (*ListUserAccessTokensResponse, error)
|
||||||
// CreateUserAccessToken creates a new access token for a user.
|
// CreateUserAccessToken creates a new access token for a user.
|
||||||
@ -102,9 +144,18 @@ type UserServiceServer interface {
|
|||||||
type UnimplementedUserServiceServer struct {
|
type UnimplementedUserServiceServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (UnimplementedUserServiceServer) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) {
|
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedUserServiceServer) CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method CreateUser not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedUserServiceServer) DeleteUser(context.Context, *DeleteUserRequest) (*DeleteUserResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method DeleteUser not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedUserServiceServer) ListUserAccessTokens(context.Context, *ListUserAccessTokensRequest) (*ListUserAccessTokensResponse, error) {
|
func (UnimplementedUserServiceServer) ListUserAccessTokens(context.Context, *ListUserAccessTokensRequest) (*ListUserAccessTokensResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListUserAccessTokens not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ListUserAccessTokens not implemented")
|
||||||
}
|
}
|
||||||
@ -127,6 +178,24 @@ func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
|
|||||||
s.RegisterService(&UserService_ServiceDesc, srv)
|
s.RegisterService(&UserService_ServiceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _UserService_ListUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListUsersRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(UserServiceServer).ListUsers(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: UserService_ListUsers_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(UserServiceServer).ListUsers(ctx, req.(*ListUsersRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(GetUserRequest)
|
in := new(GetUserRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@ -145,6 +214,42 @@ func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _UserService_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CreateUserRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(UserServiceServer).CreateUser(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: UserService_CreateUser_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(UserServiceServer).CreateUser(ctx, req.(*CreateUserRequest))
|
||||||
|
}
|
||||||
|
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: UserService_DeleteUser_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(UserServiceServer).DeleteUser(ctx, req.(*DeleteUserRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _UserService_ListUserAccessTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _UserService_ListUserAccessTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(ListUserAccessTokensRequest)
|
in := new(ListUserAccessTokensRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@ -206,10 +311,22 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
ServiceName: "slash.api.v2.UserService",
|
ServiceName: "slash.api.v2.UserService",
|
||||||
HandlerType: (*UserServiceServer)(nil),
|
HandlerType: (*UserServiceServer)(nil),
|
||||||
Methods: []grpc.MethodDesc{
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "ListUsers",
|
||||||
|
Handler: _UserService_ListUsers_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "GetUser",
|
MethodName: "GetUser",
|
||||||
Handler: _UserService_GetUser_Handler,
|
Handler: _UserService_GetUser_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "CreateUser",
|
||||||
|
Handler: _UserService_CreateUser_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "DeleteUser",
|
||||||
|
Handler: _UserService_DeleteUser_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "ListUserAccessTokens",
|
MethodName: "ListUserAccessTokens",
|
||||||
Handler: _UserService_ListUserAccessTokens_Handler,
|
Handler: _UserService_ListUserAccessTokens_Handler,
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
|
- [store/activity.proto](#store_activity-proto)
|
||||||
|
- [ActivityShorcutCreatePayload](#slash-store-ActivityShorcutCreatePayload)
|
||||||
|
|
||||||
- [store/common.proto](#store_common-proto)
|
- [store/common.proto](#store_common-proto)
|
||||||
- [RowStatus](#slash-store-RowStatus)
|
- [RowStatus](#slash-store-RowStatus)
|
||||||
|
|
||||||
@ -23,6 +26,37 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="store_activity-proto"></a>
|
||||||
|
<p align="right"><a href="#top">Top</a></p>
|
||||||
|
|
||||||
|
## store/activity.proto
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="slash-store-ActivityShorcutCreatePayload"></a>
|
||||||
|
|
||||||
|
### ActivityShorcutCreatePayload
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| shortcut_id | [int32](#int32) | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="store_common-proto"></a>
|
<a name="store_common-proto"></a>
|
||||||
<p align="right"><a href="#top">Top</a></p>
|
<p align="right"><a href="#top">Top</a></p>
|
||||||
|
|
||||||
|
153
proto/gen/store/activity.pb.go
Normal file
153
proto/gen/store/activity.pb.go
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.31.0
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: store/activity.proto
|
||||||
|
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
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 ActivityShorcutCreatePayload struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
ShortcutId int32 `protobuf:"varint,1,opt,name=shortcut_id,json=shortcutId,proto3" json:"shortcut_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ActivityShorcutCreatePayload) Reset() {
|
||||||
|
*x = ActivityShorcutCreatePayload{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_store_activity_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ActivityShorcutCreatePayload) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ActivityShorcutCreatePayload) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ActivityShorcutCreatePayload) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_store_activity_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 ActivityShorcutCreatePayload.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ActivityShorcutCreatePayload) Descriptor() ([]byte, []int) {
|
||||||
|
return file_store_activity_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ActivityShorcutCreatePayload) GetShortcutId() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ShortcutId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_store_activity_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_store_activity_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x14, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74,
|
||||||
|
0x6f, 0x72, 0x65, 0x22, 0x3f, 0x0a, 0x1c, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x53,
|
||||||
|
0x68, 0x6f, 0x72, 0x63, 0x75, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6c,
|
||||||
|
0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x5f,
|
||||||
|
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63,
|
||||||
|
0x75, 0x74, 0x49, 0x64, 0x42, 0x97, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61,
|
||||||
|
0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x0d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69,
|
||||||
|
0x74, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||||
|
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c,
|
||||||
|
0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74,
|
||||||
|
0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73,
|
||||||
|
0x68, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c,
|
||||||
|
0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, 0x74,
|
||||||
|
0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea,
|
||||||
|
0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06,
|
||||||
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_store_activity_proto_rawDescOnce sync.Once
|
||||||
|
file_store_activity_proto_rawDescData = file_store_activity_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_store_activity_proto_rawDescGZIP() []byte {
|
||||||
|
file_store_activity_proto_rawDescOnce.Do(func() {
|
||||||
|
file_store_activity_proto_rawDescData = protoimpl.X.CompressGZIP(file_store_activity_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_store_activity_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_store_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
|
var file_store_activity_proto_goTypes = []interface{}{
|
||||||
|
(*ActivityShorcutCreatePayload)(nil), // 0: slash.store.ActivityShorcutCreatePayload
|
||||||
|
}
|
||||||
|
var file_store_activity_proto_depIdxs = []int32{
|
||||||
|
0, // [0:0] is the sub-list for method output_type
|
||||||
|
0, // [0:0] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_store_activity_proto_init() }
|
||||||
|
func file_store_activity_proto_init() {
|
||||||
|
if File_store_activity_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_store_activity_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*ActivityShorcutCreatePayload); 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_store_activity_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 1,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_store_activity_proto_goTypes,
|
||||||
|
DependencyIndexes: file_store_activity_proto_depIdxs,
|
||||||
|
MessageInfos: file_store_activity_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_store_activity_proto = out.File
|
||||||
|
file_store_activity_proto_rawDesc = nil
|
||||||
|
file_store_activity_proto_goTypes = nil
|
||||||
|
file_store_activity_proto_depIdxs = nil
|
||||||
|
}
|
9
proto/store/activity.proto
Normal file
9
proto/store/activity.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package slash.store;
|
||||||
|
|
||||||
|
option go_package = "gen/store";
|
||||||
|
|
||||||
|
message ActivityShorcutCreatePayload {
|
||||||
|
int32 shortcut_id = 1;
|
||||||
|
}
|
BIN
resources/browser-extension-example.png
Normal file
BIN
resources/browser-extension-example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
resources/logo-pixel.png
Normal file
BIN
resources/logo-pixel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
resources/logo128.png
Normal file
BIN
resources/logo128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
59
server/resource.go
Normal file
59
server/resource.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/boojack/slash/server/profile"
|
||||||
|
"github.com/boojack/slash/store"
|
||||||
|
"github.com/h2non/filetype"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResourceService struct {
|
||||||
|
Profile *profile.Profile
|
||||||
|
Store *store.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResourceService(profile *profile.Profile, store *store.Store) *ResourceService {
|
||||||
|
return &ResourceService{
|
||||||
|
Profile: profile,
|
||||||
|
Store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register registers the resource service to the echo server.
|
||||||
|
func (s *ResourceService) Register(g *echo.Group) {
|
||||||
|
g.GET("/resources/:id", func(c echo.Context) error {
|
||||||
|
ctx := c.Request().Context()
|
||||||
|
resourceID := c.Param("resourceId")
|
||||||
|
resourceRelativePathSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
|
||||||
|
Key: store.WorkspaceResourceRelativePath,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "failed to workspace resource relative path setting").SetInternal(err)
|
||||||
|
}
|
||||||
|
if resourceRelativePathSetting == nil || resourceRelativePathSetting.Value == "" {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "found no workspace resource relative path setting")
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceRelativePath := resourceRelativePathSetting.Value
|
||||||
|
resourcePath := fmt.Sprintf("%s/%s", resourceRelativePath, resourceID)
|
||||||
|
buf, err := os.ReadFile(resourcePath)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to read the local resource: %s", resourcePath)).SetInternal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kind, err := filetype.Match(buf)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to match the local resource: %s", resourcePath)).SetInternal(err)
|
||||||
|
}
|
||||||
|
resourceMimeType := kind.MIME.Value
|
||||||
|
c.Response().Writer.Header().Set(echo.HeaderCacheControl, "max-age=31536000, immutable")
|
||||||
|
c.Response().Writer.Header().Set(echo.HeaderContentSecurityPolicy, "default-src 'self'")
|
||||||
|
c.Response().Writer.Header().Set("Content-Disposition", fmt.Sprintf(`filename="%s"`, resourceID))
|
||||||
|
return c.Stream(http.StatusOK, resourceMimeType, bytes.NewReader(buf))
|
||||||
|
})
|
||||||
|
}
|
@ -76,6 +76,10 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
|
|||||||
return nil, fmt.Errorf("failed to register gRPC gateway: %w", err)
|
return nil, fmt.Errorf("failed to register gRPC gateway: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register resource service.
|
||||||
|
resourceService := NewResourceService(profile, store)
|
||||||
|
resourceService.Register(rootGroup)
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +115,10 @@ func (s *Server) Shutdown(ctx context.Context) {
|
|||||||
fmt.Printf("server stopped properly\n")
|
fmt.Printf("server stopped properly\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetEcho() *echo.Echo {
|
||||||
|
return s.e
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
|
func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
|
||||||
secretSessionNameValue, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
|
secretSessionNameValue, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
|
||||||
Key: store.WorkspaceDisallowSignUp,
|
Key: store.WorkspaceDisallowSignUp,
|
||||||
|
@ -9,10 +9,10 @@ import (
|
|||||||
|
|
||||||
// Version is the service current released version.
|
// Version is the service current released version.
|
||||||
// Semantic versioning: https://semver.org/
|
// Semantic versioning: https://semver.org/
|
||||||
var Version = "0.4.1"
|
var Version = "0.4.3"
|
||||||
|
|
||||||
// DevVersion is the service current development version.
|
// DevVersion is the service current development version.
|
||||||
var DevVersion = "0.4.1"
|
var DevVersion = "0.4.3"
|
||||||
|
|
||||||
func GetCurrentVersion(mode string) string {
|
func GetCurrentVersion(mode string) string {
|
||||||
if mode == "dev" || mode == "demo" {
|
if mode == "dev" || mode == "demo" {
|
||||||
|
@ -59,3 +59,12 @@ CREATE TABLE activity (
|
|||||||
level TEXT NOT NULL CHECK (level IN ('INFO', 'WARN', 'ERROR')) DEFAULT 'INFO',
|
level TEXT NOT NULL CHECK (level IN ('INFO', 'WARN', 'ERROR')) DEFAULT 'INFO',
|
||||||
payload TEXT NOT NULL DEFAULT '{}'
|
payload TEXT NOT NULL DEFAULT '{}'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- idp
|
||||||
|
CREATE TABLE idp (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
identifier_filter TEXT NOT NULL DEFAULT '',
|
||||||
|
config TEXT NOT NULL DEFAULT '{}'
|
||||||
|
);
|
||||||
|
10
store/db/migration/prod/0.5/00_idp.sql
Normal file
10
store/db/migration/prod/0.5/00_idp.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
DROP TABLE IF EXISTS idp;
|
||||||
|
|
||||||
|
-- idp
|
||||||
|
CREATE TABLE idp (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
identifier_filter TEXT NOT NULL DEFAULT '',
|
||||||
|
config TEXT NOT NULL DEFAULT '{}'
|
||||||
|
);
|
@ -59,3 +59,12 @@ CREATE TABLE activity (
|
|||||||
level TEXT NOT NULL CHECK (level IN ('INFO', 'WARN', 'ERROR')) DEFAULT 'INFO',
|
level TEXT NOT NULL CHECK (level IN ('INFO', 'WARN', 'ERROR')) DEFAULT 'INFO',
|
||||||
payload TEXT NOT NULL DEFAULT '{}'
|
payload TEXT NOT NULL DEFAULT '{}'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- idp
|
||||||
|
CREATE TABLE idp (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
identifier_filter TEXT NOT NULL DEFAULT '',
|
||||||
|
config TEXT NOT NULL DEFAULT '{}'
|
||||||
|
);
|
||||||
|
@ -8,10 +8,12 @@ import (
|
|||||||
type WorkspaceSettingKey string
|
type WorkspaceSettingKey string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// WorkspaceDisallowSignUp is the key type for disallow sign up in workspace level.
|
|
||||||
WorkspaceDisallowSignUp WorkspaceSettingKey = "disallow-signup"
|
|
||||||
// WorkspaceSecretSessionName is the key type for secret session name.
|
// WorkspaceSecretSessionName is the key type for secret session name.
|
||||||
WorkspaceSecretSessionName WorkspaceSettingKey = "secret-session-name"
|
WorkspaceSecretSessionName WorkspaceSettingKey = "secret-session-name"
|
||||||
|
// WorkspaceDisallowSignUp is the key type for disallow sign up in workspace level.
|
||||||
|
WorkspaceDisallowSignUp WorkspaceSettingKey = "disallow-signup"
|
||||||
|
// WorkspaceResourceRelativePath is the key type for resource relative path.
|
||||||
|
WorkspaceResourceRelativePath WorkspaceSettingKey = "resource-relative-path"
|
||||||
)
|
)
|
||||||
|
|
||||||
// String returns the string format of WorkspaceSettingKey type.
|
// String returns the string format of WorkspaceSettingKey type.
|
||||||
|
93
test/server/auth_test.go
Normal file
93
test/server/auth_test.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package testserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
apiv1 "github.com/boojack/slash/api/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAuthServer(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
s, err := NewTestingServer(ctx, t)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer s.Shutdown(ctx)
|
||||||
|
|
||||||
|
signup := &apiv1.SignUpRequest{
|
||||||
|
Email: "slash@yourselfhosted.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
}
|
||||||
|
user, err := s.postAuthSignUp(signup)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
|
||||||
|
signin := &apiv1.SignInRequest{
|
||||||
|
Email: "slash@yourselfhosted.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
}
|
||||||
|
user, err = s.postAuthSignIn(signin)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
err = s.postLogout()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) postAuthSignUp(signup *apiv1.SignUpRequest) (*apiv1.User, error) {
|
||||||
|
rawData, err := json.Marshal(&signup)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to marshal signup")
|
||||||
|
}
|
||||||
|
reader := bytes.NewReader(rawData)
|
||||||
|
body, err := s.post("/api/v1/auth/signup", reader, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to post request")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &apiv1.User{}
|
||||||
|
if err = json.Unmarshal(buf.Bytes(), user); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to unmarshal post signup response")
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) postAuthSignIn(signip *apiv1.SignInRequest) (*apiv1.User, error) {
|
||||||
|
rawData, err := json.Marshal(&signip)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to marshal signin")
|
||||||
|
}
|
||||||
|
reader := bytes.NewReader(rawData)
|
||||||
|
body, err := s.post("/api/v1/auth/signin", reader, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to post request")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &apiv1.User{}
|
||||||
|
if err = json.Unmarshal(buf.Bytes(), user); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to unmarshal post signin response")
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) postLogout() error {
|
||||||
|
_, err := s.post("/api/v1/auth/logout", nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "fail to post request")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
178
test/server/server.go
Normal file
178
test/server/server.go
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
package testserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/boojack/slash/api/auth"
|
||||||
|
"github.com/boojack/slash/server"
|
||||||
|
"github.com/boojack/slash/server/profile"
|
||||||
|
"github.com/boojack/slash/store"
|
||||||
|
"github.com/boojack/slash/store/db"
|
||||||
|
"github.com/boojack/slash/test"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
// sqlite driver.
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestingServer struct {
|
||||||
|
server *server.Server
|
||||||
|
client *http.Client
|
||||||
|
profile *profile.Profile
|
||||||
|
cookie string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTestingServer(ctx context.Context, t *testing.T) (*TestingServer, error) {
|
||||||
|
profile := test.GetTestingProfile(t)
|
||||||
|
db := db.NewDB(profile)
|
||||||
|
if err := db.Open(ctx); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to open db")
|
||||||
|
}
|
||||||
|
|
||||||
|
store := store.New(db.DBInstance, profile)
|
||||||
|
server, err := server.NewServer(ctx, profile, store)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to create server")
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &TestingServer{
|
||||||
|
server: server,
|
||||||
|
client: &http.Client{},
|
||||||
|
profile: profile,
|
||||||
|
cookie: "",
|
||||||
|
}
|
||||||
|
errChan := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := s.server.Start(ctx); err != nil {
|
||||||
|
if err != http.ErrServerClosed {
|
||||||
|
errChan <- errors.Wrap(err, "failed to run main server")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := s.waitForServerStart(errChan); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to start server")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) Shutdown(ctx context.Context) {
|
||||||
|
s.server.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) waitForServerStart(errChan <-chan error) error {
|
||||||
|
ticker := time.NewTicker(100 * time.Millisecond)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if s == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
e := s.server.GetEcho()
|
||||||
|
if e == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := e.ListenerAddr()
|
||||||
|
if addr != nil && strings.Contains(addr.String(), ":") {
|
||||||
|
return nil // was started
|
||||||
|
}
|
||||||
|
case err := <-errChan:
|
||||||
|
if err == http.ErrServerClosed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) request(method, uri string, body io.Reader, params, header map[string]string) (io.ReadCloser, error) {
|
||||||
|
fullURL := fmt.Sprintf("http://localhost:%d%s", s.profile.Port, uri)
|
||||||
|
req, err := http.NewRequest(method, fullURL, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "fail to create a new %s request(%q)", method, fullURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range header {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
q := url.Values{}
|
||||||
|
for k, v := range params {
|
||||||
|
q.Add(k, v)
|
||||||
|
}
|
||||||
|
if len(q) > 0 {
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "fail to send a %s request(%q)", method, fullURL)
|
||||||
|
}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to read http response body")
|
||||||
|
}
|
||||||
|
return nil, errors.Errorf("http response error code %v body %q", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == "POST" {
|
||||||
|
if strings.Contains(uri, "/api/v1/auth/signin") || strings.Contains(uri, "/api/v1/auth/signup") {
|
||||||
|
cookie := ""
|
||||||
|
h := resp.Header.Get("Set-Cookie")
|
||||||
|
parts := strings.Split(h, "; ")
|
||||||
|
for _, p := range parts {
|
||||||
|
if strings.HasPrefix(p, fmt.Sprintf("%s=", auth.AccessTokenCookieName)) {
|
||||||
|
cookie = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cookie == "" {
|
||||||
|
return nil, errors.Errorf("unable to find access token in the login response headers")
|
||||||
|
}
|
||||||
|
s.cookie = cookie
|
||||||
|
} else if strings.Contains(uri, "/api/v1/auth/logout") {
|
||||||
|
s.cookie = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp.Body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get sends a GET client request.
|
||||||
|
func (s *TestingServer) get(url string, params map[string]string) (io.ReadCloser, error) {
|
||||||
|
return s.request("GET", url, nil, params, map[string]string{
|
||||||
|
"Cookie": s.cookie,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// post sends a POST client request.
|
||||||
|
func (s *TestingServer) post(url string, body io.Reader, params map[string]string) (io.ReadCloser, error) {
|
||||||
|
return s.request("POST", url, body, params, map[string]string{
|
||||||
|
"Cookie": s.cookie,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch sends a PATCH client request.
|
||||||
|
func (s *TestingServer) patch(url string, body io.Reader, params map[string]string) (io.ReadCloser, error) {
|
||||||
|
return s.request("PATCH", url, body, params, map[string]string{
|
||||||
|
"Cookie": s.cookie,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete sends a DELETE client request.
|
||||||
|
func (s *TestingServer) delete(url string, params map[string]string) (io.ReadCloser, error) {
|
||||||
|
return s.request("DELETE", url, nil, params, map[string]string{
|
||||||
|
"Cookie": s.cookie,
|
||||||
|
})
|
||||||
|
}
|
72
test/server/shortcut_test.go
Normal file
72
test/server/shortcut_test.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package testserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
apiv1 "github.com/boojack/slash/api/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShortcutServer(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
s, err := NewTestingServer(ctx, t)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer s.Shutdown(ctx)
|
||||||
|
|
||||||
|
signup := &apiv1.SignUpRequest{
|
||||||
|
Email: "slash@yourselfhosted.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
}
|
||||||
|
user, err := s.postAuthSignUp(signup)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
user, err = s.getCurrentUser()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
shortcutCreate := &apiv1.CreateShortcutRequest{
|
||||||
|
Name: "test",
|
||||||
|
Link: "https://google.com",
|
||||||
|
Visibility: apiv1.VisibilityPublic,
|
||||||
|
Tags: []string{},
|
||||||
|
}
|
||||||
|
shortcut, err := s.postShortcutCreate(shortcutCreate)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, shortcutCreate.Name, shortcut.Name)
|
||||||
|
require.Equal(t, shortcutCreate.Link, shortcut.Link)
|
||||||
|
err = s.deleteShortcut(shortcut.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) postShortcutCreate(request *apiv1.CreateShortcutRequest) (*apiv1.Shortcut, error) {
|
||||||
|
rawData, err := json.Marshal(&request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to marshal shortcut create")
|
||||||
|
}
|
||||||
|
reader := bytes.NewReader(rawData)
|
||||||
|
body, err := s.post("/api/v1/shortcut", reader, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to post request")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
shortcut := &apiv1.Shortcut{}
|
||||||
|
if err = json.Unmarshal(buf.Bytes(), &shortcut); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to unmarshal post shortcut response")
|
||||||
|
}
|
||||||
|
return shortcut, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) deleteShortcut(shortcutID int32) error {
|
||||||
|
_, err := s.delete(fmt.Sprintf("/api/v1/shortcut/%d", shortcutID), nil)
|
||||||
|
return err
|
||||||
|
}
|
103
test/server/user_test.go
Normal file
103
test/server/user_test.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package testserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
apiv1 "github.com/boojack/slash/api/v1"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserServer(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
s, err := NewTestingServer(ctx, t)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer s.Shutdown(ctx)
|
||||||
|
|
||||||
|
signup := &apiv1.SignUpRequest{
|
||||||
|
Email: "slash@yourselfhosted.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
}
|
||||||
|
user, err := s.postAuthSignUp(signup)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
user, err = s.getCurrentUser()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
user, err = s.getUserByID(user.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, signup.Email, user.Email)
|
||||||
|
newEmail := "test@usermemos.com"
|
||||||
|
userPatch := &apiv1.PatchUserRequest{
|
||||||
|
Email: &newEmail,
|
||||||
|
}
|
||||||
|
user, err = s.patchUser(user.ID, userPatch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, newEmail, user.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) getCurrentUser() (*apiv1.User, error) {
|
||||||
|
body, err := s.get("/api/v1/user/me", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &apiv1.User{}
|
||||||
|
if err = json.Unmarshal(buf.Bytes(), &user); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to unmarshal get user response")
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) getUserByID(userID int32) (*apiv1.User, error) {
|
||||||
|
body, err := s.get(fmt.Sprintf("/api/v1/user/%d", userID), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &apiv1.User{}
|
||||||
|
if err = json.Unmarshal(buf.Bytes(), &user); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to unmarshal get user response")
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestingServer) patchUser(userID int32, request *apiv1.PatchUserRequest) (*apiv1.User, error) {
|
||||||
|
rawData, err := json.Marshal(&request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to marshal request")
|
||||||
|
}
|
||||||
|
reader := bytes.NewReader(rawData)
|
||||||
|
body, err := s.patch(fmt.Sprintf("/api/v1/user/%d", userID), reader, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
_, err = buf.ReadFrom(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &apiv1.User{}
|
||||||
|
if err = json.Unmarshal(buf.Bytes(), user); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "fail to unmarshal patch user response")
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package tests
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
"@bufbuild/protobuf": "^1.3.0",
|
"@bufbuild/protobuf": "^1.3.0",
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/joy": "5.0.0-beta.0",
|
"@mui/joy": "5.0.0-beta.2",
|
||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.5",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
|
44
web/pnpm-lock.yaml
generated
44
web/pnpm-lock.yaml
generated
@ -15,8 +15,8 @@ dependencies:
|
|||||||
specifier: ^11.11.0
|
specifier: ^11.11.0
|
||||||
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.18)(react@18.2.0)
|
version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@mui/joy':
|
'@mui/joy':
|
||||||
specifier: 5.0.0-beta.0
|
specifier: 5.0.0-beta.2
|
||||||
version: 5.0.0-beta.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)
|
version: 5.0.0-beta.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@reduxjs/toolkit':
|
'@reduxjs/toolkit':
|
||||||
specifier: ^1.9.5
|
specifier: ^1.9.5
|
||||||
version: 1.9.5(react-redux@8.0.2)(react@18.2.0)
|
version: 1.9.5(react-redux@8.0.2)(react@18.2.0)
|
||||||
@ -670,8 +670,8 @@ packages:
|
|||||||
'@jridgewell/resolve-uri': 3.1.0
|
'@jridgewell/resolve-uri': 3.1.0
|
||||||
'@jridgewell/sourcemap-codec': 1.4.14
|
'@jridgewell/sourcemap-codec': 1.4.14
|
||||||
|
|
||||||
/@mui/base@5.0.0-beta.9(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0):
|
/@mui/base@5.0.0-beta.11(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-gm6gnPnc/lS5Z3neH0iuOrK7IbS02+oh6KsMtXYLhI6bJpHs+PNWFsBmISx7x4FSPVJZvZkb8Bw6pEXpIMFt7Q==}
|
resolution: {integrity: sha512-FdKZGPd8qmC3ZNke7CNhzcEgToc02M6WYZc9hcBsNQ17bgAd3s9F//1bDDYgMVBYxDM71V0sv/hBHlOY4I1ZVA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^17.0.0 || ^18.0.0
|
'@types/react': ^17.0.0 || ^18.0.0
|
||||||
@ -684,7 +684,7 @@ packages:
|
|||||||
'@babel/runtime': 7.22.6
|
'@babel/runtime': 7.22.6
|
||||||
'@emotion/is-prop-valid': 1.2.1
|
'@emotion/is-prop-valid': 1.2.1
|
||||||
'@mui/types': 7.2.4(@types/react@18.2.18)
|
'@mui/types': 7.2.4(@types/react@18.2.18)
|
||||||
'@mui/utils': 5.14.3(react@18.2.0)
|
'@mui/utils': 5.14.5(react@18.2.0)
|
||||||
'@popperjs/core': 2.11.8
|
'@popperjs/core': 2.11.8
|
||||||
'@types/react': 18.2.18
|
'@types/react': 18.2.18
|
||||||
clsx: 2.0.0
|
clsx: 2.0.0
|
||||||
@ -694,12 +694,12 @@ packages:
|
|||||||
react-is: 18.2.0
|
react-is: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/core-downloads-tracker@5.14.3:
|
/@mui/core-downloads-tracker@5.14.5:
|
||||||
resolution: {integrity: sha512-QxvrcDqphZoXRjsAmCaQylmWjC/8/qKWwIde1MJMna5YIst3R9O0qhKRPu36/OE2d8AeTbCVjRcRvNqhhW8jyg==}
|
resolution: {integrity: sha512-+wpGH1USwPcKMFPMvXqYPC6fEvhxM3FzxC8lyDiNK/imLyyJ6y2DPb1Oue7OGIKJWBmYBqrWWtfovrxd1aJHTA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/joy@5.0.0-beta.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0):
|
/@mui/joy@5.0.0-beta.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-WDGlbEMqXPmuwgUPEgJEPeOUJD46WragfPqTjoWEp+//0iE8kcn+YfFVgsoY31uID5UwcFWQRupxui872slANA==}
|
resolution: {integrity: sha512-5NfZcOYufTOSXh0b34YZzF1CHwuHf07cgSNdyn3WUUwg67oyNOPKhaskttX6aSp0j8Rf8OpKzd+7Ni6Em0jPgQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@emotion/react': ^11.5.0
|
'@emotion/react': ^11.5.0
|
||||||
@ -718,11 +718,11 @@ packages:
|
|||||||
'@babel/runtime': 7.22.6
|
'@babel/runtime': 7.22.6
|
||||||
'@emotion/react': 11.11.1(@types/react@18.2.18)(react@18.2.0)
|
'@emotion/react': 11.11.1(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.18)(react@18.2.0)
|
'@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@mui/base': 5.0.0-beta.9(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)
|
'@mui/base': 5.0.0-beta.11(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@mui/core-downloads-tracker': 5.14.3
|
'@mui/core-downloads-tracker': 5.14.5
|
||||||
'@mui/system': 5.14.3(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react@18.2.0)
|
'@mui/system': 5.14.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@mui/types': 7.2.4(@types/react@18.2.18)
|
'@mui/types': 7.2.4(@types/react@18.2.18)
|
||||||
'@mui/utils': 5.14.3(react@18.2.0)
|
'@mui/utils': 5.14.5(react@18.2.0)
|
||||||
'@types/react': 18.2.18
|
'@types/react': 18.2.18
|
||||||
clsx: 2.0.0
|
clsx: 2.0.0
|
||||||
csstype: 3.1.2
|
csstype: 3.1.2
|
||||||
@ -732,8 +732,8 @@ packages:
|
|||||||
react-is: 18.2.0
|
react-is: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/private-theming@5.13.7(@types/react@18.2.18)(react@18.2.0):
|
/@mui/private-theming@5.14.5(@types/react@18.2.18)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-qbSr+udcij5F9dKhGX7fEdx2drXchq7htLNr2Qg2Ma+WJ6q0ERlEqGSBiPiVDJkptcjeVL4DGmcf1wl5+vD4EA==}
|
resolution: {integrity: sha512-cC4C5RrpXpDaaZyH9QwmPhRLgz+f2SYbOty3cPkk4qPSOSfif2ZEcDD9HTENKDDd9deB+xkPKzzZhi8cxIx8Ig==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^17.0.0 || ^18.0.0
|
'@types/react': ^17.0.0 || ^18.0.0
|
||||||
@ -743,7 +743,7 @@ packages:
|
|||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.22.6
|
'@babel/runtime': 7.22.6
|
||||||
'@mui/utils': 5.14.3(react@18.2.0)
|
'@mui/utils': 5.14.5(react@18.2.0)
|
||||||
'@types/react': 18.2.18
|
'@types/react': 18.2.18
|
||||||
prop-types: 15.8.1
|
prop-types: 15.8.1
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
@ -771,8 +771,8 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/system@5.14.3(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react@18.2.0):
|
/@mui/system@5.14.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.18)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-b+C+j9+75+/iIYSa+1S4eCMc9MDNrj9hzWfExJqS2GffuNocRagjBZFyjtMqsLWLxMxQIX8Cg6j0hAioiw+WfQ==}
|
resolution: {integrity: sha512-mextXZHDeGcR7E1kx43TRARrVXy+gI4wzpUgNv7MqZs1dvTVXQGVeAT6ydj9d6FUqHBPMNLGV/21vJOrpqsL+w==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@emotion/react': ^11.5.0
|
'@emotion/react': ^11.5.0
|
||||||
@ -790,10 +790,10 @@ packages:
|
|||||||
'@babel/runtime': 7.22.6
|
'@babel/runtime': 7.22.6
|
||||||
'@emotion/react': 11.11.1(@types/react@18.2.18)(react@18.2.0)
|
'@emotion/react': 11.11.1(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.18)(react@18.2.0)
|
'@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@mui/private-theming': 5.13.7(@types/react@18.2.18)(react@18.2.0)
|
'@mui/private-theming': 5.14.5(@types/react@18.2.18)(react@18.2.0)
|
||||||
'@mui/styled-engine': 5.13.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
'@mui/styled-engine': 5.13.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
||||||
'@mui/types': 7.2.4(@types/react@18.2.18)
|
'@mui/types': 7.2.4(@types/react@18.2.18)
|
||||||
'@mui/utils': 5.14.3(react@18.2.0)
|
'@mui/utils': 5.14.5(react@18.2.0)
|
||||||
'@types/react': 18.2.18
|
'@types/react': 18.2.18
|
||||||
clsx: 2.0.0
|
clsx: 2.0.0
|
||||||
csstype: 3.1.2
|
csstype: 3.1.2
|
||||||
@ -812,8 +812,8 @@ packages:
|
|||||||
'@types/react': 18.2.18
|
'@types/react': 18.2.18
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/utils@5.14.3(react@18.2.0):
|
/@mui/utils@5.14.5(react@18.2.0):
|
||||||
resolution: {integrity: sha512-gZ6Etw+ppO43GYc1HFZSLjwd4DoZoa+RrYTD25wQLfzcSoPjVoC/zZqA2Lkq0zjgwGBQOSxKZI6jfp9uXR+kgw==}
|
resolution: {integrity: sha512-6Hzw63VR9C5xYv+CbjndoRLU6Gntal8rJ5W+GUzkyHrGWIyYPWZPa6AevnyGioySNETATe1H9oXS8f/7qgIHJA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^17.0.0 || ^18.0.0
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Button, Link, Modal, ModalDialog } from "@mui/joy";
|
import { Button, Link, Modal, ModalDialog } from "@mui/joy";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -7,12 +8,13 @@ interface Props {
|
|||||||
|
|
||||||
const AboutDialog: React.FC<Props> = (props: Props) => {
|
const AboutDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose } = props;
|
const { onClose } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={true}>
|
<Modal open={true}>
|
||||||
<ModalDialog>
|
<ModalDialog>
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-lg font-medium">About</span>
|
<span className="text-lg font-medium">{t("common.about")}</span>
|
||||||
<Button variant="plain" onClick={onClose}>
|
<Button variant="plain" onClick={onClose}>
|
||||||
<Icon.X className="w-5 h-auto text-gray-600" />
|
<Icon.X className="w-5 h-auto text-gray-600" />
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
import { Button, Modal, ModalDialog } from "@mui/joy";
|
|
||||||
import AnalyticsView from "./AnalyticsView";
|
|
||||||
import Icon from "./Icon";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
shortcutId: ShortcutId;
|
|
||||||
onClose: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnalyticsDialog: React.FC<Props> = (props: Props) => {
|
|
||||||
const { shortcutId, onClose } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal open={true}>
|
|
||||||
<ModalDialog>
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span className="text-lg font-medium">Analytics</span>
|
|
||||||
<Button variant="plain" onClick={onClose}>
|
|
||||||
<Icon.X className="w-5 h-auto text-gray-600" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className="max-w-full w-80 sm:w-96">
|
|
||||||
<AnalyticsView className="grid grid-cols-1 gap-2" shortcutId={shortcutId} />
|
|
||||||
</div>
|
|
||||||
</ModalDialog>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AnalyticsDialog;
|
|
@ -1,5 +1,6 @@
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import * as api from "../helpers/api";
|
import * as api from "../helpers/api";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ interface Props {
|
|||||||
|
|
||||||
const AnalyticsView: React.FC<Props> = (props: Props) => {
|
const AnalyticsView: React.FC<Props> = (props: Props) => {
|
||||||
const { shortcutId, className } = props;
|
const { shortcutId, className } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const [analytics, setAnalytics] = useState<AnalysisData | null>(null);
|
const [analytics, setAnalytics] = useState<AnalysisData | null>(null);
|
||||||
const [selectedDeviceTab, setSelectedDeviceTab] = useState<"os" | "browser">("browser");
|
const [selectedDeviceTab, setSelectedDeviceTab] = useState<"os" | "browser">("browser");
|
||||||
|
|
||||||
@ -24,12 +26,12 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
|
|||||||
{analytics ? (
|
{analytics ? (
|
||||||
<>
|
<>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<p className="w-full h-8 px-2">Top Sources</p>
|
<p className="w-full h-8 px-2">{t("analytics.top-sources")}</p>
|
||||||
<div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg">
|
<div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg">
|
||||||
<div className="w-full divide-y divide-gray-300">
|
<div className="w-full divide-y divide-gray-300">
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="py-2 px-2 text-left font-semibold text-sm text-gray-500">Source</span>
|
<span className="py-2 px-2 text-left font-semibold text-sm text-gray-500">{t("analytics.source")}</span>
|
||||||
<span className="py-2 pr-2 text-right font-semibold text-sm text-gray-500">Visitors</span>
|
<span className="py-2 pr-2 text-right font-semibold text-sm text-gray-500">{t("analytics.visitors")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full divide-y divide-gray-200">
|
<div className="w-full divide-y divide-gray-200">
|
||||||
{analytics.referenceData.map((reference) => (
|
{analytics.referenceData.map((reference) => (
|
||||||
@ -53,7 +55,7 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
|
|||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="w-full h-8 px-2 flex flex-row justify-between items-center">
|
<div className="w-full h-8 px-2 flex flex-row justify-between items-center">
|
||||||
<span>Devices</span>
|
<span>{t("analytics.devices")}</span>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${
|
className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${
|
||||||
@ -63,7 +65,7 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
|
|||||||
}`}
|
}`}
|
||||||
onClick={() => setSelectedDeviceTab("browser")}
|
onClick={() => setSelectedDeviceTab("browser")}
|
||||||
>
|
>
|
||||||
Browser
|
{t("analytics.browser")}
|
||||||
</button>
|
</button>
|
||||||
<span className="text-gray-200 font-mono mx-1">/</span>
|
<span className="text-gray-200 font-mono mx-1">/</span>
|
||||||
<button
|
<button
|
||||||
@ -83,8 +85,8 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
|
|||||||
{selectedDeviceTab === "browser" ? (
|
{selectedDeviceTab === "browser" ? (
|
||||||
<div className="w-full divide-y divide-gray-300">
|
<div className="w-full divide-y divide-gray-300">
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">Browsers</span>
|
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">{t("analytics.browsers")}</span>
|
||||||
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">Visitors</span>
|
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">{t("analytics.visitors")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full divide-y divide-gray-200">
|
<div className="w-full divide-y divide-gray-200">
|
||||||
{analytics.browserData.map((reference) => (
|
{analytics.browserData.map((reference) => (
|
||||||
@ -98,8 +100,8 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
|
|||||||
) : (
|
) : (
|
||||||
<div className="w-full divide-y divide-gray-300">
|
<div className="w-full divide-y divide-gray-300">
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">Operating system</span>
|
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">{t("analytics.operating-system")}</span>
|
||||||
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">Visitors</span>
|
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">{t("analytics.visitors")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full divide-y divide-gray-200">
|
<div className="w-full divide-y divide-gray-200">
|
||||||
{analytics.deviceData.map((device) => (
|
{analytics.deviceData.map((device) => (
|
||||||
@ -117,7 +119,7 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
|
|||||||
) : (
|
) : (
|
||||||
<div className="py-12 w-full flex flex-row justify-center items-center opacity-80">
|
<div className="py-12 w-full flex flex-row justify-center items-center opacity-80">
|
||||||
<Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
|
<Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
|
||||||
loading
|
{t("common.loading")}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Button, Input, Modal, ModalDialog } from "@mui/joy";
|
import { Button, Input, Modal, ModalDialog } from "@mui/joy";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -11,6 +12,7 @@ interface Props {
|
|||||||
|
|
||||||
const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
|
const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose } = props;
|
const { onClose } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const [newPassword, setNewPassword] = useState("");
|
const [newPassword, setNewPassword] = useState("");
|
||||||
const [newPasswordAgain, setNewPasswordAgain] = useState("");
|
const [newPasswordAgain, setNewPasswordAgain] = useState("");
|
||||||
@ -77,10 +79,10 @@ const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-end items-center space-x-2">
|
<div className="w-full flex flex-row justify-end items-center space-x-2">
|
||||||
<Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}>
|
<Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}>
|
||||||
Cancel
|
{t("common.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
||||||
Save
|
{t("common.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,7 @@ import { Button, Input, Modal, ModalDialog, Radio, RadioGroup } from "@mui/joy";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -33,6 +34,7 @@ interface State {
|
|||||||
|
|
||||||
const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose, onConfirm } = props;
|
const { onClose, onConfirm } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const currentUser = useUserStore().getCurrentUser();
|
const currentUser = useUserStore().getCurrentUser();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
description: "",
|
description: "",
|
||||||
@ -119,10 +121,10 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
|
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
|
||||||
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
|
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
|
||||||
Cancel
|
{t("common.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
||||||
Create
|
{t("common.create")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -164,13 +164,13 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
title: state.shortcutCreate.title,
|
title: state.shortcutCreate.title,
|
||||||
description: state.shortcutCreate.description,
|
description: state.shortcutCreate.description,
|
||||||
visibility: state.shortcutCreate.visibility,
|
visibility: state.shortcutCreate.visibility,
|
||||||
tags: tag.split(" "),
|
tags: tag.split(" ").filter(Boolean),
|
||||||
openGraphMetadata: state.shortcutCreate.openGraphMetadata,
|
openGraphMetadata: state.shortcutCreate.openGraphMetadata,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await shortcutService.createShortcut({
|
await shortcutService.createShortcut({
|
||||||
...state.shortcutCreate,
|
...state.shortcutCreate,
|
||||||
tags: tag.split(" "),
|
tags: tag.split(" ").filter(Boolean),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,10 +331,10 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
|
|
||||||
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
|
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
|
||||||
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
|
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
|
||||||
Cancel
|
{t("common.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
||||||
Save
|
{t("common.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,7 @@ import { Button, Input, Modal, ModalDialog, Radio, RadioGroup } from "@mui/joy";
|
|||||||
import { isUndefined } from "lodash-es";
|
import { isUndefined } from "lodash-es";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -20,6 +21,7 @@ const roles: Role[] = ["USER", "ADMIN"];
|
|||||||
|
|
||||||
const CreateUserDialog: React.FC<Props> = (props: Props) => {
|
const CreateUserDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose, onConfirm, user } = props;
|
const { onClose, onConfirm, user } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const [state, setState] = useState<State>({
|
const [state, setState] = useState<State>({
|
||||||
userCreate: {
|
userCreate: {
|
||||||
@ -185,10 +187,10 @@ const CreateUserDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
|
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
|
||||||
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
|
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
|
||||||
Cancel
|
{t("common.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
||||||
Save
|
{t("common.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ const DemoBanner: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="z-10 relative flex flex-row items-center justify-center w-full py-2 text-sm sm:text-lg font-medium dark:text-gray-300 bg-white dark:bg-zinc-700 shadow">
|
<div className="z-10 relative flex flex-row items-center justify-center w-full py-2 text-sm sm:text-lg font-medium dark:text-gray-300 bg-white dark:bg-zinc-700 shadow">
|
||||||
<div className="w-full max-w-6xl px-4 md:px-12 flex flex-row justify-between items-center gap-x-3">
|
<div className="w-full max-w-6xl px-4 md:px-12 flex flex-row justify-between items-center gap-x-3">
|
||||||
<span>✨Slash - An open source, self-hosted bookmarks and link sharing platform</span>
|
<span>✨🔗 Slash - An open source, self-hosted bookmarks and link sharing platform</span>
|
||||||
<a
|
<a
|
||||||
className="shadow flex flex-row justify-center items-center px-2 py-1 rounded-md text-sm sm:text-base text-white bg-blue-600 hover:bg-blue-700"
|
className="shadow flex flex-row justify-center items-center px-2 py-1 rounded-md text-sm sm:text-base text-white bg-blue-600 hover:bg-blue-700"
|
||||||
href="https://github.com/boojack/slash#deploy-with-docker-in-seconds"
|
href="https://github.com/boojack/slash#deploy-with-docker-in-seconds"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Button, Input, Modal, ModalDialog } from "@mui/joy";
|
import { Button, Input, Modal, ModalDialog } from "@mui/joy";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -11,6 +12,7 @@ interface Props {
|
|||||||
|
|
||||||
const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
|
const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose } = props;
|
const { onClose } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const currentUser = userStore.getCurrentUser();
|
const currentUser = userStore.getCurrentUser();
|
||||||
const [email, setEmail] = useState(currentUser.email);
|
const [email, setEmail] = useState(currentUser.email);
|
||||||
@ -73,10 +75,10 @@ const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-end items-center space-x-2">
|
<div className="w-full flex flex-row justify-end items-center space-x-2">
|
||||||
<Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}>
|
<Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}>
|
||||||
Cancel
|
{t("common.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
|
||||||
Save
|
{t("common.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,6 +2,7 @@ import { Button, Modal, ModalDialog } from "@mui/joy";
|
|||||||
import { QRCodeCanvas } from "qrcode.react";
|
import { QRCodeCanvas } from "qrcode.react";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { absolutifyLink } from "../helpers/utils";
|
import { absolutifyLink } from "../helpers/utils";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ interface Props {
|
|||||||
|
|
||||||
const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
|
const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { shortcut, onClose } = props;
|
const { shortcut, onClose } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
||||||
|
|
||||||
@ -49,7 +51,7 @@ const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
|
|||||||
<div className="w-full flex flex-row justify-center items-center px-4">
|
<div className="w-full flex flex-row justify-center items-center px-4">
|
||||||
<Button className="w-full" color="neutral" onClick={handleDownloadQRCodeClick}>
|
<Button className="w-full" color="neutral" onClick={handleDownloadQRCodeClick}>
|
||||||
<Icon.Download className="w-4 h-auto mr-1" />
|
<Icon.Download className="w-4 h-auto mr-1" />
|
||||||
Download
|
{t("common.download")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,8 +21,8 @@ const Header: React.FC = () => {
|
|||||||
<div className="w-full bg-gray-50 border-b border-b-gray-200">
|
<div className="w-full bg-gray-50 border-b border-b-gray-200">
|
||||||
<div className="w-full max-w-6xl mx-auto px-3 md:px-12 py-5 flex flex-row justify-between items-center">
|
<div className="w-full max-w-6xl mx-auto px-3 md:px-12 py-5 flex flex-row justify-between items-center">
|
||||||
<div className="flex flex-row justify-start items-center shrink mr-2">
|
<div className="flex flex-row justify-start items-center shrink mr-2">
|
||||||
<Link to="/" className="text-base font-mono font-medium cursor-pointer flex flex-row justify-start items-center">
|
<Link to="/" className="text-lg cursor-pointer flex flex-row justify-start items-center">
|
||||||
<img src="/logo.png" className="w-8 h-auto mr-2" alt="" />
|
<img src="/logo.png" className="w-8 h-auto mr-2 -mt-0.5" alt="" />
|
||||||
Slash
|
Slash
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import { shortcutService } from "../services";
|
import { shortcutService } from "../services";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
import { showCommonDialog } from "./Alert";
|
import { showCommonDialog } from "./Alert";
|
||||||
import AnalyticsDialog from "./AnalyticsDialog";
|
|
||||||
import CreateShortcutDialog from "./CreateShortcutDialog";
|
import CreateShortcutDialog from "./CreateShortcutDialog";
|
||||||
import GenerateQRCodeDialog from "./GenerateQRCodeDialog";
|
import GenerateQRCodeDialog from "./GenerateQRCodeDialog";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -14,10 +15,11 @@ interface Props {
|
|||||||
|
|
||||||
const ShortcutActionsDropdown = (props: Props) => {
|
const ShortcutActionsDropdown = (props: Props) => {
|
||||||
const { shortcut } = props;
|
const { shortcut } = props;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
const currentUser = useUserStore().getCurrentUser();
|
const currentUser = useUserStore().getCurrentUser();
|
||||||
const [showEditDialog, setShowEditDialog] = useState<boolean>(false);
|
const [showEditDialog, setShowEditDialog] = useState<boolean>(false);
|
||||||
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
|
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
|
||||||
const [showAnalyticsDialog, setShowAnalyticsDialog] = useState<boolean>(false);
|
|
||||||
const havePermission = currentUser.role === "ADMIN" || shortcut.creatorId === currentUser.id;
|
const havePermission = currentUser.role === "ADMIN" || shortcut.creatorId === currentUser.id;
|
||||||
|
|
||||||
const handleDeleteShortcutButtonClick = (shortcut: Shortcut) => {
|
const handleDeleteShortcutButtonClick = (shortcut: Shortcut) => {
|
||||||
@ -31,6 +33,10 @@ const ShortcutActionsDropdown = (props: Props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const gotoAnalytics = () => {
|
||||||
|
navigate(`/shortcut/${shortcut.id}#analytics`);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@ -42,7 +48,7 @@ const ShortcutActionsDropdown = (props: Props) => {
|
|||||||
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
||||||
onClick={() => setShowEditDialog(true)}
|
onClick={() => setShowEditDialog(true)}
|
||||||
>
|
>
|
||||||
<Icon.Edit className="w-4 h-auto mr-2" /> Edit
|
<Icon.Edit className="w-4 h-auto mr-2" /> {t("common.edit")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
@ -53,9 +59,9 @@ const ShortcutActionsDropdown = (props: Props) => {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
||||||
onClick={() => setShowAnalyticsDialog(true)}
|
onClick={gotoAnalytics}
|
||||||
>
|
>
|
||||||
<Icon.BarChart2 className="w-4 h-auto mr-2" /> Analytics
|
<Icon.BarChart2 className="w-4 h-auto mr-2" /> {t("analytics.self")}
|
||||||
</button>
|
</button>
|
||||||
{havePermission && (
|
{havePermission && (
|
||||||
<button
|
<button
|
||||||
@ -64,7 +70,7 @@ const ShortcutActionsDropdown = (props: Props) => {
|
|||||||
handleDeleteShortcutButtonClick(shortcut);
|
handleDeleteShortcutButtonClick(shortcut);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon.Trash className="w-4 h-auto mr-2" /> Delete
|
<Icon.Trash className="w-4 h-auto mr-2" /> {t("common.delete")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
@ -80,8 +86,6 @@ const ShortcutActionsDropdown = (props: Props) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{showQRCodeDialog && <GenerateQRCodeDialog shortcut={shortcut} onClose={() => setShowQRCodeDialog(false)} />}
|
{showQRCodeDialog && <GenerateQRCodeDialog shortcut={shortcut} onClose={() => setShowQRCodeDialog(false)} />}
|
||||||
|
|
||||||
{showAnalyticsDialog && <AnalyticsDialog shortcutId={shortcut.id} onClose={() => setShowAnalyticsDialog(false)} />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,6 @@ import { Link } from "react-router-dom";
|
|||||||
import { absolutifyLink } from "../helpers/utils";
|
import { absolutifyLink } from "../helpers/utils";
|
||||||
import useFaviconStore from "../stores/v1/favicon";
|
import useFaviconStore from "../stores/v1/favicon";
|
||||||
import useViewStore from "../stores/v1/view";
|
import useViewStore from "../stores/v1/view";
|
||||||
import AnalyticsDialog from "./AnalyticsDialog";
|
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import ShortcutActionsDropdown from "./ShortcutActionsDropdown";
|
import ShortcutActionsDropdown from "./ShortcutActionsDropdown";
|
||||||
import VisibilityIcon from "./VisibilityIcon";
|
import VisibilityIcon from "./VisibilityIcon";
|
||||||
@ -23,7 +22,6 @@ const ShortcutView = (props: Props) => {
|
|||||||
const viewStore = useViewStore();
|
const viewStore = useViewStore();
|
||||||
const faviconStore = useFaviconStore();
|
const faviconStore = useFaviconStore();
|
||||||
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
||||||
const [showAnalyticsDialog, setShowAnalyticsDialog] = useState<boolean>(false);
|
|
||||||
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -55,7 +53,7 @@ const ShortcutView = (props: Props) => {
|
|||||||
<div className="w-full flex flex-row justify-start items-center">
|
<div className="w-full flex flex-row justify-start items-center">
|
||||||
<a
|
<a
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"max-w-[calc(100%-24px) flex flex-row px-1 mr-1 justify-start items-center cursor-pointer rounded-md hover:bg-gray-100 hover:shadow"
|
"max-w-[calc(100%-36px)] flex flex-row px-1 mr-1 justify-start items-center cursor-pointer rounded-md hover:bg-gray-100 hover:shadow"
|
||||||
)}
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
href={shortcutLink}
|
href={shortcutLink}
|
||||||
@ -124,18 +122,16 @@ const ShortcutView = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="View count" variant="solid" placement="top" arrow>
|
<Tooltip title="View count" variant="solid" placement="top" arrow>
|
||||||
<div
|
<Link
|
||||||
|
to={`/shortcut/${shortcut.id}#analytics`}
|
||||||
className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm"
|
className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm"
|
||||||
onClick={() => setShowAnalyticsDialog(true)}
|
|
||||||
>
|
>
|
||||||
<Icon.BarChart2 className="w-4 h-auto mr-1" />
|
<Icon.BarChart2 className="w-4 h-auto mr-1" />
|
||||||
{shortcut.view} visits
|
{shortcut.view} visits
|
||||||
</div>
|
</Link>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showAnalyticsDialog && <AnalyticsDialog shortcutId={shortcut.id} onClose={() => setShowAnalyticsDialog(false)} />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Button, Divider, Option, Select } from "@mui/joy";
|
import { Divider, Option, Select, Switch } from "@mui/joy";
|
||||||
import { toast } from "react-hot-toast";
|
|
||||||
import useViewStore from "../stores/v1/view";
|
import useViewStore from "../stores/v1/view";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import Dropdown from "./common/Dropdown";
|
import Dropdown from "./common/Dropdown";
|
||||||
@ -10,11 +9,6 @@ const ViewSetting = () => {
|
|||||||
const { field, direction } = order;
|
const { field, direction } = order;
|
||||||
const displayStyle = viewStore.displayStyle || "full";
|
const displayStyle = viewStore.displayStyle || "full";
|
||||||
|
|
||||||
const handleReset = () => {
|
|
||||||
viewStore.setOrder({ field: "name", direction: "asc" });
|
|
||||||
toast.success("Order reset");
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
trigger={
|
trigger={
|
||||||
@ -24,13 +18,16 @@ const ViewSetting = () => {
|
|||||||
}
|
}
|
||||||
actionsClassName="!mt-3 !-right-2"
|
actionsClassName="!mt-3 !-right-2"
|
||||||
actions={
|
actions={
|
||||||
<div className="w-52 p-2 pt-0 gap-2 flex flex-col justify-start items-start" onClick={(e) => e.stopPropagation()}>
|
<div className="w-52 p-2 gap-2 flex flex-col justify-start items-start" onClick={(e) => e.stopPropagation()}>
|
||||||
<div className="w-full flex flex-row justify-between items-center mt-1">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm font-medium">View order</span>
|
<span className="text-sm shrink-0 mr-2">Compact mode</span>
|
||||||
<Button size="sm" variant="plain" color="neutral" onClick={handleReset}>
|
<Switch
|
||||||
<Icon.RefreshCw className="w-4 h-auto text-gray-500" />
|
size="sm"
|
||||||
</Button>
|
checked={displayStyle === "compact"}
|
||||||
|
onChange={(event) => viewStore.setDisplayStyle(event.target.checked ? "compact" : "full")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<Divider className="!my-1" />
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm shrink-0 mr-2">Order by</span>
|
<span className="text-sm shrink-0 mr-2">Order by</span>
|
||||||
<Select size="sm" value={field} onChange={(_, value) => viewStore.setOrder({ field: value as any })}>
|
<Select size="sm" value={field} onChange={(_, value) => viewStore.setOrder({ field: value as any })}>
|
||||||
@ -47,14 +44,6 @@ const ViewSetting = () => {
|
|||||||
<Option value={"desc"}>DESC</Option>
|
<Option value={"desc"}>DESC</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
|
||||||
<span className="text-sm shrink-0 mr-2">Display</span>
|
|
||||||
<Select size="sm" value={displayStyle} onChange={(_, value) => viewStore.setDisplayStyle(value as any)}>
|
|
||||||
<Option value={"full"}>Full</Option>
|
|
||||||
<Option value={"compact"}>Compact</Option>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
></Dropdown>
|
></Dropdown>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button } from "@mui/joy";
|
import { Button, IconButton } from "@mui/joy";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
@ -110,7 +110,7 @@ const AccessTokenSection = () => {
|
|||||||
{String(userAccessToken.expiresAt ?? "Never")}
|
{String(userAccessToken.expiresAt ?? "Never")}
|
||||||
</td>
|
</td>
|
||||||
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm">
|
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm">
|
||||||
<Button
|
<IconButton
|
||||||
color="danger"
|
color="danger"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
size="sm"
|
size="sm"
|
||||||
@ -119,7 +119,7 @@ const AccessTokenSection = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Icon.Trash className="w-4 h-auto" />
|
<Icon.Trash className="w-4 h-auto" />
|
||||||
</Button>
|
</IconButton>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
@ -19,7 +19,7 @@ const AccountSection: React.FC = () => {
|
|||||||
{isAdmin && <span className="ml-2 bg-blue-600 text-white px-2 leading-6 text-sm rounded-full">Admin</span>}
|
{isAdmin && <span className="ml-2 bg-blue-600 text-white px-2 leading-6 text-sm rounded-full">Admin</span>}
|
||||||
</p>
|
</p>
|
||||||
<p className="flex flex-row justify-start items-center">
|
<p className="flex flex-row justify-start items-center">
|
||||||
<span className="mr-3 text-gray-500 font-mono">Email: </span>
|
<span className="mr-3 text-gray-500">Email: </span>
|
||||||
{currentUser.email}
|
{currentUser.email}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-row justify-start items-center gap-2 mt-2">
|
<div className="flex flex-row justify-start items-center gap-2 mt-2">
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import { Button } from "@mui/joy";
|
import { Button, IconButton } from "@mui/joy";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
import useUserStore from "../../stores/v1/user";
|
import useUserStore from "../../stores/v1/user";
|
||||||
|
import { showCommonDialog } from "../Alert";
|
||||||
import CreateUserDialog from "../CreateUserDialog";
|
import CreateUserDialog from "../CreateUserDialog";
|
||||||
|
import Icon from "../Icon";
|
||||||
|
|
||||||
const MemberSection = () => {
|
const MemberSection = () => {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@ -18,6 +21,22 @@ const MemberSection = () => {
|
|||||||
setCurrentEditingUser(undefined);
|
setCurrentEditingUser(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteUser = async (user: User) => {
|
||||||
|
showCommonDialog({
|
||||||
|
title: "Delete User",
|
||||||
|
content: `Are you sure to delete user \`${user.nickname}\`? You cannot undo this action.`,
|
||||||
|
style: "danger",
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
await userStore.deleteUser(user.id);
|
||||||
|
toast.success(`User \`${user.nickname}\` deleted successfully`);
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(`Failed to delete user \`${user.nickname}\`: ${error.response.data.message}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full flex flex-col justify-start items-start space-y-4">
|
<div className="w-full flex flex-col justify-start items-start space-y-4">
|
||||||
@ -68,16 +87,20 @@ const MemberSection = () => {
|
|||||||
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900">{user.nickname}</td>
|
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900">{user.nickname}</td>
|
||||||
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.email}</td>
|
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.email}</td>
|
||||||
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.role}</td>
|
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{user.role}</td>
|
||||||
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium">
|
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm">
|
||||||
<button
|
<IconButton
|
||||||
className="text-indigo-600 hover:text-indigo-900"
|
size="sm"
|
||||||
|
variant="plain"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentEditingUser(user);
|
setCurrentEditingUser(user);
|
||||||
setShowCreateUserDialog(true);
|
setShowCreateUserDialog(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Edit
|
<Icon.PenBox className="w-4 h-auto" />
|
||||||
</button>
|
</IconButton>
|
||||||
|
<IconButton size="sm" color="danger" variant="plain" onClick={() => handleDeleteUser(user)}>
|
||||||
|
<Icon.Trash className="w-4 h-auto" />
|
||||||
|
</IconButton>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
@ -43,8 +43,8 @@ export function patchUser(userPatch: UserPatch) {
|
|||||||
return axios.patch<User>(`/api/v1/user/${userPatch.id}`, userPatch);
|
return axios.patch<User>(`/api/v1/user/${userPatch.id}`, userPatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteUser(userDelete: UserDelete) {
|
export function deleteUser(userId: UserId) {
|
||||||
return axios.delete(`/api/v1/user/${userDelete.id}`);
|
return axios.delete(`/api/v2/users/${userId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getShortcutList(shortcutFind?: ShortcutFind) {
|
export function getShortcutList(shortcutFind?: ShortcutFind) {
|
||||||
|
@ -1,4 +1,24 @@
|
|||||||
{
|
{
|
||||||
|
"common": {
|
||||||
|
"about": "About",
|
||||||
|
"loading": "Loading",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"save": "Save",
|
||||||
|
"create": "Create",
|
||||||
|
"download": "Download",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete"
|
||||||
|
},
|
||||||
|
"analytics": {
|
||||||
|
"self": "Analytics",
|
||||||
|
"top-sources": "Top Sources",
|
||||||
|
"source": "Source",
|
||||||
|
"visitors": "Visitors",
|
||||||
|
"devices": "Devices",
|
||||||
|
"browser": "Browser",
|
||||||
|
"browsers": "Browsers",
|
||||||
|
"operating-system": "Operating System"
|
||||||
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"private": {
|
"private": {
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
import { Button } from "@mui/joy";
|
|
||||||
import { useState } from "react";
|
|
||||||
import ChangePasswordDialog from "../components/ChangePasswordDialog";
|
|
||||||
import EditUserinfoDialog from "../components/EditUserinfoDialog";
|
|
||||||
import useUserStore from "../stores/v1/user";
|
|
||||||
|
|
||||||
const Account: React.FC = () => {
|
|
||||||
const currentUser = useUserStore().getCurrentUser();
|
|
||||||
const [showEditUserinfoDialog, setShowEditUserinfoDialog] = useState<boolean>(false);
|
|
||||||
const [showChangePasswordDialog, setShowChangePasswordDialog] = useState<boolean>(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="mx-auto max-w-6xl w-full px-3 md:px-12 py-6 flex flex-col justify-start items-start space-y-4">
|
|
||||||
<p className="text-3xl my-2">{currentUser.nickname}</p>
|
|
||||||
<p className="leading-8 flex flex-row justify-start items-center">
|
|
||||||
<span className="mr-3 text-gray-500 font-mono">Email: </span>
|
|
||||||
{currentUser.email}
|
|
||||||
</p>
|
|
||||||
<div className="flex flex-row justify-start items-center gap-2">
|
|
||||||
<Button variant="outlined" color="neutral" onClick={() => setShowEditUserinfoDialog(true)}>
|
|
||||||
Edit
|
|
||||||
</Button>
|
|
||||||
<Button variant="outlined" color="neutral" onClick={() => setShowChangePasswordDialog(true)}>
|
|
||||||
Change password
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{showEditUserinfoDialog && <EditUserinfoDialog onClose={() => setShowEditUserinfoDialog(false)} />}
|
|
||||||
|
|
||||||
{showChangePasswordDialog && <ChangePasswordDialog onClose={() => setShowChangePasswordDialog(false)} />}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Account;
|
|
@ -175,7 +175,7 @@ const ShortcutDetail = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full flex flex-col mt-8">
|
<div className="w-full flex flex-col mt-8">
|
||||||
<h3 className="pl-1 font-medium text-lg flex flex-row justify-start items-center">
|
<h3 id="analytics" className="pl-1 font-medium text-lg flex flex-row justify-start items-center">
|
||||||
<Icon.BarChart2 className="w-6 h-auto mr-1" />
|
<Icon.BarChart2 className="w-6 h-auto mr-1" />
|
||||||
Analytics
|
Analytics
|
||||||
</h3>
|
</h3>
|
||||||
|
@ -74,7 +74,7 @@ const SignIn: React.FC = () => {
|
|||||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||||
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
||||||
<img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
|
<img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
|
||||||
<span className="text-3xl font-medium font-mono opacity-80">Slash</span>
|
<span className="text-3xl opacity-80">Slash</span>
|
||||||
</div>
|
</div>
|
||||||
<form className="w-full mt-6" onSubmit={handleSigninBtnClick}>
|
<form className="w-full mt-6" onSubmit={handleSigninBtnClick}>
|
||||||
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
|
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
|
||||||
|
@ -78,7 +78,7 @@ const SignUp: React.FC = () => {
|
|||||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||||
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
||||||
<img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
|
<img src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
|
||||||
<span className="text-3xl font-medium font-mono opacity-80">Slash</span>
|
<span className="text-3xl opacity-80">Slash</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="w-full text-2xl mt-6">Create your account</p>
|
<p className="w-full text-2xl mt-6">Create your account</p>
|
||||||
<form className="w-full mt-4" onSubmit={handleSignupBtnClick}>
|
<form className="w-full mt-4" onSubmit={handleSignupBtnClick}>
|
||||||
|
@ -19,6 +19,7 @@ interface UserState {
|
|||||||
getCurrentUser: () => User;
|
getCurrentUser: () => User;
|
||||||
createUser: (userCreate: UserCreate) => Promise<User>;
|
createUser: (userCreate: UserCreate) => Promise<User>;
|
||||||
patchUser: (userPatch: UserPatch) => Promise<void>;
|
patchUser: (userPatch: UserPatch) => Promise<void>;
|
||||||
|
deleteUser: (id: UserId) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useUserStore = create<UserState>()((set, get) => ({
|
const useUserStore = create<UserState>()((set, get) => ({
|
||||||
@ -67,6 +68,12 @@ const useUserStore = create<UserState>()((set, get) => ({
|
|||||||
userMap[user.id] = user;
|
userMap[user.id] = user;
|
||||||
set(userMap);
|
set(userMap);
|
||||||
},
|
},
|
||||||
|
deleteUser: async (userId: UserId) => {
|
||||||
|
await api.deleteUser(userId);
|
||||||
|
const userMap = get().userMapById;
|
||||||
|
delete userMap[userId];
|
||||||
|
set(userMap);
|
||||||
|
},
|
||||||
getUserById: (id: UserId) => {
|
getUserById: (id: UserId) => {
|
||||||
const userMap = get().userMapById;
|
const userMap = get().userMapById;
|
||||||
return userMap[id] as User;
|
return userMap[id] as User;
|
||||||
|
@ -236,3 +236,94 @@ export declare class GetShortcutResponse extends Message<GetShortcutResponse> {
|
|||||||
static equals(a: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined, b: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined): boolean;
|
static equals(a: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined, b: GetShortcutResponse | PlainMessage<GetShortcutResponse> | undefined): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutRequest
|
||||||
|
*/
|
||||||
|
export declare class CreateShortcutRequest extends Message<CreateShortcutRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.Shortcut shortcut = 1;
|
||||||
|
*/
|
||||||
|
shortcut?: Shortcut;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateShortcutRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateShortcutRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateShortcutRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateShortcutRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateShortcutRequest;
|
||||||
|
|
||||||
|
static equals(a: CreateShortcutRequest | PlainMessage<CreateShortcutRequest> | undefined, b: CreateShortcutRequest | PlainMessage<CreateShortcutRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutResponse
|
||||||
|
*/
|
||||||
|
export declare class CreateShortcutResponse extends Message<CreateShortcutResponse> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.Shortcut shortcut = 1;
|
||||||
|
*/
|
||||||
|
shortcut?: Shortcut;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateShortcutResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateShortcutResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateShortcutResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateShortcutResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateShortcutResponse;
|
||||||
|
|
||||||
|
static equals(a: CreateShortcutResponse | PlainMessage<CreateShortcutResponse> | undefined, b: CreateShortcutResponse | PlainMessage<CreateShortcutResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutRequest
|
||||||
|
*/
|
||||||
|
export declare class DeleteShortcutRequest extends Message<DeleteShortcutRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: string name = 1;
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<DeleteShortcutRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteShortcutRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteShortcutRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteShortcutRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteShortcutRequest;
|
||||||
|
|
||||||
|
static equals(a: DeleteShortcutRequest | PlainMessage<DeleteShortcutRequest> | undefined, b: DeleteShortcutRequest | PlainMessage<DeleteShortcutRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutResponse
|
||||||
|
*/
|
||||||
|
export declare class DeleteShortcutResponse extends Message<DeleteShortcutResponse> {
|
||||||
|
constructor(data?: PartialMessage<DeleteShortcutResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteShortcutResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteShortcutResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteShortcutResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteShortcutResponse;
|
||||||
|
|
||||||
|
static equals(a: DeleteShortcutResponse | PlainMessage<DeleteShortcutResponse> | undefined, b: DeleteShortcutResponse | PlainMessage<DeleteShortcutResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -90,3 +90,41 @@ export const GetShortcutResponse = proto3.makeMessageType(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutRequest
|
||||||
|
*/
|
||||||
|
export const CreateShortcutRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateShortcutRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "shortcut", kind: "message", T: Shortcut },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateShortcutResponse
|
||||||
|
*/
|
||||||
|
export const CreateShortcutResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateShortcutResponse",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "shortcut", kind: "message", T: Shortcut },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutRequest
|
||||||
|
*/
|
||||||
|
export const DeleteShortcutRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteShortcutRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteShortcutResponse
|
||||||
|
*/
|
||||||
|
export const DeleteShortcutResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteShortcutResponse",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
139
web/src/types/proto/api/v2/user_service_pb.d.ts
vendored
139
web/src/types/proto/api/v2/user_service_pb.d.ts
vendored
@ -66,6 +66,11 @@ export declare class User extends Message<User> {
|
|||||||
*/
|
*/
|
||||||
nickname: string;
|
nickname: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: string password = 9;
|
||||||
|
*/
|
||||||
|
password: string;
|
||||||
|
|
||||||
constructor(data?: PartialMessage<User>);
|
constructor(data?: PartialMessage<User>);
|
||||||
|
|
||||||
static readonly runtime: typeof proto3;
|
static readonly runtime: typeof proto3;
|
||||||
@ -81,6 +86,49 @@ export declare class User extends Message<User> {
|
|||||||
static equals(a: User | PlainMessage<User> | undefined, b: User | PlainMessage<User> | undefined): boolean;
|
static equals(a: User | PlainMessage<User> | undefined, b: User | PlainMessage<User> | undefined): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersRequest
|
||||||
|
*/
|
||||||
|
export declare class ListUsersRequest extends Message<ListUsersRequest> {
|
||||||
|
constructor(data?: PartialMessage<ListUsersRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.ListUsersRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListUsersRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListUsersRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListUsersRequest;
|
||||||
|
|
||||||
|
static equals(a: ListUsersRequest | PlainMessage<ListUsersRequest> | undefined, b: ListUsersRequest | PlainMessage<ListUsersRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersResponse
|
||||||
|
*/
|
||||||
|
export declare class ListUsersResponse extends Message<ListUsersResponse> {
|
||||||
|
/**
|
||||||
|
* @generated from field: repeated slash.api.v2.User users = 1;
|
||||||
|
*/
|
||||||
|
users: User[];
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<ListUsersResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.ListUsersResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ListUsersResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ListUsersResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ListUsersResponse;
|
||||||
|
|
||||||
|
static equals(a: ListUsersResponse | PlainMessage<ListUsersResponse> | undefined, b: ListUsersResponse | PlainMessage<ListUsersResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message slash.api.v2.GetUserRequest
|
* @generated from message slash.api.v2.GetUserRequest
|
||||||
*/
|
*/
|
||||||
@ -129,6 +177,97 @@ export declare class GetUserResponse extends Message<GetUserResponse> {
|
|||||||
static equals(a: GetUserResponse | PlainMessage<GetUserResponse> | undefined, b: GetUserResponse | PlainMessage<GetUserResponse> | undefined): boolean;
|
static equals(a: GetUserResponse | PlainMessage<GetUserResponse> | undefined, b: GetUserResponse | PlainMessage<GetUserResponse> | undefined): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserRequest
|
||||||
|
*/
|
||||||
|
export declare class CreateUserRequest extends Message<CreateUserRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.User user = 1;
|
||||||
|
*/
|
||||||
|
user?: User;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateUserRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateUserRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateUserRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateUserRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateUserRequest;
|
||||||
|
|
||||||
|
static equals(a: CreateUserRequest | PlainMessage<CreateUserRequest> | undefined, b: CreateUserRequest | PlainMessage<CreateUserRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserResponse
|
||||||
|
*/
|
||||||
|
export declare class CreateUserResponse extends Message<CreateUserResponse> {
|
||||||
|
/**
|
||||||
|
* @generated from field: slash.api.v2.User user = 1;
|
||||||
|
*/
|
||||||
|
user?: User;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<CreateUserResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.CreateUserResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): CreateUserResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): CreateUserResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): CreateUserResponse;
|
||||||
|
|
||||||
|
static equals(a: CreateUserResponse | PlainMessage<CreateUserResponse> | undefined, b: CreateUserResponse | PlainMessage<CreateUserResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserRequest
|
||||||
|
*/
|
||||||
|
export declare class DeleteUserRequest extends Message<DeleteUserRequest> {
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 id = 1;
|
||||||
|
*/
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<DeleteUserRequest>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteUserRequest";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteUserRequest;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteUserRequest;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteUserRequest;
|
||||||
|
|
||||||
|
static equals(a: DeleteUserRequest | PlainMessage<DeleteUserRequest> | undefined, b: DeleteUserRequest | PlainMessage<DeleteUserRequest> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserResponse
|
||||||
|
*/
|
||||||
|
export declare class DeleteUserResponse extends Message<DeleteUserResponse> {
|
||||||
|
constructor(data?: PartialMessage<DeleteUserResponse>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.api.v2.DeleteUserResponse";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): DeleteUserResponse;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): DeleteUserResponse;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): DeleteUserResponse;
|
||||||
|
|
||||||
|
static equals(a: DeleteUserResponse | PlainMessage<DeleteUserResponse> | undefined, b: DeleteUserResponse | PlainMessage<DeleteUserResponse> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
||||||
*/
|
*/
|
||||||
|
@ -31,6 +31,25 @@ export const User = proto3.makeMessageType(
|
|||||||
{ no: 6, name: "role", kind: "enum", T: proto3.getEnumType(Role) },
|
{ no: 6, name: "role", kind: "enum", T: proto3.getEnumType(Role) },
|
||||||
{ no: 7, name: "email", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
{ no: 7, name: "email", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
{ no: 8, name: "nickname", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
{ no: 8, name: "nickname", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
|
{ no: 9, name: "password", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersRequest
|
||||||
|
*/
|
||||||
|
export const ListUsersRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.ListUsersRequest",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.ListUsersResponse
|
||||||
|
*/
|
||||||
|
export const ListUsersResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.ListUsersResponse",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "users", kind: "message", T: User, repeated: true },
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -54,6 +73,44 @@ export const GetUserResponse = proto3.makeMessageType(
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserRequest
|
||||||
|
*/
|
||||||
|
export const CreateUserRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateUserRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "user", kind: "message", T: User },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.CreateUserResponse
|
||||||
|
*/
|
||||||
|
export const CreateUserResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.CreateUserResponse",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "user", kind: "message", T: User },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserRequest
|
||||||
|
*/
|
||||||
|
export const DeleteUserRequest = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteUserRequest",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "id", kind: "scalar", T: 5 /* ScalarType.INT32 */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.api.v2.DeleteUserResponse
|
||||||
|
*/
|
||||||
|
export const DeleteUserResponse = proto3.makeMessageType(
|
||||||
|
"slash.api.v2.DeleteUserResponse",
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
* @generated from message slash.api.v2.ListUserAccessTokensRequest
|
||||||
*/
|
*/
|
||||||
|
32
web/src/types/proto/store/activity_pb.d.ts
vendored
Normal file
32
web/src/types/proto/store/activity_pb.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// @generated by protoc-gen-es v1.3.0
|
||||||
|
// @generated from file store/activity.proto (package slash.store, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
|
||||||
|
import { Message, proto3 } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.store.ActivityShorcutCreatePayload
|
||||||
|
*/
|
||||||
|
export declare class ActivityShorcutCreatePayload extends Message<ActivityShorcutCreatePayload> {
|
||||||
|
/**
|
||||||
|
* @generated from field: int32 shortcut_id = 1;
|
||||||
|
*/
|
||||||
|
shortcutId: number;
|
||||||
|
|
||||||
|
constructor(data?: PartialMessage<ActivityShorcutCreatePayload>);
|
||||||
|
|
||||||
|
static readonly runtime: typeof proto3;
|
||||||
|
static readonly typeName = "slash.store.ActivityShorcutCreatePayload";
|
||||||
|
static readonly fields: FieldList;
|
||||||
|
|
||||||
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ActivityShorcutCreatePayload;
|
||||||
|
|
||||||
|
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ActivityShorcutCreatePayload;
|
||||||
|
|
||||||
|
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ActivityShorcutCreatePayload;
|
||||||
|
|
||||||
|
static equals(a: ActivityShorcutCreatePayload | PlainMessage<ActivityShorcutCreatePayload> | undefined, b: ActivityShorcutCreatePayload | PlainMessage<ActivityShorcutCreatePayload> | undefined): boolean;
|
||||||
|
}
|
||||||
|
|
17
web/src/types/proto/store/activity_pb.js
Normal file
17
web/src/types/proto/store/activity_pb.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// @generated by protoc-gen-es v1.3.0
|
||||||
|
// @generated from file store/activity.proto (package slash.store, syntax proto3)
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { proto3 } from "@bufbuild/protobuf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message slash.store.ActivityShorcutCreatePayload
|
||||||
|
*/
|
||||||
|
export const ActivityShorcutCreatePayload = proto3.makeMessageType(
|
||||||
|
"slash.store.ActivityShorcutCreatePayload",
|
||||||
|
() => [
|
||||||
|
{ no: 1, name: "shortcut_id", kind: "scalar", T: 5 /* ScalarType.INT32 */ },
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
Reference in New Issue
Block a user