Beispiel #1
0
        internal async Task <TResult> MarkInviteRedeemedAsync <TResult>(Guid inviteToken, Guid loginId,
                                                                        Func <Guid, TResult> onFound,
                                                                        Func <TResult> onNotFound,
                                                                        Func <Guid, TResult> onAlreadyRedeemed,
                                                                        Func <TResult> onAlreadyInUse,
                                                                        Func <TResult> onAlreadyConnected)
        {
            var lookupResults = await await repository.FindByIdAsync(inviteToken,
                                                                     async (Documents.InviteTokenDocument tokenDocument) =>
            {
                var rollback = new RollbackAsync <TResult>();

                rollback.AddTaskUpdate(tokenDocument.InviteId,
                                       (Documents.InviteDocument inviteDoc) => { inviteDoc.LoginId = loginId; },
                                       (inviteDoc) => { inviteDoc.LoginId = default(Guid?); },
                                       onNotFound,
                                       this.repository);

                var loginLookup = new Documents.LoginActorLookupDocument()
                {
                    ActorId = tokenDocument.ActorId,
                };
                rollback.AddTaskCreate(loginId, loginLookup, onAlreadyInUse, this.repository);

                return(await rollback.ExecuteAsync(() => onFound(tokenDocument.ActorId)));
            },
                                                                     () => onNotFound().ToTask());

            return(lookupResults);
        }
Beispiel #2
0
        public async Task <TResult> CreatePasswordCredentialAsync <TResult>(Guid passwordCredentialId,
                                                                            Guid actorId, Guid loginId, DateTime?emailLastSent,
                                                                            Func <TResult> onSuccess,
                                                                            Func <TResult> onAlreadyExists,
                                                                            Func <TResult> onRelationshipAlreadyExists,
                                                                            Func <TResult> onLoginAlreadyUsed)
        {
            var rollback = new RollbackAsync <TResult>();

            var lookupDoc = new Documents.LoginActorLookupDocument
            {
                ActorId = actorId,
            };

            rollback.AddTaskCreate(loginId, lookupDoc,
                                   onLoginAlreadyUsed, this.repository);

            rollback.AddTaskCreateOrUpdate(actorId,
                                           (Documents.ActorMappingsDocument actorDoc) =>
                                           actorDoc.AddPasswordCredential(passwordCredentialId),
                                           actorDoc => actorDoc.RemovePasswordCredential(passwordCredentialId),
                                           onRelationshipAlreadyExists,
                                           this.repository);

            var passwordCredentialDoc = new Documents.PasswordCredentialDocument
            {
                LoginId       = loginId,
                EmailLastSent = emailLastSent,
            };

            rollback.AddTaskCreate(passwordCredentialId, passwordCredentialDoc,
                                   onAlreadyExists, this.repository);

            return(await rollback.ExecuteAsync(onSuccess));
        }
Beispiel #3
0
 public static void AddTaskDeleteJoin <TRollback, TDocument>(this RollbackAsync <Guid?, TRollback> rollback,
                                                             Guid docId,
                                                             Func <TDocument, Guid?> removeLink,
                                                             Action <Guid, TDocument> rollbackLink,
                                                             AzureStorageRepository repo)
     where TDocument : class, ITableEntity
 {
     rollback.AddTaskUpdate(docId,
                            (TDocument doc) =>
     {
         var joinId = removeLink(doc);
         return(joinId);
     },
                            (joinId, doc) =>
     {
         if (joinId.HasValue)
         {
             rollbackLink(joinId.Value, doc);
             return(true);
         }
         return(false);
     },
                            () => default(Guid?),
                            repo);
 }
Beispiel #4
0
        public async Task <TResult> CreateUnauthenticatedAsync <TResult>(Guid integrationId, Guid accountId,
                                                                         string methodName,
                                                                         Func <TResult> onSuccess,
                                                                         Func <TResult> onAlreadyExists)
        {
            var rollback = new RollbackAsync <TResult>();

            var docByMethod = new AccessDocument
            {
                LookupId = integrationId,
                Method   = methodName,
            };

            rollback.AddTaskCreate(accountId, methodName, docByMethod, onAlreadyExists, this.repository);

            var docById = new AccessDocument
            {
                LookupId = accountId,
                Method   = methodName,
            };

            rollback.AddTaskCreate(integrationId, docById, onAlreadyExists, this.repository);

            return(await rollback.ExecuteAsync(onSuccess));
        }
Beispiel #5
0
        internal async Task <TResult> CreateCredentialMappingAsync <TResult>(Guid credentialMappingId,
                                                                             CredentialValidationMethodTypes method, string subjectId, Guid actorId,
                                                                             Func <TResult> onSuccess,
                                                                             Func <TResult> onAlreadyExists,
                                                                             Func <TResult> onTokenAlreadyInUse)
        {
            var rollback = new RollbackAsync <TResult>();

            var methodName           = Enum.GetName(typeof(CredentialValidationMethodTypes), method);
            var credentialMappingDoc = new Documents.CredentialMappingDocument()
            {
                Method  = methodName,
                Subject = subjectId,
                ActorId = actorId,
            };

            rollback.AddTaskCreate(credentialMappingId, credentialMappingDoc, onAlreadyExists, this.repository);

            var lookupDocument = new Azure.Documents.CredentialMappingLookupDocument()
            {
                CredentialMappingId = credentialMappingId,
                Method  = methodName,
                Subject = subjectId,
            };

            rollback.AddTaskCreate(subjectId, methodName, lookupDocument, onTokenAlreadyInUse, this.repository);

            rollback.AddTaskCreateOrUpdate(actorId,
                                           (Documents.ActorMappingsDocument authDoc) => authDoc.AddInviteId(credentialMappingId),
                                           (authDoc) => authDoc.RemoveInviteId(credentialMappingId),
                                           onAlreadyExists, // This should fail on the action above as well
                                           this.repository);

            return(await rollback.ExecuteAsync(onSuccess));
        }
Beispiel #6
0
        public async Task <TResult> CreateAuthenticatedAsync <TResult>(Guid integrationId, Guid authenticationId,
                                                                       string methodName, IDictionary <string, string> paramSet,
                                                                       Func <TResult> onSuccess,
                                                                       Func <TResult> onAlreadyExists)
        {
            var rollback = new RollbackAsync <TResult>();

            var docByMethod = new AccessDocument
            {
                LookupId = integrationId,
                Method   = methodName,
            };

            rollback.AddTaskCreate(authenticationId, methodName, docByMethod, onAlreadyExists, this.repository);

            var integrationDoc = new AuthenticationRequestDocument
            {
                LinkedAuthenticationId = authenticationId,
                Method = methodName,
                Action = Enum.GetName(typeof(AuthenticationActions), AuthenticationActions.access)
            };

            integrationDoc.SetExtraParams(paramSet);
            rollback.AddTaskCreate(integrationId, integrationDoc, onAlreadyExists, this.repository);

            return(await rollback.ExecuteAsync(onSuccess));
        }
Beispiel #7
0
        public async Task <TResult> CreateAsync <TResult>(Guid integrationId, Guid accountId,
                                                          CredentialValidationMethodTypes method, IDictionary <string, string> paramSet,
                                                          Func <TResult> onSuccess,
                                                          Func <TResult> onAlreadyExists)
        {
            var methodName  = Enum.GetName(typeof(CredentialValidationMethodTypes), method);
            var docByMethod = new AccessDocument
            {
                LookupId = integrationId,
                Method   = methodName,
            };

            docByMethod.SetExtraParams(paramSet);
            var docById = new AccessDocument
            {
                LookupId = accountId,
                Method   = methodName,
            };

            docById.SetExtraParams(paramSet);
            var rollback = new RollbackAsync <TResult>();

            rollback.AddTaskCreate(accountId, methodName, docByMethod, onAlreadyExists, this.repository);
            rollback.AddTaskCreate(integrationId, docById, onAlreadyExists, this.repository);
            return(await rollback.ExecuteAsync(onSuccess));
        }
        internal static Task <TResult> CreateAsync <TResult>(Guid processStageId, Guid actorId,
                                                             Guid processStageTypeId, string title,
                                                             KeyValuePair <Guid[], Guid>[] confirmableActorIds, Guid[] editableActorIds, Guid[] viewableActorIds,
                                                             Func <TResult> onSuccess,
                                                             Func <TResult> onAlreadyExists)
        {
            return(AzureStorageRepository.Connection(
                       azureStorageRepository =>
            {
                var rollback = new RollbackAsync <TResult>();

                var procStageDoc = new ProcessStageDocument()
                {
                    Owner = actorId,
                    ProcessStageType = processStageTypeId,
                    Title = title,
                };
                procStageDoc.SetConfirmables(confirmableActorIds);
                procStageDoc.SetEditables(editableActorIds);
                procStageDoc.SetViewables(viewableActorIds);
                rollback.AddTaskCreate(processStageId, procStageDoc,
                                       onAlreadyExists, azureStorageRepository);

                rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStageActorLookupDocument>(actorId,
                                                                                                    (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processStageId),
                                                                                                    lookupDoc => lookupDoc.RemoveLookupDocumentId(processStageId),
                                                                                                    azureStorageRepository);


                return rollback.ExecuteAsync(onSuccess);
            }));
        }
Beispiel #9
0
        public async Task <TResult> CreateAsync <TResult>(
            Guid id, Guid actorId, string name,
            Func <TResult> onSuccess,
            Func <TResult> onAlreadyExists,
            Func <TResult> onActorNotFound)
        {
            var rollback = new RollbackAsync <TResult>();
            var document = new Documents.RoleDocument()
            {
                Name    = name,
                ActorId = actorId,
            };

            rollback.AddTaskCreate(id, document, onAlreadyExists, this.azureStorageRepository);

            rollback.AddTaskCreateOrUpdate(actorId,
                                           (Documents.ActorMappingsDocument actorDoc) =>
            {
                actorDoc.AddRole(id);
                return(true);
            },
                                           (actorDoc) => actorDoc.RemoveRole(id),
                                           onActorNotFound,
                                           this.azureStorageRepository);

            return(await rollback.ExecuteAsync(onSuccess));
        }
 public static Task <TResult> Transaction <TResult>(Func <RollbackAsync <TResult>, AzureStorageRepository, Func <TResult> > onConnected)
 {
     return(AzureStorageRepository.Connection(
                connection =>
     {
         var rollback = new RollbackAsync <TResult>();
         var onSuccess = onConnected(rollback, connection);
         return rollback.ExecuteAsync(onSuccess);
     }));
 }
Beispiel #11
0
        public static void AddTaskCreateOrUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                                        Guid docId, string partitionKey,
                                                                        Func <bool, TDocument, bool> isMutated,
                                                                        Action <TDocument> mutateRollback,
                                                                        AzureStorageRepository repo)
            where TDocument : class, ITableEntity
        {
            rollback.AddTask(
                (success, failure) =>
            {
                return(repo.CreateOrUpdateAsync <TDocument, RollbackAsync <TRollback> .RollbackResult>(docId, partitionKey,
                                                                                                       async(created, doc, save) =>
                {
                    if (!isMutated(created, doc))
                    {
                        return success(
                            async() =>
                        {
                            if (created)
                            {
                                await repo.DeleteAsync(doc,
                                                       () => true,
                                                       () => false);
                            }
                        });
                    }

                    await save(doc);
                    return success(
                        async() =>
                    {
                        if (created)
                        {
                            await repo.DeleteIfAsync <TDocument, bool>(docId,
                                                                       async(docDelete, delete) =>
                            {
                                // TODO: Check etag if(docDelete.ET)
                                await delete();
                                return true;
                            },
                                                                       () => false);
                            return;
                        }
                        await repo.UpdateAsync <TDocument, bool>(docId,
                                                                 async(docRollback, saveRollback) =>
                        {
                            mutateRollback(docRollback);
                            await saveRollback(docRollback);
                            return true;
                        },
                                                                 () => false);
                    });
                }));
            });
        }
Beispiel #12
0
 public static void AddTaskCheckup <TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                          Guid docId,
                                                          Func <TRollback> onDoesNotExists,
                                                          AzureStorageRepository repo)
     where TDocument : class, ITableEntity
 {
     rollback.AddTask(
         async(success, failure) =>
     {
         return(await repo.FindByIdAsync(docId,
                                         (TDocument doc) => success(() => 1.ToTask()), () => failure(onDoesNotExists())));
     });
 }
Beispiel #13
0
        public static void AddTaskAsyncCreateOrUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                                             Guid docId,
                                                                             Func <TDocument, Task <bool> > isValidAndMutate,
                                                                             Func <TDocument, Task <bool> > mutateRollback,
                                                                             Func <TRollback> onFail,
                                                                             AzureStorageRepository repo)
            where TDocument : class, ITableEntity
        {
            rollback.AddTask(
                (success, failure) =>
            {
                return(repo.CreateOrUpdateAsync <TDocument, RollbackAsync <TRollback> .RollbackResult>(docId,
                                                                                                       async(created, doc, save) =>
                {
                    if (!await isValidAndMutate(doc))
                    {
                        return failure(onFail());
                    }

                    await save(doc);
                    return success(
                        async() =>
                    {
                        if (created)
                        {
                            await repo.DeleteIfAsync <TDocument, bool>(docId,
                                                                       async(docDelete, delete) =>
                            {
                                // TODO: Check etag if(docDelete.ET)
                                await delete();
                                return true;
                            },
                                                                       () => false);
                            return;
                        }
                        await repo.UpdateAsync <TDocument, bool>(docId,
                                                                 async(docRollback, saveRollback) =>
                        {
                            if (await mutateRollback(docRollback))
                            {
                                await saveRollback(docRollback);
                            }
                            return true;
                        },
                                                                 () => false);
                    });
                }));
            });
        }
Beispiel #14
0
        public static void AddTaskAsyncUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                                     Guid docId,
                                                                     Func <TDocument, Task <bool> > mutateUpdate,
                                                                     Func <TDocument, Task> mutateRollback,
                                                                     Func <TRollback> onNotFound,
                                                                     AzureStorageRepository repo)
            where TDocument : class, ITableEntity
        {
            rollback.AddTask(
                async(success, failure) =>
            {
                var r = await repo.UpdateAsync <TDocument, int>(docId,
                                                                async(doc, save) =>
                {
                    if (!await mutateUpdate(doc))
                    {
                        return(1);
                    }
                    await save(doc);
                    return(0);
                },
                                                                () => - 1);
                if (r == 0)
                {
                    return(success(
                               async() =>
                    {
                        await repo.UpdateAsync <TDocument, bool>(docId,
                                                                 async(doc, save) =>
                        {
                            await mutateRollback(doc);
                            await save(doc);
                            return true;
                        },
                                                                 () => false);
                    }));
                }
                if (r == 1)
                {
                    return(success(() => true.ToTask()));
                }

                return(failure(onNotFound()));
            });
        }
Beispiel #15
0
        public async Task <TResult> CreateOrUpdateAsync <TResult>(Guid actorId, Guid claimId, string type, string value,
                                                                  Func <TResult> onSuccess,
                                                                  Func <TResult> onFailure,
                                                                  Func <TResult> onActorNotFound)
        {
            return(await await repository.FindLinkedDocumentsAsync <ActorMappingsDocument, ClaimDocument, Task <TResult> >(actorId,
                                                                                                                           (ActorMappingsDocument actorMappingsDocument) => actorMappingsDocument.Claims.ToGuidsFromByteArray(),
                                                                                                                           async (ActorMappingsDocument actorMappingsDocument, ClaimDocument[] claimDocuments) =>
            {
                var claimDocs =
                    claimDocuments.Where(
                        doc => string.Compare(doc.Type, type, StringComparison.OrdinalIgnoreCase) == 0)
                    .ToArray();
                if (claimDocs.Length >= 1)
                {
                    var claimDoc = claimDocs[0];
                    return await repository.UpdateAsync <ClaimDocument, TResult>(claimDoc.ClaimId,
                                                                                 async(currentDoc, saveAsync) =>
                    {
                        currentDoc.Value = value;
                        await saveAsync(currentDoc);
                        return onSuccess();
                    },
                                                                                 () => onFailure());
                }

                var rollback = new RollbackAsync <TResult>();
                var newClaimDoc = new ClaimDocument()
                {
                    ClaimId = claimId,
                    Issuer = actorId.ToString("N"),     //TODO - Is this is the correct issuer data???
                    Type = type,
                    Value = value
                };
                rollback.AddTaskCreate(claimId, newClaimDoc, onFailure, repository);
                rollback.AddTaskUpdate(actorId,
                                       (ActorMappingsDocument actorMapDocument) => actorMapDocument.AddClaim(claimId),
                                       (actorMapDocument) => actorMapDocument.RemoveClaim(claimId),
                                       onActorNotFound, repository);
                return await rollback.ExecuteAsync(onSuccess);
            },
                                                                                                                           () => onActorNotFound().ToTask()));
        }
Beispiel #16
0
 public static void AddTaskUpdate <T, TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                            Guid docId,
                                                            Func <
                                                                TDocument,
                                                                Func <T, UpdateCallback <T> >, // Save + Success
                                                                Func <UpdateCallback <T> >,    // No Save + Success
                                                                UpdateCallback <T> > mutateUpdate,
                                                            Func <T, TDocument, bool> mutateRollback,
                                                            Func <TRollback> onNotFound,
                                                            AzureStorageRepository repo)
     where TDocument : class, ITableEntity
 {
     rollback.AddTaskUpdate(docId,
                            (doc, save, successNoSave, fail) =>
                            mutateUpdate(doc, save, successNoSave),
                            mutateRollback,
                            "This version of update does not support a failure case".AsFunctionException <TRollback>(), // should never happen
                            onNotFound,
                            repo);
 }
Beispiel #17
0
 public static void AddTaskCreate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                         Guid docId, string partitionKey, TDocument document,
                                                         Func <TRollback> onAlreadyExists,
                                                         AzureStorageRepository repo)
     where TDocument : class, ITableEntity
 {
     rollback.AddTask(
         async(success, failure) =>
     {
         return(await repo.CreateAsync(docId, partitionKey, document,
                                       () => success(
                                           async() =>
         {
             await repo.DeleteIfAsync <TDocument, bool>(docId, partitionKey,
                                                        async(doc, delete) => { await delete(); return true; },
                                                        () => false);
         }),
                                       () => failure(onAlreadyExists())));
     });
 }
Beispiel #18
0
 public static void AddTaskUpdate <T, TRollback, TDocument>(this RollbackAsync <T, TRollback> rollback,
                                                            Guid docId,
                                                            Func <TDocument, T> mutateUpdate,
                                                            Func <T, TDocument, bool> mutateRollback,
                                                            Func <T> ifNotFound,
                                                            AzureStorageRepository repo)
     where TDocument : class, ITableEntity
 {
     rollback.AddTask(
         async(success, failure) =>
     {
         var r = await repo.UpdateAsync <TDocument, Carry <T>?>(docId,
                                                                async(doc, save) =>
         {
             var carry = mutateUpdate(doc);
             await save(doc);
             return(new Carry <T>
             {
                 carry = carry,
             });
         },
                                                                () => default(Carry <T>?));
         if (r.HasValue)
         {
             return(success(r.Value.carry,
                            async() =>
             {
                 await repo.UpdateAsync <TDocument, bool>(docId,
                                                          async(doc, save) =>
                 {
                     mutateRollback(r.Value.carry, doc);
                     await save(doc);
                     return true;
                 },
                                                          () => false);
             }));
         }
         return(success(ifNotFound(), () => ((object)null).ToTask()));
     });
 }
Beispiel #19
0
 public static void AddTaskUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                         Guid docId,
                                                         Func <
                                                             TDocument,
                                                             Func <UpdateCallback <bool> >, // Save + Success
                                                             Func <UpdateCallback <bool> >, // No Save + Success
                                                             Func <UpdateCallback <bool> >, // Reject
                                                             UpdateCallback <bool> > mutateUpdate,
                                                         Func <TDocument, bool> mutateRollback,
                                                         Func <TRollback> onMutateRejected,
                                                         Func <TRollback> onNotFound,
                                                         AzureStorageRepository repo)
     where TDocument : class, ITableEntity
 {
     rollback.AddTaskUpdate <bool, TRollback, TDocument>(docId,
                                                         (doc, save, successNoSave, reject) => mutateUpdate(doc,
                                                                                                            () => save(true),
                                                                                                            () => successNoSave(),
                                                                                                            () => reject()),
                                                         (throwAway, doc) => { mutateRollback(doc); return(true); },
                                                         onMutateRejected,
                                                         onNotFound,
                                                         repo);
 }
Beispiel #20
0
        public static void AddTaskUpdate <T, TRollback, TDocument>(this RollbackAsync <TRollback> rollback,
                                                                   Guid docId,
                                                                   Func <
                                                                       TDocument,
                                                                       Func <T, UpdateCallback <T> >, // Save + Success
                                                                       Func <UpdateCallback <T> >,    // No Save + Success
                                                                       Func <UpdateCallback <T> >,    // Reject
                                                                       UpdateCallback <T> > mutateUpdate,
                                                                   Func <T, TDocument, bool> mutateRollback,
                                                                   Func <TRollback> onMutateRejected,
                                                                   Func <TRollback> onNotFound,
                                                                   AzureStorageRepository repo)
            where TDocument : class, ITableEntity
        {
            rollback.AddTask(
                async(success, failure) =>
            {
                var r = await repo.UpdateAsync <TDocument, UpdateCallback <T> >(docId,
                                                                                async(doc, save) =>
                {
                    var passThrough = mutateUpdate(doc,
                                                   (passThroughSuccess) => UpdateCallback <T> .Save(passThroughSuccess),
                                                   () => UpdateCallback <T> .SuccessNoSave(),
                                                   () => UpdateCallback <T> .Reject());
                    if (passThrough.save)
                    {
                        await save(doc);
                    }
                    return(passThrough);
                },
                                                                                () => UpdateCallback <T> .NotFound());

                if (!r.found)
                {
                    return(failure(onNotFound()));
                }
                if (!r.success)
                {
                    return(failure(onMutateRejected()));
                }

                return(success(
                           async() =>
                {
                    if (r.save)
                    {
                        await repo.UpdateAsync <TDocument, bool>(docId,
                                                                 async(doc, save) =>
                        {
                            if (mutateRollback(r.t, doc))
                            {
                                await save(doc);
                            }
                            return true;
                        },
                                                                 () => false);
                    }

                    // If this was not saved, there is no reason to do anything on the rollback
                }));
            });
        }
Beispiel #21
0
        internal async Task <TResult> CreateCredentialMappingAsync <TResult>(Guid credentialMappingId,
                                                                             Guid loginId, Guid actorId, string email, Guid token, DateTime lastSent, bool isToken, bool overrideLoginId,
                                                                             Func <TResult> onSuccess,
                                                                             Func <TResult> onAlreadyExists,
                                                                             Func <TResult> onTokenAlreadyInUse,
                                                                             Func <TResult> onLoginAlreadyInUse)
        {
            var rollback = new RollbackAsync <TResult>();

            var inviteDocument = new Documents.InviteDocument()
            {
                ActorId  = actorId,
                Email    = email,
                IsToken  = isToken,
                LastSent = lastSent,
                Token    = token,
                LoginId  = loginId,
            };

            rollback.AddTaskCreate(credentialMappingId, inviteDocument, onAlreadyExists, this.repository);

            var inviteTokenDocument = new Documents.InviteTokenDocument()
            {
                ActorId  = actorId,
                InviteId = credentialMappingId,
            };

            rollback.AddTaskCreate(token, inviteTokenDocument, onTokenAlreadyInUse, this.repository);

            if (overrideLoginId)
            {
                var oldActorId = default(Guid);
                rollback.AddTaskCreateOrUpdate(loginId,
                                               (Documents.LoginActorLookupDocument loginActorDocument) =>
                {
                    oldActorId = loginActorDocument.ActorId;
                    loginActorDocument.ActorId = actorId;
                    return(true);
                },
                                               (loginActorDocument) =>
                {
                    loginActorDocument.ActorId = oldActorId;
                    return(true);
                },
                                               () => { throw new Exception("Login override failed"); }, // Should never happend because always return true on mutate
                                               this.repository);
            }
            else
            {
                var loginActorDocument = new Documents.LoginActorLookupDocument()
                {
                    ActorId = actorId,
                };
                rollback.AddTaskCreate(loginId, loginActorDocument, onLoginAlreadyInUse, this.repository);
            }

            rollback.AddTaskCreateOrUpdate(actorId,
                                           (Documents.ActorMappingsDocument authDoc) => authDoc.AddInviteId(credentialMappingId),
                                           (authDoc) => authDoc.RemoveInviteId(credentialMappingId),
                                           onAlreadyExists, // This should fail on the action above as well
                                           this.repository);

            return(await rollback.ExecuteAsync(onSuccess));
        }
        public static async Task <TResult> AddJoinAsync <TJoin, TDocJoin, TDoc1, TDoc2, TResult>(this AzureStorageRepository repo,
                                                                                                 Guid id, Guid id1, Guid id2, TDocJoin document,
                                                                                                 Func <TDoc1, TJoin[]> getJoins1,
                                                                                                 Func <TDoc2, TJoin[]> getJoins2,
                                                                                                 Func <TJoin, Guid> id1FromJoin,
                                                                                                 Func <TJoin, Guid> id2FromJoin,
                                                                                                 Action <TDoc1> mutateUpdate1,
                                                                                                 Action <TDoc1> mutateRollback1,
                                                                                                 Action <TDoc2> mutateUpdate2,
                                                                                                 Action <TDoc2> mutateRollback2,
                                                                                                 Func <TResult> onSuccess,
                                                                                                 Func <TResult> joinIdAlreadyExist,
                                                                                                 Func <TJoin, TResult> joinAlreadyExist,
                                                                                                 Func <TResult> doc1DoesNotExist,
                                                                                                 Func <TResult> doc2DoesNotExist)
            where TDocJoin : class, ITableEntity
            where TDoc1 : class, ITableEntity
            where TDoc2 : class, ITableEntity
        {
            var parallel = new RollbackAsync <TResult>();

            var duplicateJoin1 = default(TJoin);

            parallel.AddTaskUpdate <Guid, TResult, TDoc1>(id1,
                                                          (doc, successSave, successNoSave, reject) =>
            {
                var matches = getJoins1(doc).Where(join => id2FromJoin(join) == id2).ToArray();
                if (matches.Length > 0)
                {
                    duplicateJoin1 = matches[0];
                    return(reject());
                }
                mutateUpdate1(doc);
                return(successSave(id1));
            },
                                                          (id1Again, doc) => { mutateRollback1(doc); return(true); },
                                                          () => joinAlreadyExist(duplicateJoin1),
                                                          doc1DoesNotExist,
                                                          repo);

            var duplicateJoin2 = default(TJoin);

            parallel.AddTaskUpdate <Guid, TResult, TDoc2>(id2,
                                                          (doc, successSave, successNoSave, reject) =>
            {
                var matches = getJoins2(doc).Where(join => id1FromJoin(join) == id1).ToArray();
                if (matches.Length > 0)
                {
                    duplicateJoin2 = matches[0];
                    return(reject());
                }
                mutateUpdate2(doc);
                return(successSave(id2));
            },
                                                          (id1Again, doc) => { mutateRollback2(doc); return(true); },
                                                          () => joinAlreadyExist(duplicateJoin2),
                                                          doc2DoesNotExist,
                                                          repo);

            //parallel.AddTaskUpdate(id2,
            //    mutateUpdate2,
            //    mutateRollback2,
            //    doc2DoesNotExist,
            //    repo);

            parallel.AddTaskCreate(id, document,
                                   () => joinIdAlreadyExist(),
                                   repo);

            var result = await parallel.ExecuteAsync(
                () => onSuccess(),
                (failureResult) => failureResult);

            return(result);
        }
        internal static Task <TResult> CreateAsync <TResult>(Guid processId,
                                                             Guid processStageId,
                                                             Guid actorId, Guid resourceId, Type resourceType, DateTime createdOn,
                                                             Process.ProcessStageResource[] resources,
                                                             Guid?previousStepId, DateTime?confirmedWhen, Guid?confirmedBy,
                                                             Guid [] lookupActorIds,
                                                             Func <TResult> onSuccess,
                                                             Func <TResult> onAlreadyExists)
        {
            return(AzureStorageRepository.Connection(
                       azureStorageRepository =>
            {
                var rollback = new RollbackAsync <TResult>();

                var resourceTypeString = resourceType.AssemblyQualifiedName;
                var processDocument = new ProcessDocument()
                {
                    ProcessStage = processStageId,

                    Resource = resourceId,
                    ResourceType = resourceTypeString,
                    CreatedOn = createdOn,
                    Owner = actorId,

                    ConfirmedBy = confirmedBy,
                    PreviousStep = previousStepId,
                    ConfirmedWhen = confirmedWhen,
                };
                processDocument.SetResources(resources);
                rollback.AddTaskCreate(processId, processDocument,
                                       onAlreadyExists, azureStorageRepository);

                foreach (var lookupActorId in lookupActorIds.Distinct())
                {
                    rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStepActorLookupDocument>(lookupActorId, resourceTypeString,
                                                                                                       (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processId),
                                                                                                       actorDoc => actorDoc.RemoveLookupDocumentId(processId),
                                                                                                       azureStorageRepository);
                }

                rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStepResourceLookupDocument>(resourceId, resourceTypeString,
                                                                                                      (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processId),
                                                                                                      actorDoc => actorDoc.RemoveLookupDocumentId(processId),
                                                                                                      azureStorageRepository);

                bool[] updates = resources
                                 .Select(
                    resource =>
                {
                    if (!resource.resourceId.HasValue)
                    {
                        return true;
                    }
                    rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStepResourceKeyLookupDocument>(
                        resource.resourceId.Value, resource.type.AssemblyQualifiedName,
                        (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processId),
                        lookupDoc => lookupDoc.RemoveLookupDocumentId(processId),
                        azureStorageRepository);
                    return true;
                })
                                 .ToArray();

                return rollback.ExecuteAsync(onSuccess);
            }));
        }
Beispiel #24
0
        public static async Task <TRollback> ExecuteDeleteJoinAsync <TRollback, TDocument>(this RollbackAsync <Guid?, TRollback> rollback,
                                                                                           Func <TRollback> onSuccess,
                                                                                           AzureStorageRepository repo)
            where TDocument : class, ITableEntity
        {
            var result = await await rollback.ExecuteAsync <Task <TRollback> >(
                async (joinIds) =>
            {
                var joinId = joinIds.First(joinIdCandidate => joinIdCandidate.HasValue);
                if (!joinId.HasValue)
                {
                    return(onSuccess());
                }
                return(await repo.DeleteIfAsync <TDocument, TRollback>(joinId.Value,
                                                                       async(doc, delete) =>
                {
                    await delete();
                    return onSuccess();
                },
                                                                       () =>
                {
                    // TODO: Log data inconsistency
                    return onSuccess();
                }));
            },
                (failureResult) => failureResult.ToTask());

            return(result);
        }
Beispiel #25
0
 public static async Task <TRollback> ExecuteAsync <TRollback>(this RollbackAsync <TRollback> rollback,
                                                               Func <TRollback> onSuccess)
 {
     return(await rollback.ExecuteAsync(onSuccess, r => r));
 }