/// <summary>
        /// Sends notification to team members when project is closed.
        /// </summary>
        /// <param name="closeProjectModel">CloseProjectModel model containing project closure metadata.</param>
        /// <param name="projectTitle">Title of the project.</param>
        /// <param name="projectOwnerName">Owner of the project.</param>
        /// <returns>A Task representing notification sent to all members in project.</returns>
        public async Task SendProjectClosureNotificationAsync(
            CloseProjectModel closeProjectModel,
            string projectTitle,
            string projectOwnerName)
        {
            closeProjectModel = closeProjectModel ?? throw new ArgumentNullException(nameof(closeProjectModel));

            foreach (var participant in closeProjectModel.ProjectParticipantDetails)
            {
                List <string> acquiredSkills = participant.AcquiredSkills.Split(new char[] { ';' }, System.StringSplitOptions.RemoveEmptyEntries).ToList();
                var           adaptiveCard   = MessageFactory.Attachment(UserNotificationCard.SendProjectClosureCard(
                                                                             projectTitle,
                                                                             projectOwnerName,
                                                                             this.botOptions.Value.ManifestId,
                                                                             participant.Feedback,
                                                                             acquiredSkills,
                                                                             this.localizer));

                var userDetails = await this.userDetailProvider.GetUserDetailsAsync(participant.UserId);

                if (userDetails != null)
                {
                    await this.SendNotificationAsync(
                        userDetails.UserConversationId,
                        adaptiveCard,
                        userDetails.ServiceUrl);
                }
            }
        }
Beispiel #2
0
        public async Task <IActionResult> CloseProjectAsync(CloseProjectModel closeProjectModel)
        {
            this.logger.LogInformation("call to close a project.");

            try
            {
                if (closeProjectModel == null)
                {
                    this.logger.LogError("Close project details is null or empty.");
                    return(this.BadRequest("Close project details is null or empty."));
                }

                if (string.IsNullOrEmpty(closeProjectModel.ProjectId))
                {
                    this.logger.LogError("ProjectId is found null or empty while closing the project.");
                    return(this.BadRequest("ProjectId cannot be null or empty."));
                }

                var projectDetails = await this.projectStorageProvider.GetProjectAsync(this.UserAadId, closeProjectModel.ProjectId);

                // Only projects with 'Active' status are allowed to close.
                if (projectDetails == null || projectDetails.IsRemoved || projectDetails.Status != (int)ProjectStatus.Active)
                {
                    this.logger.LogError($"Project {closeProjectModel.ProjectId} does not exists.");
                    this.RecordEvent("Close project - HTTP Post call failed");

                    return(this.NotFound($"Project does not exists or only projects with 'Active' status are allowed to close."));
                }

                // Check if any participants has joined project
                if (!string.IsNullOrEmpty(projectDetails.ProjectParticipantsUserIds))
                {
                    // Get participants
                    var projectMembers = projectDetails.ProjectParticipantsUserIds.Split(';');
                    List <ProjectParticipantModel> projectParticipants = new List <ProjectParticipantModel>();

                    // If client app fails to send participants list with acquired skills return bad request error.
                    if (closeProjectModel.ProjectParticipantDetails == null)
                    {
                        this.logger.LogInformation($"Project participants for project {projectDetails.ProjectId} does not exists while changing status to closed.");
                        return(this.BadRequest("Project participants does not exists."));
                    }

                    foreach (var participant in closeProjectModel.ProjectParticipantDetails)
                    {
                        if (projectMembers.Contains(participant.UserId))
                        {
                            projectParticipants.Add(participant);
                        }
                    }

                    // Save user acquired skills for a project in storage for all user's who joined this project.
                    foreach (var participant in projectParticipants)
                    {
                        var acquiredSkillEntity = new AcquiredSkillsEntity()
                        {
                            ProjectId         = projectDetails.ProjectId,
                            UserId            = participant.UserId,
                            AcquiredSkills    = participant.AcquiredSkills,
                            CreatedDate       = DateTime.UtcNow,
                            Feedback          = participant.Feedback,
                            ProjectClosedDate = DateTime.UtcNow,
                            ProjectOwnerName  = projectDetails.CreatedByName,
                            ProjectTitle      = projectDetails.Title,
                        };

                        // Save user acquired skills for a project in storage for all user's who joined this project.
                        var updatedSkillResult = await this.acquiredSkillStorageProvider.UpsertAcquiredSkillAsync(acquiredSkillEntity);

                        if (updatedSkillResult)
                        {
                            this.logger.LogInformation($"User: {participant.UserId} skills added successfully.");
                        }
                        else
                        {
                            this.logger.LogInformation($"Error while adding skills for a user: {participant.UserId}.");
                        }
                    }
                }

                projectDetails.ProjectClosedDate = DateTime.UtcNow;
                projectDetails.Status            = (int)ProjectStatus.Closed;

                // The current implementation leverages Azure table storage to map use skills and after successful execution marks the project status as closed.
                // Azure table storage do not support transactions and in case of failure while updating the skills, the user can re-trigger close operation and already added skills of user will be updated.
                // In case of partial failure in updating the skills and if project status is not updated as closed, still Participants whose skills are updated successfully, will be able to see the acquired skills in tab.
                var isProjectClosed = await this.projectStorageProvider.UpdateProjectAsync(projectDetails);

                if (isProjectClosed)
                {
                    await this.projectSearchService.RunIndexerOnDemandAsync();

                    this.RecordEvent("Closed project - HTTP Get call succeeded.");
                    this.logger.LogInformation($"Project {projectDetails.ProjectId} closed successfully.");

                    // Send notification to users on project closure.
                    await this.notificationHelper.SendProjectClosureNotificationAsync(
                        closeProjectModel,
                        projectDetails.Title,
                        projectDetails.CreatedByName);

                    return(this.Ok(isProjectClosed));
                }
                else
                {
                    this.logger.LogInformation($"Error while closing the project {projectDetails.ProjectId}.");
                }

                return(this.Ok(false));
            }
            catch (Exception ex)
            {
                this.RecordEvent($"Error while closing project by user {this.UserAadId}.");
                this.logger.LogError(ex, $"Error while closing project by user {this.UserAadId}.");
                throw;
            }
        }