github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/invite/impl_applyjoinworkspace.go (about) 1 /* 2 * Copyright (c) 2023-present unTill Pro, Ltd. 3 */ 4 5 package invite 6 7 import ( 8 "fmt" 9 10 "github.com/voedger/voedger/pkg/appdef" 11 "github.com/voedger/voedger/pkg/istructs" 12 "github.com/voedger/voedger/pkg/itokens" 13 payloads "github.com/voedger/voedger/pkg/itokens-payloads" 14 "github.com/voedger/voedger/pkg/state" 15 "github.com/voedger/voedger/pkg/sys/authnz" 16 "github.com/voedger/voedger/pkg/sys/collection" 17 coreutils "github.com/voedger/voedger/pkg/utils" 18 "github.com/voedger/voedger/pkg/utils/federation" 19 ) 20 21 func asyncProjectorApplyJoinWorkspace(timeFunc coreutils.TimeFunc, federation federation.IFederation, tokens itokens.ITokens) istructs.Projector { 22 return istructs.Projector{ 23 Name: qNameAPApplyJoinWorkspace, 24 Func: applyJoinWorkspace(timeFunc, federation, tokens), 25 } 26 } 27 28 func applyJoinWorkspace(timeFunc coreutils.TimeFunc, federation federation.IFederation, tokens itokens.ITokens) func(event istructs.IPLogEvent, state istructs.IState, intents istructs.IIntents) (err error) { 29 return func(event istructs.IPLogEvent, s istructs.IState, intents istructs.IIntents) (err error) { 30 // it is AFTER EXECUTE ON (InitiateJoinWorkspace) so no doc checking here 31 skbCDocInvite, err := s.KeyBuilder(state.Record, qNameCDocInvite) 32 if err != nil { 33 return 34 } 35 skbCDocInvite.PutRecordID(state.Field_ID, event.ArgumentObject().AsRecordID(field_InviteID)) 36 svCDocInvite, err := s.MustExist(skbCDocInvite) 37 if err != nil { 38 return 39 } 40 41 login := svCDocInvite.AsString(Field_Login) 42 subjectExists, err := SubjectExistsByLogin(login, s) // for backward compatibility 43 if err == nil && !subjectExists { 44 actualLogin := svCDocInvite.AsString(field_ActualLogin) 45 subjectExists, err = SubjectExistsByLogin(actualLogin, s) 46 } 47 if err != nil { 48 // notest 49 return err 50 } 51 52 if subjectExists { 53 // cdoc.sys.Subject exists by login -> skip 54 // see https://github.com/voedger/voedger/issues/1107 55 // && svCDocInvite.AsInt32(field_State) == State_Joined -> insert cdoc.sys.Subject with an existing login -> unique violation -> the projector stuck 56 return nil 57 } 58 59 skbCDocWorkspaceDescriptor, err := s.KeyBuilder(state.Record, authnz.QNameCDocWorkspaceDescriptor) 60 if err != nil { 61 return err 62 } 63 skbCDocWorkspaceDescriptor.PutQName(state.Field_Singleton, authnz.QNameCDocWorkspaceDescriptor) 64 svCDocWorkspaceDescriptor, err := s.MustExist(skbCDocWorkspaceDescriptor) 65 if err != nil { 66 return 67 } 68 69 appQName := s.App() 70 71 token, err := payloads.GetSystemPrincipalToken(tokens, appQName) 72 if err != nil { 73 return 74 } 75 _, err = federation.Func( 76 fmt.Sprintf("api/%s/%d/c.sys.CreateJoinedWorkspace", appQName, svCDocInvite.AsInt64(field_InviteeProfileWSID)), 77 fmt.Sprintf(`{"args":{"Roles":"%s","InvitingWorkspaceWSID":%d,"WSName":"%s"}}`, 78 svCDocInvite.AsString(Field_Roles), event.Workspace(), svCDocWorkspaceDescriptor.AsString(authnz.Field_WSName)), 79 coreutils.WithAuthorizeBy(token), 80 coreutils.WithDiscardResponse(), 81 ) 82 if err != nil { 83 return 84 } 85 86 // Find cdoc.sys.Subject by cdoc.air.Invite 87 skbViewCollection, err := s.KeyBuilder(state.View, collection.QNameCollectionView) 88 if err != nil { 89 return 90 } 91 skbViewCollection.PutInt32(collection.Field_PartKey, collection.PartitionKeyCollection) 92 skbViewCollection.PutQName(collection.Field_DocQName, QNameCDocSubject) 93 94 var svCDocSubject istructs.IStateValue 95 if svCDocInvite.AsRecordID(field_SubjectID) != istructs.NullRecordID { 96 err = s.Read(skbViewCollection, func(key istructs.IKey, value istructs.IStateValue) (err error) { 97 if svCDocSubject != nil { 98 return nil 99 } 100 if svCDocInvite.AsRecordID(field_SubjectID) == value.AsRecordID(appdef.SystemField_ID) { 101 svCDocSubject = value 102 } 103 return nil 104 }) 105 if err != nil { 106 return 107 } 108 } 109 110 var body string 111 // Store cdoc.sys.Subject 112 if svCDocSubject == nil { 113 // svCDocInvite.AsString(Field_Login) is actually c.sys.InitiateInvitationByEMail.Email 114 body = fmt.Sprintf(`{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"sys.Subject","Login":"%s","Roles":"%s","SubjectKind":%d,"ProfileWSID":%d}}]}`, 115 svCDocInvite.AsString(field_ActualLogin), svCDocInvite.AsString(Field_Roles), svCDocInvite.AsInt32(authnz.Field_SubjectKind), 116 svCDocInvite.AsInt64(field_InviteeProfileWSID)) 117 } else { 118 body = fmt.Sprintf(`{"cuds":[{"sys.ID":%d,"fields":{"Roles":"%s"}}]}`, 119 svCDocSubject.AsRecordID(appdef.SystemField_ID), svCDocInvite.AsString(Field_Roles)) 120 } 121 resp, err := federation.Func( 122 fmt.Sprintf("api/%s/%d/c.sys.CUD", appQName, event.Workspace()), 123 body, 124 coreutils.WithAuthorizeBy(token)) 125 if err != nil { 126 return 127 } 128 129 //Store cdoc.sys.Invite 130 //TODO why Login update??? 131 if svCDocSubject == nil { 132 body = fmt.Sprintf(`{"cuds":[{"sys.ID":%d,"fields":{"State":%d,"SubjectID":%d,"Updated":%d}}]}`, 133 svCDocInvite.AsRecordID(appdef.SystemField_ID), State_Joined, resp.NewID(), timeFunc().UnixMilli()) 134 } else { 135 body = fmt.Sprintf(`{"cuds":[{"sys.ID":%d,"fields":{"State":%d,"Updated":%d}}]}`, 136 svCDocInvite.AsRecordID(appdef.SystemField_ID), State_Joined, timeFunc().UnixMilli()) 137 } 138 _, err = federation.Func( 139 fmt.Sprintf("api/%s/%d/c.sys.CUD", appQName, event.Workspace()), 140 body, 141 coreutils.WithAuthorizeBy(token), 142 coreutils.WithDiscardResponse()) 143 144 return err 145 } 146 }