Ejemplo n.º 1
0
        protected override async Task <List <int> > SaveExecuteAsync(List <AgentForSave> entities, ExpandExpression expand, bool returnIds)
        {
            var(blobsToDelete, blobsToSave, imageIds) = await ImageUtilities.ExtractImages <Agent, AgentForSave>(_repo, entities, BlobName);

            // Save the agents
            var ids = await _repo.Agents__Save(
                DefinitionId,
                entities : entities,
                imageIds : imageIds,
                returnIds : returnIds);

            // Delete the blobs retrieved earlier
            if (blobsToDelete.Any())
            {
                await _blobService.DeleteBlobsAsync(blobsToDelete);
            }

            // Save new blobs if any
            if (blobsToSave.Any())
            {
                await _blobService.SaveBlobsAsync(blobsToSave);
            }

            return(ids);
        }
Ejemplo n.º 2
0
 public async Task DeleteBlobsAsync(IEnumerable <string> blobNames)
 {
     await _blobService.DeleteBlobsAsync(blobNames);
 }
Ejemplo n.º 3
0
        protected override async Task <List <int> > SaveExecuteAsync(List <DocumentForSave> entities, ExpandExpression expand, bool returnIds)
        {
            var blobsToSave = new List <(string, byte[])>();

            // Prepare the list of attachments with extras
            var attachments = new List <AttachmentWithExtras>();

            foreach (var(doc, docIndex) in entities.Select((d, i) => (d, i)))
            {
                if (doc.Attachments != null)
                {
                    doc.Attachments.ForEach(att =>
                    {
                        var attWithExtras = new AttachmentWithExtras
                        {
                            Id            = att.Id,
                            FileName      = att.FileName,
                            FileExtension = att.FileExtension,
                            DocumentIndex = docIndex,
                        };

                        // If new attachment
                        if (att.Id == 0)
                        {
                            // Add extras: file Id and size
                            byte[] file          = att.File;
                            string fileId        = Guid.NewGuid().ToString();
                            attWithExtras.FileId = fileId;
                            attWithExtras.Size   = file.LongLength;

                            // Also add to blobsToCreate
                            string blobName = BlobName(fileId);
                            blobsToSave.Add((blobName, file));
                        }

                        attachments.Add(attWithExtras);
                    });
                }
            }

            // Save the documents
            var(ids, fileIdsToDelete) = await _repo.Documents__Save(
                DefinitionId,
                documents : entities,
                attachments : attachments,
                returnIds : returnIds);

            // Assign new documents to the current user
            var userInfo = await _repo.GetUserInfoAsync();

            var currentUserId = userInfo.UserId.Value;
            var newDocIds     = entities.Select((doc, index) => (doc, index)).Where(e => e.doc.Id == 0).Select(e => ids[e.index]);
            await _repo.Documents__Assign(newDocIds, currentUserId, null);

            // Delete the file Ids retrieved earlier if any
            if (fileIdsToDelete.Any())
            {
                var blobsToDelete = fileIdsToDelete.Select(fileId => BlobName(fileId));
                await _blobService.DeleteBlobsAsync(blobsToDelete);
            }

            // Save new blobs if any
            if (blobsToSave.Any())
            {
                await _blobService.SaveBlobsAsync(blobsToSave);
            }

            // Return the new Ids
            return(ids);
        }
Ejemplo n.º 4
0
        protected override async Task <List <int> > SaveExecuteAsync(List <UserForSave> entities, ExpandExpression expand, bool returnIds)
        {
            // NOTE: this method is not optimized for massive bulk (e.g. 1,000+ users), since it relies
            // on querying identity through UserManager one email at a time but it should be acceptable
            // with the usual workloads, customers with more than 200 users are rare anyways

            // Step (1) enlist the app repo
            _appRepo.EnlistTransaction(Transaction.Current); // So that it is not affected by admin trx scope later

            // Step (2): If Embedded Identity Server is enabled, create any emails that don't already exist there
            var usersToInvite = new List <(EmbeddedIdentityServerUser IdUser, UserForSave User)>();

            if (_options.EmbeddedIdentityServerEnabled)
            {
                _identityTrxScope = ControllerUtilities.CreateTransaction(TransactionScopeOption.RequiresNew);

                foreach (var entity in entities)
                {
                    var email = entity.Email;

                    // In case the user was added in a previous failed transaction
                    // or something, we always try to be forgiving in the code
                    var identityUser = await _userManager.FindByNameAsync(email) ??
                                       await _userManager.FindByEmailAsync(email);

                    // This is truly a new user, create it
                    if (identityUser == null)
                    {
                        // Create the identity user
                        identityUser = new EmbeddedIdentityServerUser
                        {
                            UserName       = email,
                            Email          = email,
                            EmailConfirmed = !_options.EmailEnabled

                                             // Note: If the system is integrated with an email service, user emails
                                             // are automatically confirmed, otherwise users must confirm their
                        };

                        var result = await _userManager.CreateAsync(identityUser);

                        if (!result.Succeeded)
                        {
                            string msg = string.Join(", ", result.Errors.Select(e => e.Description));
                            _logger.LogError(msg);

                            throw new BadRequestException($"An unexpected error occurred while creating an account for '{email}'");
                        }
                    }

                    // Mark for invitation later
                    if (!identityUser.EmailConfirmed)
                    {
                        usersToInvite.Add((identityUser, entity));
                    }
                }
            }

            // Step (3): Extract the images
            var(blobsToDelete, blobsToSave, imageIds) = await ImageUtilities.ExtractImages <User, UserForSave>(_appRepo, entities, BlobName);

            // Step (4): Save the users in the app database
            var ids = await _appRepo.Users__Save(entities, imageIds, returnIds);

            // Step (5): Delete old images from the blob storage
            if (blobsToDelete.Any())
            {
                await _blobService.DeleteBlobsAsync(blobsToDelete);
            }

            // Step (6): Save new images to the blob storage
            if (blobsToSave.Any())
            {
                await _blobService.SaveBlobsAsync(blobsToSave);
            }

            // Step (7) Same the emails in the admin database
            var tenantId = _tenantIdAccessor.GetTenantId();

            _adminTrxScope = ControllerUtilities.CreateTransaction(TransactionScopeOption.RequiresNew);
            _adminRepo.EnlistTransaction(Transaction.Current);
            var oldEmails = new List <string>(); // Emails are readonly after the first save
            var newEmails = entities.Where(e => e.Id == 0).Select(e => e.Email);
            await _adminRepo.GlobalUsers__Save(newEmails, oldEmails, tenantId);

            // Step (8): Send the invitation emails
            if (usersToInvite.Any()) // This will be empty if embedded identity is disabled or if email is disabled
            {
                var userIds       = usersToInvite.Select(e => e.User.Id).ToArray();
                var tos           = new List <string>();
                var subjects      = new List <string>();
                var substitutions = new List <Dictionary <string, string> >();
                foreach (var(idUser, user) in usersToInvite)
                {
                    // Add the email sender parameters
                    var(subject, body) = await MakeInvitationEmailAsync(idUser, user.Name, user.Name2, user.Name3, user.PreferredLanguage);

                    tos.Add(idUser.Email);
                    subjects.Add(subject);
                    substitutions.Add(new Dictionary <string, string> {
                        { "-message-", body }
                    });
                }

                await _emailSender.SendEmailBulkAsync(
                    tos : tos,
                    subjects : subjects,
                    htmlMessage : $"-message-",
                    substitutions : substitutions.ToList()
                    );
            }

            // Return the new Ids
            return(ids);
        }