refactor: rename workspace to instance throughout codebase

Remove work-related terminology by renaming "workspace" to "instance"
across the entire application. This change better reflects that Memos
is a self-hosted tool suitable for personal and non-work use cases.

Breaking Changes:
- API endpoints: /api/v1/workspace/* → /api/v1/instance/*
- gRPC service: WorkspaceService → InstanceService
- Proto types: WorkspaceSetting → InstanceSetting
- Frontend translation keys: workspace-section → instance-section

Backend Changes:
- Renamed proto definitions and regenerated code
- Updated all store layer methods and database drivers
- Renamed service implementations and API handlers
- Updated cache from workspaceSettingCache to instanceSettingCache

Frontend Changes:
- Renamed service client: workspaceServiceClient → instanceServiceClient
- Updated all React components and state management
- Refactored stores: workspace.ts → instance.ts
- Updated all 32 locale translation files

All tests pass and both backend and frontend build successfully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steven 2025-11-05 23:35:35 +08:00
parent d98ee36178
commit 4c1d1c70d1
111 changed files with 3291 additions and 5290 deletions

View File

@ -122,7 +122,7 @@ The server uses `cmux` (connection multiplexer) to serve both gRPC and HTTP on t
- **HTTP/1.1** → Echo server (REST API via gRPC-Gateway, static files, RSS)
**API Services** (defined in `proto/api/v1/*.proto`):
- `WorkspaceService` - Workspace settings and profiles
- `InstanceService` - Instance settings and profiles
- `AuthService` - Authentication and session management
- `UserService` - User management
- `MemoService` - Core memo CRUD operations
@ -147,7 +147,7 @@ The `store.Driver` interface (`store/driver.go`) defines all data access methods
- `store/db/postgres/` - PostgreSQL driver
**Migrations:**
Each driver contains its own migration files in subdirectories. Schema version tracking is stored in `workspace_setting` (key: `bb.general.version`). The `store/migrator.go` orchestrates migrations across all drivers.
Each driver contains its own migration files in subdirectories. Schema version tracking is stored in `instance_setting` (key: `bb.general.version`). The `store/migrator.go` orchestrates migrations across all drivers.
**Key Models:**
- `Memo` - Core note/memo entity
@ -157,7 +157,7 @@ Each driver contains its own migration files in subdirectories. Schema version t
- `Activity` - Activity log entries
- `Inbox` - Inbox items
- `Reaction` - Emoji reactions
- `WorkspaceSetting` - Workspace-level configuration
- `InstanceSetting` - Instance-level configuration
- `UserSetting` - User preferences
- `IdentityProvider` - OAuth/SSO provider configs

View File

@ -10,30 +10,30 @@ import "google/protobuf/field_mask.proto";
option go_package = "gen/api/v1";
service WorkspaceService {
// Gets the workspace profile.
rpc GetWorkspaceProfile(GetWorkspaceProfileRequest) returns (WorkspaceProfile) {
option (google.api.http) = {get: "/api/v1/workspace/profile"};
service InstanceService {
// Gets the instance profile.
rpc GetInstanceProfile(GetInstanceProfileRequest) returns (InstanceProfile) {
option (google.api.http) = {get: "/api/v1/instance/profile"};
}
// Gets a workspace setting.
rpc GetWorkspaceSetting(GetWorkspaceSettingRequest) returns (WorkspaceSetting) {
option (google.api.http) = {get: "/api/v1/{name=workspace/settings/*}"};
// Gets an instance setting.
rpc GetInstanceSetting(GetInstanceSettingRequest) returns (InstanceSetting) {
option (google.api.http) = {get: "/api/v1/{name=instance/settings/*}"};
option (google.api.method_signature) = "name";
}
// Updates a workspace setting.
rpc UpdateWorkspaceSetting(UpdateWorkspaceSettingRequest) returns (WorkspaceSetting) {
// Updates an instance setting.
rpc UpdateInstanceSetting(UpdateInstanceSettingRequest) returns (InstanceSetting) {
option (google.api.http) = {
patch: "/api/v1/{setting.name=workspace/settings/*}"
patch: "/api/v1/{setting.name=instance/settings/*}"
body: "setting"
};
option (google.api.method_signature) = "setting,update_mask";
}
}
// Workspace profile message containing basic workspace information.
message WorkspaceProfile {
// Instance profile message containing basic instance information.
message InstanceProfile {
// The name of instance owner.
// Format: users/{user}
string owner = 1;
@ -48,20 +48,20 @@ message WorkspaceProfile {
string instance_url = 6;
}
// Request for workspace profile.
message GetWorkspaceProfileRequest {}
// Request for instance profile.
message GetInstanceProfileRequest {}
// A workspace setting resource.
message WorkspaceSetting {
// An instance setting resource.
message InstanceSetting {
option (google.api.resource) = {
type: "memos.api.v1/WorkspaceSetting"
pattern: "workspace/settings/{setting}"
singular: "workspaceSetting"
plural: "workspaceSettings"
type: "memos.api.v1/InstanceSetting"
pattern: "instance/settings/{setting}"
singular: "instanceSetting"
plural: "instanceSettings"
};
// The name of the workspace setting.
// Format: workspace/settings/{setting}
// The name of the instance setting.
// Format: instance/settings/{setting}
string name = 1 [(google.api.field_behavior) = IDENTIFIER];
oneof value {
@ -70,7 +70,7 @@ message WorkspaceSetting {
MemoRelatedSetting memo_related_setting = 4;
}
// Enumeration of workspace setting keys.
// Enumeration of instance setting keys.
enum Key {
KEY_UNSPECIFIED = 0;
// GENERAL is the key for general settings.
@ -81,7 +81,7 @@ message WorkspaceSetting {
MEMO_RELATED = 3;
}
// General workspace settings configuration.
// General instance settings configuration.
message GeneralSetting {
// theme is the name of the selected theme.
// This references a CSS file in the web/public/themes/ directory.
@ -106,7 +106,7 @@ message WorkspaceSetting {
// disallow_change_nickname disallows changing nickname.
bool disallow_change_nickname = 9;
// Custom profile configuration for workspace branding.
// Custom profile configuration for instance branding.
message CustomProfile {
string title = 1;
string description = 2;
@ -115,7 +115,7 @@ message WorkspaceSetting {
}
}
// Storage configuration settings for workspace attachments.
// Storage configuration settings for instance attachments.
message StorageSetting {
// Storage type enumeration for different storage backends.
enum StorageType {
@ -149,7 +149,7 @@ message WorkspaceSetting {
S3Config s3_config = 4;
}
// Memo-related workspace settings and policies.
// Memo-related instance settings and policies.
message MemoRelatedSetting {
// disallow_public_visibility disallows set memo as public visibility.
bool disallow_public_visibility = 1;
@ -172,20 +172,20 @@ message WorkspaceSetting {
}
}
// Request message for GetWorkspaceSetting method.
message GetWorkspaceSettingRequest {
// The resource name of the workspace setting.
// Format: workspace/settings/{setting}
// Request message for GetInstanceSetting method.
message GetInstanceSettingRequest {
// The resource name of the instance setting.
// Format: instance/settings/{setting}
string name = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {type: "memos.api.v1/WorkspaceSetting"}
(google.api.resource_reference) = {type: "memos.api.v1/InstanceSetting"}
];
}
// Request message for UpdateWorkspaceSetting method.
message UpdateWorkspaceSettingRequest {
// The workspace setting resource which replaces the resource on the server.
WorkspaceSetting setting = 1 [(google.api.field_behavior) = REQUIRED];
// Request message for UpdateInstanceSetting method.
message UpdateInstanceSettingRequest {
// The instance setting resource which replaces the resource on the server.
InstanceSetting setting = 1 [(google.api.field_behavior) = REQUIRED];
// The list of fields to update.
google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = OPTIONAL];

View File

@ -74,7 +74,7 @@ func (IdentityProvider_Type) EnumDescriptor() ([]byte, []int) {
type IdentityProvider struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The resource name of the identity provider.
// Format: identityProviders/{idp}
// Format: identity-providers/{idp}
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// Required. The type of the identity provider.
Type IdentityProvider_Type `protobuf:"varint,2,opt,name=type,proto3,enum=memos.api.v1.IdentityProvider_Type" json:"type,omitempty"`
@ -463,7 +463,7 @@ func (x *ListIdentityProvidersResponse) GetIdentityProviders() []*IdentityProvid
type GetIdentityProviderRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Required. The resource name of the identity provider to get.
// Format: identityProviders/{idp}
// Format: identity-providers/{idp}
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
@ -619,7 +619,7 @@ func (x *UpdateIdentityProviderRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
type DeleteIdentityProviderRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Required. The resource name of the identity provider to delete.
// Format: identityProviders/{idp}
// Format: identity-providers/{idp}
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
@ -666,7 +666,7 @@ var File_api_v1_idp_service_proto protoreflect.FileDescriptor
const file_api_v1_idp_service_proto_rawDesc = "" +
"\n" +
"\x18api/v1/idp_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\"\x8b\x03\n" +
"\x18api/v1/idp_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\"\x8c\x03\n" +
"\x10IdentityProvider\x12\x17\n" +
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12<\n" +
"\x04type\x18\x02 \x01(\x0e2#.memos.api.v1.IdentityProvider.TypeB\x03\xe0A\x02R\x04type\x12\x19\n" +
@ -676,8 +676,8 @@ const file_api_v1_idp_service_proto_rawDesc = "" +
"\x04Type\x12\x14\n" +
"\x10TYPE_UNSPECIFIED\x10\x00\x12\n" +
"\n" +
"\x06OAUTH2\x10\x01:f\xeaAc\n" +
"\x1dmemos.api.v1/IdentityProvider\x12\x17identityProviders/{idp}\x1a\x04name*\x11identityProviders2\x10identityProvider\"e\n" +
"\x06OAUTH2\x10\x01:g\xeaAd\n" +
"\x1dmemos.api.v1/IdentityProvider\x12\x18identity-providers/{idp}\x1a\x04name*\x11identityProviders2\x10identityProvider\"e\n" +
"\x16IdentityProviderConfig\x12A\n" +
"\roauth2_config\x18\x01 \x01(\v2\x1a.memos.api.v1.OAuth2ConfigH\x00R\foauth2ConfigB\b\n" +
"\x06config\"\x86\x01\n" +
@ -712,13 +712,13 @@ const file_api_v1_idp_service_proto_rawDesc = "" +
"updateMask\"Z\n" +
"\x1dDeleteIdentityProviderRequest\x129\n" +
"\x04name\x18\x01 \x01(\tB%\xe0A\x02\xfaA\x1f\n" +
"\x1dmemos.api.v1/IdentityProviderR\x04name2\xe2\x06\n" +
"\x17IdentityProviderService\x12\x93\x01\n" +
"\x15ListIdentityProviders\x12*.memos.api.v1.ListIdentityProvidersRequest\x1a+.memos.api.v1.ListIdentityProvidersResponse\"!\x82\xd3\xe4\x93\x02\x1b\x12\x19/api/v1/identityProviders\x12\x92\x01\n" +
"\x13GetIdentityProvider\x12(.memos.api.v1.GetIdentityProviderRequest\x1a\x1e.memos.api.v1.IdentityProvider\"1\xdaA\x04name\x82\xd3\xe4\x93\x02$\x12\"/api/v1/{name=identityProviders/*}\x12\xaf\x01\n" +
"\x16CreateIdentityProvider\x12+.memos.api.v1.CreateIdentityProviderRequest\x1a\x1e.memos.api.v1.IdentityProvider\"H\xdaA\x11identity_provider\x82\xd3\xe4\x93\x02.:\x11identity_provider\"\x19/api/v1/identityProviders\x12\xd6\x01\n" +
"\x16UpdateIdentityProvider\x12+.memos.api.v1.UpdateIdentityProviderRequest\x1a\x1e.memos.api.v1.IdentityProvider\"o\xdaA\x1didentity_provider,update_mask\x82\xd3\xe4\x93\x02I:\x11identity_provider24/api/v1/{identity_provider.name=identityProviders/*}\x12\x90\x01\n" +
"\x16DeleteIdentityProvider\x12+.memos.api.v1.DeleteIdentityProviderRequest\x1a\x16.google.protobuf.Empty\"1\xdaA\x04name\x82\xd3\xe4\x93\x02$*\"/api/v1/{name=identityProviders/*}B\xa7\x01\n" +
"\x1dmemos.api.v1/IdentityProviderR\x04name2\xe7\x06\n" +
"\x17IdentityProviderService\x12\x94\x01\n" +
"\x15ListIdentityProviders\x12*.memos.api.v1.ListIdentityProvidersRequest\x1a+.memos.api.v1.ListIdentityProvidersResponse\"\"\x82\xd3\xe4\x93\x02\x1c\x12\x1a/api/v1/identity-providers\x12\x93\x01\n" +
"\x13GetIdentityProvider\x12(.memos.api.v1.GetIdentityProviderRequest\x1a\x1e.memos.api.v1.IdentityProvider\"2\xdaA\x04name\x82\xd3\xe4\x93\x02%\x12#/api/v1/{name=identity-providers/*}\x12\xb0\x01\n" +
"\x16CreateIdentityProvider\x12+.memos.api.v1.CreateIdentityProviderRequest\x1a\x1e.memos.api.v1.IdentityProvider\"I\xdaA\x11identity_provider\x82\xd3\xe4\x93\x02/:\x11identity_provider\"\x1a/api/v1/identity-providers\x12\xd7\x01\n" +
"\x16UpdateIdentityProvider\x12+.memos.api.v1.UpdateIdentityProviderRequest\x1a\x1e.memos.api.v1.IdentityProvider\"p\xdaA\x1didentity_provider,update_mask\x82\xd3\xe4\x93\x02J:\x11identity_provider25/api/v1/{identity_provider.name=identity-providers/*}\x12\x91\x01\n" +
"\x16DeleteIdentityProvider\x12+.memos.api.v1.DeleteIdentityProviderRequest\x1a\x16.google.protobuf.Empty\"2\xdaA\x04name\x82\xd3\xe4\x93\x02%*#/api/v1/{name=identity-providers/*}B\xa7\x01\n" +
"\x10com.memos.api.v1B\x0fIdpServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
var (

View File

@ -268,7 +268,7 @@ func RegisterIdentityProviderServiceHandlerServer(ctx context.Context, mux *runt
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/ListIdentityProviders", runtime.WithHTTPPathPattern("/api/v1/identityProviders"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/ListIdentityProviders", runtime.WithHTTPPathPattern("/api/v1/identity-providers"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -288,7 +288,7 @@ func RegisterIdentityProviderServiceHandlerServer(ctx context.Context, mux *runt
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/GetIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identityProviders/*}"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/GetIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identity-providers/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -308,7 +308,7 @@ func RegisterIdentityProviderServiceHandlerServer(ctx context.Context, mux *runt
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/CreateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/identityProviders"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/CreateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/identity-providers"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -328,7 +328,7 @@ func RegisterIdentityProviderServiceHandlerServer(ctx context.Context, mux *runt
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/UpdateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{identity_provider.name=identityProviders/*}"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/UpdateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{identity_provider.name=identity-providers/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -348,7 +348,7 @@ func RegisterIdentityProviderServiceHandlerServer(ctx context.Context, mux *runt
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/DeleteIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identityProviders/*}"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/DeleteIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identity-providers/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -406,7 +406,7 @@ func RegisterIdentityProviderServiceHandlerClient(ctx context.Context, mux *runt
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/ListIdentityProviders", runtime.WithHTTPPathPattern("/api/v1/identityProviders"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/ListIdentityProviders", runtime.WithHTTPPathPattern("/api/v1/identity-providers"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -423,7 +423,7 @@ func RegisterIdentityProviderServiceHandlerClient(ctx context.Context, mux *runt
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/GetIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identityProviders/*}"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/GetIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identity-providers/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -440,7 +440,7 @@ func RegisterIdentityProviderServiceHandlerClient(ctx context.Context, mux *runt
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/CreateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/identityProviders"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/CreateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/identity-providers"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -457,7 +457,7 @@ func RegisterIdentityProviderServiceHandlerClient(ctx context.Context, mux *runt
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/UpdateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{identity_provider.name=identityProviders/*}"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/UpdateIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{identity_provider.name=identity-providers/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -474,7 +474,7 @@ func RegisterIdentityProviderServiceHandlerClient(ctx context.Context, mux *runt
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/DeleteIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identityProviders/*}"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.IdentityProviderService/DeleteIdentityProvider", runtime.WithHTTPPathPattern("/api/v1/{name=identity-providers/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@ -491,11 +491,11 @@ func RegisterIdentityProviderServiceHandlerClient(ctx context.Context, mux *runt
}
var (
pattern_IdentityProviderService_ListIdentityProviders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "identityProviders"}, ""))
pattern_IdentityProviderService_GetIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "identityProviders", "name"}, ""))
pattern_IdentityProviderService_CreateIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "identityProviders"}, ""))
pattern_IdentityProviderService_UpdateIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "identityProviders", "identity_provider.name"}, ""))
pattern_IdentityProviderService_DeleteIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "identityProviders", "name"}, ""))
pattern_IdentityProviderService_ListIdentityProviders_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "identity-providers"}, ""))
pattern_IdentityProviderService_GetIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "identity-providers", "name"}, ""))
pattern_IdentityProviderService_CreateIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "identity-providers"}, ""))
pattern_IdentityProviderService_UpdateIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "identity-providers", "identity_provider.name"}, ""))
pattern_IdentityProviderService_DeleteIdentityProvider_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "identity-providers", "name"}, ""))
)
var (

View File

@ -1,617 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.10
// protoc (unknown)
// source: api/v1/inbox_service.proto
package apiv1
import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
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)
)
// Status enumeration for inbox notifications.
type Inbox_Status int32
const (
// Unspecified status.
Inbox_STATUS_UNSPECIFIED Inbox_Status = 0
// The notification is unread.
Inbox_UNREAD Inbox_Status = 1
// The notification is archived.
Inbox_ARCHIVED Inbox_Status = 2
)
// Enum value maps for Inbox_Status.
var (
Inbox_Status_name = map[int32]string{
0: "STATUS_UNSPECIFIED",
1: "UNREAD",
2: "ARCHIVED",
}
Inbox_Status_value = map[string]int32{
"STATUS_UNSPECIFIED": 0,
"UNREAD": 1,
"ARCHIVED": 2,
}
)
func (x Inbox_Status) Enum() *Inbox_Status {
p := new(Inbox_Status)
*p = x
return p
}
func (x Inbox_Status) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Inbox_Status) Descriptor() protoreflect.EnumDescriptor {
return file_api_v1_inbox_service_proto_enumTypes[0].Descriptor()
}
func (Inbox_Status) Type() protoreflect.EnumType {
return &file_api_v1_inbox_service_proto_enumTypes[0]
}
func (x Inbox_Status) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Inbox_Status.Descriptor instead.
func (Inbox_Status) EnumDescriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{0, 0}
}
// Type enumeration for inbox notifications.
type Inbox_Type int32
const (
// Unspecified type.
Inbox_TYPE_UNSPECIFIED Inbox_Type = 0
// Memo comment notification.
Inbox_MEMO_COMMENT Inbox_Type = 1
)
// Enum value maps for Inbox_Type.
var (
Inbox_Type_name = map[int32]string{
0: "TYPE_UNSPECIFIED",
1: "MEMO_COMMENT",
}
Inbox_Type_value = map[string]int32{
"TYPE_UNSPECIFIED": 0,
"MEMO_COMMENT": 1,
}
)
func (x Inbox_Type) Enum() *Inbox_Type {
p := new(Inbox_Type)
*p = x
return p
}
func (x Inbox_Type) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Inbox_Type) Descriptor() protoreflect.EnumDescriptor {
return file_api_v1_inbox_service_proto_enumTypes[1].Descriptor()
}
func (Inbox_Type) Type() protoreflect.EnumType {
return &file_api_v1_inbox_service_proto_enumTypes[1]
}
func (x Inbox_Type) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Inbox_Type.Descriptor instead.
func (Inbox_Type) EnumDescriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{0, 1}
}
type Inbox struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The resource name of the inbox.
// Format: inboxes/{inbox}
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// The sender of the inbox notification.
// Format: users/{user}
Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"`
// The receiver of the inbox notification.
// Format: users/{user}
Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"`
// The status of the inbox notification.
Status Inbox_Status `protobuf:"varint,4,opt,name=status,proto3,enum=memos.api.v1.Inbox_Status" json:"status,omitempty"`
// Output only. The creation timestamp.
CreateTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"`
// The type of the inbox notification.
Type Inbox_Type `protobuf:"varint,6,opt,name=type,proto3,enum=memos.api.v1.Inbox_Type" json:"type,omitempty"`
// Optional. The activity ID associated with this inbox notification.
ActivityId *int32 `protobuf:"varint,7,opt,name=activity_id,json=activityId,proto3,oneof" json:"activity_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Inbox) Reset() {
*x = Inbox{}
mi := &file_api_v1_inbox_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Inbox) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Inbox) ProtoMessage() {}
func (x *Inbox) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_inbox_service_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Inbox.ProtoReflect.Descriptor instead.
func (*Inbox) Descriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{0}
}
func (x *Inbox) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Inbox) GetSender() string {
if x != nil {
return x.Sender
}
return ""
}
func (x *Inbox) GetReceiver() string {
if x != nil {
return x.Receiver
}
return ""
}
func (x *Inbox) GetStatus() Inbox_Status {
if x != nil {
return x.Status
}
return Inbox_STATUS_UNSPECIFIED
}
func (x *Inbox) GetCreateTime() *timestamppb.Timestamp {
if x != nil {
return x.CreateTime
}
return nil
}
func (x *Inbox) GetType() Inbox_Type {
if x != nil {
return x.Type
}
return Inbox_TYPE_UNSPECIFIED
}
func (x *Inbox) GetActivityId() int32 {
if x != nil && x.ActivityId != nil {
return *x.ActivityId
}
return 0
}
type ListInboxesRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Required. The parent resource whose inboxes will be listed.
// Format: users/{user}
Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"`
// Optional. The maximum number of inboxes to return.
// The service may return fewer than this value.
// If unspecified, at most 50 inboxes will be returned.
// The maximum value is 1000; values above 1000 will be coerced to 1000.
PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
// Optional. A page token, received from a previous `ListInboxes` call.
// Provide this to retrieve the subsequent page.
PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
// Optional. Filter to apply to the list results.
// Example: "status=UNREAD" or "type=MEMO_COMMENT"
// Supported operators: =, !=
// Supported fields: status, type, sender, create_time
Filter string `protobuf:"bytes,4,opt,name=filter,proto3" json:"filter,omitempty"`
// Optional. The order to sort results by.
// Example: "create_time desc" or "status asc"
OrderBy string `protobuf:"bytes,5,opt,name=order_by,json=orderBy,proto3" json:"order_by,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListInboxesRequest) Reset() {
*x = ListInboxesRequest{}
mi := &file_api_v1_inbox_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListInboxesRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListInboxesRequest) ProtoMessage() {}
func (x *ListInboxesRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_inbox_service_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListInboxesRequest.ProtoReflect.Descriptor instead.
func (*ListInboxesRequest) Descriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{1}
}
func (x *ListInboxesRequest) GetParent() string {
if x != nil {
return x.Parent
}
return ""
}
func (x *ListInboxesRequest) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
func (x *ListInboxesRequest) GetPageToken() string {
if x != nil {
return x.PageToken
}
return ""
}
func (x *ListInboxesRequest) GetFilter() string {
if x != nil {
return x.Filter
}
return ""
}
func (x *ListInboxesRequest) GetOrderBy() string {
if x != nil {
return x.OrderBy
}
return ""
}
type ListInboxesResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The list of inboxes.
Inboxes []*Inbox `protobuf:"bytes,1,rep,name=inboxes,proto3" json:"inboxes,omitempty"`
// A token that can be sent as `page_token` to retrieve the next page.
// If this field is omitted, there are no subsequent pages.
NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"`
// The total count of inboxes (may be approximate).
TotalSize int32 `protobuf:"varint,3,opt,name=total_size,json=totalSize,proto3" json:"total_size,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListInboxesResponse) Reset() {
*x = ListInboxesResponse{}
mi := &file_api_v1_inbox_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListInboxesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListInboxesResponse) ProtoMessage() {}
func (x *ListInboxesResponse) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_inbox_service_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListInboxesResponse.ProtoReflect.Descriptor instead.
func (*ListInboxesResponse) Descriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{2}
}
func (x *ListInboxesResponse) GetInboxes() []*Inbox {
if x != nil {
return x.Inboxes
}
return nil
}
func (x *ListInboxesResponse) GetNextPageToken() string {
if x != nil {
return x.NextPageToken
}
return ""
}
func (x *ListInboxesResponse) GetTotalSize() int32 {
if x != nil {
return x.TotalSize
}
return 0
}
type UpdateInboxRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Required. The inbox to update.
Inbox *Inbox `protobuf:"bytes,1,opt,name=inbox,proto3" json:"inbox,omitempty"`
// Required. The list of fields to update.
UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"`
// Optional. If set to true, allows updating missing fields.
AllowMissing bool `protobuf:"varint,3,opt,name=allow_missing,json=allowMissing,proto3" json:"allow_missing,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UpdateInboxRequest) Reset() {
*x = UpdateInboxRequest{}
mi := &file_api_v1_inbox_service_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UpdateInboxRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UpdateInboxRequest) ProtoMessage() {}
func (x *UpdateInboxRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_inbox_service_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UpdateInboxRequest.ProtoReflect.Descriptor instead.
func (*UpdateInboxRequest) Descriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{3}
}
func (x *UpdateInboxRequest) GetInbox() *Inbox {
if x != nil {
return x.Inbox
}
return nil
}
func (x *UpdateInboxRequest) GetUpdateMask() *fieldmaskpb.FieldMask {
if x != nil {
return x.UpdateMask
}
return nil
}
func (x *UpdateInboxRequest) GetAllowMissing() bool {
if x != nil {
return x.AllowMissing
}
return false
}
type DeleteInboxRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Required. The resource name of the inbox to delete.
// Format: inboxes/{inbox}
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteInboxRequest) Reset() {
*x = DeleteInboxRequest{}
mi := &file_api_v1_inbox_service_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteInboxRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteInboxRequest) ProtoMessage() {}
func (x *DeleteInboxRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_inbox_service_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteInboxRequest.ProtoReflect.Descriptor instead.
func (*DeleteInboxRequest) Descriptor() ([]byte, []int) {
return file_api_v1_inbox_service_proto_rawDescGZIP(), []int{4}
}
func (x *DeleteInboxRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
var File_api_v1_inbox_service_proto protoreflect.FileDescriptor
const file_api_v1_inbox_service_proto_rawDesc = "" +
"\n" +
"\x1aapi/v1/inbox_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xf3\x03\n" +
"\x05Inbox\x12\x17\n" +
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12\x1b\n" +
"\x06sender\x18\x02 \x01(\tB\x03\xe0A\x03R\x06sender\x12\x1f\n" +
"\breceiver\x18\x03 \x01(\tB\x03\xe0A\x03R\breceiver\x127\n" +
"\x06status\x18\x04 \x01(\x0e2\x1a.memos.api.v1.Inbox.StatusB\x03\xe0A\x01R\x06status\x12@\n" +
"\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x03R\n" +
"createTime\x121\n" +
"\x04type\x18\x06 \x01(\x0e2\x18.memos.api.v1.Inbox.TypeB\x03\xe0A\x03R\x04type\x12)\n" +
"\vactivity_id\x18\a \x01(\x05B\x03\xe0A\x01H\x00R\n" +
"activityId\x88\x01\x01\":\n" +
"\x06Status\x12\x16\n" +
"\x12STATUS_UNSPECIFIED\x10\x00\x12\n" +
"\n" +
"\x06UNREAD\x10\x01\x12\f\n" +
"\bARCHIVED\x10\x02\".\n" +
"\x04Type\x12\x14\n" +
"\x10TYPE_UNSPECIFIED\x10\x00\x12\x10\n" +
"\fMEMO_COMMENT\x10\x01:>\xeaA;\n" +
"\x12memos.api.v1/Inbox\x12\x0finboxes/{inbox}\x1a\x04name*\ainboxes2\x05inboxB\x0e\n" +
"\f_activity_id\"\xca\x01\n" +
"\x12ListInboxesRequest\x121\n" +
"\x06parent\x18\x01 \x01(\tB\x19\xe0A\x02\xfaA\x13\n" +
"\x11memos.api.v1/UserR\x06parent\x12 \n" +
"\tpage_size\x18\x02 \x01(\x05B\x03\xe0A\x01R\bpageSize\x12\"\n" +
"\n" +
"page_token\x18\x03 \x01(\tB\x03\xe0A\x01R\tpageToken\x12\x1b\n" +
"\x06filter\x18\x04 \x01(\tB\x03\xe0A\x01R\x06filter\x12\x1e\n" +
"\border_by\x18\x05 \x01(\tB\x03\xe0A\x01R\aorderBy\"\x8b\x01\n" +
"\x13ListInboxesResponse\x12-\n" +
"\ainboxes\x18\x01 \x03(\v2\x13.memos.api.v1.InboxR\ainboxes\x12&\n" +
"\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\x12\x1d\n" +
"\n" +
"total_size\x18\x03 \x01(\x05R\ttotalSize\"\xb0\x01\n" +
"\x12UpdateInboxRequest\x12.\n" +
"\x05inbox\x18\x01 \x01(\v2\x13.memos.api.v1.InboxB\x03\xe0A\x02R\x05inbox\x12@\n" +
"\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskB\x03\xe0A\x02R\n" +
"updateMask\x12(\n" +
"\rallow_missing\x18\x03 \x01(\bB\x03\xe0A\x01R\fallowMissing\"D\n" +
"\x12DeleteInboxRequest\x12.\n" +
"\x04name\x18\x01 \x01(\tB\x1a\xe0A\x02\xfaA\x14\n" +
"\x12memos.api.v1/InboxR\x04name2\x92\x03\n" +
"\fInboxService\x12\x85\x01\n" +
"\vListInboxes\x12 .memos.api.v1.ListInboxesRequest\x1a!.memos.api.v1.ListInboxesResponse\"1\xdaA\x06parent\x82\xd3\xe4\x93\x02\"\x12 /api/v1/{parent=users/*}/inboxes\x12\x87\x01\n" +
"\vUpdateInbox\x12 .memos.api.v1.UpdateInboxRequest\x1a\x13.memos.api.v1.Inbox\"A\xdaA\x11inbox,update_mask\x82\xd3\xe4\x93\x02':\x05inbox2\x1e/api/v1/{inbox.name=inboxes/*}\x12p\n" +
"\vDeleteInbox\x12 .memos.api.v1.DeleteInboxRequest\x1a\x16.google.protobuf.Empty\"'\xdaA\x04name\x82\xd3\xe4\x93\x02\x1a*\x18/api/v1/{name=inboxes/*}B\xa9\x01\n" +
"\x10com.memos.api.v1B\x11InboxServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
var (
file_api_v1_inbox_service_proto_rawDescOnce sync.Once
file_api_v1_inbox_service_proto_rawDescData []byte
)
func file_api_v1_inbox_service_proto_rawDescGZIP() []byte {
file_api_v1_inbox_service_proto_rawDescOnce.Do(func() {
file_api_v1_inbox_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_v1_inbox_service_proto_rawDesc), len(file_api_v1_inbox_service_proto_rawDesc)))
})
return file_api_v1_inbox_service_proto_rawDescData
}
var file_api_v1_inbox_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_api_v1_inbox_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_api_v1_inbox_service_proto_goTypes = []any{
(Inbox_Status)(0), // 0: memos.api.v1.Inbox.Status
(Inbox_Type)(0), // 1: memos.api.v1.Inbox.Type
(*Inbox)(nil), // 2: memos.api.v1.Inbox
(*ListInboxesRequest)(nil), // 3: memos.api.v1.ListInboxesRequest
(*ListInboxesResponse)(nil), // 4: memos.api.v1.ListInboxesResponse
(*UpdateInboxRequest)(nil), // 5: memos.api.v1.UpdateInboxRequest
(*DeleteInboxRequest)(nil), // 6: memos.api.v1.DeleteInboxRequest
(*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp
(*fieldmaskpb.FieldMask)(nil), // 8: google.protobuf.FieldMask
(*emptypb.Empty)(nil), // 9: google.protobuf.Empty
}
var file_api_v1_inbox_service_proto_depIdxs = []int32{
0, // 0: memos.api.v1.Inbox.status:type_name -> memos.api.v1.Inbox.Status
7, // 1: memos.api.v1.Inbox.create_time:type_name -> google.protobuf.Timestamp
1, // 2: memos.api.v1.Inbox.type:type_name -> memos.api.v1.Inbox.Type
2, // 3: memos.api.v1.ListInboxesResponse.inboxes:type_name -> memos.api.v1.Inbox
2, // 4: memos.api.v1.UpdateInboxRequest.inbox:type_name -> memos.api.v1.Inbox
8, // 5: memos.api.v1.UpdateInboxRequest.update_mask:type_name -> google.protobuf.FieldMask
3, // 6: memos.api.v1.InboxService.ListInboxes:input_type -> memos.api.v1.ListInboxesRequest
5, // 7: memos.api.v1.InboxService.UpdateInbox:input_type -> memos.api.v1.UpdateInboxRequest
6, // 8: memos.api.v1.InboxService.DeleteInbox:input_type -> memos.api.v1.DeleteInboxRequest
4, // 9: memos.api.v1.InboxService.ListInboxes:output_type -> memos.api.v1.ListInboxesResponse
2, // 10: memos.api.v1.InboxService.UpdateInbox:output_type -> memos.api.v1.Inbox
9, // 11: memos.api.v1.InboxService.DeleteInbox:output_type -> google.protobuf.Empty
9, // [9:12] is the sub-list for method output_type
6, // [6:9] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_api_v1_inbox_service_proto_init() }
func file_api_v1_inbox_service_proto_init() {
if File_api_v1_inbox_service_proto != nil {
return
}
file_api_v1_inbox_service_proto_msgTypes[0].OneofWrappers = []any{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_v1_inbox_service_proto_rawDesc), len(file_api_v1_inbox_service_proto_rawDesc)),
NumEnums: 2,
NumMessages: 5,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_api_v1_inbox_service_proto_goTypes,
DependencyIndexes: file_api_v1_inbox_service_proto_depIdxs,
EnumInfos: file_api_v1_inbox_service_proto_enumTypes,
MessageInfos: file_api_v1_inbox_service_proto_msgTypes,
}.Build()
File_api_v1_inbox_service_proto = out.File
file_api_v1_inbox_service_proto_goTypes = nil
file_api_v1_inbox_service_proto_depIdxs = nil
}

View File

@ -1,381 +0,0 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: api/v1/inbox_service.proto
/*
Package apiv1 is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package apiv1
import (
"context"
"errors"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
var filter_InboxService_ListInboxes_0 = &utilities.DoubleArray{Encoding: map[string]int{"parent": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
func request_InboxService_ListInboxes_0(ctx context.Context, marshaler runtime.Marshaler, client InboxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq ListInboxesRequest
metadata runtime.ServerMetadata
err error
)
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
val, ok := pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_InboxService_ListInboxes_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListInboxes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_InboxService_ListInboxes_0(ctx context.Context, marshaler runtime.Marshaler, server InboxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq ListInboxesRequest
metadata runtime.ServerMetadata
err error
)
val, ok := pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_InboxService_ListInboxes_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListInboxes(ctx, &protoReq)
return msg, metadata, err
}
var filter_InboxService_UpdateInbox_0 = &utilities.DoubleArray{Encoding: map[string]int{"inbox": 0, "name": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}}
func request_InboxService_UpdateInbox_0(ctx context.Context, marshaler runtime.Marshaler, client InboxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq UpdateInboxRequest
metadata runtime.ServerMetadata
err error
)
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.Inbox); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Inbox); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
} else {
protoReq.UpdateMask = fieldMask
}
}
val, ok := pathParams["inbox.name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "inbox.name")
}
err = runtime.PopulateFieldFromPath(&protoReq, "inbox.name", val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "inbox.name", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_InboxService_UpdateInbox_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.UpdateInbox(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_InboxService_UpdateInbox_0(ctx context.Context, marshaler runtime.Marshaler, server InboxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq UpdateInboxRequest
metadata runtime.ServerMetadata
err error
)
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.Inbox); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 {
if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Inbox); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
} else {
protoReq.UpdateMask = fieldMask
}
}
val, ok := pathParams["inbox.name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "inbox.name")
}
err = runtime.PopulateFieldFromPath(&protoReq, "inbox.name", val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "inbox.name", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_InboxService_UpdateInbox_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.UpdateInbox(ctx, &protoReq)
return msg, metadata, err
}
func request_InboxService_DeleteInbox_0(ctx context.Context, marshaler runtime.Marshaler, client InboxServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq DeleteInboxRequest
metadata runtime.ServerMetadata
err error
)
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
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.DeleteInbox(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_InboxService_DeleteInbox_0(ctx context.Context, marshaler runtime.Marshaler, server InboxServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq DeleteInboxRequest
metadata runtime.ServerMetadata
err error
)
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.DeleteInbox(ctx, &protoReq)
return msg, metadata, err
}
// RegisterInboxServiceHandlerServer registers the http handlers for service InboxService to "mux".
// UnaryRPC :call InboxServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterInboxServiceHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterInboxServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server InboxServiceServer) error {
mux.Handle(http.MethodGet, pattern_InboxService_ListInboxes_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)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.InboxService/ListInboxes", runtime.WithHTTPPathPattern("/api/v1/{parent=users/*}/inboxes"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_InboxService_ListInboxes_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_InboxService_ListInboxes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodPatch, pattern_InboxService_UpdateInbox_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)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.InboxService/UpdateInbox", runtime.WithHTTPPathPattern("/api/v1/{inbox.name=inboxes/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_InboxService_UpdateInbox_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_InboxService_UpdateInbox_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodDelete, pattern_InboxService_DeleteInbox_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)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.InboxService/DeleteInbox", runtime.WithHTTPPathPattern("/api/v1/{name=inboxes/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_InboxService_DeleteInbox_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_InboxService_DeleteInbox_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterInboxServiceHandlerFromEndpoint is same as RegisterInboxServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterInboxServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterInboxServiceHandler(ctx, mux, conn)
}
// RegisterInboxServiceHandler registers the http handlers for service InboxService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterInboxServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterInboxServiceHandlerClient(ctx, mux, NewInboxServiceClient(conn))
}
// RegisterInboxServiceHandlerClient registers the http handlers for service InboxService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "InboxServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "InboxServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "InboxServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterInboxServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client InboxServiceClient) error {
mux.Handle(http.MethodGet, pattern_InboxService_ListInboxes_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)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.InboxService/ListInboxes", runtime.WithHTTPPathPattern("/api/v1/{parent=users/*}/inboxes"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_InboxService_ListInboxes_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_InboxService_ListInboxes_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodPatch, pattern_InboxService_UpdateInbox_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)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.InboxService/UpdateInbox", runtime.WithHTTPPathPattern("/api/v1/{inbox.name=inboxes/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_InboxService_UpdateInbox_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_InboxService_UpdateInbox_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodDelete, pattern_InboxService_DeleteInbox_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)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.InboxService/DeleteInbox", runtime.WithHTTPPathPattern("/api/v1/{name=inboxes/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_InboxService_DeleteInbox_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_InboxService_DeleteInbox_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_InboxService_ListInboxes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "users", "parent", "inboxes"}, ""))
pattern_InboxService_UpdateInbox_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "inboxes", "inbox.name"}, ""))
pattern_InboxService_DeleteInbox_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "inboxes", "name"}, ""))
)
var (
forward_InboxService_ListInboxes_0 = runtime.ForwardResponseMessage
forward_InboxService_UpdateInbox_0 = runtime.ForwardResponseMessage
forward_InboxService_DeleteInbox_0 = runtime.ForwardResponseMessage
)

View File

@ -1,204 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: api/v1/inbox_service.proto
package apiv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
InboxService_ListInboxes_FullMethodName = "/memos.api.v1.InboxService/ListInboxes"
InboxService_UpdateInbox_FullMethodName = "/memos.api.v1.InboxService/UpdateInbox"
InboxService_DeleteInbox_FullMethodName = "/memos.api.v1.InboxService/DeleteInbox"
)
// InboxServiceClient is the client API for InboxService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type InboxServiceClient interface {
// ListInboxes lists inboxes for a user.
ListInboxes(ctx context.Context, in *ListInboxesRequest, opts ...grpc.CallOption) (*ListInboxesResponse, error)
// UpdateInbox updates an inbox.
UpdateInbox(ctx context.Context, in *UpdateInboxRequest, opts ...grpc.CallOption) (*Inbox, error)
// DeleteInbox deletes an inbox.
DeleteInbox(ctx context.Context, in *DeleteInboxRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type inboxServiceClient struct {
cc grpc.ClientConnInterface
}
func NewInboxServiceClient(cc grpc.ClientConnInterface) InboxServiceClient {
return &inboxServiceClient{cc}
}
func (c *inboxServiceClient) ListInboxes(ctx context.Context, in *ListInboxesRequest, opts ...grpc.CallOption) (*ListInboxesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListInboxesResponse)
err := c.cc.Invoke(ctx, InboxService_ListInboxes_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *inboxServiceClient) UpdateInbox(ctx context.Context, in *UpdateInboxRequest, opts ...grpc.CallOption) (*Inbox, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Inbox)
err := c.cc.Invoke(ctx, InboxService_UpdateInbox_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *inboxServiceClient) DeleteInbox(ctx context.Context, in *DeleteInboxRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, InboxService_DeleteInbox_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// InboxServiceServer is the server API for InboxService service.
// All implementations must embed UnimplementedInboxServiceServer
// for forward compatibility.
type InboxServiceServer interface {
// ListInboxes lists inboxes for a user.
ListInboxes(context.Context, *ListInboxesRequest) (*ListInboxesResponse, error)
// UpdateInbox updates an inbox.
UpdateInbox(context.Context, *UpdateInboxRequest) (*Inbox, error)
// DeleteInbox deletes an inbox.
DeleteInbox(context.Context, *DeleteInboxRequest) (*emptypb.Empty, error)
mustEmbedUnimplementedInboxServiceServer()
}
// UnimplementedInboxServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedInboxServiceServer struct{}
func (UnimplementedInboxServiceServer) ListInboxes(context.Context, *ListInboxesRequest) (*ListInboxesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListInboxes not implemented")
}
func (UnimplementedInboxServiceServer) UpdateInbox(context.Context, *UpdateInboxRequest) (*Inbox, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateInbox not implemented")
}
func (UnimplementedInboxServiceServer) DeleteInbox(context.Context, *DeleteInboxRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteInbox not implemented")
}
func (UnimplementedInboxServiceServer) mustEmbedUnimplementedInboxServiceServer() {}
func (UnimplementedInboxServiceServer) testEmbeddedByValue() {}
// UnsafeInboxServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to InboxServiceServer will
// result in compilation errors.
type UnsafeInboxServiceServer interface {
mustEmbedUnimplementedInboxServiceServer()
}
func RegisterInboxServiceServer(s grpc.ServiceRegistrar, srv InboxServiceServer) {
// If the following call pancis, it indicates UnimplementedInboxServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&InboxService_ServiceDesc, srv)
}
func _InboxService_ListInboxes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListInboxesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InboxServiceServer).ListInboxes(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: InboxService_ListInboxes_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InboxServiceServer).ListInboxes(ctx, req.(*ListInboxesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _InboxService_UpdateInbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateInboxRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InboxServiceServer).UpdateInbox(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: InboxService_UpdateInbox_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InboxServiceServer).UpdateInbox(ctx, req.(*UpdateInboxRequest))
}
return interceptor(ctx, in, info, handler)
}
func _InboxService_DeleteInbox_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteInboxRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InboxServiceServer).DeleteInbox(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: InboxService_DeleteInbox_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InboxServiceServer).DeleteInbox(ctx, req.(*DeleteInboxRequest))
}
return interceptor(ctx, in, info, handler)
}
// InboxService_ServiceDesc is the grpc.ServiceDesc for InboxService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var InboxService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "memos.api.v1.InboxService",
HandlerType: (*InboxServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ListInboxes",
Handler: _InboxService_ListInboxes_Handler,
},
{
MethodName: "UpdateInbox",
Handler: _InboxService_UpdateInbox_Handler,
},
{
MethodName: "DeleteInbox",
Handler: _InboxService_DeleteInbox_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v1/inbox_service.proto",
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: api/v1/workspace_service.proto
// source: api/v1/instance_service.proto
/*
Package apiv1 is a reverse proxy.
@ -35,30 +35,30 @@ var (
_ = metadata.Join
)
func request_WorkspaceService_GetWorkspaceProfile_0(ctx context.Context, marshaler runtime.Marshaler, client WorkspaceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func request_InstanceService_GetInstanceProfile_0(ctx context.Context, marshaler runtime.Marshaler, client InstanceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetWorkspaceProfileRequest
protoReq GetInstanceProfileRequest
metadata runtime.ServerMetadata
)
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
msg, err := client.GetWorkspaceProfile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.GetInstanceProfile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WorkspaceService_GetWorkspaceProfile_0(ctx context.Context, marshaler runtime.Marshaler, server WorkspaceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func local_request_InstanceService_GetInstanceProfile_0(ctx context.Context, marshaler runtime.Marshaler, server InstanceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetWorkspaceProfileRequest
protoReq GetInstanceProfileRequest
metadata runtime.ServerMetadata
)
msg, err := server.GetWorkspaceProfile(ctx, &protoReq)
msg, err := server.GetInstanceProfile(ctx, &protoReq)
return msg, metadata, err
}
func request_WorkspaceService_GetWorkspaceSetting_0(ctx context.Context, marshaler runtime.Marshaler, client WorkspaceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func request_InstanceService_GetInstanceSetting_0(ctx context.Context, marshaler runtime.Marshaler, client InstanceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetWorkspaceSettingRequest
protoReq GetInstanceSettingRequest
metadata runtime.ServerMetadata
err error
)
@ -73,13 +73,13 @@ func request_WorkspaceService_GetWorkspaceSetting_0(ctx context.Context, marshal
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
msg, err := client.GetWorkspaceSetting(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.GetInstanceSetting(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WorkspaceService_GetWorkspaceSetting_0(ctx context.Context, marshaler runtime.Marshaler, server WorkspaceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func local_request_InstanceService_GetInstanceSetting_0(ctx context.Context, marshaler runtime.Marshaler, server InstanceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetWorkspaceSettingRequest
protoReq GetInstanceSettingRequest
metadata runtime.ServerMetadata
err error
)
@ -91,15 +91,15 @@ func local_request_WorkspaceService_GetWorkspaceSetting_0(ctx context.Context, m
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
msg, err := server.GetWorkspaceSetting(ctx, &protoReq)
msg, err := server.GetInstanceSetting(ctx, &protoReq)
return msg, metadata, err
}
var filter_WorkspaceService_UpdateWorkspaceSetting_0 = &utilities.DoubleArray{Encoding: map[string]int{"setting": 0, "name": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}}
var filter_InstanceService_UpdateInstanceSetting_0 = &utilities.DoubleArray{Encoding: map[string]int{"setting": 0, "name": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}}
func request_WorkspaceService_UpdateWorkspaceSetting_0(ctx context.Context, marshaler runtime.Marshaler, client WorkspaceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func request_InstanceService_UpdateInstanceSetting_0(ctx context.Context, marshaler runtime.Marshaler, client InstanceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq UpdateWorkspaceSettingRequest
protoReq UpdateInstanceSettingRequest
metadata runtime.ServerMetadata
err error
)
@ -131,16 +131,16 @@ func request_WorkspaceService_UpdateWorkspaceSetting_0(ctx context.Context, mars
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WorkspaceService_UpdateWorkspaceSetting_0); err != nil {
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_InstanceService_UpdateInstanceSetting_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.UpdateWorkspaceSetting(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.UpdateInstanceSetting(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_WorkspaceService_UpdateWorkspaceSetting_0(ctx context.Context, marshaler runtime.Marshaler, server WorkspaceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func local_request_InstanceService_UpdateInstanceSetting_0(ctx context.Context, marshaler runtime.Marshaler, server InstanceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq UpdateWorkspaceSettingRequest
protoReq UpdateInstanceSettingRequest
metadata runtime.ServerMetadata
err error
)
@ -169,86 +169,86 @@ func local_request_WorkspaceService_UpdateWorkspaceSetting_0(ctx context.Context
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_WorkspaceService_UpdateWorkspaceSetting_0); err != nil {
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_InstanceService_UpdateInstanceSetting_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.UpdateWorkspaceSetting(ctx, &protoReq)
msg, err := server.UpdateInstanceSetting(ctx, &protoReq)
return msg, metadata, err
}
// RegisterWorkspaceServiceHandlerServer registers the http handlers for service WorkspaceService to "mux".
// UnaryRPC :call WorkspaceServiceServer directly.
// RegisterInstanceServiceHandlerServer registers the http handlers for service InstanceService to "mux".
// UnaryRPC :call InstanceServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterWorkspaceServiceHandlerFromEndpoint instead.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterInstanceServiceHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterWorkspaceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server WorkspaceServiceServer) error {
mux.Handle(http.MethodGet, pattern_WorkspaceService_GetWorkspaceProfile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
func RegisterInstanceServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server InstanceServiceServer) error {
mux.Handle(http.MethodGet, pattern_InstanceService_GetInstanceProfile_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)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.WorkspaceService/GetWorkspaceProfile", runtime.WithHTTPPathPattern("/api/v1/workspace/profile"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.InstanceService/GetInstanceProfile", runtime.WithHTTPPathPattern("/api/v1/instance/profile"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WorkspaceService_GetWorkspaceProfile_0(annotatedContext, inboundMarshaler, server, req, pathParams)
resp, md, err := local_request_InstanceService_GetInstanceProfile_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_WorkspaceService_GetWorkspaceProfile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_InstanceService_GetInstanceProfile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_WorkspaceService_GetWorkspaceSetting_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle(http.MethodGet, pattern_InstanceService_GetInstanceSetting_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)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.WorkspaceService/GetWorkspaceSetting", runtime.WithHTTPPathPattern("/api/v1/{name=workspace/settings/*}"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.InstanceService/GetInstanceSetting", runtime.WithHTTPPathPattern("/api/v1/{name=instance/settings/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WorkspaceService_GetWorkspaceSetting_0(annotatedContext, inboundMarshaler, server, req, pathParams)
resp, md, err := local_request_InstanceService_GetInstanceSetting_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_WorkspaceService_GetWorkspaceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_InstanceService_GetInstanceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodPatch, pattern_WorkspaceService_UpdateWorkspaceSetting_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle(http.MethodPatch, pattern_InstanceService_UpdateInstanceSetting_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)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.WorkspaceService/UpdateWorkspaceSetting", runtime.WithHTTPPathPattern("/api/v1/{setting.name=workspace/settings/*}"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.InstanceService/UpdateInstanceSetting", runtime.WithHTTPPathPattern("/api/v1/{setting.name=instance/settings/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_WorkspaceService_UpdateWorkspaceSetting_0(annotatedContext, inboundMarshaler, server, req, pathParams)
resp, md, err := local_request_InstanceService_UpdateInstanceSetting_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_WorkspaceService_UpdateWorkspaceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_InstanceService_UpdateInstanceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterWorkspaceServiceHandlerFromEndpoint is same as RegisterWorkspaceServiceHandler but
// RegisterInstanceServiceHandlerFromEndpoint is same as RegisterInstanceServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterWorkspaceServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
func RegisterInstanceServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
@ -267,83 +267,83 @@ func RegisterWorkspaceServiceHandlerFromEndpoint(ctx context.Context, mux *runti
}
}()
}()
return RegisterWorkspaceServiceHandler(ctx, mux, conn)
return RegisterInstanceServiceHandler(ctx, mux, conn)
}
// RegisterWorkspaceServiceHandler registers the http handlers for service WorkspaceService to "mux".
// RegisterInstanceServiceHandler registers the http handlers for service InstanceService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterWorkspaceServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterWorkspaceServiceHandlerClient(ctx, mux, NewWorkspaceServiceClient(conn))
func RegisterInstanceServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterInstanceServiceHandlerClient(ctx, mux, NewInstanceServiceClient(conn))
}
// RegisterWorkspaceServiceHandlerClient registers the http handlers for service WorkspaceService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "WorkspaceServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WorkspaceServiceClient"
// RegisterInstanceServiceHandlerClient registers the http handlers for service InstanceService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "InstanceServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "InstanceServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "WorkspaceServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterWorkspaceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WorkspaceServiceClient) error {
mux.Handle(http.MethodGet, pattern_WorkspaceService_GetWorkspaceProfile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
// "InstanceServiceClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterInstanceServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client InstanceServiceClient) error {
mux.Handle(http.MethodGet, pattern_InstanceService_GetInstanceProfile_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)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.WorkspaceService/GetWorkspaceProfile", runtime.WithHTTPPathPattern("/api/v1/workspace/profile"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.InstanceService/GetInstanceProfile", runtime.WithHTTPPathPattern("/api/v1/instance/profile"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WorkspaceService_GetWorkspaceProfile_0(annotatedContext, inboundMarshaler, client, req, pathParams)
resp, md, err := request_InstanceService_GetInstanceProfile_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_WorkspaceService_GetWorkspaceProfile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_InstanceService_GetInstanceProfile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_WorkspaceService_GetWorkspaceSetting_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle(http.MethodGet, pattern_InstanceService_GetInstanceSetting_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)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.WorkspaceService/GetWorkspaceSetting", runtime.WithHTTPPathPattern("/api/v1/{name=workspace/settings/*}"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.InstanceService/GetInstanceSetting", runtime.WithHTTPPathPattern("/api/v1/{name=instance/settings/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WorkspaceService_GetWorkspaceSetting_0(annotatedContext, inboundMarshaler, client, req, pathParams)
resp, md, err := request_InstanceService_GetInstanceSetting_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_WorkspaceService_GetWorkspaceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_InstanceService_GetInstanceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodPatch, pattern_WorkspaceService_UpdateWorkspaceSetting_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle(http.MethodPatch, pattern_InstanceService_UpdateInstanceSetting_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)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.WorkspaceService/UpdateWorkspaceSetting", runtime.WithHTTPPathPattern("/api/v1/{setting.name=workspace/settings/*}"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.InstanceService/UpdateInstanceSetting", runtime.WithHTTPPathPattern("/api/v1/{setting.name=instance/settings/*}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_WorkspaceService_UpdateWorkspaceSetting_0(annotatedContext, inboundMarshaler, client, req, pathParams)
resp, md, err := request_InstanceService_UpdateInstanceSetting_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_WorkspaceService_UpdateWorkspaceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_InstanceService_UpdateInstanceSetting_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_WorkspaceService_GetWorkspaceProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "workspace", "profile"}, ""))
pattern_WorkspaceService_GetWorkspaceSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 3, 5, 4}, []string{"api", "v1", "workspace", "settings", "name"}, ""))
pattern_WorkspaceService_UpdateWorkspaceSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 3, 5, 4}, []string{"api", "v1", "workspace", "settings", "setting.name"}, ""))
pattern_InstanceService_GetInstanceProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "instance", "profile"}, ""))
pattern_InstanceService_GetInstanceSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 3, 5, 4}, []string{"api", "v1", "instance", "settings", "name"}, ""))
pattern_InstanceService_UpdateInstanceSetting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 3, 5, 4}, []string{"api", "v1", "instance", "settings", "setting.name"}, ""))
)
var (
forward_WorkspaceService_GetWorkspaceProfile_0 = runtime.ForwardResponseMessage
forward_WorkspaceService_GetWorkspaceSetting_0 = runtime.ForwardResponseMessage
forward_WorkspaceService_UpdateWorkspaceSetting_0 = runtime.ForwardResponseMessage
forward_InstanceService_GetInstanceProfile_0 = runtime.ForwardResponseMessage
forward_InstanceService_GetInstanceSetting_0 = runtime.ForwardResponseMessage
forward_InstanceService_UpdateInstanceSetting_0 = runtime.ForwardResponseMessage
)

View File

@ -0,0 +1,203 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: api/v1/instance_service.proto
package apiv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
InstanceService_GetInstanceProfile_FullMethodName = "/memos.api.v1.InstanceService/GetInstanceProfile"
InstanceService_GetInstanceSetting_FullMethodName = "/memos.api.v1.InstanceService/GetInstanceSetting"
InstanceService_UpdateInstanceSetting_FullMethodName = "/memos.api.v1.InstanceService/UpdateInstanceSetting"
)
// InstanceServiceClient is the client API for InstanceService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type InstanceServiceClient interface {
// Gets the instance profile.
GetInstanceProfile(ctx context.Context, in *GetInstanceProfileRequest, opts ...grpc.CallOption) (*InstanceProfile, error)
// Gets an instance setting.
GetInstanceSetting(ctx context.Context, in *GetInstanceSettingRequest, opts ...grpc.CallOption) (*InstanceSetting, error)
// Updates an instance setting.
UpdateInstanceSetting(ctx context.Context, in *UpdateInstanceSettingRequest, opts ...grpc.CallOption) (*InstanceSetting, error)
}
type instanceServiceClient struct {
cc grpc.ClientConnInterface
}
func NewInstanceServiceClient(cc grpc.ClientConnInterface) InstanceServiceClient {
return &instanceServiceClient{cc}
}
func (c *instanceServiceClient) GetInstanceProfile(ctx context.Context, in *GetInstanceProfileRequest, opts ...grpc.CallOption) (*InstanceProfile, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(InstanceProfile)
err := c.cc.Invoke(ctx, InstanceService_GetInstanceProfile_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *instanceServiceClient) GetInstanceSetting(ctx context.Context, in *GetInstanceSettingRequest, opts ...grpc.CallOption) (*InstanceSetting, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(InstanceSetting)
err := c.cc.Invoke(ctx, InstanceService_GetInstanceSetting_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *instanceServiceClient) UpdateInstanceSetting(ctx context.Context, in *UpdateInstanceSettingRequest, opts ...grpc.CallOption) (*InstanceSetting, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(InstanceSetting)
err := c.cc.Invoke(ctx, InstanceService_UpdateInstanceSetting_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// InstanceServiceServer is the server API for InstanceService service.
// All implementations must embed UnimplementedInstanceServiceServer
// for forward compatibility.
type InstanceServiceServer interface {
// Gets the instance profile.
GetInstanceProfile(context.Context, *GetInstanceProfileRequest) (*InstanceProfile, error)
// Gets an instance setting.
GetInstanceSetting(context.Context, *GetInstanceSettingRequest) (*InstanceSetting, error)
// Updates an instance setting.
UpdateInstanceSetting(context.Context, *UpdateInstanceSettingRequest) (*InstanceSetting, error)
mustEmbedUnimplementedInstanceServiceServer()
}
// UnimplementedInstanceServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedInstanceServiceServer struct{}
func (UnimplementedInstanceServiceServer) GetInstanceProfile(context.Context, *GetInstanceProfileRequest) (*InstanceProfile, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetInstanceProfile not implemented")
}
func (UnimplementedInstanceServiceServer) GetInstanceSetting(context.Context, *GetInstanceSettingRequest) (*InstanceSetting, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetInstanceSetting not implemented")
}
func (UnimplementedInstanceServiceServer) UpdateInstanceSetting(context.Context, *UpdateInstanceSettingRequest) (*InstanceSetting, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateInstanceSetting not implemented")
}
func (UnimplementedInstanceServiceServer) mustEmbedUnimplementedInstanceServiceServer() {}
func (UnimplementedInstanceServiceServer) testEmbeddedByValue() {}
// UnsafeInstanceServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to InstanceServiceServer will
// result in compilation errors.
type UnsafeInstanceServiceServer interface {
mustEmbedUnimplementedInstanceServiceServer()
}
func RegisterInstanceServiceServer(s grpc.ServiceRegistrar, srv InstanceServiceServer) {
// If the following call pancis, it indicates UnimplementedInstanceServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&InstanceService_ServiceDesc, srv)
}
func _InstanceService_GetInstanceProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetInstanceProfileRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InstanceServiceServer).GetInstanceProfile(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: InstanceService_GetInstanceProfile_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InstanceServiceServer).GetInstanceProfile(ctx, req.(*GetInstanceProfileRequest))
}
return interceptor(ctx, in, info, handler)
}
func _InstanceService_GetInstanceSetting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetInstanceSettingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InstanceServiceServer).GetInstanceSetting(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: InstanceService_GetInstanceSetting_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InstanceServiceServer).GetInstanceSetting(ctx, req.(*GetInstanceSettingRequest))
}
return interceptor(ctx, in, info, handler)
}
func _InstanceService_UpdateInstanceSetting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateInstanceSettingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InstanceServiceServer).UpdateInstanceSetting(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: InstanceService_UpdateInstanceSetting_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InstanceServiceServer).UpdateInstanceSetting(ctx, req.(*UpdateInstanceSettingRequest))
}
return interceptor(ctx, in, info, handler)
}
// InstanceService_ServiceDesc is the grpc.ServiceDesc for InstanceService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var InstanceService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "memos.api.v1.InstanceService",
HandlerType: (*InstanceServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetInstanceProfile",
Handler: _InstanceService_GetInstanceProfile_Handler,
},
{
MethodName: "GetInstanceSetting",
Handler: _InstanceService_GetInstanceSetting_Handler,
},
{
MethodName: "UpdateInstanceSetting",
Handler: _InstanceService_UpdateInstanceSetting_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v1/instance_service.proto",
}

File diff suppressed because it is too large Load Diff

View File

@ -1,203 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: api/v1/workspace_service.proto
package apiv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
WorkspaceService_GetWorkspaceProfile_FullMethodName = "/memos.api.v1.WorkspaceService/GetWorkspaceProfile"
WorkspaceService_GetWorkspaceSetting_FullMethodName = "/memos.api.v1.WorkspaceService/GetWorkspaceSetting"
WorkspaceService_UpdateWorkspaceSetting_FullMethodName = "/memos.api.v1.WorkspaceService/UpdateWorkspaceSetting"
)
// WorkspaceServiceClient is the client API for WorkspaceService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type WorkspaceServiceClient interface {
// Gets the workspace profile.
GetWorkspaceProfile(ctx context.Context, in *GetWorkspaceProfileRequest, opts ...grpc.CallOption) (*WorkspaceProfile, error)
// Gets a workspace setting.
GetWorkspaceSetting(ctx context.Context, in *GetWorkspaceSettingRequest, opts ...grpc.CallOption) (*WorkspaceSetting, error)
// Updates a workspace setting.
UpdateWorkspaceSetting(ctx context.Context, in *UpdateWorkspaceSettingRequest, opts ...grpc.CallOption) (*WorkspaceSetting, error)
}
type workspaceServiceClient struct {
cc grpc.ClientConnInterface
}
func NewWorkspaceServiceClient(cc grpc.ClientConnInterface) WorkspaceServiceClient {
return &workspaceServiceClient{cc}
}
func (c *workspaceServiceClient) GetWorkspaceProfile(ctx context.Context, in *GetWorkspaceProfileRequest, opts ...grpc.CallOption) (*WorkspaceProfile, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(WorkspaceProfile)
err := c.cc.Invoke(ctx, WorkspaceService_GetWorkspaceProfile_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *workspaceServiceClient) GetWorkspaceSetting(ctx context.Context, in *GetWorkspaceSettingRequest, opts ...grpc.CallOption) (*WorkspaceSetting, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(WorkspaceSetting)
err := c.cc.Invoke(ctx, WorkspaceService_GetWorkspaceSetting_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *workspaceServiceClient) UpdateWorkspaceSetting(ctx context.Context, in *UpdateWorkspaceSettingRequest, opts ...grpc.CallOption) (*WorkspaceSetting, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(WorkspaceSetting)
err := c.cc.Invoke(ctx, WorkspaceService_UpdateWorkspaceSetting_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// WorkspaceServiceServer is the server API for WorkspaceService service.
// All implementations must embed UnimplementedWorkspaceServiceServer
// for forward compatibility.
type WorkspaceServiceServer interface {
// Gets the workspace profile.
GetWorkspaceProfile(context.Context, *GetWorkspaceProfileRequest) (*WorkspaceProfile, error)
// Gets a workspace setting.
GetWorkspaceSetting(context.Context, *GetWorkspaceSettingRequest) (*WorkspaceSetting, error)
// Updates a workspace setting.
UpdateWorkspaceSetting(context.Context, *UpdateWorkspaceSettingRequest) (*WorkspaceSetting, error)
mustEmbedUnimplementedWorkspaceServiceServer()
}
// UnimplementedWorkspaceServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedWorkspaceServiceServer struct{}
func (UnimplementedWorkspaceServiceServer) GetWorkspaceProfile(context.Context, *GetWorkspaceProfileRequest) (*WorkspaceProfile, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetWorkspaceProfile not implemented")
}
func (UnimplementedWorkspaceServiceServer) GetWorkspaceSetting(context.Context, *GetWorkspaceSettingRequest) (*WorkspaceSetting, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetWorkspaceSetting not implemented")
}
func (UnimplementedWorkspaceServiceServer) UpdateWorkspaceSetting(context.Context, *UpdateWorkspaceSettingRequest) (*WorkspaceSetting, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateWorkspaceSetting not implemented")
}
func (UnimplementedWorkspaceServiceServer) mustEmbedUnimplementedWorkspaceServiceServer() {}
func (UnimplementedWorkspaceServiceServer) testEmbeddedByValue() {}
// UnsafeWorkspaceServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to WorkspaceServiceServer will
// result in compilation errors.
type UnsafeWorkspaceServiceServer interface {
mustEmbedUnimplementedWorkspaceServiceServer()
}
func RegisterWorkspaceServiceServer(s grpc.ServiceRegistrar, srv WorkspaceServiceServer) {
// If the following call pancis, it indicates UnimplementedWorkspaceServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&WorkspaceService_ServiceDesc, srv)
}
func _WorkspaceService_GetWorkspaceProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetWorkspaceProfileRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WorkspaceServiceServer).GetWorkspaceProfile(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: WorkspaceService_GetWorkspaceProfile_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WorkspaceServiceServer).GetWorkspaceProfile(ctx, req.(*GetWorkspaceProfileRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WorkspaceService_GetWorkspaceSetting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetWorkspaceSettingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WorkspaceServiceServer).GetWorkspaceSetting(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: WorkspaceService_GetWorkspaceSetting_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WorkspaceServiceServer).GetWorkspaceSetting(ctx, req.(*GetWorkspaceSettingRequest))
}
return interceptor(ctx, in, info, handler)
}
func _WorkspaceService_UpdateWorkspaceSetting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateWorkspaceSettingRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(WorkspaceServiceServer).UpdateWorkspaceSetting(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: WorkspaceService_UpdateWorkspaceSetting_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(WorkspaceServiceServer).UpdateWorkspaceSetting(ctx, req.(*UpdateWorkspaceSettingRequest))
}
return interceptor(ctx, in, info, handler)
}
// WorkspaceService_ServiceDesc is the grpc.ServiceDesc for WorkspaceService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var WorkspaceService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "memos.api.v1.WorkspaceService",
HandlerType: (*WorkspaceServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetWorkspaceProfile",
Handler: _WorkspaceService_GetWorkspaceProfile_Handler,
},
{
MethodName: "GetWorkspaceSetting",
Handler: _WorkspaceService_GetWorkspaceSetting_Handler,
},
{
MethodName: "UpdateWorkspaceSetting",
Handler: _WorkspaceService_UpdateWorkspaceSetting_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v1/workspace_service.proto",
}

View File

@ -304,7 +304,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/identityProviders:
/api/v1/identity-providers:
get:
tags:
- IdentityProviderService
@ -355,16 +355,16 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/identityProviders/{identityProvider}:
/api/v1/identity-providers/{identity-provider}:
get:
tags:
- IdentityProviderService
description: GetIdentityProvider gets an identity provider.
operationId: IdentityProviderService_GetIdentityProvider
parameters:
- name: identityProvider
- name: identity-provider
in: path
description: The identityProvider id.
description: The identity-provider id.
required: true
schema:
type: string
@ -387,9 +387,9 @@ paths:
description: DeleteIdentityProvider deletes an identity provider.
operationId: IdentityProviderService_DeleteIdentityProvider
parameters:
- name: identityProvider
- name: identity-provider
in: path
description: The identityProvider id.
description: The identity-provider id.
required: true
schema:
type: string
@ -409,9 +409,9 @@ paths:
description: UpdateIdentityProvider updates an identity provider.
operationId: IdentityProviderService_UpdateIdentityProvider
parameters:
- name: identityProvider
- name: identity-provider
in: path
description: The identityProvider id.
description: The identity-provider id.
required: true
schema:
type: string
@ -442,6 +442,88 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/instance/profile:
get:
tags:
- InstanceService
description: Gets the instance profile.
operationId: InstanceService_GetInstanceProfile
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/InstanceProfile'
default:
description: Default error response
content:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/instance/{instance}/*:
get:
tags:
- InstanceService
description: Gets an instance setting.
operationId: InstanceService_GetInstanceSetting
parameters:
- name: instance
in: path
description: The instance id.
required: true
schema:
type: string
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/InstanceSetting'
default:
description: Default error response
content:
application/json:
schema:
$ref: '#/components/schemas/Status'
patch:
tags:
- InstanceService
description: Updates an instance setting.
operationId: InstanceService_UpdateInstanceSetting
parameters:
- name: instance
in: path
description: The instance id.
required: true
schema:
type: string
- name: updateMask
in: query
description: The list of fields to update.
schema:
type: string
format: field-mask
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/InstanceSetting'
required: true
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/InstanceSetting'
default:
description: Default error response
content:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/memos:
get:
tags:
@ -1886,88 +1968,6 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/workspace/profile:
get:
tags:
- WorkspaceService
description: Gets the workspace profile.
operationId: WorkspaceService_GetWorkspaceProfile
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/WorkspaceProfile'
default:
description: Default error response
content:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/workspace/{workspace}/*:
get:
tags:
- WorkspaceService
description: Gets a workspace setting.
operationId: WorkspaceService_GetWorkspaceSetting
parameters:
- name: workspace
in: path
description: The workspace id.
required: true
schema:
type: string
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/WorkspaceSetting'
default:
description: Default error response
content:
application/json:
schema:
$ref: '#/components/schemas/Status'
patch:
tags:
- WorkspaceService
description: Updates a workspace setting.
operationId: WorkspaceService_UpdateWorkspaceSetting
parameters:
- name: workspace
in: path
description: The workspace id.
required: true
schema:
type: string
- name: updateMask
in: query
description: The list of fields to update.
schema:
type: string
format: field-mask
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/WorkspaceSetting'
required: true
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/WorkspaceSetting'
default:
description: Default error response
content:
application/json:
schema:
$ref: '#/components/schemas/Status'
/file/attachments/{attachment}/{filename:
get:
tags:
@ -2195,7 +2195,7 @@ components:
type: string
locale:
type: string
description: Custom profile configuration for workspace branding.
description: Custom profile configuration for instance branding.
GetCurrentSessionResponse:
type: object
properties:
@ -2226,7 +2226,7 @@ components:
type: string
description: |-
The resource name of the identity provider.
Format: identityProviders/{idp}
Format: identity-providers/{idp}
type:
enum:
- TYPE_UNSPECIFIED
@ -2249,6 +2249,138 @@ components:
properties:
oauth2Config:
$ref: '#/components/schemas/OAuth2Config'
InstanceProfile:
type: object
properties:
owner:
type: string
description: |-
The name of instance owner.
Format: users/{user}
version:
type: string
description: Version is the current version of instance.
mode:
type: string
description: Mode is the instance mode (e.g. "prod", "dev" or "demo").
instanceUrl:
type: string
description: Instance URL is the URL of the instance.
description: Instance profile message containing basic instance information.
InstanceSetting:
type: object
properties:
name:
type: string
description: |-
The name of the instance setting.
Format: instance/settings/{setting}
generalSetting:
$ref: '#/components/schemas/InstanceSetting_GeneralSetting'
storageSetting:
$ref: '#/components/schemas/InstanceSetting_StorageSetting'
memoRelatedSetting:
$ref: '#/components/schemas/InstanceSetting_MemoRelatedSetting'
description: An instance setting resource.
InstanceSetting_GeneralSetting:
type: object
properties:
theme:
type: string
description: |-
theme is the name of the selected theme.
This references a CSS file in the web/public/themes/ directory.
disallowUserRegistration:
type: boolean
description: disallow_user_registration disallows user registration.
disallowPasswordAuth:
type: boolean
description: disallow_password_auth disallows password authentication.
additionalScript:
type: string
description: additional_script is the additional script.
additionalStyle:
type: string
description: additional_style is the additional style.
customProfile:
allOf:
- $ref: '#/components/schemas/GeneralSetting_CustomProfile'
description: custom_profile is the custom profile.
weekStartDayOffset:
type: integer
description: |-
week_start_day_offset is the week start day offset from Sunday.
0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
Default is Sunday.
format: int32
disallowChangeUsername:
type: boolean
description: disallow_change_username disallows changing username.
disallowChangeNickname:
type: boolean
description: disallow_change_nickname disallows changing nickname.
description: General instance settings configuration.
InstanceSetting_MemoRelatedSetting:
type: object
properties:
disallowPublicVisibility:
type: boolean
description: disallow_public_visibility disallows set memo as public visibility.
displayWithUpdateTime:
type: boolean
description: display_with_update_time orders and displays memo with update time.
contentLengthLimit:
type: integer
description: content_length_limit is the limit of content length. Unit is byte.
format: int32
enableDoubleClickEdit:
type: boolean
description: enable_double_click_edit enables editing on double click.
enableLinkPreview:
type: boolean
description: enable_link_preview enables links preview.
reactions:
type: array
items:
type: string
description: reactions is the list of reactions.
disableMarkdownShortcuts:
type: boolean
description: disable_markdown_shortcuts disallow the registration of markdown shortcuts.
enableBlurNsfwContent:
type: boolean
description: enable_blur_nsfw_content enables blurring of content marked as not safe for work (NSFW).
nsfwTags:
type: array
items:
type: string
description: nsfw_tags is the list of tags that mark content as NSFW for blurring.
description: Memo-related instance settings and policies.
InstanceSetting_StorageSetting:
type: object
properties:
storageType:
enum:
- STORAGE_TYPE_UNSPECIFIED
- DATABASE
- LOCAL
- S3
type: string
description: storage_type is the storage type.
format: enum
filepathTemplate:
type: string
description: |-
The template of file path.
e.g. assets/{timestamp}_{filename}
uploadSizeLimitMb:
type: string
description: The max upload size in megabytes.
s3Config:
allOf:
- $ref: '#/components/schemas/StorageSetting_S3Config'
description: The S3 config.
description: Storage configuration settings for instance attachments.
ListActivitiesResponse:
type: object
properties:
@ -3057,144 +3189,12 @@ components:
description: The last update time of the webhook.
format: date-time
description: UserWebhook represents a webhook owned by a user.
WorkspaceProfile:
type: object
properties:
owner:
type: string
description: |-
The name of instance owner.
Format: users/{user}
version:
type: string
description: Version is the current version of instance.
mode:
type: string
description: Mode is the instance mode (e.g. "prod", "dev" or "demo").
instanceUrl:
type: string
description: Instance URL is the URL of the instance.
description: Workspace profile message containing basic workspace information.
WorkspaceSetting:
type: object
properties:
name:
type: string
description: |-
The name of the workspace setting.
Format: workspace/settings/{setting}
generalSetting:
$ref: '#/components/schemas/WorkspaceSetting_GeneralSetting'
storageSetting:
$ref: '#/components/schemas/WorkspaceSetting_StorageSetting'
memoRelatedSetting:
$ref: '#/components/schemas/WorkspaceSetting_MemoRelatedSetting'
description: A workspace setting resource.
WorkspaceSetting_GeneralSetting:
type: object
properties:
theme:
type: string
description: |-
theme is the name of the selected theme.
This references a CSS file in the web/public/themes/ directory.
disallowUserRegistration:
type: boolean
description: disallow_user_registration disallows user registration.
disallowPasswordAuth:
type: boolean
description: disallow_password_auth disallows password authentication.
additionalScript:
type: string
description: additional_script is the additional script.
additionalStyle:
type: string
description: additional_style is the additional style.
customProfile:
allOf:
- $ref: '#/components/schemas/GeneralSetting_CustomProfile'
description: custom_profile is the custom profile.
weekStartDayOffset:
type: integer
description: |-
week_start_day_offset is the week start day offset from Sunday.
0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
Default is Sunday.
format: int32
disallowChangeUsername:
type: boolean
description: disallow_change_username disallows changing username.
disallowChangeNickname:
type: boolean
description: disallow_change_nickname disallows changing nickname.
description: General workspace settings configuration.
WorkspaceSetting_MemoRelatedSetting:
type: object
properties:
disallowPublicVisibility:
type: boolean
description: disallow_public_visibility disallows set memo as public visibility.
displayWithUpdateTime:
type: boolean
description: display_with_update_time orders and displays memo with update time.
contentLengthLimit:
type: integer
description: content_length_limit is the limit of content length. Unit is byte.
format: int32
enableDoubleClickEdit:
type: boolean
description: enable_double_click_edit enables editing on double click.
enableLinkPreview:
type: boolean
description: enable_link_preview enables links preview.
reactions:
type: array
items:
type: string
description: reactions is the list of reactions.
disableMarkdownShortcuts:
type: boolean
description: disable_markdown_shortcuts disallow the registration of markdown shortcuts.
enableBlurNsfwContent:
type: boolean
description: enable_blur_nsfw_content enables blurring of content marked as not safe for work (NSFW).
nsfwTags:
type: array
items:
type: string
description: nsfw_tags is the list of tags that mark content as NSFW for blurring.
description: Memo-related workspace settings and policies.
WorkspaceSetting_StorageSetting:
type: object
properties:
storageType:
enum:
- STORAGE_TYPE_UNSPECIFIED
- DATABASE
- LOCAL
- S3
type: string
description: storage_type is the storage type.
format: enum
filepathTemplate:
type: string
description: |-
The template of file path.
e.g. assets/{timestamp}_{filename}
uploadSizeLimitMb:
type: string
description: The max upload size in megabytes.
s3Config:
allOf:
- $ref: '#/components/schemas/StorageSetting_S3Config'
description: The S3 config.
description: Storage configuration settings for workspace attachments.
tags:
- name: ActivityService
- name: AttachmentService
- name: AuthService
- name: IdentityProviderService
- name: InstanceService
- name: MemoService
- name: ShortcutService
- name: UserService
- name: WorkspaceService

View File

@ -210,7 +210,7 @@ var File_store_attachment_proto protoreflect.FileDescriptor
const file_store_attachment_proto_rawDesc = "" +
"\n" +
"\x16store/attachment.proto\x12\vmemos.store\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1dstore/workspace_setting.proto\"\x8c\x02\n" +
"\x16store/attachment.proto\x12\vmemos.store\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1cstore/instance_setting.proto\"\x8c\x02\n" +
"\x11AttachmentPayload\x12F\n" +
"\ts3_object\x18\x01 \x01(\v2'.memos.store.AttachmentPayload.S3ObjectH\x00R\bs3Object\x1a\xa3\x01\n" +
"\bS3Object\x129\n" +
@ -262,7 +262,7 @@ func file_store_attachment_proto_init() {
if File_store_attachment_proto != nil {
return
}
file_store_workspace_setting_proto_init()
file_store_instance_setting_proto_init()
file_store_attachment_proto_msgTypes[0].OneofWrappers = []any{
(*AttachmentPayload_S3Object_)(nil),
}

View File

@ -3,7 +3,7 @@ syntax = "proto3";
package memos.store;
import "google/protobuf/timestamp.proto";
import "store/workspace_setting.proto";
import "store/instance_setting.proto";
option go_package = "gen/store";

View File

@ -4,8 +4,8 @@ package memos.store;
option go_package = "gen/store";
enum WorkspaceSettingKey {
WORKSPACE_SETTING_KEY_UNSPECIFIED = 0;
enum InstanceSettingKey {
INSTANCE_SETTING_KEY_UNSPECIFIED = 0;
// BASIC is the key for basic settings.
BASIC = 1;
// GENERAL is the key for general settings.
@ -16,24 +16,24 @@ enum WorkspaceSettingKey {
MEMO_RELATED = 4;
}
message WorkspaceSetting {
WorkspaceSettingKey key = 1;
message InstanceSetting {
InstanceSettingKey key = 1;
oneof value {
WorkspaceBasicSetting basic_setting = 2;
WorkspaceGeneralSetting general_setting = 3;
WorkspaceStorageSetting storage_setting = 4;
WorkspaceMemoRelatedSetting memo_related_setting = 5;
InstanceBasicSetting basic_setting = 2;
InstanceGeneralSetting general_setting = 3;
InstanceStorageSetting storage_setting = 4;
InstanceMemoRelatedSetting memo_related_setting = 5;
}
}
message WorkspaceBasicSetting {
// The secret key for workspace. Mainly used for session management.
message InstanceBasicSetting {
// The secret key for instance. Mainly used for session management.
string secret_key = 1;
// The current schema version of database.
string schema_version = 2;
}
message WorkspaceGeneralSetting {
message InstanceGeneralSetting {
// theme is the name of the selected theme.
// This references a CSS file in the web/public/themes/ directory.
string theme = 1;
@ -46,7 +46,7 @@ message WorkspaceGeneralSetting {
// additional_style is the additional style.
string additional_style = 5;
// custom_profile is the custom profile.
WorkspaceCustomProfile custom_profile = 6;
InstanceCustomProfile custom_profile = 6;
// week_start_day_offset is the week start day offset from Sunday.
// 0: Sunday, 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday
// Default is Sunday.
@ -57,14 +57,14 @@ message WorkspaceGeneralSetting {
bool disallow_change_nickname = 9;
}
message WorkspaceCustomProfile {
message InstanceCustomProfile {
string title = 1;
string description = 2;
string logo_url = 3;
string locale = 4;
}
message WorkspaceStorageSetting {
message InstanceStorageSetting {
enum StorageType {
STORAGE_TYPE_UNSPECIFIED = 0;
// STORAGE_TYPE_DATABASE is the database storage type.
@ -95,7 +95,7 @@ message StorageS3Config {
bool use_path_style = 6;
}
message WorkspaceMemoRelatedSetting {
message InstanceMemoRelatedSetting {
// disallow_public_visibility disallows set memo as public visibility.
bool disallow_public_visibility = 1;
// display_with_update_time orders and displays memo with update time.

View File

@ -9,7 +9,6 @@ RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -ldflags="-s -w" -o memos ./cmd/memos
# Make workspace with above generated files.
FROM alpine:latest AS monolithic
WORKDIR /usr/local/memos

View File

@ -1,8 +1,8 @@
package v1
var authenticationAllowlistMethods = map[string]bool{
"/memos.api.v1.WorkspaceService/GetWorkspaceProfile": true,
"/memos.api.v1.WorkspaceService/GetWorkspaceSetting": true,
"/memos.api.v1.InstanceService/GetInstanceProfile": true,
"/memos.api.v1.InstanceService/GetInstanceSetting": true,
"/memos.api.v1.IdentityProviderService/ListIdentityProviders": true,
"/memos.api.v1.AuthService/CreateSession": true,
"/memos.api.v1.AuthService/GetCurrentSession": true,
@ -24,7 +24,7 @@ func isUnauthorizeAllowedMethod(fullMethodName string) bool {
var allowedMethodsOnlyForAdmin = map[string]bool{
"/memos.api.v1.UserService/CreateUser": true,
"/memos.api.v1.WorkspaceService/UpdateWorkspaceSetting": true,
"/memos.api.v1.InstanceService/UpdateInstanceSetting": true,
}
// isOnlyForAdminAllowedMethod returns true if the method is allowed to be called only by admin.

View File

@ -84,12 +84,12 @@ func (s *APIV1Service) CreateAttachment(ctx context.Context, request *v1pb.Creat
Type: request.Attachment.Type,
}
workspaceStorageSetting, err := s.Store.GetWorkspaceStorageSetting(ctx)
instanceStorageSetting, err := s.Store.GetInstanceStorageSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace storage setting: %v", err)
return nil, status.Errorf(codes.Internal, "failed to get instance storage setting: %v", err)
}
size := binary.Size(request.Attachment.Content)
uploadSizeLimit := int(workspaceStorageSetting.UploadSizeLimitMb) * MebiByte
uploadSizeLimit := int(instanceStorageSetting.UploadSizeLimitMb) * MebiByte
if uploadSizeLimit == 0 {
uploadSizeLimit = MaxUploadBufferSizeBytes
}
@ -395,15 +395,15 @@ func convertAttachmentFromStore(attachment *store.Attachment) *v1pb.Attachment {
// SaveAttachmentBlob save the blob of attachment based on the storage config.
func SaveAttachmentBlob(ctx context.Context, profile *profile.Profile, stores *store.Store, create *store.Attachment) error {
workspaceStorageSetting, err := stores.GetWorkspaceStorageSetting(ctx)
instanceStorageSetting, err := stores.GetInstanceStorageSetting(ctx)
if err != nil {
return errors.Wrap(err, "Failed to find workspace storage setting")
return errors.Wrap(err, "Failed to find instance storage setting")
}
if workspaceStorageSetting.StorageType == storepb.WorkspaceStorageSetting_LOCAL {
if instanceStorageSetting.StorageType == storepb.InstanceStorageSetting_LOCAL {
filepathTemplate := "assets/{timestamp}_{filename}"
if workspaceStorageSetting.FilepathTemplate != "" {
filepathTemplate = workspaceStorageSetting.FilepathTemplate
if instanceStorageSetting.FilepathTemplate != "" {
filepathTemplate = instanceStorageSetting.FilepathTemplate
}
internalPath := filepathTemplate
@ -435,8 +435,8 @@ func SaveAttachmentBlob(ctx context.Context, profile *profile.Profile, stores *s
create.Reference = internalPath
create.Blob = nil
create.StorageType = storepb.AttachmentStorageType_LOCAL
} else if workspaceStorageSetting.StorageType == storepb.WorkspaceStorageSetting_S3 {
s3Config := workspaceStorageSetting.S3Config
} else if instanceStorageSetting.StorageType == storepb.InstanceStorageSetting_S3 {
s3Config := instanceStorageSetting.S3Config
if s3Config == nil {
return errors.Errorf("No actived external storage found")
}
@ -445,7 +445,7 @@ func SaveAttachmentBlob(ctx context.Context, profile *profile.Profile, stores *s
return errors.Wrap(err, "Failed to create s3 client")
}
filepathTemplate := workspaceStorageSetting.FilepathTemplate
filepathTemplate := instanceStorageSetting.FilepathTemplate
if !strings.Contains(filepathTemplate, "{filename}") {
filepathTemplate = filepath.Join(filepathTemplate, "{filename}")
}

View File

@ -99,12 +99,12 @@ func (s *APIV1Service) CreateSession(ctx context.Context, request *v1pb.CreateSe
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(passwordCredentials.Password)); err != nil {
return nil, status.Errorf(codes.InvalidArgument, unmatchedUsernameAndPasswordError)
}
workspaceGeneralSetting, err := s.Store.GetWorkspaceGeneralSetting(ctx)
instanceGeneralSetting, err := s.Store.GetInstanceGeneralSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace general setting, error: %v", err)
return nil, status.Errorf(codes.Internal, "failed to get instance general setting, error: %v", err)
}
// Check if the password auth in is allowed.
if workspaceGeneralSetting.DisallowPasswordAuth && user.Role == store.RoleUser {
if instanceGeneralSetting.DisallowPasswordAuth && user.Role == store.RoleUser {
return nil, status.Errorf(codes.PermissionDenied, "password signin is not allowed")
}
existingUser = user
@ -155,11 +155,11 @@ func (s *APIV1Service) CreateSession(ctx context.Context, request *v1pb.CreateSe
}
if user == nil {
// Check if the user is allowed to sign up.
workspaceGeneralSetting, err := s.Store.GetWorkspaceGeneralSetting(ctx)
instanceGeneralSetting, err := s.Store.GetInstanceGeneralSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace general setting, error: %v", err)
return nil, status.Errorf(codes.Internal, "failed to get instance general setting, error: %v", err)
}
if workspaceGeneralSetting.DisallowUserRegistration {
if instanceGeneralSetting.DisallowUserRegistration {
return nil, status.Errorf(codes.PermissionDenied, "user registration is not allowed")
}

View File

@ -13,9 +13,9 @@ import (
"github.com/usememos/memos/store"
)
// GetWorkspaceProfile returns the workspace profile.
func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorkspaceProfileRequest) (*v1pb.WorkspaceProfile, error) {
workspaceProfile := &v1pb.WorkspaceProfile{
// GetInstanceProfile returns the instance profile.
func (s *APIV1Service) GetInstanceProfile(ctx context.Context, _ *v1pb.GetInstanceProfileRequest) (*v1pb.InstanceProfile, error) {
instanceProfile := &v1pb.InstanceProfile{
Version: s.Profile.Version,
Mode: s.Profile.Mode,
InstanceUrl: s.Profile.InstanceURL,
@ -25,47 +25,47 @@ func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorks
return nil, status.Errorf(codes.Internal, "failed to get instance owner: %v", err)
}
if owner != nil {
workspaceProfile.Owner = owner.Name
instanceProfile.Owner = owner.Name
}
return workspaceProfile, nil
return instanceProfile, nil
}
func (s *APIV1Service) GetWorkspaceSetting(ctx context.Context, request *v1pb.GetWorkspaceSettingRequest) (*v1pb.WorkspaceSetting, error) {
workspaceSettingKeyString, err := ExtractWorkspaceSettingKeyFromName(request.Name)
func (s *APIV1Service) GetInstanceSetting(ctx context.Context, request *v1pb.GetInstanceSettingRequest) (*v1pb.InstanceSetting, error) {
instanceSettingKeyString, err := ExtractInstanceSettingKeyFromName(request.Name)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid workspace setting name: %v", err)
return nil, status.Errorf(codes.InvalidArgument, "invalid instance setting name: %v", err)
}
workspaceSettingKey := storepb.WorkspaceSettingKey(storepb.WorkspaceSettingKey_value[workspaceSettingKeyString])
// Get workspace setting from store with default value.
switch workspaceSettingKey {
case storepb.WorkspaceSettingKey_BASIC:
_, err = s.Store.GetWorkspaceBasicSetting(ctx)
case storepb.WorkspaceSettingKey_GENERAL:
_, err = s.Store.GetWorkspaceGeneralSetting(ctx)
case storepb.WorkspaceSettingKey_MEMO_RELATED:
_, err = s.Store.GetWorkspaceMemoRelatedSetting(ctx)
case storepb.WorkspaceSettingKey_STORAGE:
_, err = s.Store.GetWorkspaceStorageSetting(ctx)
instanceSettingKey := storepb.InstanceSettingKey(storepb.InstanceSettingKey_value[instanceSettingKeyString])
// Get instance setting from store with default value.
switch instanceSettingKey {
case storepb.InstanceSettingKey_BASIC:
_, err = s.Store.GetInstanceBasicSetting(ctx)
case storepb.InstanceSettingKey_GENERAL:
_, err = s.Store.GetInstanceGeneralSetting(ctx)
case storepb.InstanceSettingKey_MEMO_RELATED:
_, err = s.Store.GetInstanceMemoRelatedSetting(ctx)
case storepb.InstanceSettingKey_STORAGE:
_, err = s.Store.GetInstanceStorageSetting(ctx)
default:
return nil, status.Errorf(codes.InvalidArgument, "unsupported workspace setting key: %v", workspaceSettingKey)
return nil, status.Errorf(codes.InvalidArgument, "unsupported instance setting key: %v", instanceSettingKey)
}
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace setting: %v", err)
return nil, status.Errorf(codes.Internal, "failed to get instance setting: %v", err)
}
workspaceSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Name: workspaceSettingKey.String(),
instanceSetting, err := s.Store.GetInstanceSetting(ctx, &store.FindInstanceSetting{
Name: instanceSettingKey.String(),
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace setting: %v", err)
return nil, status.Errorf(codes.Internal, "failed to get instance setting: %v", err)
}
if workspaceSetting == nil {
return nil, status.Errorf(codes.NotFound, "workspace setting not found")
if instanceSetting == nil {
return nil, status.Errorf(codes.NotFound, "instance setting not found")
}
// For storage setting, only host can get it.
if workspaceSetting.Key == storepb.WorkspaceSettingKey_STORAGE {
if instanceSetting.Key == storepb.InstanceSettingKey_STORAGE {
user, err := s.GetCurrentUser(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
@ -75,10 +75,10 @@ func (s *APIV1Service) GetWorkspaceSetting(ctx context.Context, request *v1pb.Ge
}
}
return convertWorkspaceSettingFromStore(workspaceSetting), nil
return convertInstanceSettingFromStore(instanceSetting), nil
}
func (s *APIV1Service) UpdateWorkspaceSetting(ctx context.Context, request *v1pb.UpdateWorkspaceSettingRequest) (*v1pb.WorkspaceSetting, error) {
func (s *APIV1Service) UpdateInstanceSetting(ctx context.Context, request *v1pb.UpdateInstanceSettingRequest) (*v1pb.InstanceSetting, error) {
user, err := s.GetCurrentUser(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
@ -93,64 +93,64 @@ func (s *APIV1Service) UpdateWorkspaceSetting(ctx context.Context, request *v1pb
// TODO: Apply update_mask if specified
_ = request.UpdateMask
updateSetting := convertWorkspaceSettingToStore(request.Setting)
workspaceSetting, err := s.Store.UpsertWorkspaceSetting(ctx, updateSetting)
updateSetting := convertInstanceSettingToStore(request.Setting)
instanceSetting, err := s.Store.UpsertInstanceSetting(ctx, updateSetting)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to upsert workspace setting: %v", err)
return nil, status.Errorf(codes.Internal, "failed to upsert instance setting: %v", err)
}
return convertWorkspaceSettingFromStore(workspaceSetting), nil
return convertInstanceSettingFromStore(instanceSetting), nil
}
func convertWorkspaceSettingFromStore(setting *storepb.WorkspaceSetting) *v1pb.WorkspaceSetting {
workspaceSetting := &v1pb.WorkspaceSetting{
Name: fmt.Sprintf("workspace/settings/%s", setting.Key.String()),
func convertInstanceSettingFromStore(setting *storepb.InstanceSetting) *v1pb.InstanceSetting {
instanceSetting := &v1pb.InstanceSetting{
Name: fmt.Sprintf("instance/settings/%s", setting.Key.String()),
}
switch setting.Value.(type) {
case *storepb.WorkspaceSetting_GeneralSetting:
workspaceSetting.Value = &v1pb.WorkspaceSetting_GeneralSetting_{
GeneralSetting: convertWorkspaceGeneralSettingFromStore(setting.GetGeneralSetting()),
case *storepb.InstanceSetting_GeneralSetting:
instanceSetting.Value = &v1pb.InstanceSetting_GeneralSetting_{
GeneralSetting: convertInstanceGeneralSettingFromStore(setting.GetGeneralSetting()),
}
case *storepb.WorkspaceSetting_StorageSetting:
workspaceSetting.Value = &v1pb.WorkspaceSetting_StorageSetting_{
StorageSetting: convertWorkspaceStorageSettingFromStore(setting.GetStorageSetting()),
case *storepb.InstanceSetting_StorageSetting:
instanceSetting.Value = &v1pb.InstanceSetting_StorageSetting_{
StorageSetting: convertInstanceStorageSettingFromStore(setting.GetStorageSetting()),
}
case *storepb.WorkspaceSetting_MemoRelatedSetting:
workspaceSetting.Value = &v1pb.WorkspaceSetting_MemoRelatedSetting_{
MemoRelatedSetting: convertWorkspaceMemoRelatedSettingFromStore(setting.GetMemoRelatedSetting()),
case *storepb.InstanceSetting_MemoRelatedSetting:
instanceSetting.Value = &v1pb.InstanceSetting_MemoRelatedSetting_{
MemoRelatedSetting: convertInstanceMemoRelatedSettingFromStore(setting.GetMemoRelatedSetting()),
}
}
return workspaceSetting
return instanceSetting
}
func convertWorkspaceSettingToStore(setting *v1pb.WorkspaceSetting) *storepb.WorkspaceSetting {
settingKeyString, _ := ExtractWorkspaceSettingKeyFromName(setting.Name)
workspaceSetting := &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey(storepb.WorkspaceSettingKey_value[settingKeyString]),
Value: &storepb.WorkspaceSetting_GeneralSetting{
GeneralSetting: convertWorkspaceGeneralSettingToStore(setting.GetGeneralSetting()),
func convertInstanceSettingToStore(setting *v1pb.InstanceSetting) *storepb.InstanceSetting {
settingKeyString, _ := ExtractInstanceSettingKeyFromName(setting.Name)
instanceSetting := &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey(storepb.InstanceSettingKey_value[settingKeyString]),
Value: &storepb.InstanceSetting_GeneralSetting{
GeneralSetting: convertInstanceGeneralSettingToStore(setting.GetGeneralSetting()),
},
}
switch workspaceSetting.Key {
case storepb.WorkspaceSettingKey_GENERAL:
workspaceSetting.Value = &storepb.WorkspaceSetting_GeneralSetting{
GeneralSetting: convertWorkspaceGeneralSettingToStore(setting.GetGeneralSetting()),
switch instanceSetting.Key {
case storepb.InstanceSettingKey_GENERAL:
instanceSetting.Value = &storepb.InstanceSetting_GeneralSetting{
GeneralSetting: convertInstanceGeneralSettingToStore(setting.GetGeneralSetting()),
}
case storepb.WorkspaceSettingKey_STORAGE:
workspaceSetting.Value = &storepb.WorkspaceSetting_StorageSetting{
StorageSetting: convertWorkspaceStorageSettingToStore(setting.GetStorageSetting()),
case storepb.InstanceSettingKey_STORAGE:
instanceSetting.Value = &storepb.InstanceSetting_StorageSetting{
StorageSetting: convertInstanceStorageSettingToStore(setting.GetStorageSetting()),
}
case storepb.WorkspaceSettingKey_MEMO_RELATED:
workspaceSetting.Value = &storepb.WorkspaceSetting_MemoRelatedSetting{
MemoRelatedSetting: convertWorkspaceMemoRelatedSettingToStore(setting.GetMemoRelatedSetting()),
case storepb.InstanceSettingKey_MEMO_RELATED:
instanceSetting.Value = &storepb.InstanceSetting_MemoRelatedSetting{
MemoRelatedSetting: convertInstanceMemoRelatedSettingToStore(setting.GetMemoRelatedSetting()),
}
default:
// Keep the default GeneralSetting value
}
return workspaceSetting
return instanceSetting
}
func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSetting) *v1pb.WorkspaceSetting_GeneralSetting {
func convertInstanceGeneralSettingFromStore(setting *storepb.InstanceGeneralSetting) *v1pb.InstanceSetting_GeneralSetting {
if setting == nil {
return nil
}
@ -160,7 +160,7 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe
theme = "default"
}
generalSetting := &v1pb.WorkspaceSetting_GeneralSetting{
generalSetting := &v1pb.InstanceSetting_GeneralSetting{
Theme: theme,
DisallowUserRegistration: setting.DisallowUserRegistration,
DisallowPasswordAuth: setting.DisallowPasswordAuth,
@ -171,7 +171,7 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe
DisallowChangeNickname: setting.DisallowChangeNickname,
}
if setting.CustomProfile != nil {
generalSetting.CustomProfile = &v1pb.WorkspaceSetting_GeneralSetting_CustomProfile{
generalSetting.CustomProfile = &v1pb.InstanceSetting_GeneralSetting_CustomProfile{
Title: setting.CustomProfile.Title,
Description: setting.CustomProfile.Description,
LogoUrl: setting.CustomProfile.LogoUrl,
@ -181,11 +181,11 @@ func convertWorkspaceGeneralSettingFromStore(setting *storepb.WorkspaceGeneralSe
return generalSetting
}
func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceSetting_GeneralSetting) *storepb.WorkspaceGeneralSetting {
func convertInstanceGeneralSettingToStore(setting *v1pb.InstanceSetting_GeneralSetting) *storepb.InstanceGeneralSetting {
if setting == nil {
return nil
}
generalSetting := &storepb.WorkspaceGeneralSetting{
generalSetting := &storepb.InstanceGeneralSetting{
Theme: setting.Theme,
DisallowUserRegistration: setting.DisallowUserRegistration,
DisallowPasswordAuth: setting.DisallowPasswordAuth,
@ -196,7 +196,7 @@ func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceSetting_Genera
DisallowChangeNickname: setting.DisallowChangeNickname,
}
if setting.CustomProfile != nil {
generalSetting.CustomProfile = &storepb.WorkspaceCustomProfile{
generalSetting.CustomProfile = &storepb.InstanceCustomProfile{
Title: setting.CustomProfile.Title,
Description: setting.CustomProfile.Description,
LogoUrl: setting.CustomProfile.LogoUrl,
@ -206,17 +206,17 @@ func convertWorkspaceGeneralSettingToStore(setting *v1pb.WorkspaceSetting_Genera
return generalSetting
}
func convertWorkspaceStorageSettingFromStore(settingpb *storepb.WorkspaceStorageSetting) *v1pb.WorkspaceSetting_StorageSetting {
func convertInstanceStorageSettingFromStore(settingpb *storepb.InstanceStorageSetting) *v1pb.InstanceSetting_StorageSetting {
if settingpb == nil {
return nil
}
setting := &v1pb.WorkspaceSetting_StorageSetting{
StorageType: v1pb.WorkspaceSetting_StorageSetting_StorageType(settingpb.StorageType),
setting := &v1pb.InstanceSetting_StorageSetting{
StorageType: v1pb.InstanceSetting_StorageSetting_StorageType(settingpb.StorageType),
FilepathTemplate: settingpb.FilepathTemplate,
UploadSizeLimitMb: settingpb.UploadSizeLimitMb,
}
if settingpb.S3Config != nil {
setting.S3Config = &v1pb.WorkspaceSetting_StorageSetting_S3Config{
setting.S3Config = &v1pb.InstanceSetting_StorageSetting_S3Config{
AccessKeyId: settingpb.S3Config.AccessKeyId,
AccessKeySecret: settingpb.S3Config.AccessKeySecret,
Endpoint: settingpb.S3Config.Endpoint,
@ -228,12 +228,12 @@ func convertWorkspaceStorageSettingFromStore(settingpb *storepb.WorkspaceStorage
return setting
}
func convertWorkspaceStorageSettingToStore(setting *v1pb.WorkspaceSetting_StorageSetting) *storepb.WorkspaceStorageSetting {
func convertInstanceStorageSettingToStore(setting *v1pb.InstanceSetting_StorageSetting) *storepb.InstanceStorageSetting {
if setting == nil {
return nil
}
settingpb := &storepb.WorkspaceStorageSetting{
StorageType: storepb.WorkspaceStorageSetting_StorageType(setting.StorageType),
settingpb := &storepb.InstanceStorageSetting{
StorageType: storepb.InstanceStorageSetting_StorageType(setting.StorageType),
FilepathTemplate: setting.FilepathTemplate,
UploadSizeLimitMb: setting.UploadSizeLimitMb,
}
@ -250,11 +250,11 @@ func convertWorkspaceStorageSettingToStore(setting *v1pb.WorkspaceSetting_Storag
return settingpb
}
func convertWorkspaceMemoRelatedSettingFromStore(setting *storepb.WorkspaceMemoRelatedSetting) *v1pb.WorkspaceSetting_MemoRelatedSetting {
func convertInstanceMemoRelatedSettingFromStore(setting *storepb.InstanceMemoRelatedSetting) *v1pb.InstanceSetting_MemoRelatedSetting {
if setting == nil {
return nil
}
return &v1pb.WorkspaceSetting_MemoRelatedSetting{
return &v1pb.InstanceSetting_MemoRelatedSetting{
DisallowPublicVisibility: setting.DisallowPublicVisibility,
DisplayWithUpdateTime: setting.DisplayWithUpdateTime,
ContentLengthLimit: setting.ContentLengthLimit,
@ -267,11 +267,11 @@ func convertWorkspaceMemoRelatedSettingFromStore(setting *storepb.WorkspaceMemoR
}
}
func convertWorkspaceMemoRelatedSettingToStore(setting *v1pb.WorkspaceSetting_MemoRelatedSetting) *storepb.WorkspaceMemoRelatedSetting {
func convertInstanceMemoRelatedSettingToStore(setting *v1pb.InstanceSetting_MemoRelatedSetting) *storepb.InstanceMemoRelatedSetting {
if setting == nil {
return nil
}
return &storepb.WorkspaceMemoRelatedSetting{
return &storepb.InstanceMemoRelatedSetting{
DisallowPublicVisibility: setting.DisallowPublicVisibility,
DisplayWithUpdateTime: setting.DisplayWithUpdateTime,
ContentLengthLimit: setting.ContentLengthLimit,

View File

@ -35,11 +35,11 @@ func (s *APIV1Service) CreateMemo(ctx context.Context, request *v1pb.CreateMemoR
Content: request.Memo.Content,
Visibility: convertVisibilityToStore(request.Memo.Visibility),
}
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
}
if workspaceMemoRelatedSetting.DisallowPublicVisibility && create.Visibility == store.Public {
if instanceMemoRelatedSetting.DisallowPublicVisibility && create.Visibility == store.Public {
return nil, status.Errorf(codes.PermissionDenied, "disable public memos system setting is enabled")
}
contentLengthLimit, err := s.getContentLengthLimit(ctx)
@ -147,11 +147,11 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq
}
}
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
}
if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
memoFind.OrderByUpdatedTs = true
}
@ -340,12 +340,12 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
update.Content = &memo.Content
update.Payload = memo.Payload
} else if path == "visibility" {
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
}
visibility := convertVisibilityToStore(request.Memo.Visibility)
if workspaceMemoRelatedSetting.DisallowPublicVisibility && visibility == store.Public {
if instanceMemoRelatedSetting.DisallowPublicVisibility && visibility == store.Public {
return nil, status.Errorf(codes.PermissionDenied, "disable public memos system setting is enabled")
}
update.Visibility = &visibility
@ -365,9 +365,9 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
update.UpdatedTs = &updatedTs
} else if path == "display_time" {
displayTs := request.Memo.DisplayTime.AsTime().Unix()
memoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
memoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
return nil, status.Errorf(codes.Internal, "failed to get instance memo related setting")
}
if memoRelatedSetting.DisplayWithUpdateTime {
update.UpdatedTs = &displayTs
@ -680,11 +680,11 @@ func (s *APIV1Service) ListMemoComments(ctx context.Context, request *v1pb.ListM
}
func (s *APIV1Service) getContentLengthLimit(ctx context.Context) (int, error) {
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return 0, status.Errorf(codes.Internal, "failed to get workspace memo related setting")
return 0, status.Errorf(codes.Internal, "failed to get instance memo related setting")
}
return int(workspaceMemoRelatedSetting.ContentLengthLimit), nil
return int(instanceMemoRelatedSetting.ContentLengthLimit), nil
}
// DispatchMemoCreatedWebhook dispatches webhook when memo is created.

View File

@ -15,11 +15,11 @@ import (
func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Memo, reactions []*store.Reaction, attachments []*store.Attachment) (*v1pb.Memo, error) {
displayTs := memo.CreatedTs
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace memo related setting")
return nil, errors.Wrap(err, "failed to get instance memo related setting")
}
if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
displayTs = memo.UpdatedTs
}

View File

@ -10,7 +10,7 @@ import (
)
const (
WorkspaceSettingNamePrefix = "workspace/settings/"
InstanceSettingNamePrefix = "instance/settings/"
UserNamePrefix = "users/"
MemoNamePrefix = "memos/"
AttachmentNamePrefix = "attachments/"
@ -41,20 +41,20 @@ func GetNameParentTokens(name string, tokenPrefixes ...string) ([]string, error)
return tokens, nil
}
func ExtractWorkspaceSettingKeyFromName(name string) (string, error) {
const prefix = "workspace/settings/"
func ExtractInstanceSettingKeyFromName(name string) (string, error) {
const prefix = "instance/settings/"
if !strings.HasPrefix(name, prefix) {
return "", errors.Errorf("invalid workspace setting name: expected prefix %q, got %q", prefix, name)
return "", errors.Errorf("invalid instance setting name: expected prefix %q, got %q", prefix, name)
}
settingKey := strings.TrimPrefix(name, prefix)
if settingKey == "" {
return "", errors.Errorf("invalid workspace setting name: empty setting key in %q", name)
return "", errors.Errorf("invalid instance setting name: empty setting key in %q", name)
}
// Ensure there are no additional path segments
if strings.Contains(settingKey, "/") {
return "", errors.Errorf("invalid workspace setting name: setting key cannot contain '/' in %q", name)
return "", errors.Errorf("invalid instance setting name: setting key cannot contain '/' in %q", name)
}
return settingKey, nil

View File

@ -10,17 +10,17 @@ import (
v1pb "github.com/usememos/memos/proto/gen/api/v1"
)
func TestGetWorkspaceProfile(t *testing.T) {
func TestGetInstanceProfile(t *testing.T) {
ctx := context.Background()
t.Run("GetWorkspaceProfile returns workspace profile", func(t *testing.T) {
t.Run("GetInstanceProfile returns instance profile", func(t *testing.T) {
// Create test service for this specific test
ts := NewTestService(t)
defer ts.Cleanup()
// Call GetWorkspaceProfile directly
req := &v1pb.GetWorkspaceProfileRequest{}
resp, err := ts.Service.GetWorkspaceProfile(ctx, req)
// Call GetInstanceProfile directly
req := &v1pb.GetInstanceProfileRequest{}
resp, err := ts.Service.GetInstanceProfile(ctx, req)
// Verify response
require.NoError(t, err)
@ -35,7 +35,7 @@ func TestGetWorkspaceProfile(t *testing.T) {
require.Empty(t, resp.Owner)
})
t.Run("GetWorkspaceProfile with owner", func(t *testing.T) {
t.Run("GetInstanceProfile with owner", func(t *testing.T) {
// Create test service for this specific test
ts := NewTestService(t)
defer ts.Cleanup()
@ -45,9 +45,9 @@ func TestGetWorkspaceProfile(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, hostUser)
// Call GetWorkspaceProfile directly
req := &v1pb.GetWorkspaceProfileRequest{}
resp, err := ts.Service.GetWorkspaceProfile(ctx, req)
// Call GetInstanceProfile directly
req := &v1pb.GetInstanceProfileRequest{}
resp, err := ts.Service.GetInstanceProfile(ctx, req)
// Verify response
require.NoError(t, err)
@ -64,7 +64,7 @@ func TestGetWorkspaceProfile(t *testing.T) {
})
}
func TestGetWorkspaceProfile_Concurrency(t *testing.T) {
func TestGetInstanceProfile_Concurrency(t *testing.T) {
ctx := context.Background()
t.Run("Concurrent access to service", func(t *testing.T) {
@ -79,13 +79,13 @@ func TestGetWorkspaceProfile_Concurrency(t *testing.T) {
// Make concurrent requests
numGoroutines := 10
results := make(chan *v1pb.WorkspaceProfile, numGoroutines)
results := make(chan *v1pb.InstanceProfile, numGoroutines)
errors := make(chan error, numGoroutines)
for i := 0; i < numGoroutines; i++ {
go func() {
req := &v1pb.GetWorkspaceProfileRequest{}
resp, err := ts.Service.GetWorkspaceProfile(ctx, req)
req := &v1pb.GetInstanceProfileRequest{}
resp, err := ts.Service.GetInstanceProfile(ctx, req)
if err != nil {
errors <- err
return
@ -110,24 +110,24 @@ func TestGetWorkspaceProfile_Concurrency(t *testing.T) {
})
}
func TestGetWorkspaceSetting(t *testing.T) {
func TestGetInstanceSetting(t *testing.T) {
ctx := context.Background()
t.Run("GetWorkspaceSetting - general setting", func(t *testing.T) {
t.Run("GetInstanceSetting - general setting", func(t *testing.T) {
// Create test service for this specific test
ts := NewTestService(t)
defer ts.Cleanup()
// Call GetWorkspaceSetting for general setting
req := &v1pb.GetWorkspaceSettingRequest{
Name: "workspace/settings/GENERAL",
// Call GetInstanceSetting for general setting
req := &v1pb.GetInstanceSettingRequest{
Name: "instance/settings/GENERAL",
}
resp, err := ts.Service.GetWorkspaceSetting(ctx, req)
resp, err := ts.Service.GetInstanceSetting(ctx, req)
// Verify response
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, "workspace/settings/GENERAL", resp.Name)
require.Equal(t, "instance/settings/GENERAL", resp.Name)
// The general setting should have a general_setting field
generalSetting := resp.GetGeneralSetting()
@ -139,7 +139,7 @@ func TestGetWorkspaceSetting(t *testing.T) {
require.Empty(t, generalSetting.AdditionalScript)
})
t.Run("GetWorkspaceSetting - storage setting", func(t *testing.T) {
t.Run("GetInstanceSetting - storage setting", func(t *testing.T) {
// Create test service for this specific test
ts := NewTestService(t)
defer ts.Cleanup()
@ -151,56 +151,56 @@ func TestGetWorkspaceSetting(t *testing.T) {
// Add user to context
userCtx := ts.CreateUserContext(ctx, hostUser.ID)
// Call GetWorkspaceSetting for storage setting
req := &v1pb.GetWorkspaceSettingRequest{
Name: "workspace/settings/STORAGE",
// Call GetInstanceSetting for storage setting
req := &v1pb.GetInstanceSettingRequest{
Name: "instance/settings/STORAGE",
}
resp, err := ts.Service.GetWorkspaceSetting(userCtx, req)
resp, err := ts.Service.GetInstanceSetting(userCtx, req)
// Verify response
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, "workspace/settings/STORAGE", resp.Name)
require.Equal(t, "instance/settings/STORAGE", resp.Name)
// The storage setting should have a storage_setting field
storageSetting := resp.GetStorageSetting()
require.NotNil(t, storageSetting)
})
t.Run("GetWorkspaceSetting - memo related setting", func(t *testing.T) {
t.Run("GetInstanceSetting - memo related setting", func(t *testing.T) {
// Create test service for this specific test
ts := NewTestService(t)
defer ts.Cleanup()
// Call GetWorkspaceSetting for memo related setting
req := &v1pb.GetWorkspaceSettingRequest{
Name: "workspace/settings/MEMO_RELATED",
// Call GetInstanceSetting for memo related setting
req := &v1pb.GetInstanceSettingRequest{
Name: "instance/settings/MEMO_RELATED",
}
resp, err := ts.Service.GetWorkspaceSetting(ctx, req)
resp, err := ts.Service.GetInstanceSetting(ctx, req)
// Verify response
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, "workspace/settings/MEMO_RELATED", resp.Name)
require.Equal(t, "instance/settings/MEMO_RELATED", resp.Name)
// The memo related setting should have a memo_related_setting field
memoRelatedSetting := resp.GetMemoRelatedSetting()
require.NotNil(t, memoRelatedSetting)
})
t.Run("GetWorkspaceSetting - invalid setting name", func(t *testing.T) {
t.Run("GetInstanceSetting - invalid setting name", func(t *testing.T) {
// Create test service for this specific test
ts := NewTestService(t)
defer ts.Cleanup()
// Call GetWorkspaceSetting with invalid name
req := &v1pb.GetWorkspaceSettingRequest{
// Call GetInstanceSetting with invalid name
req := &v1pb.GetInstanceSettingRequest{
Name: "invalid/setting/name",
}
_, err := ts.Service.GetWorkspaceSetting(ctx, req)
_, err := ts.Service.GetInstanceSetting(ctx, req)
// Should return an error
require.Error(t, err)
require.Contains(t, err.Error(), "invalid workspace setting name")
require.Contains(t, err.Error(), "invalid instance setting name")
})
}

View File

@ -241,14 +241,14 @@ func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserR
ID: user.ID,
UpdatedTs: &currentTs,
}
workspaceGeneralSetting, err := s.Store.GetWorkspaceGeneralSetting(ctx)
instanceGeneralSetting, err := s.Store.GetInstanceGeneralSetting(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get workspace general setting: %v", err)
return nil, status.Errorf(codes.Internal, "failed to get instance general setting: %v", err)
}
for _, field := range request.UpdateMask.Paths {
switch field {
case "username":
if workspaceGeneralSetting.DisallowChangeUsername {
if instanceGeneralSetting.DisallowChangeUsername {
return nil, status.Errorf(codes.PermissionDenied, "permission denied: disallow change username")
}
if !base.UIDMatcher.MatchString(strings.ToLower(request.User.Username)) {
@ -256,7 +256,7 @@ func (s *APIV1Service) UpdateUser(ctx context.Context, request *v1pb.UpdateUserR
}
update.Username = &request.User.Username
case "display_name":
if workspaceGeneralSetting.DisallowChangeNickname {
if instanceGeneralSetting.DisallowChangeNickname {
return nil, status.Errorf(codes.PermissionDenied, "permission denied: disallow change nickname")
}
update.Nickname = &request.User.DisplayName

View File

@ -15,9 +15,9 @@ import (
)
func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUserStatsRequest) (*v1pb.ListAllUserStatsResponse, error) {
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace memo related setting")
return nil, errors.Wrap(err, "failed to get instance memo related setting")
}
normalStatus := store.Normal
@ -50,7 +50,7 @@ func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUser
userMemoStatMap := make(map[int32]*v1pb.UserStats)
for _, memo := range memos {
displayTs := memo.CreatedTs
if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
displayTs = memo.UpdatedTs
}
userMemoStatMap[memo.CreatorID] = &v1pb.UserStats{
@ -101,9 +101,9 @@ func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserSt
return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
}
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
instanceMemoRelatedSetting, err := s.Store.GetInstanceMemoRelatedSetting(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace memo related setting")
return nil, errors.Wrap(err, "failed to get instance memo related setting")
}
displayTimestamps := []*timestamppb.Timestamp{}
@ -116,7 +116,7 @@ func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserSt
for _, memo := range memos {
displayTs := memo.CreatedTs
if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
if instanceMemoRelatedSetting.DisplayWithUpdateTime {
displayTs = memo.UpdatedTs
}
displayTimestamps = append(displayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))

View File

@ -23,7 +23,7 @@ import (
type APIV1Service struct {
grpc_health_v1.UnimplementedHealthServer
v1pb.UnimplementedWorkspaceServiceServer
v1pb.UnimplementedInstanceServiceServer
v1pb.UnimplementedAuthServiceServer
v1pb.UnimplementedUserServiceServer
v1pb.UnimplementedMemoServiceServer
@ -53,7 +53,7 @@ func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store
grpcServer: grpcServer,
}
grpc_health_v1.RegisterHealthServer(grpcServer, apiv1Service)
v1pb.RegisterWorkspaceServiceServer(grpcServer, apiv1Service)
v1pb.RegisterInstanceServiceServer(grpcServer, apiv1Service)
v1pb.RegisterAuthServiceServer(grpcServer, apiv1Service)
v1pb.RegisterUserServiceServer(grpcServer, apiv1Service)
v1pb.RegisterMemoServiceServer(grpcServer, apiv1Service)
@ -87,7 +87,7 @@ func (s *APIV1Service) RegisterGateway(ctx context.Context, echoServer *echo.Ech
}
gwMux := runtime.NewServeMux()
if err := v1pb.RegisterWorkspaceServiceHandler(ctx, gwMux, conn); err != nil {
if err := v1pb.RegisterInstanceServiceHandler(ctx, gwMux, conn); err != nil {
return err
}
if err := v1pb.RegisterAuthServiceHandler(ctx, gwMux, conn); err != nil {

View File

@ -161,7 +161,7 @@ func (s *RSSService) getRSSItemDescription(content string) (string, error) {
}
func getRSSHeading(ctx context.Context, stores *store.Store) (RSSHeading, error) {
settings, err := stores.GetWorkspaceGeneralSetting(ctx)
settings, err := stores.GetInstanceGeneralSetting(ctx)
if err != nil {
return RSSHeading{}, err
}

View File

@ -44,7 +44,7 @@ func (r *Runner) RunOnce(ctx context.Context) {
}
func (r *Runner) CheckAndPresign(ctx context.Context) {
workspaceStorageSetting, err := r.Store.GetWorkspaceStorageSetting(ctx)
instanceStorageSetting, err := r.Store.GetInstanceStorageSetting(ctx)
if err != nil {
return
}
@ -88,7 +88,7 @@ func (r *Runner) CheckAndPresign(ctx context.Context) {
}
}
s3Config := workspaceStorageSetting.GetS3Config()
s3Config := instanceStorageSetting.GetS3Config()
if s3ObjectPayload.S3Config != nil {
s3Config = s3ObjectPayload.S3Config
}

View File

@ -60,14 +60,14 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
s.profiler.StartMemoryMonitor(ctx)
}
workspaceBasicSetting, err := s.getOrUpsertWorkspaceBasicSetting(ctx)
instanceBasicSetting, err := s.getOrUpsertInstanceBasicSetting(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace basic setting")
return nil, errors.Wrap(err, "failed to get instance basic setting")
}
secret := "usememos"
if profile.Mode == "prod" {
secret = workspaceBasicSetting.SecretKey
secret = instanceBasicSetting.SecretKey
}
s.Secret = secret
@ -229,27 +229,27 @@ func (s *Server) StartBackgroundRunners(ctx context.Context) {
slog.Info("background runners started", "goroutines", runtime.NumGoroutine())
}
func (s *Server) getOrUpsertWorkspaceBasicSetting(ctx context.Context) (*storepb.WorkspaceBasicSetting, error) {
workspaceBasicSetting, err := s.Store.GetWorkspaceBasicSetting(ctx)
func (s *Server) getOrUpsertInstanceBasicSetting(ctx context.Context) (*storepb.InstanceBasicSetting, error) {
instanceBasicSetting, err := s.Store.GetInstanceBasicSetting(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace basic setting")
return nil, errors.Wrap(err, "failed to get instance basic setting")
}
modified := false
if workspaceBasicSetting.SecretKey == "" {
workspaceBasicSetting.SecretKey = uuid.NewString()
if instanceBasicSetting.SecretKey == "" {
instanceBasicSetting.SecretKey = uuid.NewString()
modified = true
}
if modified {
workspaceSetting, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_BASIC,
Value: &storepb.WorkspaceSetting_BasicSetting{BasicSetting: workspaceBasicSetting},
instanceSetting, err := s.Store.UpsertInstanceSetting(ctx, &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_BASIC,
Value: &storepb.InstanceSetting_BasicSetting{BasicSetting: instanceBasicSetting},
})
if err != nil {
return nil, errors.Wrap(err, "failed to upsert workspace setting")
return nil, errors.Wrap(err, "failed to upsert instance setting")
}
workspaceBasicSetting = workspaceSetting.GetBasicSetting()
instanceBasicSetting = instanceSetting.GetBasicSetting()
}
return workspaceBasicSetting, nil
return instanceBasicSetting, nil
}
// stacktraceError wraps an underlying error and captures the stacktrace. It

View File

@ -141,16 +141,16 @@ func (s *Store) DeleteAttachment(ctx context.Context, delete *DeleteAttachment)
if s3ObjectPayload == nil {
return errors.Errorf("No s3 object found")
}
workspaceStorageSetting, err := s.GetWorkspaceStorageSetting(ctx)
instanceStorageSetting, err := s.GetInstanceStorageSetting(ctx)
if err != nil {
return errors.Wrap(err, "failed to get workspace storage setting")
return errors.Wrap(err, "failed to get instance storage setting")
}
s3Config := s3ObjectPayload.S3Config
if s3Config == nil {
if workspaceStorageSetting.S3Config == nil {
if instanceStorageSetting.S3Config == nil {
return errors.Errorf("S3 config is not found")
}
s3Config = workspaceStorageSetting.S3Config
s3Config = instanceStorageSetting.S3Config
}
s3Client, err := s3.NewClient(ctx, s3Config)

View File

@ -7,7 +7,7 @@ import (
"github.com/usememos/memos/store"
)
func (d *DB) UpsertWorkspaceSetting(ctx context.Context, upsert *store.WorkspaceSetting) (*store.WorkspaceSetting, error) {
func (d *DB) UpsertInstanceSetting(ctx context.Context, upsert *store.InstanceSetting) (*store.InstanceSetting, error) {
stmt := "INSERT INTO `system_setting` (`name`, `value`, `description`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `value` = ?, `description` = ?"
_, err := d.db.ExecContext(
ctx,
@ -25,7 +25,7 @@ func (d *DB) UpsertWorkspaceSetting(ctx context.Context, upsert *store.Workspace
return upsert, nil
}
func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspaceSetting) ([]*store.WorkspaceSetting, error) {
func (d *DB) ListInstanceSettings(ctx context.Context, find *store.FindInstanceSetting) ([]*store.InstanceSetting, error) {
where, args := []string{"1 = 1"}, []any{}
if find.Name != "" {
where, args = append(where, "`name` = ?"), append(args, find.Name)
@ -38,9 +38,9 @@ func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspac
}
defer rows.Close()
list := []*store.WorkspaceSetting{}
list := []*store.InstanceSetting{}
for rows.Next() {
systemSettingMessage := &store.WorkspaceSetting{}
systemSettingMessage := &store.InstanceSetting{}
if err := rows.Scan(
&systemSettingMessage.Name,
&systemSettingMessage.Value,
@ -58,7 +58,7 @@ func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspac
return list, nil
}
func (d *DB) DeleteWorkspaceSetting(ctx context.Context, delete *store.DeleteWorkspaceSetting) error {
func (d *DB) DeleteInstanceSetting(ctx context.Context, delete *store.DeleteInstanceSetting) error {
stmt := "DELETE FROM `system_setting` WHERE `name` = ?"
_, err := d.db.ExecContext(ctx, stmt, delete.Name)
return err

View File

@ -7,7 +7,7 @@ import (
"github.com/usememos/memos/store"
)
func (d *DB) UpsertWorkspaceSetting(ctx context.Context, upsert *store.WorkspaceSetting) (*store.WorkspaceSetting, error) {
func (d *DB) UpsertInstanceSetting(ctx context.Context, upsert *store.InstanceSetting) (*store.InstanceSetting, error) {
stmt := `
INSERT INTO system_setting (
name, value, description
@ -25,7 +25,7 @@ func (d *DB) UpsertWorkspaceSetting(ctx context.Context, upsert *store.Workspace
return upsert, nil
}
func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspaceSetting) ([]*store.WorkspaceSetting, error) {
func (d *DB) ListInstanceSettings(ctx context.Context, find *store.FindInstanceSetting) ([]*store.InstanceSetting, error) {
where, args := []string{"1 = 1"}, []any{}
if find.Name != "" {
where, args = append(where, "name = "+placeholder(len(args)+1)), append(args, find.Name)
@ -45,9 +45,9 @@ func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspac
}
defer rows.Close()
list := []*store.WorkspaceSetting{}
list := []*store.InstanceSetting{}
for rows.Next() {
systemSettingMessage := &store.WorkspaceSetting{}
systemSettingMessage := &store.InstanceSetting{}
if err := rows.Scan(
&systemSettingMessage.Name,
&systemSettingMessage.Value,
@ -65,7 +65,7 @@ func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspac
return list, nil
}
func (d *DB) DeleteWorkspaceSetting(ctx context.Context, delete *store.DeleteWorkspaceSetting) error {
func (d *DB) DeleteInstanceSetting(ctx context.Context, delete *store.DeleteInstanceSetting) error {
stmt := `DELETE FROM system_setting WHERE name = $1`
_, err := d.db.ExecContext(ctx, stmt, delete.Name)
return err

View File

@ -7,7 +7,7 @@ import (
"github.com/usememos/memos/store"
)
func (d *DB) UpsertWorkspaceSetting(ctx context.Context, upsert *store.WorkspaceSetting) (*store.WorkspaceSetting, error) {
func (d *DB) UpsertInstanceSetting(ctx context.Context, upsert *store.InstanceSetting) (*store.InstanceSetting, error) {
stmt := `
INSERT INTO system_setting (
name, value, description
@ -25,7 +25,7 @@ func (d *DB) UpsertWorkspaceSetting(ctx context.Context, upsert *store.Workspace
return upsert, nil
}
func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspaceSetting) ([]*store.WorkspaceSetting, error) {
func (d *DB) ListInstanceSettings(ctx context.Context, find *store.FindInstanceSetting) ([]*store.InstanceSetting, error) {
where, args := []string{"1 = 1"}, []any{}
if find.Name != "" {
where, args = append(where, "name = ?"), append(args, find.Name)
@ -45,9 +45,9 @@ func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspac
}
defer rows.Close()
list := []*store.WorkspaceSetting{}
list := []*store.InstanceSetting{}
for rows.Next() {
systemSettingMessage := &store.WorkspaceSetting{}
systemSettingMessage := &store.InstanceSetting{}
if err := rows.Scan(
&systemSettingMessage.Name,
&systemSettingMessage.Value,
@ -65,7 +65,7 @@ func (d *DB) ListWorkspaceSettings(ctx context.Context, find *store.FindWorkspac
return list, nil
}
func (d *DB) DeleteWorkspaceSetting(ctx context.Context, delete *store.DeleteWorkspaceSetting) error {
func (d *DB) DeleteInstanceSetting(ctx context.Context, delete *store.DeleteInstanceSetting) error {
stmt := "DELETE FROM system_setting WHERE name = ?"
_, err := d.db.ExecContext(ctx, stmt, delete.Name)
return err

View File

@ -15,7 +15,7 @@ type Driver interface {
// MigrationHistory model related methods.
// NOTE: These methods are deprecated. The migration_history table is no longer used
// for tracking schema versions. Schema version is now stored in workspace_setting.
// for tracking schema versions. Schema version is now stored in instance_setting.
// These methods are kept for backward compatibility to migrate existing installations.
FindMigrationHistoryList(ctx context.Context, find *FindMigrationHistory) ([]*MigrationHistory, error)
UpsertMigrationHistory(ctx context.Context, upsert *UpsertMigrationHistory) (*MigrationHistory, error)
@ -41,10 +41,10 @@ type Driver interface {
ListMemoRelations(ctx context.Context, find *FindMemoRelation) ([]*MemoRelation, error)
DeleteMemoRelation(ctx context.Context, delete *DeleteMemoRelation) error
// WorkspaceSetting model related methods.
UpsertWorkspaceSetting(ctx context.Context, upsert *WorkspaceSetting) (*WorkspaceSetting, error)
ListWorkspaceSettings(ctx context.Context, find *FindWorkspaceSetting) ([]*WorkspaceSetting, error)
DeleteWorkspaceSetting(ctx context.Context, delete *DeleteWorkspaceSetting) error
// InstanceSetting model related methods.
UpsertInstanceSetting(ctx context.Context, upsert *InstanceSetting) (*InstanceSetting, error)
ListInstanceSettings(ctx context.Context, find *FindInstanceSetting) ([]*InstanceSetting, error)
DeleteInstanceSetting(ctx context.Context, delete *DeleteInstanceSetting) error
// User model related methods.
CreateUser(ctx context.Context, create *User) (*User, error)

245
store/instance_setting.go Normal file
View File

@ -0,0 +1,245 @@
package store
import (
"context"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb "github.com/usememos/memos/proto/gen/store"
)
type InstanceSetting struct {
Name string
Value string
Description string
}
type FindInstanceSetting struct {
Name string
}
type DeleteInstanceSetting struct {
Name string
}
func (s *Store) UpsertInstanceSetting(ctx context.Context, upsert *storepb.InstanceSetting) (*storepb.InstanceSetting, error) {
instanceSettingRaw := &InstanceSetting{
Name: upsert.Key.String(),
}
var valueBytes []byte
var err error
if upsert.Key == storepb.InstanceSettingKey_BASIC {
valueBytes, err = protojson.Marshal(upsert.GetBasicSetting())
} else if upsert.Key == storepb.InstanceSettingKey_GENERAL {
valueBytes, err = protojson.Marshal(upsert.GetGeneralSetting())
} else if upsert.Key == storepb.InstanceSettingKey_STORAGE {
valueBytes, err = protojson.Marshal(upsert.GetStorageSetting())
} else if upsert.Key == storepb.InstanceSettingKey_MEMO_RELATED {
valueBytes, err = protojson.Marshal(upsert.GetMemoRelatedSetting())
} else {
return nil, errors.Errorf("unsupported instance setting key: %v", upsert.Key)
}
if err != nil {
return nil, errors.Wrap(err, "failed to marshal instance setting value")
}
valueString := string(valueBytes)
instanceSettingRaw.Value = valueString
instanceSettingRaw, err = s.driver.UpsertInstanceSetting(ctx, instanceSettingRaw)
if err != nil {
return nil, errors.Wrap(err, "Failed to upsert instance setting")
}
instanceSetting, err := convertInstanceSettingFromRaw(instanceSettingRaw)
if err != nil {
return nil, errors.Wrap(err, "Failed to convert instance setting")
}
s.instanceSettingCache.Set(ctx, instanceSetting.Key.String(), instanceSetting)
return instanceSetting, nil
}
func (s *Store) ListInstanceSettings(ctx context.Context, find *FindInstanceSetting) ([]*storepb.InstanceSetting, error) {
list, err := s.driver.ListInstanceSettings(ctx, find)
if err != nil {
return nil, err
}
instanceSettings := []*storepb.InstanceSetting{}
for _, instanceSettingRaw := range list {
instanceSetting, err := convertInstanceSettingFromRaw(instanceSettingRaw)
if err != nil {
return nil, errors.Wrap(err, "Failed to convert instance setting")
}
if instanceSetting == nil {
continue
}
s.instanceSettingCache.Set(ctx, instanceSetting.Key.String(), instanceSetting)
instanceSettings = append(instanceSettings, instanceSetting)
}
return instanceSettings, nil
}
func (s *Store) GetInstanceSetting(ctx context.Context, find *FindInstanceSetting) (*storepb.InstanceSetting, error) {
if cache, ok := s.instanceSettingCache.Get(ctx, find.Name); ok {
instanceSetting, ok := cache.(*storepb.InstanceSetting)
if ok {
return instanceSetting, nil
}
}
list, err := s.ListInstanceSettings(ctx, find)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, nil
}
if len(list) > 1 {
return nil, errors.Errorf("found multiple instance settings with key %s", find.Name)
}
return list[0], nil
}
func (s *Store) GetInstanceBasicSetting(ctx context.Context) (*storepb.InstanceBasicSetting, error) {
instanceSetting, err := s.GetInstanceSetting(ctx, &FindInstanceSetting{
Name: storepb.InstanceSettingKey_BASIC.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get instance basic setting")
}
instanceBasicSetting := &storepb.InstanceBasicSetting{}
if instanceSetting != nil {
instanceBasicSetting = instanceSetting.GetBasicSetting()
}
s.instanceSettingCache.Set(ctx, storepb.InstanceSettingKey_BASIC.String(), &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_BASIC,
Value: &storepb.InstanceSetting_BasicSetting{BasicSetting: instanceBasicSetting},
})
return instanceBasicSetting, nil
}
func (s *Store) GetInstanceGeneralSetting(ctx context.Context) (*storepb.InstanceGeneralSetting, error) {
instanceSetting, err := s.GetInstanceSetting(ctx, &FindInstanceSetting{
Name: storepb.InstanceSettingKey_GENERAL.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get instance general setting")
}
instanceGeneralSetting := &storepb.InstanceGeneralSetting{}
if instanceSetting != nil {
instanceGeneralSetting = instanceSetting.GetGeneralSetting()
}
s.instanceSettingCache.Set(ctx, storepb.InstanceSettingKey_GENERAL.String(), &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_GENERAL,
Value: &storepb.InstanceSetting_GeneralSetting{GeneralSetting: instanceGeneralSetting},
})
return instanceGeneralSetting, nil
}
// DefaultContentLengthLimit is the default limit of content length in bytes. 8KB.
const DefaultContentLengthLimit = 8 * 1024
// DefaultReactions is the default reactions for memo related setting.
var DefaultReactions = []string{"👍", "👎", "❤️", "🎉", "😄", "😕", "😢", "😡"}
// DefaultNsfwTags is the default tags that mark content as NSFW for blurring.
var DefaultNsfwTags = []string{"nsfw"}
func (s *Store) GetInstanceMemoRelatedSetting(ctx context.Context) (*storepb.InstanceMemoRelatedSetting, error) {
instanceSetting, err := s.GetInstanceSetting(ctx, &FindInstanceSetting{
Name: storepb.InstanceSettingKey_MEMO_RELATED.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get instance general setting")
}
instanceMemoRelatedSetting := &storepb.InstanceMemoRelatedSetting{}
if instanceSetting != nil {
instanceMemoRelatedSetting = instanceSetting.GetMemoRelatedSetting()
}
if instanceMemoRelatedSetting.ContentLengthLimit < DefaultContentLengthLimit {
instanceMemoRelatedSetting.ContentLengthLimit = DefaultContentLengthLimit
}
if len(instanceMemoRelatedSetting.Reactions) == 0 {
instanceMemoRelatedSetting.Reactions = append(instanceMemoRelatedSetting.Reactions, DefaultReactions...)
}
if len(instanceMemoRelatedSetting.NsfwTags) == 0 {
instanceMemoRelatedSetting.NsfwTags = append(instanceMemoRelatedSetting.NsfwTags, DefaultNsfwTags...)
}
s.instanceSettingCache.Set(ctx, storepb.InstanceSettingKey_MEMO_RELATED.String(), &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_MEMO_RELATED,
Value: &storepb.InstanceSetting_MemoRelatedSetting{MemoRelatedSetting: instanceMemoRelatedSetting},
})
return instanceMemoRelatedSetting, nil
}
const (
defaultInstanceStorageType = storepb.InstanceStorageSetting_DATABASE
defaultInstanceUploadSizeLimitMb = 30
defaultInstanceFilepathTemplate = "assets/{timestamp}_{filename}"
)
func (s *Store) GetInstanceStorageSetting(ctx context.Context) (*storepb.InstanceStorageSetting, error) {
instanceSetting, err := s.GetInstanceSetting(ctx, &FindInstanceSetting{
Name: storepb.InstanceSettingKey_STORAGE.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get instance storage setting")
}
instanceStorageSetting := &storepb.InstanceStorageSetting{}
if instanceSetting != nil {
instanceStorageSetting = instanceSetting.GetStorageSetting()
}
if instanceStorageSetting.StorageType == storepb.InstanceStorageSetting_STORAGE_TYPE_UNSPECIFIED {
instanceStorageSetting.StorageType = defaultInstanceStorageType
}
if instanceStorageSetting.UploadSizeLimitMb == 0 {
instanceStorageSetting.UploadSizeLimitMb = defaultInstanceUploadSizeLimitMb
}
if instanceStorageSetting.FilepathTemplate == "" {
instanceStorageSetting.FilepathTemplate = defaultInstanceFilepathTemplate
}
s.instanceSettingCache.Set(ctx, storepb.InstanceSettingKey_STORAGE.String(), &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_STORAGE,
Value: &storepb.InstanceSetting_StorageSetting{StorageSetting: instanceStorageSetting},
})
return instanceStorageSetting, nil
}
func convertInstanceSettingFromRaw(instanceSettingRaw *InstanceSetting) (*storepb.InstanceSetting, error) {
instanceSetting := &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey(storepb.InstanceSettingKey_value[instanceSettingRaw.Name]),
}
switch instanceSettingRaw.Name {
case storepb.InstanceSettingKey_BASIC.String():
basicSetting := &storepb.InstanceBasicSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(instanceSettingRaw.Value), basicSetting); err != nil {
return nil, err
}
instanceSetting.Value = &storepb.InstanceSetting_BasicSetting{BasicSetting: basicSetting}
case storepb.InstanceSettingKey_GENERAL.String():
generalSetting := &storepb.InstanceGeneralSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(instanceSettingRaw.Value), generalSetting); err != nil {
return nil, err
}
instanceSetting.Value = &storepb.InstanceSetting_GeneralSetting{GeneralSetting: generalSetting}
case storepb.InstanceSettingKey_STORAGE.String():
storageSetting := &storepb.InstanceStorageSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(instanceSettingRaw.Value), storageSetting); err != nil {
return nil, err
}
instanceSetting.Value = &storepb.InstanceSetting_StorageSetting{StorageSetting: storageSetting}
case storepb.InstanceSettingKey_MEMO_RELATED.String():
memoRelatedSetting := &storepb.InstanceMemoRelatedSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(instanceSettingRaw.Value), memoRelatedSetting); err != nil {
return nil, err
}
instanceSetting.Value = &storepb.InstanceSetting_MemoRelatedSetting{MemoRelatedSetting: memoRelatedSetting}
default:
// Skip unsupported instance setting key.
return nil, nil
}
return instanceSetting, nil
}

View File

@ -2,8 +2,8 @@ package store
// MigrationHistory represents a record in the migration_history table.
// NOTE: The migration_history table is deprecated in favor of storing schema version
// in workspace_setting (BASIC setting). This is kept for backward compatibility only.
// Migration from migration_history to workspace_setting happens automatically during startup.
// in system_setting (BASIC setting). This is kept for backward compatibility only.
// Migration from migration_history to system_setting happens automatically during startup.
type MigrationHistory struct {
Version string
CreatedTs int64

View File

@ -21,19 +21,19 @@ import (
// Migration System Overview:
//
// The migration system handles database schema versioning and upgrades.
// Schema version is stored in workspace_setting (the new system).
// Schema version is stored in system_setting (the new system).
// The old migration_history table is deprecated but still supported for backward compatibility.
//
// Migration Flow:
// 1. preMigrate: Check if DB is initialized. If not, apply LATEST.sql
// 2. normalizeMigrationHistoryList: Normalize old migration_history records (for pre-0.22 installations)
// 3. migrateSchemaVersionToSetting: Migrate version from migration_history to workspace_setting
// 3. migrateSchemaVersionToSetting: Migrate version from migration_history to system_setting
// 4. Migrate (prod mode): Apply incremental migrations from current to target version
// 5. Migrate (demo mode): Seed database with demo data
//
// Version Tracking:
// - New installations: Schema version set in workspace_setting immediately
// - Old installations: Version migrated from migration_history to workspace_setting automatically
// - New installations: Schema version set in system_setting immediately
// - Old installations: Version migrated from migration_history to system_setting automatically
// - Empty version: Treated as 0.0.0 and all migrations applied
//
// Migration Files:
@ -118,25 +118,25 @@ func (s *Store) Migrate(ctx context.Context) error {
switch s.profile.Mode {
case modeProd:
workspaceBasicSetting, err := s.GetWorkspaceBasicSetting(ctx)
instanceBasicSetting, err := s.GetInstanceBasicSetting(ctx)
if err != nil {
return errors.Wrap(err, "failed to get workspace basic setting")
return errors.Wrap(err, "failed to get instance basic setting")
}
currentSchemaVersion, err := s.GetCurrentSchemaVersion()
if err != nil {
return errors.Wrap(err, "failed to get current schema version")
}
// Check for downgrade (but skip if schema version is empty - that means fresh/old installation)
if !isVersionEmpty(workspaceBasicSetting.SchemaVersion) && version.IsVersionGreaterThan(workspaceBasicSetting.SchemaVersion, currentSchemaVersion) {
if !isVersionEmpty(instanceBasicSetting.SchemaVersion) && version.IsVersionGreaterThan(instanceBasicSetting.SchemaVersion, currentSchemaVersion) {
slog.Error("cannot downgrade schema version",
slog.String("databaseVersion", workspaceBasicSetting.SchemaVersion),
slog.String("databaseVersion", instanceBasicSetting.SchemaVersion),
slog.String("currentVersion", currentSchemaVersion),
)
return errors.Errorf("cannot downgrade schema version from %s to %s", workspaceBasicSetting.SchemaVersion, currentSchemaVersion)
return errors.Errorf("cannot downgrade schema version from %s to %s", instanceBasicSetting.SchemaVersion, currentSchemaVersion)
}
// Apply migrations if needed (including when schema version is empty)
if isVersionEmpty(workspaceBasicSetting.SchemaVersion) || version.IsVersionGreaterThan(currentSchemaVersion, workspaceBasicSetting.SchemaVersion) {
if err := s.applyMigrations(ctx, workspaceBasicSetting.SchemaVersion, currentSchemaVersion); err != nil {
if isVersionEmpty(instanceBasicSetting.SchemaVersion) || version.IsVersionGreaterThan(currentSchemaVersion, instanceBasicSetting.SchemaVersion) {
if err := s.applyMigrations(ctx, instanceBasicSetting.SchemaVersion, currentSchemaVersion); err != nil {
return errors.Wrap(err, "failed to apply migrations")
}
}
@ -363,19 +363,19 @@ func (*Store) execute(ctx context.Context, tx *sql.Tx, stmt string) error {
return nil
}
// updateCurrentSchemaVersion updates the current schema version in the workspace basic setting.
// It retrieves the workspace basic setting, updates the schema version, and upserts the setting back to the database.
// updateCurrentSchemaVersion updates the current schema version in the instance basic setting.
// It retrieves the instance basic setting, updates the schema version, and upserts the setting back to the database.
func (s *Store) updateCurrentSchemaVersion(ctx context.Context, schemaVersion string) error {
workspaceBasicSetting, err := s.GetWorkspaceBasicSetting(ctx)
instanceBasicSetting, err := s.GetInstanceBasicSetting(ctx)
if err != nil {
return errors.Wrap(err, "failed to get workspace basic setting")
return errors.Wrap(err, "failed to get instance basic setting")
}
workspaceBasicSetting.SchemaVersion = schemaVersion
if _, err := s.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_BASIC,
Value: &storepb.WorkspaceSetting_BasicSetting{BasicSetting: workspaceBasicSetting},
instanceBasicSetting.SchemaVersion = schemaVersion
if _, err := s.UpsertInstanceSetting(ctx, &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_BASIC,
Value: &storepb.InstanceSetting_BasicSetting{BasicSetting: instanceBasicSetting},
}); err != nil {
return errors.Wrap(err, "failed to upsert workspace setting")
return errors.Wrap(err, "failed to upsert instance setting")
}
return nil
}
@ -383,7 +383,7 @@ func (s *Store) updateCurrentSchemaVersion(ctx context.Context, schemaVersion st
// normalizeMigrationHistoryList normalizes the migration history list.
// It checks the existing migration history and updates it to the latest schema version if necessary.
// NOTE: This is a transition function for backward compatibility with the deprecated migration_history table.
// This ensures that old installations (< 0.22) have their migration_history normalized before migrating to workspace_setting.
// This ensures that old installations (< 0.22) have their migration_history normalized before migrating to system_setting.
func (s *Store) normalizeMigrationHistoryList(ctx context.Context) error {
migrationHistoryList, err := s.driver.FindMigrationHistoryList(ctx, &FindMigrationHistory{})
if err != nil {
@ -435,11 +435,11 @@ func (s *Store) normalizeMigrationHistoryList(ctx context.Context) error {
return nil
}
// migrateSchemaVersionToSetting migrates the schema version from the migration history to the workspace basic setting.
// It retrieves the migration history, sorts the versions, and updates the workspace basic setting if necessary.
// migrateSchemaVersionToSetting migrates the schema version from the migration history to the instance basic setting.
// It retrieves the migration history, sorts the versions, and updates the instance basic setting if necessary.
// NOTE: This is a transition function for backward compatibility with the deprecated migration_history table.
// The migration_history table is deprecated in favor of storing schema version in workspace_setting.
// This handles upgrades from old installations that only have migration_history but no workspace_setting.
// The migration_history table is deprecated in favor of storing schema version in system_setting.
// This handles upgrades from old installations that only have migration_history but no system_setting.
func (s *Store) migrateSchemaVersionToSetting(ctx context.Context) error {
migrationHistoryList, err := s.driver.FindMigrationHistoryList(ctx, &FindMigrationHistory{})
if err != nil {
@ -455,16 +455,16 @@ func (s *Store) migrateSchemaVersionToSetting(ctx context.Context) error {
sort.Sort(version.SortVersion(versions))
latestVersion := versions[len(versions)-1]
workspaceBasicSetting, err := s.GetWorkspaceBasicSetting(ctx)
instanceBasicSetting, err := s.GetInstanceBasicSetting(ctx)
if err != nil {
return errors.Wrap(err, "failed to get workspace basic setting")
return errors.Wrap(err, "failed to get instance basic setting")
}
// If workspace_setting has no schema version (empty), or migration_history has a newer version, update workspace_setting.
// If instance_setting has no schema version (empty), or migration_history has a newer version, update instance_setting.
// This handles upgrades from old installations where schema version was only tracked in migration_history.
if isVersionEmpty(workspaceBasicSetting.SchemaVersion) || version.IsVersionGreaterThan(latestVersion, workspaceBasicSetting.SchemaVersion) {
slog.Info("migrating schema version from migration_history to workspace_setting",
slog.String("from", workspaceBasicSetting.SchemaVersion),
if isVersionEmpty(instanceBasicSetting.SchemaVersion) || version.IsVersionGreaterThan(latestVersion, instanceBasicSetting.SchemaVersion) {
slog.Info("migrating schema version from migration_history to instance_setting",
slog.String("from", instanceBasicSetting.SchemaVersion),
slog.String("to", latestVersion),
)
if err := s.updateCurrentSchemaVersion(ctx, latestVersion); err != nil {

View File

@ -16,7 +16,7 @@ type Store struct {
cacheConfig cache.Config
// Caches
workspaceSettingCache *cache.Cache // cache for workspace settings
instanceSettingCache *cache.Cache // cache for instance settings
userCache *cache.Cache // cache for users
userSettingCache *cache.Cache // cache for user settings
}
@ -35,7 +35,7 @@ func New(driver Driver, profile *profile.Profile) *Store {
driver: driver,
profile: profile,
cacheConfig: cacheConfig,
workspaceSettingCache: cache.New(cacheConfig),
instanceSettingCache: cache.New(cacheConfig),
userCache: cache.New(cacheConfig),
userSettingCache: cache.New(cacheConfig),
}
@ -49,7 +49,7 @@ func (s *Store) GetDriver() Driver {
func (s *Store) Close() error {
// Stop all cache cleanup goroutines
s.workspaceSettingCache.Close()
s.instanceSettingCache.Close()
s.userCache.Close()
s.userSettingCache.Close()

View File

@ -0,0 +1,31 @@
package test
import (
"context"
"testing"
"github.com/stretchr/testify/require"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func TestInstanceSettingV1Store(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
instanceSetting, err := ts.UpsertInstanceSetting(ctx, &storepb.InstanceSetting{
Key: storepb.InstanceSettingKey_GENERAL,
Value: &storepb.InstanceSetting_GeneralSetting{
GeneralSetting: &storepb.InstanceGeneralSetting{
AdditionalScript: "",
},
},
})
require.NoError(t, err)
setting, err := ts.GetInstanceSetting(ctx, &store.FindInstanceSetting{
Name: storepb.InstanceSettingKey_GENERAL.String(),
})
require.NoError(t, err)
require.Equal(t, instanceSetting, setting)
ts.Close()
}

View File

@ -1,31 +0,0 @@
package test
import (
"context"
"testing"
"github.com/stretchr/testify/require"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
)
func TestWorkspaceSettingV1Store(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
workspaceSetting, err := ts.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_GENERAL,
Value: &storepb.WorkspaceSetting_GeneralSetting{
GeneralSetting: &storepb.WorkspaceGeneralSetting{
AdditionalScript: "",
},
},
})
require.NoError(t, err)
setting, err := ts.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Name: storepb.WorkspaceSettingKey_GENERAL.String(),
})
require.NoError(t, err)
require.Equal(t, workspaceSetting, setting)
ts.Close()
}

View File

@ -1,245 +0,0 @@
package store
import (
"context"
"github.com/pkg/errors"
"google.golang.org/protobuf/encoding/protojson"
storepb "github.com/usememos/memos/proto/gen/store"
)
type WorkspaceSetting struct {
Name string
Value string
Description string
}
type FindWorkspaceSetting struct {
Name string
}
type DeleteWorkspaceSetting struct {
Name string
}
func (s *Store) UpsertWorkspaceSetting(ctx context.Context, upsert *storepb.WorkspaceSetting) (*storepb.WorkspaceSetting, error) {
workspaceSettingRaw := &WorkspaceSetting{
Name: upsert.Key.String(),
}
var valueBytes []byte
var err error
if upsert.Key == storepb.WorkspaceSettingKey_BASIC {
valueBytes, err = protojson.Marshal(upsert.GetBasicSetting())
} else if upsert.Key == storepb.WorkspaceSettingKey_GENERAL {
valueBytes, err = protojson.Marshal(upsert.GetGeneralSetting())
} else if upsert.Key == storepb.WorkspaceSettingKey_STORAGE {
valueBytes, err = protojson.Marshal(upsert.GetStorageSetting())
} else if upsert.Key == storepb.WorkspaceSettingKey_MEMO_RELATED {
valueBytes, err = protojson.Marshal(upsert.GetMemoRelatedSetting())
} else {
return nil, errors.Errorf("unsupported workspace setting key: %v", upsert.Key)
}
if err != nil {
return nil, errors.Wrap(err, "failed to marshal workspace setting value")
}
valueString := string(valueBytes)
workspaceSettingRaw.Value = valueString
workspaceSettingRaw, err = s.driver.UpsertWorkspaceSetting(ctx, workspaceSettingRaw)
if err != nil {
return nil, errors.Wrap(err, "Failed to upsert workspace setting")
}
workspaceSetting, err := convertWorkspaceSettingFromRaw(workspaceSettingRaw)
if err != nil {
return nil, errors.Wrap(err, "Failed to convert workspace setting")
}
s.workspaceSettingCache.Set(ctx, workspaceSetting.Key.String(), workspaceSetting)
return workspaceSetting, nil
}
func (s *Store) ListWorkspaceSettings(ctx context.Context, find *FindWorkspaceSetting) ([]*storepb.WorkspaceSetting, error) {
list, err := s.driver.ListWorkspaceSettings(ctx, find)
if err != nil {
return nil, err
}
workspaceSettings := []*storepb.WorkspaceSetting{}
for _, workspaceSettingRaw := range list {
workspaceSetting, err := convertWorkspaceSettingFromRaw(workspaceSettingRaw)
if err != nil {
return nil, errors.Wrap(err, "Failed to convert workspace setting")
}
if workspaceSetting == nil {
continue
}
s.workspaceSettingCache.Set(ctx, workspaceSetting.Key.String(), workspaceSetting)
workspaceSettings = append(workspaceSettings, workspaceSetting)
}
return workspaceSettings, nil
}
func (s *Store) GetWorkspaceSetting(ctx context.Context, find *FindWorkspaceSetting) (*storepb.WorkspaceSetting, error) {
if cache, ok := s.workspaceSettingCache.Get(ctx, find.Name); ok {
workspaceSetting, ok := cache.(*storepb.WorkspaceSetting)
if ok {
return workspaceSetting, nil
}
}
list, err := s.ListWorkspaceSettings(ctx, find)
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, nil
}
if len(list) > 1 {
return nil, errors.Errorf("found multiple workspace settings with key %s", find.Name)
}
return list[0], nil
}
func (s *Store) GetWorkspaceBasicSetting(ctx context.Context) (*storepb.WorkspaceBasicSetting, error) {
workspaceSetting, err := s.GetWorkspaceSetting(ctx, &FindWorkspaceSetting{
Name: storepb.WorkspaceSettingKey_BASIC.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace basic setting")
}
workspaceBasicSetting := &storepb.WorkspaceBasicSetting{}
if workspaceSetting != nil {
workspaceBasicSetting = workspaceSetting.GetBasicSetting()
}
s.workspaceSettingCache.Set(ctx, storepb.WorkspaceSettingKey_BASIC.String(), &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_BASIC,
Value: &storepb.WorkspaceSetting_BasicSetting{BasicSetting: workspaceBasicSetting},
})
return workspaceBasicSetting, nil
}
func (s *Store) GetWorkspaceGeneralSetting(ctx context.Context) (*storepb.WorkspaceGeneralSetting, error) {
workspaceSetting, err := s.GetWorkspaceSetting(ctx, &FindWorkspaceSetting{
Name: storepb.WorkspaceSettingKey_GENERAL.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace general setting")
}
workspaceGeneralSetting := &storepb.WorkspaceGeneralSetting{}
if workspaceSetting != nil {
workspaceGeneralSetting = workspaceSetting.GetGeneralSetting()
}
s.workspaceSettingCache.Set(ctx, storepb.WorkspaceSettingKey_GENERAL.String(), &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_GENERAL,
Value: &storepb.WorkspaceSetting_GeneralSetting{GeneralSetting: workspaceGeneralSetting},
})
return workspaceGeneralSetting, nil
}
// DefaultContentLengthLimit is the default limit of content length in bytes. 8KB.
const DefaultContentLengthLimit = 8 * 1024
// DefaultReactions is the default reactions for memo related setting.
var DefaultReactions = []string{"👍", "👎", "❤️", "🎉", "😄", "😕", "😢", "😡"}
// DefaultNsfwTags is the default tags that mark content as NSFW for blurring.
var DefaultNsfwTags = []string{"nsfw"}
func (s *Store) GetWorkspaceMemoRelatedSetting(ctx context.Context) (*storepb.WorkspaceMemoRelatedSetting, error) {
workspaceSetting, err := s.GetWorkspaceSetting(ctx, &FindWorkspaceSetting{
Name: storepb.WorkspaceSettingKey_MEMO_RELATED.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace general setting")
}
workspaceMemoRelatedSetting := &storepb.WorkspaceMemoRelatedSetting{}
if workspaceSetting != nil {
workspaceMemoRelatedSetting = workspaceSetting.GetMemoRelatedSetting()
}
if workspaceMemoRelatedSetting.ContentLengthLimit < DefaultContentLengthLimit {
workspaceMemoRelatedSetting.ContentLengthLimit = DefaultContentLengthLimit
}
if len(workspaceMemoRelatedSetting.Reactions) == 0 {
workspaceMemoRelatedSetting.Reactions = append(workspaceMemoRelatedSetting.Reactions, DefaultReactions...)
}
if len(workspaceMemoRelatedSetting.NsfwTags) == 0 {
workspaceMemoRelatedSetting.NsfwTags = append(workspaceMemoRelatedSetting.NsfwTags, DefaultNsfwTags...)
}
s.workspaceSettingCache.Set(ctx, storepb.WorkspaceSettingKey_MEMO_RELATED.String(), &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_MEMO_RELATED,
Value: &storepb.WorkspaceSetting_MemoRelatedSetting{MemoRelatedSetting: workspaceMemoRelatedSetting},
})
return workspaceMemoRelatedSetting, nil
}
const (
defaultWorkspaceStorageType = storepb.WorkspaceStorageSetting_DATABASE
defaultWorkspaceUploadSizeLimitMb = 30
defaultWorkspaceFilepathTemplate = "assets/{timestamp}_{filename}"
)
func (s *Store) GetWorkspaceStorageSetting(ctx context.Context) (*storepb.WorkspaceStorageSetting, error) {
workspaceSetting, err := s.GetWorkspaceSetting(ctx, &FindWorkspaceSetting{
Name: storepb.WorkspaceSettingKey_STORAGE.String(),
})
if err != nil {
return nil, errors.Wrap(err, "failed to get workspace storage setting")
}
workspaceStorageSetting := &storepb.WorkspaceStorageSetting{}
if workspaceSetting != nil {
workspaceStorageSetting = workspaceSetting.GetStorageSetting()
}
if workspaceStorageSetting.StorageType == storepb.WorkspaceStorageSetting_STORAGE_TYPE_UNSPECIFIED {
workspaceStorageSetting.StorageType = defaultWorkspaceStorageType
}
if workspaceStorageSetting.UploadSizeLimitMb == 0 {
workspaceStorageSetting.UploadSizeLimitMb = defaultWorkspaceUploadSizeLimitMb
}
if workspaceStorageSetting.FilepathTemplate == "" {
workspaceStorageSetting.FilepathTemplate = defaultWorkspaceFilepathTemplate
}
s.workspaceSettingCache.Set(ctx, storepb.WorkspaceSettingKey_STORAGE.String(), &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey_STORAGE,
Value: &storepb.WorkspaceSetting_StorageSetting{StorageSetting: workspaceStorageSetting},
})
return workspaceStorageSetting, nil
}
func convertWorkspaceSettingFromRaw(workspaceSettingRaw *WorkspaceSetting) (*storepb.WorkspaceSetting, error) {
workspaceSetting := &storepb.WorkspaceSetting{
Key: storepb.WorkspaceSettingKey(storepb.WorkspaceSettingKey_value[workspaceSettingRaw.Name]),
}
switch workspaceSettingRaw.Name {
case storepb.WorkspaceSettingKey_BASIC.String():
basicSetting := &storepb.WorkspaceBasicSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(workspaceSettingRaw.Value), basicSetting); err != nil {
return nil, err
}
workspaceSetting.Value = &storepb.WorkspaceSetting_BasicSetting{BasicSetting: basicSetting}
case storepb.WorkspaceSettingKey_GENERAL.String():
generalSetting := &storepb.WorkspaceGeneralSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(workspaceSettingRaw.Value), generalSetting); err != nil {
return nil, err
}
workspaceSetting.Value = &storepb.WorkspaceSetting_GeneralSetting{GeneralSetting: generalSetting}
case storepb.WorkspaceSettingKey_STORAGE.String():
storageSetting := &storepb.WorkspaceStorageSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(workspaceSettingRaw.Value), storageSetting); err != nil {
return nil, err
}
workspaceSetting.Value = &storepb.WorkspaceSetting_StorageSetting{StorageSetting: storageSetting}
case storepb.WorkspaceSettingKey_MEMO_RELATED.String():
memoRelatedSetting := &storepb.WorkspaceMemoRelatedSetting{}
if err := protojsonUnmarshaler.Unmarshal([]byte(workspaceSettingRaw.Value), memoRelatedSetting); err != nil {
return nil, err
}
workspaceSetting.Value = &storepb.WorkspaceSetting_MemoRelatedSetting{MemoRelatedSetting: memoRelatedSetting}
default:
// Skip unsupported workspace setting key.
return nil, nil
}
return workspaceSetting, nil
}

View File

@ -3,16 +3,16 @@ import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Outlet } from "react-router-dom";
import useNavigateTo from "./hooks/useNavigateTo";
import { userStore, workspaceStore } from "./store";
import { userStore, instanceStore } from "./store";
import { cleanupExpiredOAuthState } from "./utils/oauth";
import { loadTheme } from "./utils/theme";
const App = observer(() => {
const { i18n } = useTranslation();
const navigateTo = useNavigateTo();
const workspaceProfile = workspaceStore.state.profile;
const instanceProfile = instanceStore.state.profile;
const userGeneralSetting = userStore.state.userGeneralSetting;
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const instanceGeneralSetting = instanceStore.state.generalSetting;
// Clean up expired OAuth states on app initialization
useEffect(() => {
@ -21,41 +21,41 @@ const App = observer(() => {
// Redirect to sign up page if no instance owner.
useEffect(() => {
if (!workspaceProfile.owner) {
if (!instanceProfile.owner) {
navigateTo("/auth/signup");
}
}, [workspaceProfile.owner]);
}, [instanceProfile.owner]);
useEffect(() => {
if (workspaceGeneralSetting.additionalStyle) {
if (instanceGeneralSetting.additionalStyle) {
const styleEl = document.createElement("style");
styleEl.innerHTML = workspaceGeneralSetting.additionalStyle;
styleEl.innerHTML = instanceGeneralSetting.additionalStyle;
styleEl.setAttribute("type", "text/css");
document.body.insertAdjacentElement("beforeend", styleEl);
}
}, [workspaceGeneralSetting.additionalStyle]);
}, [instanceGeneralSetting.additionalStyle]);
useEffect(() => {
if (workspaceGeneralSetting.additionalScript) {
if (instanceGeneralSetting.additionalScript) {
const scriptEl = document.createElement("script");
scriptEl.innerHTML = workspaceGeneralSetting.additionalScript;
scriptEl.innerHTML = instanceGeneralSetting.additionalScript;
document.head.appendChild(scriptEl);
}
}, [workspaceGeneralSetting.additionalScript]);
}, [instanceGeneralSetting.additionalScript]);
// Dynamic update metadata with customized profile.
useEffect(() => {
if (!workspaceGeneralSetting.customProfile) {
if (!instanceGeneralSetting.customProfile) {
return;
}
document.title = workspaceGeneralSetting.customProfile.title;
document.title = instanceGeneralSetting.customProfile.title;
const link = document.querySelector("link[rel~='icon']") as HTMLLinkElement;
link.href = workspaceGeneralSetting.customProfile.logoUrl || "/logo.webp";
}, [workspaceGeneralSetting.customProfile]);
link.href = instanceGeneralSetting.customProfile.logoUrl || "/logo.webp";
}, [instanceGeneralSetting.customProfile]);
useEffect(() => {
const currentLocale = workspaceStore.state.locale;
const currentLocale = instanceStore.state.locale;
// This will trigger re-rendering of the whole app.
i18n.changeLanguage(currentLocale);
document.documentElement.setAttribute("lang", currentLocale);
@ -64,26 +64,26 @@ const App = observer(() => {
} else {
document.documentElement.setAttribute("dir", "ltr");
}
}, [workspaceStore.state.locale]);
}, [instanceStore.state.locale]);
useEffect(() => {
if (!userGeneralSetting) {
return;
}
workspaceStore.state.setPartial({
locale: userGeneralSetting.locale || workspaceStore.state.locale,
theme: userGeneralSetting.theme || workspaceStore.state.theme,
instanceStore.state.setPartial({
locale: userGeneralSetting.locale || instanceStore.state.locale,
theme: userGeneralSetting.theme || instanceStore.state.theme,
});
}, [userGeneralSetting?.locale, userGeneralSetting?.theme]);
// Load theme when workspace theme changes or user setting changes
// Load theme when instance theme changes or user setting changes
useEffect(() => {
const currentTheme = userGeneralSetting?.theme || workspaceStore.state.theme;
const currentTheme = userGeneralSetting?.theme || instanceStore.state.theme;
if (currentTheme) {
loadTheme(currentTheme);
}
}, [userGeneralSetting?.theme, workspaceStore.state.theme]);
}, [userGeneralSetting?.theme, instanceStore.state.theme]);
return <Outlet />;
});

View File

@ -2,7 +2,7 @@ import dayjs from "dayjs";
import { observer } from "mobx-react-lite";
import { memo, useMemo } from "react";
import { TooltipProvider } from "@/components/ui/tooltip";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import type { ActivityCalendarProps } from "@/types/statistics";
import { useTranslate } from "@/utils/i18n";
import { CalendarCell } from "./CalendarCell";
@ -12,7 +12,7 @@ export const ActivityCalendar = memo(
observer((props: ActivityCalendarProps) => {
const t = useTranslate();
const { month, selectedDate, data, onClick } = props;
const weekStartDayOffset = workspaceStore.state.generalSetting.weekStartDayOffset;
const weekStartDayOffset = instanceStore.state.generalSetting.weekStartDayOffset;
const today = useMemo(() => dayjs().format("YYYY-MM-DD"), []);
const selectedDateFormatted = useMemo(() => dayjs(selectedDate).format("YYYY-MM-DD"), [selectedDate]);

View File

@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite";
import { cn } from "@/lib/utils";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import LocaleSelect from "./LocaleSelect";
import ThemeSelect from "./ThemeSelect";
@ -11,8 +11,8 @@ interface Props {
const AuthFooter = observer(({ className }: Props) => {
return (
<div className={cn("mt-4 flex flex-row items-center justify-center w-full gap-2", className)}>
<LocaleSelect value={workspaceStore.state.locale} onChange={(locale) => workspaceStore.state.setPartial({ locale })} />
<ThemeSelect value={workspaceStore.state.theme} onValueChange={(theme) => workspaceStore.state.setPartial({ theme })} />
<LocaleSelect value={instanceStore.state.locale} onChange={(locale) => instanceStore.state.setPartial({ locale })} />
<ThemeSelect value={instanceStore.state.theme} onValueChange={(theme) => instanceStore.state.setPartial({ theme })} />
</div>
);
});

View File

@ -19,7 +19,7 @@ import { useLocation } from "react-router-dom";
import ConfirmDialog from "@/components/ConfirmDialog";
import useNavigateTo from "@/hooks/useNavigateTo";
import { memoStore, userStore } from "@/store";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import { State } from "@/types/proto/api/v1/common";
import { Memo } from "@/types/proto/api/v1/memo_service";
import { useTranslate } from "@/utils/i18n";
@ -119,7 +119,7 @@ const MemoActionMenu = observer((props: Props) => {
};
const handleCopyLink = () => {
let host = workspaceStore.state.profile.instanceUrl;
let host = instanceStore.state.profile.instanceUrl;
if (host === "") {
host = window.location.origin;
}

View File

@ -13,7 +13,7 @@ import { isValidUrl } from "@/helpers/utils";
import useAsyncEffect from "@/hooks/useAsyncEffect";
import useCurrentUser from "@/hooks/useCurrentUser";
import { cn } from "@/lib/utils";
import { memoStore, attachmentStore, userStore, workspaceStore } from "@/store";
import { memoStore, attachmentStore, userStore, instanceStore } from "@/store";
import { extractMemoIdFromName } from "@/store/common";
import { Attachment } from "@/types/proto/api/v1/attachment_service";
import { Location, Memo, MemoRelation, MemoRelation_Type, Visibility } from "@/types/proto/api/v1/memo_service";
@ -81,7 +81,7 @@ const MemoEditor = observer((props: Props) => {
relation.memo?.name === memoName && relation.relatedMemo?.name !== memoName && relation.type === MemoRelation_Type.REFERENCE,
)
: state.relationList.filter((relation) => relation.type === MemoRelation_Type.REFERENCE);
const workspaceMemoRelatedSetting = workspaceStore.state.memoRelatedSetting;
const instanceMemoRelatedSetting = instanceStore.state.memoRelatedSetting;
useEffect(() => {
editorRef.current?.setContent(contentCache || "");
@ -95,7 +95,7 @@ const MemoEditor = observer((props: Props) => {
useAsyncEffect(async () => {
let visibility = convertVisibilityFromString(userGeneralSetting?.memoVisibility || "PRIVATE");
if (workspaceMemoRelatedSetting.disallowPublicVisibility && visibility === Visibility.PUBLIC) {
if (instanceMemoRelatedSetting.disallowPublicVisibility && visibility === Visibility.PUBLIC) {
visibility = Visibility.PROTECTED;
}
if (parentMemoName) {
@ -106,7 +106,7 @@ const MemoEditor = observer((props: Props) => {
...prevState,
memoVisibility: convertVisibilityFromString(visibility),
}));
}, [parentMemoName, userGeneralSetting?.memoVisibility, workspaceMemoRelatedSetting.disallowPublicVisibility]);
}, [parentMemoName, userGeneralSetting?.memoVisibility, instanceMemoRelatedSetting.disallowPublicVisibility]);
useAsyncEffect(async () => {
if (!memoName) {
@ -156,7 +156,7 @@ const MemoEditor = observer((props: Props) => {
handleSaveBtnClick();
return;
}
if (!workspaceMemoRelatedSetting.disableMarkdownShortcuts) {
if (!instanceMemoRelatedSetting.disableMarkdownShortcuts) {
handleEditorKeydownWithMarkdownShortcuts(event, editorRef.current);
}
}

View File

@ -7,7 +7,7 @@ import useAsyncEffect from "@/hooks/useAsyncEffect";
import useCurrentUser from "@/hooks/useCurrentUser";
import useNavigateTo from "@/hooks/useNavigateTo";
import { cn } from "@/lib/utils";
import { memoStore, userStore, workspaceStore } from "@/store";
import { memoStore, userStore, instanceStore } from "@/store";
import { State } from "@/types/proto/api/v1/common";
import { Memo, MemoRelation_Type, Visibility } from "@/types/proto/api/v1/memo_service";
import { useTranslate } from "@/utils/i18n";
@ -52,7 +52,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
urls: [],
index: 0,
});
const workspaceMemoRelatedSetting = workspaceStore.state.memoRelatedSetting;
const instanceMemoRelatedSetting = instanceStore.state.memoRelatedSetting;
const referencedMemos = memo.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE);
const commentAmount = memo.relations.filter(
(relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo?.name === memo.name,
@ -63,8 +63,8 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`);
const parentPage = props.parentPage || location.pathname;
const nsfw =
workspaceMemoRelatedSetting.enableBlurNsfwContent &&
memo.tags?.some((tag) => workspaceMemoRelatedSetting.nsfwTags.some((nsfwTag) => tag === nsfwTag || tag.startsWith(`${nsfwTag}/`)));
instanceMemoRelatedSetting.enableBlurNsfwContent &&
memo.tags?.some((tag) => instanceMemoRelatedSetting.nsfwTags.some((nsfwTag) => tag === nsfwTag || tag.startsWith(`${nsfwTag}/`)));
// Initial related data: creator.
useAsyncEffect(async () => {
@ -103,7 +103,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
return;
}
if (workspaceMemoRelatedSetting.enableDoubleClickEdit) {
if (instanceMemoRelatedSetting.enableDoubleClickEdit) {
e.preventDefault();
setShowEditor(true);
}

View File

@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite";
import { cn } from "@/lib/utils";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import UserAvatar from "./UserAvatar";
interface Props {
@ -10,9 +10,9 @@ interface Props {
const MemosLogo = observer((props: Props) => {
const { collapsed } = props;
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const title = workspaceGeneralSetting.customProfile?.title || "Memos";
const avatarUrl = workspaceGeneralSetting.customProfile?.logoUrl || "/full-logo.webp";
const instanceGeneralSetting = instanceStore.state.generalSetting;
const title = instanceGeneralSetting.customProfile?.title || "Memos";
const avatarUrl = instanceGeneralSetting.customProfile?.logoUrl || "/full-logo.webp";
return (
<div className={cn("relative w-full h-auto shrink-0", props.className)}>

View File

@ -3,16 +3,16 @@ import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import Navigation from "./Navigation";
import UserAvatar from "./UserAvatar";
const NavigationDrawer = observer(() => {
const location = useLocation();
const [open, setOpen] = useState(false);
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const title = workspaceGeneralSetting.customProfile?.title || "Memos";
const avatarUrl = workspaceGeneralSetting.customProfile?.logoUrl || "/full-logo.webp";
const instanceGeneralSetting = instanceStore.state.generalSetting;
const title = instanceGeneralSetting.customProfile?.title || "Memos";
const avatarUrl = instanceGeneralSetting.customProfile?.logoUrl || "/full-logo.webp";
useEffect(() => {
setOpen(false);

View File

@ -8,7 +8,7 @@ import { Input } from "@/components/ui/input";
import { authServiceClient } from "@/grpcweb";
import useLoading from "@/hooks/useLoading";
import useNavigateTo from "@/hooks/useNavigateTo";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import { initialUserStore } from "@/store/user";
import { useTranslate } from "@/utils/i18n";
@ -16,8 +16,8 @@ const PasswordSignInForm = observer(() => {
const t = useTranslate();
const navigateTo = useNavigateTo();
const actionBtnLoadingState = useLoading(false);
const [username, setUsername] = useState(workspaceStore.state.profile.mode === "demo" ? "demo" : "");
const [password, setPassword] = useState(workspaceStore.state.profile.mode === "demo" ? "secret" : "");
const [username, setUsername] = useState(instanceStore.state.profile.mode === "demo" ? "demo" : "");
const [password, setPassword] = useState(instanceStore.state.profile.mode === "demo" ? "secret" : "");
const handleUsernameInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const text = e.target.value as string;

View File

@ -5,7 +5,7 @@ import useClickAway from "react-use/lib/useClickAway";
import { memoServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import { cn } from "@/lib/utils";
import { memoStore, workspaceStore } from "@/store";
import { memoStore, instanceStore } from "@/store";
import { Memo } from "@/types/proto/api/v1/memo_service";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
@ -20,7 +20,7 @@ const ReactionSelector = observer((props: Props) => {
const currentUser = useCurrentUser();
const [open, setOpen] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
const workspaceMemoRelatedSetting = workspaceStore.state.memoRelatedSetting;
const instanceMemoRelatedSetting = instanceStore.state.memoRelatedSetting;
useClickAway(containerRef, () => {
setOpen(false);
@ -76,7 +76,7 @@ const ReactionSelector = observer((props: Props) => {
<PopoverContent align="center" className="max-w-[90vw] sm:max-w-md">
<div ref={containerRef}>
<div className="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-1 max-h-64 overflow-y-auto">
{workspaceMemoRelatedSetting.reactions.map((reactionType) => {
{instanceMemoRelatedSetting.reactions.map((reactionType) => {
return (
<span
key={reactionType}

View File

@ -9,35 +9,35 @@ import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea";
import { identityProviderServiceClient } from "@/grpcweb";
import useDialog from "@/hooks/useDialog";
import { workspaceStore } from "@/store";
import { workspaceSettingNamePrefix } from "@/store/common";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { IdentityProvider } from "@/types/proto/api/v1/idp_service";
import { WorkspaceSetting_GeneralSetting, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
import { InstanceSetting_GeneralSetting, InstanceSetting_Key } from "@/types/proto/api/v1/instance_service";
import { useTranslate } from "@/utils/i18n";
import ThemeSelect from "../ThemeSelect";
import UpdateCustomizedProfileDialog from "../UpdateCustomizedProfileDialog";
const WorkspaceSection = observer(() => {
const InstanceSection = observer(() => {
const t = useTranslate();
const customizeDialog = useDialog();
const originalSetting = WorkspaceSetting_GeneralSetting.fromPartial(
workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.GENERAL)?.generalSetting || {},
const originalSetting = InstanceSetting_GeneralSetting.fromPartial(
instanceStore.getInstanceSettingByKey(InstanceSetting_Key.GENERAL)?.generalSetting || {},
);
const [workspaceGeneralSetting, setWorkspaceGeneralSetting] = useState<WorkspaceSetting_GeneralSetting>(originalSetting);
const [instanceGeneralSetting, setInstanceGeneralSetting] = useState<InstanceSetting_GeneralSetting>(originalSetting);
const [identityProviderList, setIdentityProviderList] = useState<IdentityProvider[]>([]);
useEffect(() => {
setWorkspaceGeneralSetting({ ...workspaceGeneralSetting, customProfile: originalSetting.customProfile });
}, [workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.GENERAL)]);
setInstanceGeneralSetting({ ...instanceGeneralSetting, customProfile: originalSetting.customProfile });
}, [instanceStore.getInstanceSettingByKey(InstanceSetting_Key.GENERAL)]);
const handleUpdateCustomizedProfileButtonClick = () => {
customizeDialog.open();
};
const updatePartialSetting = (partial: Partial<WorkspaceSetting_GeneralSetting>) => {
setWorkspaceGeneralSetting(
WorkspaceSetting_GeneralSetting.fromPartial({
...workspaceGeneralSetting,
const updatePartialSetting = (partial: Partial<InstanceSetting_GeneralSetting>) => {
setInstanceGeneralSetting(
InstanceSetting_GeneralSetting.fromPartial({
...instanceGeneralSetting,
...partial,
}),
);
@ -45,9 +45,9 @@ const WorkspaceSection = observer(() => {
const handleSaveGeneralSetting = async () => {
try {
await workspaceStore.upsertWorkspaceSetting({
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.GENERAL}`,
generalSetting: workspaceGeneralSetting,
await instanceStore.upsertInstanceSetting({
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.GENERAL}`,
generalSetting: instanceGeneralSetting,
});
} catch (error: any) {
toast.error(error.details);
@ -72,7 +72,7 @@ const WorkspaceSection = observer(() => {
<div className="w-full flex flex-row justify-between items-center">
<div>
{t("setting.system-section.server-name")}:{" "}
<span className="font-mono font-bold">{workspaceGeneralSetting.customProfile?.title || "Memos"}</span>
<span className="font-mono font-bold">{instanceGeneralSetting.customProfile?.title || "Memos"}</span>
</div>
<Button variant="outline" onClick={handleUpdateCustomizedProfileButtonClick}>
{t("common.edit")}
@ -83,7 +83,7 @@ const WorkspaceSection = observer(() => {
<div className="w-full flex flex-row justify-between items-center">
<span>Theme</span>
<ThemeSelect
value={workspaceGeneralSetting.theme || "default"}
value={instanceGeneralSetting.theme || "default"}
onValueChange={(value: string) => updatePartialSetting({ theme: value })}
className="min-w-fit"
/>
@ -95,7 +95,7 @@ const WorkspaceSection = observer(() => {
className="font-mono w-full"
rows={3}
placeholder={t("setting.system-section.additional-style-placeholder")}
value={workspaceGeneralSetting.additionalStyle}
value={instanceGeneralSetting.additionalStyle}
onChange={(event) => updatePartialSetting({ additionalStyle: event.target.value })}
/>
<div className="w-full flex flex-row justify-between items-center">
@ -105,46 +105,46 @@ const WorkspaceSection = observer(() => {
className="font-mono w-full"
rows={3}
placeholder={t("setting.system-section.additional-script-placeholder")}
value={workspaceGeneralSetting.additionalScript}
value={instanceGeneralSetting.additionalScript}
onChange={(event) => updatePartialSetting({ additionalScript: event.target.value })}
/>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.workspace-section.disallow-user-registration")}</span>
<span>{t("setting.instance-section.disallow-user-registration")}</span>
<Switch
disabled={workspaceStore.state.profile.mode === "demo"}
checked={workspaceGeneralSetting.disallowUserRegistration}
disabled={instanceStore.state.profile.mode === "demo"}
checked={instanceGeneralSetting.disallowUserRegistration}
onCheckedChange={(checked) => updatePartialSetting({ disallowUserRegistration: checked })}
/>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.workspace-section.disallow-password-auth")}</span>
<span>{t("setting.instance-section.disallow-password-auth")}</span>
<Switch
disabled={
workspaceStore.state.profile.mode === "demo" ||
(identityProviderList.length === 0 && !workspaceGeneralSetting.disallowPasswordAuth)
instanceStore.state.profile.mode === "demo" ||
(identityProviderList.length === 0 && !instanceGeneralSetting.disallowPasswordAuth)
}
checked={workspaceGeneralSetting.disallowPasswordAuth}
checked={instanceGeneralSetting.disallowPasswordAuth}
onCheckedChange={(checked) => updatePartialSetting({ disallowPasswordAuth: checked })}
/>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.workspace-section.disallow-change-username")}</span>
<span>{t("setting.instance-section.disallow-change-username")}</span>
<Switch
checked={workspaceGeneralSetting.disallowChangeUsername}
checked={instanceGeneralSetting.disallowChangeUsername}
onCheckedChange={(checked) => updatePartialSetting({ disallowChangeUsername: checked })}
/>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span>{t("setting.workspace-section.disallow-change-nickname")}</span>
<span>{t("setting.instance-section.disallow-change-nickname")}</span>
<Switch
checked={workspaceGeneralSetting.disallowChangeNickname}
checked={instanceGeneralSetting.disallowChangeNickname}
onCheckedChange={(checked) => updatePartialSetting({ disallowChangeNickname: checked })}
/>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="truncate">{t("setting.workspace-section.week-start-day")}</span>
<span className="truncate">{t("setting.instance-section.week-start-day")}</span>
<Select
value={workspaceGeneralSetting.weekStartDayOffset.toString()}
value={instanceGeneralSetting.weekStartDayOffset.toString()}
onValueChange={(value) => {
updatePartialSetting({ weekStartDayOffset: parseInt(value) || 0 });
}}
@ -153,14 +153,14 @@ const WorkspaceSection = observer(() => {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="-1">{t("setting.workspace-section.saturday")}</SelectItem>
<SelectItem value="0">{t("setting.workspace-section.sunday")}</SelectItem>
<SelectItem value="1">{t("setting.workspace-section.monday")}</SelectItem>
<SelectItem value="-1">{t("setting.instance-section.saturday")}</SelectItem>
<SelectItem value="0">{t("setting.instance-section.sunday")}</SelectItem>
<SelectItem value="1">{t("setting.instance-section.monday")}</SelectItem>
</SelectContent>
</Select>
</div>
<div className="mt-2 w-full flex justify-end">
<Button disabled={isEqual(workspaceGeneralSetting, originalSetting)} onClick={handleSaveGeneralSetting}>
<Button disabled={isEqual(instanceGeneralSetting, originalSetting)} onClick={handleSaveGeneralSetting}>
{t("common.save")}
</Button>
</div>
@ -169,7 +169,7 @@ const WorkspaceSection = observer(() => {
open={customizeDialog.isOpen}
onOpenChange={customizeDialog.setOpen}
onSuccess={() => {
// Refresh workspace settings if needed
// Refresh instance settings if needed
toast.success("Profile updated successfully!");
}}
/>
@ -177,4 +177,4 @@ const WorkspaceSection = observer(() => {
);
});
export default WorkspaceSection;
export default InstanceSection;

View File

@ -7,24 +7,24 @@ import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { workspaceStore } from "@/store";
import { workspaceSettingNamePrefix } from "@/store/common";
import { WorkspaceSetting_MemoRelatedSetting, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { InstanceSetting_MemoRelatedSetting, InstanceSetting_Key } from "@/types/proto/api/v1/instance_service";
import { useTranslate } from "@/utils/i18n";
const MemoRelatedSettings = observer(() => {
const t = useTranslate();
const [originalSetting, setOriginalSetting] = useState<WorkspaceSetting_MemoRelatedSetting>(workspaceStore.state.memoRelatedSetting);
const [memoRelatedSetting, setMemoRelatedSetting] = useState<WorkspaceSetting_MemoRelatedSetting>(originalSetting);
const [originalSetting, setOriginalSetting] = useState<InstanceSetting_MemoRelatedSetting>(instanceStore.state.memoRelatedSetting);
const [memoRelatedSetting, setMemoRelatedSetting] = useState<InstanceSetting_MemoRelatedSetting>(originalSetting);
const [editingReaction, setEditingReaction] = useState<string>("");
const [editingNsfwTag, setEditingNsfwTag] = useState<string>("");
const updatePartialSetting = (partial: Partial<WorkspaceSetting_MemoRelatedSetting>) => {
const newWorkspaceMemoRelatedSetting = WorkspaceSetting_MemoRelatedSetting.fromPartial({
const updatePartialSetting = (partial: Partial<InstanceSetting_MemoRelatedSetting>) => {
const newInstanceMemoRelatedSetting = InstanceSetting_MemoRelatedSetting.fromPartial({
...memoRelatedSetting,
...partial,
});
setMemoRelatedSetting(newWorkspaceMemoRelatedSetting);
setMemoRelatedSetting(newInstanceMemoRelatedSetting);
};
const upsertReaction = () => {
@ -52,8 +52,8 @@ const MemoRelatedSettings = observer(() => {
}
try {
await workspaceStore.upsertWorkspaceSetting({
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.MEMO_RELATED}`,
await instanceStore.upsertInstanceSetting({
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.MEMO_RELATED}`,
memoRelatedSetting,
});
setOriginalSetting(memoRelatedSetting);

View File

@ -1,7 +1,7 @@
import { observer } from "mobx-react-lite";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import { userStore, workspaceStore } from "@/store";
import { userStore, instanceStore } from "@/store";
import { Visibility } from "@/types/proto/api/v1/memo_service";
import { UserSetting_GeneralSetting } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
@ -16,8 +16,8 @@ const PreferencesSection = observer(() => {
const generalSetting = userStore.state.userGeneralSetting;
const handleLocaleSelectChange = async (locale: Locale) => {
// Update workspace store immediately for instant UI feedback
workspaceStore.state.setPartial({ locale });
// Update instance store immediately for instant UI feedback
instanceStore.state.setPartial({ locale });
// Persist to user settings
await userStore.updateUserGeneralSetting({ locale }, ["locale"]);
};

View File

@ -9,87 +9,83 @@ import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Switch } from "@/components/ui/switch";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { workspaceStore } from "@/store";
import { workspaceSettingNamePrefix } from "@/store/common";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import {
WorkspaceSetting_Key,
WorkspaceSetting_StorageSetting,
WorkspaceSetting_StorageSetting_S3Config,
WorkspaceSetting_StorageSetting_StorageType,
} from "@/types/proto/api/v1/workspace_service";
InstanceSetting_Key,
InstanceSetting_StorageSetting,
InstanceSetting_StorageSetting_S3Config,
InstanceSetting_StorageSetting_StorageType,
} from "@/types/proto/api/v1/instance_service";
import { useTranslate } from "@/utils/i18n";
const StorageSection = observer(() => {
const t = useTranslate();
const [workspaceStorageSetting, setWorkspaceStorageSetting] = useState<WorkspaceSetting_StorageSetting>(
WorkspaceSetting_StorageSetting.fromPartial(
workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.STORAGE)?.storageSetting || {},
),
const [instanceStorageSetting, setInstanceStorageSetting] = useState<InstanceSetting_StorageSetting>(
InstanceSetting_StorageSetting.fromPartial(instanceStore.getInstanceSettingByKey(InstanceSetting_Key.STORAGE)?.storageSetting || {}),
);
useEffect(() => {
setWorkspaceStorageSetting(
WorkspaceSetting_StorageSetting.fromPartial(
workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.STORAGE)?.storageSetting || {},
),
setInstanceStorageSetting(
InstanceSetting_StorageSetting.fromPartial(instanceStore.getInstanceSettingByKey(InstanceSetting_Key.STORAGE)?.storageSetting || {}),
);
}, [workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.STORAGE)]);
}, [instanceStore.getInstanceSettingByKey(InstanceSetting_Key.STORAGE)]);
const allowSaveStorageSetting = useMemo(() => {
if (workspaceStorageSetting.uploadSizeLimitMb <= 0) {
if (instanceStorageSetting.uploadSizeLimitMb <= 0) {
return false;
}
const origin = WorkspaceSetting_StorageSetting.fromPartial(
workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.STORAGE)?.storageSetting || {},
const origin = InstanceSetting_StorageSetting.fromPartial(
instanceStore.getInstanceSettingByKey(InstanceSetting_Key.STORAGE)?.storageSetting || {},
);
if (workspaceStorageSetting.storageType === WorkspaceSetting_StorageSetting_StorageType.LOCAL) {
if (workspaceStorageSetting.filepathTemplate.length === 0) {
if (instanceStorageSetting.storageType === InstanceSetting_StorageSetting_StorageType.LOCAL) {
if (instanceStorageSetting.filepathTemplate.length === 0) {
return false;
}
} else if (workspaceStorageSetting.storageType === WorkspaceSetting_StorageSetting_StorageType.S3) {
} else if (instanceStorageSetting.storageType === InstanceSetting_StorageSetting_StorageType.S3) {
if (
workspaceStorageSetting.s3Config?.accessKeyId.length === 0 ||
workspaceStorageSetting.s3Config?.accessKeySecret.length === 0 ||
workspaceStorageSetting.s3Config?.endpoint.length === 0 ||
workspaceStorageSetting.s3Config?.region.length === 0 ||
workspaceStorageSetting.s3Config?.bucket.length === 0
instanceStorageSetting.s3Config?.accessKeyId.length === 0 ||
instanceStorageSetting.s3Config?.accessKeySecret.length === 0 ||
instanceStorageSetting.s3Config?.endpoint.length === 0 ||
instanceStorageSetting.s3Config?.region.length === 0 ||
instanceStorageSetting.s3Config?.bucket.length === 0
) {
return false;
}
}
return !isEqual(origin, workspaceStorageSetting);
}, [workspaceStorageSetting, workspaceStore.state]);
return !isEqual(origin, instanceStorageSetting);
}, [instanceStorageSetting, instanceStore.state]);
const handleMaxUploadSizeChanged = async (event: React.FocusEvent<HTMLInputElement>) => {
let num = parseInt(event.target.value);
if (Number.isNaN(num)) {
num = 0;
}
const update: WorkspaceSetting_StorageSetting = {
...workspaceStorageSetting,
const update: InstanceSetting_StorageSetting = {
...instanceStorageSetting,
uploadSizeLimitMb: num,
};
setWorkspaceStorageSetting(update);
setInstanceStorageSetting(update);
};
const handleFilepathTemplateChanged = async (event: React.FocusEvent<HTMLInputElement>) => {
const update: WorkspaceSetting_StorageSetting = {
...workspaceStorageSetting,
const update: InstanceSetting_StorageSetting = {
...instanceStorageSetting,
filepathTemplate: event.target.value,
};
setWorkspaceStorageSetting(update);
setInstanceStorageSetting(update);
};
const handlePartialS3ConfigChanged = async (s3Config: Partial<WorkspaceSetting_StorageSetting_S3Config>) => {
const update: WorkspaceSetting_StorageSetting = {
...workspaceStorageSetting,
s3Config: WorkspaceSetting_StorageSetting_S3Config.fromPartial({
...workspaceStorageSetting.s3Config,
const handlePartialS3ConfigChanged = async (s3Config: Partial<InstanceSetting_StorageSetting_S3Config>) => {
const update: InstanceSetting_StorageSetting = {
...instanceStorageSetting,
s3Config: InstanceSetting_StorageSetting_S3Config.fromPartial({
...instanceStorageSetting.s3Config,
...s3Config,
}),
};
setWorkspaceStorageSetting(update);
setInstanceStorageSetting(update);
};
const handleS3ConfigAccessKeyIdChanged = async (event: React.FocusEvent<HTMLInputElement>) => {
@ -118,18 +114,18 @@ const StorageSection = observer(() => {
});
};
const handleStorageTypeChanged = async (storageType: WorkspaceSetting_StorageSetting_StorageType) => {
const update: WorkspaceSetting_StorageSetting = {
...workspaceStorageSetting,
const handleStorageTypeChanged = async (storageType: InstanceSetting_StorageSetting_StorageType) => {
const update: InstanceSetting_StorageSetting = {
...instanceStorageSetting,
storageType: storageType,
};
setWorkspaceStorageSetting(update);
setInstanceStorageSetting(update);
};
const saveWorkspaceStorageSetting = async () => {
await workspaceStore.upsertWorkspaceSetting({
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.STORAGE}`,
storageSetting: workspaceStorageSetting,
const saveInstanceStorageSetting = async () => {
await instanceStore.upsertInstanceSetting({
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.STORAGE}`,
storageSetting: instanceStorageSetting,
});
toast.success("Updated");
};
@ -138,22 +134,22 @@ const StorageSection = observer(() => {
<div className="w-full flex flex-col gap-2 pt-2 pb-4">
<div className="font-medium text-muted-foreground">{t("setting.storage-section.current-storage")}</div>
<RadioGroup
value={workspaceStorageSetting.storageType}
value={instanceStorageSetting.storageType}
onValueChange={(value) => {
handleStorageTypeChanged(value as WorkspaceSetting_StorageSetting_StorageType);
handleStorageTypeChanged(value as InstanceSetting_StorageSetting_StorageType);
}}
className="flex flex-row gap-4"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value={WorkspaceSetting_StorageSetting_StorageType.DATABASE} id="database" />
<RadioGroupItem value={InstanceSetting_StorageSetting_StorageType.DATABASE} id="database" />
<Label htmlFor="database">{t("setting.storage-section.type-database")}</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value={WorkspaceSetting_StorageSetting_StorageType.LOCAL} id="local" />
<RadioGroupItem value={InstanceSetting_StorageSetting_StorageType.LOCAL} id="local" />
<Label htmlFor="local">{t("setting.storage-section.type-local")}</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value={WorkspaceSetting_StorageSetting_StorageType.S3} id="s3" />
<RadioGroupItem value={InstanceSetting_StorageSetting_StorageType.S3} id="s3" />
<Label htmlFor="s3">S3</Label>
</div>
</RadioGroup>
@ -171,26 +167,26 @@ const StorageSection = observer(() => {
</Tooltip>
</TooltipProvider>
</div>
<Input className="w-16 font-mono" value={workspaceStorageSetting.uploadSizeLimitMb} onChange={handleMaxUploadSizeChanged} />
<Input className="w-16 font-mono" value={instanceStorageSetting.uploadSizeLimitMb} onChange={handleMaxUploadSizeChanged} />
</div>
{workspaceStorageSetting.storageType !== WorkspaceSetting_StorageSetting_StorageType.DATABASE && (
{instanceStorageSetting.storageType !== InstanceSetting_StorageSetting_StorageType.DATABASE && (
<div className="w-full flex flex-row justify-between items-center">
<span className="text-muted-foreground mr-1">{t("setting.storage-section.filepath-template")}</span>
<Input
className="w-64"
value={workspaceStorageSetting.filepathTemplate}
value={instanceStorageSetting.filepathTemplate}
placeholder="assets/{timestamp}_{filename}"
onChange={handleFilepathTemplateChanged}
/>
</div>
)}
{workspaceStorageSetting.storageType === WorkspaceSetting_StorageSetting_StorageType.S3 && (
{instanceStorageSetting.storageType === InstanceSetting_StorageSetting_StorageType.S3 && (
<>
<div className="w-full flex flex-row justify-between items-center">
<span className="text-muted-foreground mr-1">Access key id</span>
<Input
className="w-64"
value={workspaceStorageSetting.s3Config?.accessKeyId}
value={instanceStorageSetting.s3Config?.accessKeyId}
placeholder=""
onChange={handleS3ConfigAccessKeyIdChanged}
/>
@ -199,7 +195,7 @@ const StorageSection = observer(() => {
<span className="text-muted-foreground mr-1">Access key secret</span>
<Input
className="w-64"
value={workspaceStorageSetting.s3Config?.accessKeySecret}
value={instanceStorageSetting.s3Config?.accessKeySecret}
placeholder=""
onChange={handleS3ConfigAccessKeySecretChanged}
/>
@ -208,40 +204,30 @@ const StorageSection = observer(() => {
<span className="text-muted-foreground mr-1">Endpoint</span>
<Input
className="w-64"
value={workspaceStorageSetting.s3Config?.endpoint}
value={instanceStorageSetting.s3Config?.endpoint}
placeholder=""
onChange={handleS3ConfigEndpointChanged}
/>
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="text-muted-foreground mr-1">Region</span>
<Input
className="w-64"
value={workspaceStorageSetting.s3Config?.region}
placeholder=""
onChange={handleS3ConfigRegionChanged}
/>
<Input className="w-64" value={instanceStorageSetting.s3Config?.region} placeholder="" onChange={handleS3ConfigRegionChanged} />
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="text-muted-foreground mr-1">Bucket</span>
<Input
className="w-64"
value={workspaceStorageSetting.s3Config?.bucket}
placeholder=""
onChange={handleS3ConfigBucketChanged}
/>
<Input className="w-64" value={instanceStorageSetting.s3Config?.bucket} placeholder="" onChange={handleS3ConfigBucketChanged} />
</div>
<div className="w-full flex flex-row justify-between items-center">
<span className="text-muted-foreground mr-1">Use Path Style</span>
<Switch
checked={workspaceStorageSetting.s3Config?.usePathStyle}
checked={instanceStorageSetting.s3Config?.usePathStyle}
onCheckedChange={(checked) => handleS3ConfigUsePathStyleChanged({ target: { checked } } as any)}
/>
</div>
</>
)}
<div>
<Button disabled={!allowSaveStorageSetting} onClick={saveWorkspaceStorageSetting}>
<Button disabled={!allowSaveStorageSetting} onClick={saveInstanceStorageSetting}>
{t("common.save")}
</Button>
</div>

View File

@ -1,6 +1,6 @@
import { Moon, Palette, Sun, Wallpaper } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import { THEME_OPTIONS } from "@/utils/theme";
interface ThemeSelectProps {
@ -17,13 +17,13 @@ const THEME_ICONS: Record<string, JSX.Element> = {
};
const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {}) => {
const currentTheme = value || workspaceStore.state.theme || "default";
const currentTheme = value || instanceStore.state.theme || "default";
const handleThemeChange = (newTheme: Theme) => {
if (onValueChange) {
onValueChange(newTheme);
} else {
workspaceStore.setTheme(newTheme);
instanceStore.setTheme(newTheme);
}
};

View File

@ -9,7 +9,7 @@ import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { convertFileToBase64 } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser";
import { userStore, workspaceStore } from "@/store";
import { userStore, instanceStore } from "@/store";
import { User as UserPb } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n";
import UserAvatar from "./UserAvatar";
@ -38,7 +38,7 @@ function UpdateAccountDialog({ open, onOpenChange, onSuccess }: Props) {
email: currentUser.email,
description: currentUser.description,
});
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const instanceGeneralSetting = instanceStore.state.generalSetting;
const handleCloseBtnClick = () => {
onOpenChange(false);
@ -179,7 +179,7 @@ function UpdateAccountDialog({ open, onOpenChange, onSuccess }: Props) {
id="username"
value={state.username}
onChange={handleUsernameChanged}
disabled={workspaceGeneralSetting.disallowChangeUsername}
disabled={instanceGeneralSetting.disallowChangeUsername}
/>
</div>
<div className="grid gap-2">
@ -191,7 +191,7 @@ function UpdateAccountDialog({ open, onOpenChange, onSuccess }: Props) {
id="displayName"
value={state.displayName}
onChange={handleDisplayNameChanged}
disabled={workspaceGeneralSetting.disallowChangeNickname}
disabled={instanceGeneralSetting.disallowChangeNickname}
/>
</div>
<div className="grid gap-2">

View File

@ -5,9 +5,9 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { workspaceStore } from "@/store";
import { workspaceSettingNamePrefix } from "@/store/common";
import { WorkspaceSetting_GeneralSetting_CustomProfile, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
import { instanceStore } from "@/store";
import { instanceSettingNamePrefix } from "@/store/common";
import { InstanceSetting_GeneralSetting_CustomProfile, InstanceSetting_Key } from "@/types/proto/api/v1/instance_service";
import { useTranslate } from "@/utils/i18n";
import LocaleSelect from "./LocaleSelect";
import ThemeSelect from "./ThemeSelect";
@ -20,14 +20,14 @@ interface Props {
function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props) {
const t = useTranslate();
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const [customProfile, setCustomProfile] = useState<WorkspaceSetting_GeneralSetting_CustomProfile>(
WorkspaceSetting_GeneralSetting_CustomProfile.fromPartial(workspaceGeneralSetting.customProfile || {}),
const instanceGeneralSetting = instanceStore.state.generalSetting;
const [customProfile, setCustomProfile] = useState<InstanceSetting_GeneralSetting_CustomProfile>(
InstanceSetting_GeneralSetting_CustomProfile.fromPartial(instanceGeneralSetting.customProfile || {}),
);
const [isLoading, setIsLoading] = useState(false);
const setPartialState = (partialState: Partial<WorkspaceSetting_GeneralSetting_CustomProfile>) => {
const setPartialState = (partialState: Partial<InstanceSetting_GeneralSetting_CustomProfile>) => {
setCustomProfile((state) => ({
...state,
...partialState,
@ -79,10 +79,10 @@ function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props)
setIsLoading(true);
try {
await workspaceStore.upsertWorkspaceSetting({
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.GENERAL}`,
await instanceStore.upsertInstanceSetting({
name: `${instanceSettingNamePrefix}${InstanceSetting_Key.GENERAL}`,
generalSetting: {
...workspaceGeneralSetting,
...instanceGeneralSetting,
customProfile: customProfile,
},
});
@ -102,7 +102,7 @@ function UpdateCustomizedProfileDialog({ open, onOpenChange, onSuccess }: Props)
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>{t("setting.system-section.customize-server.title")}</DialogTitle>
<DialogDescription>Customize your workspace appearance and settings.</DialogDescription>
<DialogDescription>Customize your instance appearance and settings.</DialogDescription>
</DialogHeader>
<div className="grid gap-4">

View File

@ -6,7 +6,7 @@ import useNavigateTo from "@/hooks/useNavigateTo";
import { locales } from "@/i18n";
import { cn } from "@/lib/utils";
import { Routes } from "@/router";
import { userStore, workspaceStore } from "@/store";
import { userStore, instanceStore } from "@/store";
import { getLocaleDisplayName, useTranslate } from "@/utils/i18n";
import { THEME_OPTIONS } from "@/utils/theme";
import UserAvatar from "./UserAvatar";
@ -34,8 +34,8 @@ const UserMenu = observer((props: Props) => {
const currentTheme = generalSetting?.theme || "default";
const handleLocaleChange = async (locale: Locale) => {
// Update workspace store immediately for instant UI feedback
workspaceStore.state.setPartial({ locale });
// Update instance store immediately for instant UI feedback
instanceStore.state.setPartial({ locale });
// Persist to user settings
await userStore.updateUserGeneralSetting({ locale }, ["locale"]);
};

View File

@ -3,10 +3,10 @@ import { ActivityServiceDefinition } from "./types/proto/api/v1/activity_service
import { AttachmentServiceDefinition } from "./types/proto/api/v1/attachment_service";
import { AuthServiceDefinition } from "./types/proto/api/v1/auth_service";
import { IdentityProviderServiceDefinition } from "./types/proto/api/v1/idp_service";
import { InstanceServiceDefinition } from "./types/proto/api/v1/instance_service";
import { MemoServiceDefinition } from "./types/proto/api/v1/memo_service";
import { ShortcutServiceDefinition } from "./types/proto/api/v1/shortcut_service";
import { UserServiceDefinition } from "./types/proto/api/v1/user_service";
import { WorkspaceServiceDefinition } from "./types/proto/api/v1/workspace_service";
const channel = createChannel(
window.location.origin,
@ -17,7 +17,7 @@ const channel = createChannel(
const clientFactory = createClientFactory();
export const workspaceServiceClient = clientFactory.create(WorkspaceServiceDefinition, channel);
export const instanceServiceClient = clientFactory.create(InstanceServiceDefinition, channel);
export const authServiceClient = clientFactory.create(AuthServiceDefinition, channel);

View File

@ -1,9 +1,9 @@
import { useMemo } from "react";
import { userStore, workspaceStore } from "@/store";
import { userStore, instanceStore } from "@/store";
import { extractUserIdFromName } from "@/store/common";
import memoFilterStore from "@/store/memoFilter";
import { InstanceSetting_Key } from "@/types/proto/api/v1/instance_service";
import { Visibility } from "@/types/proto/api/v1/memo_service";
import { WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
// Helper function to extract shortcut ID from resource name
// Format: users/{user}/shortcuts/{shortcut}
@ -121,8 +121,8 @@ export const useMemoFilters = (options: UseMemoFiltersOptions = {}): string | un
} else if (filter.factor === "property.hasCode") {
conditions.push(`has_code`);
} else if (filter.factor === "displayTime") {
// Check workspace setting for display time factor
const displayWithUpdateTime = workspaceStore.getWorkspaceSettingByKey(WorkspaceSetting_Key.MEMO_RELATED).memoRelatedSetting
// Check instance setting for display time factor
const displayWithUpdateTime = instanceStore.getInstanceSettingByKey(InstanceSetting_Key.MEMO_RELATED).memoRelatedSetting
?.displayWithUpdateTime;
const factor = displayWithUpdateTime ? "updated_ts" : "created_ts";

View File

@ -8,7 +8,7 @@ import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { cn } from "@/lib/utils";
import Loading from "@/pages/Loading";
import { Routes } from "@/router";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import memoFilterStore from "@/store/memoFilter";
const RootLayout = observer(() => {
@ -23,7 +23,7 @@ const RootLayout = observer(() => {
useEffect(() => {
if (!currentUser) {
// If disallowPublicVisibility is enabled, redirect to the login page if the user is not logged in.
if (workspaceStore.state.memoRelatedSetting.disallowPublicVisibility) {
if (instanceStore.state.memoRelatedSetting.disallowPublicVisibility) {
window.location.href = Routes.AUTH;
return;
} else if (

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "الرابط"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "عدم السماح بتغيير الاسم المستعار",
"disallow-change-username": "عدم السماح بتغيير اسم المستخدم",
"disallow-password-auth": "عدم السماح بالمصادقة بكلمة المرور",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "No permetis canviar el sobrenom",
"disallow-change-username": "No permetis canviar el nom d'usuari",
"disallow-password-auth": "No permetis autenticació per contrasenya",

View File

@ -393,7 +393,7 @@
"title": "Webhooky",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Zakázat změnu přezdívky",
"disallow-change-username": "Zakázat změnu uživatelského jména",
"disallow-password-auth": "Zakázat ověřování heslem",

View File

@ -395,7 +395,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Ändern des Spitznamens verbieten",
"disallow-change-username": "Ändern des Benutzernamens verbieten",
"disallow-password-auth": "Passwort-Authentifizierung verbieten",

View File

@ -441,7 +441,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Disallow changing nickname",
"disallow-change-username": "Disallow changing username",
"disallow-password-auth": "Disallow password auth",

View File

@ -406,7 +406,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "No permitir cambiar apodo",
"disallow-change-username": "No permitir cambiar nombre de usuario",
"disallow-password-auth": "No permitir autenticación por contraseña",

View File

@ -385,7 +385,7 @@
"title": "وب‌هوک‌ها",
"url": "آدرس"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "غیرفعال‌سازی تغییر نام مستعار",
"disallow-change-username": "غیرفعال‌سازی تغییر نام کاربری",
"disallow-password-auth": "غیرفعال‌سازی احراز هویت با گذرواژه",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Interdire le changement de surnom",
"disallow-change-username": "Interdire le changement de nom d'utilisateur",
"disallow-password-auth": "Interdire l'authentification par mot de passe",

View File

@ -411,7 +411,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "उपनाम बदलने की अनुमति न दें",
"disallow-change-username": "उपयोगकर्ता नाम बदलने की अनुमति न दें",
"disallow-password-auth": "पासवर्ड प्रमाणीकरण की अनुमति न दें",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Onemogući promjenu nadimka",
"disallow-change-username": "Onemogući promjenu korisničkog imena",
"disallow-password-auth": "Onemogući autentikaciju lozinkom",

View File

@ -409,7 +409,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Becenév módosításának tiltása",
"disallow-change-username": "Felhasználónév módosításának tiltása",
"disallow-password-auth": "Jelszavas hitelesítés tiltása",

View File

@ -410,7 +410,7 @@
"title": "Webhook",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Larangan mengubah nama panggilan",
"disallow-change-username": "Larangan mengubah nama pengguna",
"disallow-password-auth": "Larangan autentikasi kata sandi",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Non consentire cambio nickname",
"disallow-change-username": "Non consentire cambio nome utente",
"disallow-password-auth": "Non consentire autenticazione password",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "ニックネーム変更を禁止",
"disallow-change-username": "ユーザー名変更を禁止",
"disallow-password-auth": "パスワード認証を禁止",

View File

@ -410,7 +410,7 @@
"title": "Webhook-ები",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "მეტსახელის შეცვლის აკრძალვა",
"disallow-change-username": "მომხმარებლის სახელის შეცვლის აკრძალვა",
"disallow-password-auth": "პაროლით ავთენტიკაციის აკრძალვა",

View File

@ -410,7 +410,7 @@
"title": "Webhook",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "닉네임 변경 금지",
"disallow-change-username": "유저네임 변경 금지",
"disallow-password-auth": "비밀번호 인증 금지",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "टोपणनाव बदलण्यास मनाई करा",
"disallow-change-username": "वापरकर्तानाव बदलण्यास मनाई करा",
"disallow-password-auth": "पासवर्ड प्रमाणीकरणास मनाई करा",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Ikke tillat endring av kallenavn",
"disallow-change-username": "Ikke tillat endring av brukernavn",
"disallow-password-auth": "Ikke tillat autentisering med passord",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Wijzigen van bijnaam niet toestaan",
"disallow-change-username": "Wijzigen van gebruikersnaam niet toestaan",
"disallow-password-auth": "Wachtwoordauthenticatie niet toestaan",

View File

@ -410,7 +410,7 @@
"title": "Webhooki",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Zabroń zmiany pseudonimu",
"disallow-change-username": "Zabroń zmiany nazwy użytkownika",
"disallow-password-auth": "Zabroń uwierzytelniania hasłem",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Impedir troca de apelido",
"disallow-change-username": "Impedir troca de nome de usuário",
"disallow-password-auth": "Impedir autenticação por senha",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Desativar alteração de apelido",
"disallow-change-username": "Desativar alteração de nome de utilizador",
"disallow-password-auth": "Desativar autenticação por palavra-passe",

View File

@ -376,7 +376,7 @@
"title": "Вебхуки",
"url": "Ссылка"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Запретить смену псевдонима",
"disallow-change-username": "Запретить смену имени пользователя",
"disallow-password-auth": "Запретить вход по паролю",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Onemogoči spremembo vzdevka",
"disallow-change-username": "Onemogoči spremembo uporabniškega imena",
"disallow-password-auth": "Onemogoči preverjanje gesla",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Förbjud ändring av smeknamn",
"disallow-change-username": "Förbjud ändring av användarnamn",
"disallow-password-auth": "Förbjud lösenordsautentisering",

View File

@ -410,7 +410,7 @@
"title": "Webhooks",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "ไม่อนุญาตให้เปลี่ยนชื่อเล่น",
"disallow-change-username": "ไม่อนุญาตให้เปลี่ยนชื่อผู้ใช้",
"disallow-password-auth": "ไม่อนุญาตให้ยืนยันตัวตนด้วยรหัสผ่าน",

View File

@ -410,7 +410,7 @@
"title": "Webhook'lar",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Takma ad değiştirmeyi yasakla",
"disallow-change-username": "Kullanıcı adı değiştirmeyi yasakla",
"disallow-password-auth": "Şifre ile kimlik doğrulamayı yasakla",

View File

@ -410,7 +410,7 @@
"title": "Вебхуки",
"url": "URL"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Заборонити зміну нікнейму",
"disallow-change-username": "Заборонити зміну імені користувача",
"disallow-password-auth": "Заборонити авторизацію за паролем",

View File

@ -324,7 +324,7 @@
"title": "Webhook",
"url": "Url"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "Không cho phép đổi biệt danh",
"disallow-change-username": "Không cho phép đổi tên người dùng",
"disallow-password-auth": "Không cho phép xác thực bằng mật khẩu",

View File

@ -406,7 +406,7 @@
},
"no-webhooks-found": "没有 webhooks。"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "禁止修改用户昵称",
"disallow-change-username": "禁止修改用户名",
"disallow-password-auth": "禁用密码登录",

View File

@ -435,7 +435,7 @@
"title": "Webhook",
"url": "網址"
},
"workspace-section": {
"instance-section": {
"disallow-change-nickname": "禁止變更暱稱",
"disallow-change-username": "禁止變更使用者名稱",
"disallow-password-auth": "禁止使用密碼登入",

View File

@ -8,8 +8,8 @@ import "./index.css";
import router from "./router";
// Configure MobX before importing any stores
import "./store/config";
import { initialInstanceStore } from "./store/instance";
import { initialUserStore } from "./store/user";
import { initialWorkspaceStore } from "./store/workspace";
import { applyThemeEarly } from "./utils/theme";
import "leaflet/dist/leaflet.css";
@ -24,7 +24,7 @@ const Main = observer(() => (
));
(async () => {
await initialWorkspaceStore();
await initialInstanceStore();
await initialUserStore();
const container = document.getElementById("root");

View File

@ -1,17 +1,17 @@
import { observer } from "mobx-react-lite";
import AuthFooter from "@/components/AuthFooter";
import PasswordSignInForm from "@/components/PasswordSignInForm";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
const AdminSignIn = observer(() => {
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const instanceGeneralSetting = instanceStore.state.generalSetting;
return (
<div className="py-4 sm:py-8 w-80 max-w-full min-h-svh mx-auto flex flex-col justify-start items-center">
<div className="w-full py-4 grow flex flex-col justify-center items-center">
<div className="w-full flex flex-row justify-center items-center mb-6">
<img className="h-14 w-auto rounded-full shadow" src={workspaceGeneralSetting.customProfile?.logoUrl || "/logo.webp"} alt="" />
<p className="ml-2 text-5xl text-foreground opacity-80">{workspaceGeneralSetting.customProfile?.title || "Memos"}</p>
<img className="h-14 w-auto rounded-full shadow" src={instanceGeneralSetting.customProfile?.logoUrl || "/logo.webp"} alt="" />
<p className="ml-2 text-5xl text-foreground opacity-80">{instanceGeneralSetting.customProfile?.title || "Memos"}</p>
</div>
<p className="w-full text-xl font-medium text-muted-foreground">Sign in with admin accounts</p>
<PasswordSignInForm />

View File

@ -3,6 +3,7 @@ import { observer } from "mobx-react-lite";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useLocation } from "react-router-dom";
import MobileHeader from "@/components/MobileHeader";
import InstanceSection from "@/components/Settings/InstanceSection";
import MemberSection from "@/components/Settings/MemberSection";
import MemoRelatedSettings from "@/components/Settings/MemoRelatedSettings";
import MyAccountSection from "@/components/Settings/MyAccountSection";
@ -10,13 +11,12 @@ import PreferencesSection from "@/components/Settings/PreferencesSection";
import SSOSection from "@/components/Settings/SSOSection";
import SectionMenuItem from "@/components/Settings/SectionMenuItem";
import StorageSection from "@/components/Settings/StorageSection";
import WorkspaceSection from "@/components/Settings/WorkspaceSection";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import useCurrentUser from "@/hooks/useCurrentUser";
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import { InstanceSetting_Key } from "@/types/proto/api/v1/instance_service";
import { User_Role } from "@/types/proto/api/v1/user_service";
import { WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
import { useTranslate } from "@/utils/i18n";
type SettingSection = "my-account" | "preference" | "member" | "system" | "memo-related" | "storage" | "sso";
@ -71,10 +71,10 @@ const Setting = observer(() => {
return;
}
// Initial fetch for workspace settings.
// Initial fetch for instance settings.
(async () => {
[WorkspaceSetting_Key.MEMO_RELATED, WorkspaceSetting_Key.STORAGE].forEach(async (key) => {
await workspaceStore.fetchWorkspaceSetting(key);
[InstanceSetting_Key.MEMO_RELATED, InstanceSetting_Key.STORAGE].forEach(async (key) => {
await instanceStore.fetchInstanceSetting(key);
});
})();
}, [isHost]);
@ -115,7 +115,7 @@ const Setting = observer(() => {
/>
))}
<span className="px-3 mt-2 opacity-70 text-sm">
{t("setting.version")}: v{workspaceStore.state.profile.version}
{t("setting.version")}: v{instanceStore.state.profile.version}
</span>
</div>
</>
@ -143,7 +143,7 @@ const Setting = observer(() => {
) : state.selectedSection === "member" ? (
<MemberSection />
) : state.selectedSection === "system" ? (
<WorkspaceSection />
<InstanceSection />
) : state.selectedSection === "memo-related" ? (
<MemoRelatedSettings />
) : state.selectedSection === "storage" ? (

View File

@ -10,7 +10,7 @@ import { identityProviderServiceClient } from "@/grpcweb";
import { absolutifyLink } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser";
import { Routes } from "@/router";
import { workspaceStore } from "@/store";
import { instanceStore } from "@/store";
import { extractIdentityProviderIdFromName } from "@/store/common";
import { IdentityProvider, IdentityProvider_Type } from "@/types/proto/api/v1/idp_service";
import { useTranslate } from "@/utils/i18n";
@ -20,7 +20,7 @@ const SignIn = observer(() => {
const t = useTranslate();
const currentUser = useCurrentUser();
const [identityProviderList, setIdentityProviderList] = useState<IdentityProvider[]>([]);
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const instanceGeneralSetting = instanceStore.state.generalSetting;
// Redirect to root page if already signed in.
useEffect(() => {
@ -71,15 +71,15 @@ const SignIn = observer(() => {
<div className="py-4 sm:py-8 w-80 max-w-full min-h-svh mx-auto flex flex-col justify-start items-center">
<div className="w-full py-4 grow flex flex-col justify-center items-center">
<div className="w-full flex flex-row justify-center items-center mb-6">
<img className="h-14 w-auto rounded-full shadow" src={workspaceGeneralSetting.customProfile?.logoUrl || "/logo.webp"} alt="" />
<p className="ml-2 text-5xl text-foreground opacity-80">{workspaceGeneralSetting.customProfile?.title || "Memos"}</p>
<img className="h-14 w-auto rounded-full shadow" src={instanceGeneralSetting.customProfile?.logoUrl || "/logo.webp"} alt="" />
<p className="ml-2 text-5xl text-foreground opacity-80">{instanceGeneralSetting.customProfile?.title || "Memos"}</p>
</div>
{!workspaceGeneralSetting.disallowPasswordAuth ? (
{!instanceGeneralSetting.disallowPasswordAuth ? (
<PasswordSignInForm />
) : (
identityProviderList.length == 0 && <p className="w-full text-2xl mt-2 text-muted-foreground">Password auth is not allowed.</p>
)}
{!workspaceGeneralSetting.disallowUserRegistration && !workspaceGeneralSetting.disallowPasswordAuth && (
{!instanceGeneralSetting.disallowUserRegistration && !instanceGeneralSetting.disallowPasswordAuth && (
<p className="w-full mt-4 text-sm">
<span className="text-muted-foreground">{t("auth.sign-up-tip")}</span>
<Link to="/auth/signup" className="cursor-pointer ml-2 text-primary hover:underline" viewTransition>
@ -89,7 +89,7 @@ const SignIn = observer(() => {
)}
{identityProviderList.length > 0 && (
<>
{!workspaceGeneralSetting.disallowPasswordAuth && (
{!instanceGeneralSetting.disallowPasswordAuth && (
<div className="relative my-4 w-full">
<Separator />
<div className="absolute inset-0 flex items-center justify-center">

Some files were not shown because too many files have changed in this diff Show More