Changes
12 changed files (+234/-22)
-
-
@@ -22,6 +22,9 @@Projection *workspace.Users permissions map[string]map[types.Permission]struct{} // { カスタムフィールド定義ID: { ユーザID: 値 } } customAttributes map[string]map[string]string } func NewUsers() *Users {
-
@@ -31,7 +34,8 @@ eventSeq: nil,Projection: &workspace.Users{ Users: []*workspace.Users_User{}, }, permissions: make(map[string]map[types.Permission]struct{}), permissions: make(map[string]map[types.Permission]struct{}), customAttributes: make(map[string]map[string]string), } }
-
@@ -46,6 +50,7 @@ return NewUsers(), nil} permissions := make(map[string]map[types.Permission]struct{}) customAttributes := make(map[string]map[string]string) for _, u := range payload.Users { perms := make(map[types.Permission]struct{})
-
@@ -54,13 +59,23 @@ perms[p] = struct{}{}} permissions[u.GetId()] = perms for _, c := range u.CustomAttributes { defId := c.GetId() if customAttributes[defId] == nil { customAttributes[defId] = make(map[string]string) } customAttributes[defId][u.GetId()] = c.GetValue() } } return &Users{ hasSnapshot: true, eventSeq: &seq, Projection: payload, permissions: permissions, hasSnapshot: true, eventSeq: &seq, Projection: payload, permissions: permissions, customAttributes: customAttributes, }, nil }
-
@@ -177,6 +192,15 @@ for _, perm := range ev.UserPermissionsRevoked.Permissions {delete(p.permissions[id], perm) } } case *workspaceEventsv1.Event_CustomAttributeDefined: p.customAttributes[ev.CustomAttributeDefined.GetId()] = make(map[string]string) case *workspaceEventsv1.Event_CustomAttributeUndefined: delete(p.customAttributes, ev.CustomAttributeUndefined.GetId()) case *workspaceEventsv1.Event_CustomAttributeSet: defId := ev.CustomAttributeSet.GetCustomAttributeId() if p.customAttributes[defId] != nil { p.customAttributes[defId][ev.CustomAttributeSet.GetUserId()] = ev.CustomAttributeSet.GetValue() } } for _, user := range p.Projection.Users {
-
@@ -185,7 +209,9 @@ user.Permissions = slices.Clone(fullAccess)continue } permissions := p.permissions[user.GetId()] userId := user.GetId() permissions := p.permissions[userId] s := make([]types.Permission, 0, len(permissions))
-
@@ -193,8 +219,18 @@ for perm := range permissions {s = append(s, perm) } c := make([]*workspace.Users_User_CustomAttribute, 0, len(p.customAttributes)) for defId, values := range p.customAttributes { c = append(c, &workspace.Users_User_CustomAttribute{ Id: proto.String(defId), Value: proto.String(values[userId]), }) } slices.Sort(s) user.Permissions = slices.Compact(s) user.CustomAttributes = c } p.eventSeq = &container.Seq
-
-
-
@@ -237,3 +237,19 @@ },}, } } func SetCustomAttribute(userId string, id string, value string) *eventV1.Event { return &eventV1.Event{ Event: &eventV1.Event_WorkspaceEvent{ WorkspaceEvent: &workspaceEvent.Event{ Event: &workspaceEvent.Event_CustomAttributeSet{ CustomAttributeSet: &workspaceEvent.CustomAttributeSet{ UserId: proto.String(userId), CustomAttributeId: proto.String(id), Value: proto.String(value), }, }, }, }, } }
-
-
-
@@ -235,7 +235,7 @@ logger.Debug("Created an initial admin user", "id", id)return connect.NewResponse(&workspaceV2.CreateInitialAdminResponse{ Result: &workspaceV2.CreateInitialAdminResponse_Ok{ Ok: projectionUserToMessage(u), Ok: projectionUserToMessage(u, ws.Projection), }, }), nil }
-
-
-
@@ -71,6 +71,12 @@ return createUserSystemError("Database error"), nil} defer tx.Rollback() ws, err := projection.GetWorkspace(tx) if err != nil { logger.Error("Failed to read workspace projection", "error", err) return createUserSystemError("Database error"), nil } users, err := projection.GetUsers(tx) if err != nil { logger.Error("Failed to read users projection", "error", err)
-
@@ -83,7 +89,7 @@ logger.Error("Failed to read login_jwt_secret projection", "error", err)return createUserSystemError("Database error"), nil } if err := event.UpdateProjections(tx, users, secret); err != nil { if err := event.UpdateProjections(tx, ws, users, secret); err != nil { logger.Error("Failed to update projections", "error", err) return createUserSystemError("Database error"), nil }
-
@@ -172,11 +178,23 @@keyID := make([]byte, 32) rand.Read(keyID) err = event.AppendEvents(tx, []*eventV1.Event{ events := make([]*eventV1.Event, 0, 2+len(req.Msg.CustomAttributes)) events = append( events, workspaceEvent.CreateUser(id, name, displayName, keyID), workspaceEvent.ConfigurePasswordLogin(id, password), }) if err != nil { ) for _, attr := range req.Msg.CustomAttributes { events = append( events, workspaceEvent.SetCustomAttribute( id, attr.GetDefinition().GetId().GetValue(), attr.GetValue(), ), ) } if err := event.AppendEvents(tx, events); err != nil { logger.Error("Failed to append user creation events", "error", err) return createUserSystemError("Database error"), nil }
-
@@ -283,7 +301,7 @@ logger.Debug("Created a new user", "id", id)return connect.NewResponse(&workspaceV2.CreateUserResponse{ Result: &workspaceV2.CreateUserResponse_Ok{ Ok: projectionUserToMessage(u), Ok: projectionUserToMessage(u, ws.Projection), }, }), nil }
-
-
-
@@ -156,7 +156,7 @@ }res := connect.NewResponse(&workspaceV2.DeleteUserResponse{ Result: &workspaceV2.DeleteUserResponse_Ok{ Ok: projectionUserToMessage(u), Ok: projectionUserToMessage(u, workspace.Projection), }, })
-
-
-
@@ -50,6 +50,12 @@ return getLoginUserSystemError("Database error"), nil} defer tx.Rollback() ws, err := projection.GetWorkspace(tx) if err != nil { logger.Error("Failed to read workspace projection", "error", err) return getLoginUserSystemError("Database error"), nil } users, err := projection.GetUsers(tx) if err != nil { logger.Error("Failed to read users projection", "error", err)
-
@@ -62,7 +68,7 @@ logger.Error("Failed to read login_jwt_secret projection", "error", err)return getLoginUserSystemError("Database error"), nil } if err := event.UpdateProjections(tx, users, secret); err != nil { if err := event.UpdateProjections(tx, ws, users, secret); err != nil { logger.Error("Failed to update projections", "error", err) return getLoginUserSystemError("Database error"), nil }
-
@@ -90,7 +96,7 @@ }return connect.NewResponse(&workspaceV2.GetLoginUserResponse{ Result: &workspaceV2.GetLoginUserResponse_Ok{ Ok: projectionUserToMessage(user), Ok: projectionUserToMessage(user, ws.Projection), }, }), nil }
-
-
-
@@ -11,7 +11,7 @@ "pocka.jp/x/yamori/proto/go/backend/workspace/v1/types"workspaceV2 "pocka.jp/x/yamori/proto/go/workspace/v2" ) func projectionUserToMessage(p *projection.Users_User) *workspaceV2.User { func projectionUserToMessage(p *projection.Users_User, ws *projection.Workspace) *workspaceV2.User { permissions := workspaceV2.UserPermissions{} for _, perm := range p.Permissions {
-
@@ -33,6 +33,35 @@ permissions.CanUpdateWorkspace = proto.Bool(true)} } customAttributes := make([]*workspaceV2.CustomAttribute, len(ws.CustomAttributes)) DefLoop: for i, def := range ws.CustomAttributes { for _, attr := range p.CustomAttributes { if def.GetId() == attr.GetId() { customAttributes[i] = &workspaceV2.CustomAttribute{ Definition: &workspaceV2.CustomAttributeDefinition{ Id: &workspaceV2.CustomAttributeDefinitionID{ Value: def.Id, }, DisplayName: def.DisplayName, }, Value: attr.Value, } continue DefLoop } } customAttributes[i] = &workspaceV2.CustomAttribute{ Definition: &workspaceV2.CustomAttributeDefinition{ Id: &workspaceV2.CustomAttributeDefinitionID{ Value: def.Id, }, DisplayName: def.DisplayName, }, } } return &workspaceV2.User{ Id: &workspaceV2.UserID{ Value: p.Id,
-
@@ -42,8 +71,9 @@ DisplayName: p.DisplayName,LoginMethod: &workspaceV2.LoginMethod{ PasswordConfigured: proto.Bool(p.PasswordLogin != nil), }, IsAdmin: p.IsAdmin, Permissions: &permissions, IsAdmin: p.IsAdmin, Permissions: &permissions, CustomAttributes: customAttributes, } }
-
@@ -62,7 +92,7 @@ func projectionWorkspaceToMessage(p *projection.Workspace, u *projection.Users) *workspaceV2.Workspace {users := make([]*workspaceV2.User, len(u.Users)) for i, user := range u.Users { users[i] = projectionUserToMessage(user) users[i] = projectionUserToMessage(user, p) } customAttributeDefs := make([]*workspaceV2.CustomAttributeDefinition, len(p.CustomAttributes))
-
-
-
@@ -74,6 +74,18 @@ },}), nil } ws, err := projection.GetWorkspace(tx) if err != nil { logger.Error("Failed to read workspace projection", "error", err) return connect.NewResponse(&workspaceV2.LoginResponse{ Result: &workspaceV2.LoginResponse_SystemError{ SystemError: &errorV1.SystemError{ Message: proto.String("Database error"), }, }, }), nil } secret, err := projection.GetLoginJwtSecret(tx) if err != nil { logger.Error("Failed to read login_jwt_secret projection", "error", err)
-
@@ -86,7 +98,7 @@ },}), nil } if err := event.UpdateProjections(tx, users, secret); err != nil { if err := event.UpdateProjections(tx, ws, users, secret); err != nil { logger.Error("Failed to update projections", "error", err) return connect.NewResponse(&workspaceV2.LoginResponse{ Result: &workspaceV2.LoginResponse_SystemError{
-
@@ -125,7 +137,7 @@ }res := connect.NewResponse(&workspaceV2.LoginResponse{ Result: &workspaceV2.LoginResponse_Ok{ Ok: projectionUserToMessage(u), Ok: projectionUserToMessage(u, ws.Projection), }, })
-
-
-
@@ -287,7 +287,7 @@ for _, updated := range users.Projection.Users {if updated.GetId() == id { return connect.NewResponse(&workspaceV2.UpdateUserResponse{ Result: &workspaceV2.UpdateUserResponse_Ok{ Ok: projectionUserToMessage(updated), Ok: projectionUserToMessage(updated, workspace.Projection), }, }), nil }
-
-
-
@@ -20,6 +20,16 @@func TestCreateUserGetOK(t *testing.T) { server, jar := setupLogin(t) customAttrFoo, err := setupCustomAttributeDefinitions(server, jar, "Foo") if err != nil { t.Fatal(err) } customAttrBar, err := setupCustomAttributeDefinitions(server, jar, "Bar") if err != nil { t.Fatal(err) } httpClient := server.Client() httpClient.Jar = jar
-
@@ -31,6 +41,14 @@ connect.NewRequest(&workspaceV2.CreateUserRequest{Name: proto.String("bob"), DisplayName: proto.String("Bob"), Password: proto.String("bob_password"), CustomAttributes: []*workspaceV2.CustomAttribute{ { Definition: &workspaceV2.CustomAttributeDefinition{ Id: customAttrBar, }, Value: proto.String("Bob's Bar"), }, }, }), ) if err != nil {
-
@@ -66,6 +84,42 @@ }if l.Ok.GetName() != "bob" { t.Errorf("Expected bob, got %s", l.Ok.GetName()) } if len(l.Ok.CustomAttributes) != 2 { t.Fatalf("Expected 2 custom attributes, got %d", len(l.Ok.CustomAttributes)) } for _, attr := range l.Ok.CustomAttributes { if attr.Definition.Id.GetValue() == customAttrFoo.GetValue() { if attr.Definition.GetDisplayName() != "Foo" { t.Errorf("Expected custom attribute Foo to be named Foo, got %s", attr.Definition.GetDisplayName()) } if attr.GetValue() != "" { t.Errorf("Expected custom attribute Foo to be empty, got %s", attr.GetValue()) } continue } if attr.Definition.Id.GetValue() == customAttrBar.GetValue() { if attr.Definition.GetDisplayName() != "Bar" { t.Errorf("Expected custom attribute Bar to be named Bar, got %s", attr.Definition.GetDisplayName()) } if attr.GetValue() != "Bob's Bar" { t.Errorf("Expected custom attribute Bar to be \"Bob's Bar\", got \"%s\"", attr.GetValue()) } continue } t.Errorf( "Unexpected custom attribute, id=%s, display_name=%s", attr.Definition.Id.GetValue(), attr.Definition.GetDisplayName(), ) } }
-
-
-
@@ -8,6 +8,7 @@import ( "context" "database/sql" "fmt" "io" "log/slog" "net/http"
-
@@ -170,3 +171,36 @@ }return server, jar } // setupCustomAttributeDefinitions はログインされたユーザでカスタムフィールドを // ワークスペース上に定義する。返り値は作成された定義の ID 。 func setupCustomAttributeDefinitions( server *memhttp.Server, jar http.CookieJar, displayName string, ) (*workspaceV2.CustomAttributeDefinitionID, error) { httpClient := server.Client() httpClient.Jar = jar client := v2connect.NewWorkspaceServiceClient(httpClient, server.URL()) def, err := client.PutCustomAttributeDefinition( context.Background(), connect.NewRequest(&workspaceV2.PutCustomAttributeDefinitionRequest{ DisplayName: proto.String(displayName), }), ) if err != nil { return nil, err } v, ok := def.Msg.Result.(*workspaceV2.PutCustomAttributeDefinitionResponse_Ok) if !ok { typeName := reflect.Indirect(reflect.ValueOf(def.Msg.Result)) return nil, fmt.Errorf("Expected ok, got %s", typeName.Type().Name()) } if v.Ok.GetDisplayName() != displayName { return nil, fmt.Errorf("Expected \"Foo\", got \"%s\"", v.Ok.GetDisplayName()) } return v.Ok.Id, nil }
-
-
-
@@ -21,6 +21,11 @@ bytes salt = 2;} message User { message CustomAttribute { string id = 1; string value = 2; } string id = 1; string name = 2; string display_name = 3;
-
@@ -28,6 +33,7 @@ PasswordLogin password_login = 4;bool is_admin = 5; bytes key_id = 6; repeated yamori.backend.workspace.v1.types.v1.Permission permissions = 7; repeated CustomAttribute custom_attributes = 8; } repeated User users = 1;
-