public async Task <ActionResult <ReportingCase> > GetCaseItem(int?id)
        {
            if (id == null)
            {
                return(NotFound());
            }
            // get the reporting case
            ReportingCase repCase = await _context.ReportingCases
                                    .Include(rc => rc.Comments)
                                    .Include(rc => rc.CaseItems)
                                    .Include(rc => rc.ConcernedAgencies)
                                    .SingleOrDefaultAsync(rc => rc.Id == id);

            if (repCase == default)
            {
                return(NotFound());
            }
            // get the logged in user id
            string currUserId = _userManager.GetUserId(User);
            // check if user is admin
            bool isCurrUserAdmin = User.IsInRole(SecurityConstants.AdminRoleString);

            // check if user is not authorized to see the case
            if (!(isCurrUserAdmin || repCase.ConcernedAgencies.Any(ca => ca.UserId == currUserId) || repCase.CreatedById == currUserId))
            {
                return(Unauthorized());
            }
            return(repCase);
        }
        public async Task <IActionResult> Edit(int?id)
        {
            // get the reporting case
            ReportingCase repCase = await _context.ReportingCases.Include(rc => rc.ConcernedAgencies)
                                    .ThenInclude(ca => ca.User)
                                    .Include(rc => rc.CaseItems)
                                    .SingleOrDefaultAsync(rc => rc.Id == id);

            ReportingCaseEditVM vm = new ReportingCaseEditVM
            {
                DownTime          = repCase.DownTime,
                CaseItems         = repCase.CaseItems,
                ResolutionTime    = repCase.ResolutionTime,
                ConcernedAgencies = repCase.ConcernedAgencies
            };

            if (repCase.ConcernedAgencies.Count > 0)
            {
                vm.ConcernedAgencyId = repCase.ConcernedAgencies[0].UserId;
            }
            var userList = await _context.Users.ToListAsync();

            ViewData["userId"] = new SelectList(userList, nameof(IdentityUser.Id), nameof(IdentityUser.UserName));
            ViewBag.caseId     = id;
            return(View(vm));
        }
        public async Task <IActionResult> AddAttachement([FromForm] CaseAttachmentFormModel caseAttachmentInfo)
        {
            // get the reporting case
            ReportingCase repCase = await _context.ReportingCases.SingleOrDefaultAsync(rc => rc.Id == caseAttachmentInfo.Id);

            if (repCase == default)
            {
                return(NotFound());
            }
            // get the logged in user id
            string currUserId = _userManager.GetUserId(User);
            // check if user is admin
            bool isCurrUserAdmin = User.IsInRole(SecurityConstants.AdminRoleString);

            // check if requesting user is creator / concerned agency for authorizing issue editing
            if (!(isCurrUserAdmin || repCase.CreatedById == currUserId))
            {
                return(Unauthorized());
            }
            // Getting Attachment
            IFormFile attachment = caseAttachmentInfo.CaseAttachment;

            // Saving attachment on Server
            if (attachment.Length > 0)
            {
                // create a new filename with timestamp
                string attachmentPath = $"{DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss")}_{Guid.NewGuid()}{Path.GetExtension(attachment.FileName)}";
                string filePath       = Path.Combine(_folderPaths.AttachmentsFolder, attachmentPath);
                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    attachment.CopyTo(fileStream);
                    repCase.AttachmentName = attachment.FileName;
                    repCase.AttachmentPath = attachmentPath;
                }
            }
            try
            {
                _context.Update(repCase);
                await _context.SaveChangesAsync();

                return(Ok());
            }
            catch (DbUpdateConcurrencyException)
            {
                // check if the we are trying to edit was already deleted due to concurrency
                if (!_context.ReportingCases.Any(rc => rc.Id == caseAttachmentInfo.Id))
                {
                    return(NotFound());
                }
                else
                {
                    throw;
                }
            }
        }
        public async Task <IActionResult> DeleteAttachement([FromRoute] int?id)
        {
            if (id == null)
            {
                return(NotFound());
            }
            // get the reporting case
            ReportingCase repCase = await _context.ReportingCases.SingleOrDefaultAsync(rc => rc.Id == id);

            if (repCase == default)
            {
                return(NotFound());
            }
            // get the logged in user id
            string currUserId = _userManager.GetUserId(User);
            // check if user is admin
            bool isCurrUserAdmin = User.IsInRole(SecurityConstants.AdminRoleString);

            // check if requesting user is creator / concerned agency for authorizing issue editing
            if (!(isCurrUserAdmin || repCase.CreatedById == currUserId))
            {
                return(Unauthorized());
            }
            repCase.AttachmentName = null;
            repCase.AttachmentPath = null;
            //todo delete file from storage
            try
            {
                _context.Update(repCase);
                await _context.SaveChangesAsync();

                return(Ok());
            }
            catch (DbUpdateConcurrencyException)
            {
                // check if the we are trying to edit was already deleted due to concurrency
                if (!_context.ReportingCases.Any(rc => rc.Id == id))
                {
                    return(NotFound());
                }
                else
                {
                    throw;
                }
            }
        }
        public async Task <ActionResult> AddCaseComment([FromRoute] int?id, [FromBody] CommentAddFormModel vm)
        {
            if (id == null)
            {
                return(NotFound());
            }
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }
            // get the reporting case
            ReportingCase repCase = await _context.ReportingCases.Include(rc => rc.ConcernedAgencies)
                                    .Include(rc => rc.CreatedBy)
                                    .Include(rc => rc.Comments).ThenInclude(co => co.CreatedBy)
                                    .Include(rc => rc.Comments).ThenInclude(co => co.LastModifiedBy)
                                    .Include(rc => rc.ConcernedAgencies).ThenInclude(ca => ca.User)
                                    .SingleOrDefaultAsync(rc => rc.Id == id);

            if (repCase == default)
            {
                return(NotFound());
            }
            // get the logged in user id
            string currUserId = _userManager.GetUserId(User);
            // check if user is admin
            bool isCurrUserAdmin = User.IsInRole(SecurityConstants.AdminRoleString);

            // check if user is not authorized to see the case
            if (!(isCurrUserAdmin || repCase.ConcernedAgencies.Any(ca => ca.UserId == currUserId) || repCase.CreatedById == currUserId))
            {
                return(Unauthorized());
            }

            // get the latest comment
            ReportingCaseComment latestComment = repCase.Comments.OrderByDescending(co => co.Created).FirstOrDefault();

            if (latestComment != default && latestComment.Tag.Equals(CommentTag.Closed))
            {
                // issue is closed in this block
                // check if admin user is trying to re open issue
                if (!vm.Tag.Equals(CommentTag.Reopened))
                {
                    return(BadRequest($"This issue with id {id} is already closed"));
                }
            }
            else
            {
                // issue is open in this block
                if (vm.Tag.Equals(CommentTag.Reopened))
                {
                    return(BadRequest("We can only reopen a closed issue"));
                }
                //if (vm.Tag.Equals(CommentTag.Closed))
                //{
                //    if (!isCurrUserAdmin)
                //    {
                //        return BadRequest("Only admin can close an issue");
                //    }
                //}
            }

            // add new comment
            ReportingCaseComment newComm = new ReportingCaseComment()
            {
                Comment = vm.Comment, Tag = vm.Tag, ReportingCaseId = repCase.Id
            };

            _context.ReportingCaseComments.Add(newComm);
            await _context.SaveChangesAsync();

            return(Ok(newComm));
        }
        public async Task <ActionResult <ReportingCase> > EditCaseItem(int?id, [FromBody] ReportingCase vm)
        {
            if (id == null)
            {
                return(NotFound());
            }

            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            // get the reporting case
            ReportingCase repCase = await _context.ReportingCases.Include(rc => rc.ConcernedAgencies)
                                    .SingleOrDefaultAsync(rc => rc.Id == id);

            if (repCase == null)
            {
                return(NotFound());
            }

            // get the logged in user id
            string currUserId = _userManager.GetUserId(User);
            // check if user is admin
            bool isCurrUserAdmin = User.IsInRole(SecurityConstants.AdminRoleString);

            // check if requesting user is creator / concerned agency for authorizing issue editing
            if (!(isCurrUserAdmin || repCase.CreatedById == currUserId))
            {
                return(Unauthorized());
            }

            // update the reporting case
            repCase.ResolutionTime = vm.ResolutionTime;
            repCase.DownTime       = vm.DownTime;
            repCase.CaseItems      = vm.CaseItems;
            try
            {
                _context.Update(repCase);
                await _context.SaveChangesAsync();


                // get the concerned agency Ids
                List <ReportingCaseConcerned> existingconcernedAgencies = await _context.ReportingCaseConcerneds
                                                                          .Where(rcc => rcc.ReportingCaseId == id)
                                                                          .ToListAsync();

                foreach (ReportingCaseConcerned conAgency in existingconcernedAgencies)
                {
                    if (!vm.ConcernedAgencies.Any(ca => ca.UserId == conAgency.UserId))
                    {
                        //check if existing concerned agency is deleted
                        _context.ReportingCaseConcerneds.Remove(conAgency);
                        await _context.SaveChangesAsync();

                        IdentityUser user = await _context.Users.FindAsync(conAgency.UserId);

                        await _emailSender.SendEmailAsync(user.Email,
                                                          "WRLDC Issue alert",
                                                          $"Sir/Madam,<br>You are being removed from an issue with id <b>{repCase.Id}</b> in WRLDC issues portal." +
                                                          "<br><br>For kind information please<br><br>Regards<br>IT WRLDC");
                    }
                }

                foreach (ReportingCaseConcerned concernedAgency in vm.ConcernedAgencies)
                {
                    string concernedAgencyId = concernedAgency.UserId;
                    if (!existingconcernedAgencies.Any(ca => ca.UserId == concernedAgencyId))
                    {
                        // check if we need to add a new concerned agency
                        // _context.ReportingCaseConcerneds.Remove(conc);
                        // await _context.SaveChangesAsync();
                        ReportingCaseConcerned concerned = new ReportingCaseConcerned()
                        {
                            ReportingCaseId = repCase.Id,
                            UserId          = concernedAgencyId
                        };
                        _context.Add(concerned);
                        int numInserted = await _context.SaveChangesAsync();

                        IdentityUser user = await _context.Users.FindAsync(concernedAgencyId);

                        string caseDetail = String.Join("<br>", repCase.CaseItems.Select(ci => $"{ci.Question} - {ci.Response}").ToArray());
                        await _emailSender.SendEmailAsync(user.Email,
                                                          "WRLDC Issue alert",
                                                          $"Sir/Madam,<br>You are being associated with an issue with id <b>{repCase.Id}</b> in WRLDC issues portal." +
                                                          "<br><b>Issue Details</b>" +
                                                          $"<br>{caseDetail}" +
                                                          "<br><br>For kind information please<br><br>Regards<br>IT WRLDC");
                    }
                }
                return(Ok(repCase));
            }
            catch (DbUpdateConcurrencyException)
            {
                // check if the we are trying to edit was already deleted due to concurrency
                if (!_context.ReportingCases.Any(rc => rc.Id == id))
                {
                    return(NotFound());
                }
                else
                {
                    throw;
                }
            }
        }
        public async Task <IActionResult> Edit(int id, ReportingCaseEditVM vm)
        {
            if (ModelState.IsValid)
            {
                IdentityUser adminUser = await _userManager.FindByNameAsync("admin");

                // get the reporting case
                ReportingCase repCase = await _context.ReportingCases.Include(rc => rc.ConcernedAgencies)
                                        .SingleOrDefaultAsync(rc => rc.Id == id);

                if (repCase == null)
                {
                    return(NotFound());
                }
                // update the reporting case
                repCase.ResolutionTime = vm.ResolutionTime;
                repCase.DownTime       = vm.DownTime;
                repCase.CaseItems      = vm.CaseItems;
                try
                {
                    _context.Update(repCase);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    // check if the we are trying to edit was already deleted due to concurrency
                    if (!_context.ReportingCases.Any(ci => ci.Id == id))
                    {
                        return(NotFound());
                    }
                    else
                    {
                        throw;
                    }
                }

                // get the concerned agency Ids
                List <string> concernedUserIds = await _context.ReportingCaseConcerneds
                                                 .Where(rcc => rcc.ReportingCaseId == id)
                                                 .Select(rcc => rcc.UserId).ToListAsync();

                if (!concernedUserIds.Any(usr => usr == vm.ConcernedAgencyId))
                {
                    // check if we need to add a new concerned agency
                    // _context.ReportingCaseConcerneds.Remove(conc);
                    // await _context.SaveChangesAsync();
                    ReportingCaseConcerned concerned = new ReportingCaseConcerned()
                    {
                        ReportingCaseId = repCase.Id,
                        UserId          = vm.ConcernedAgencyId
                    };
                    _context.Add(concerned);
                    int numInserted = await _context.SaveChangesAsync();

                    IdentityUser user = await _context.Users.FindAsync(vm.ConcernedAgencyId);

                    string caseDetail = String.Join("<br>", repCase.CaseItems.Select(ci => $"{ci.Question} - {ci.Response}").ToArray());
                    await _emailSender.SendEmailAsync($"{user.Email};{adminUser.Email}",
                                                      "WRLDC Issue alert",
                                                      $"Sir/Madam,<br>You are being associated with an issue with id <b>{repCase.Id}</b> in WRLDC Issues portal." +
                                                      "<br><b>Issue Details</b>" +
                                                      $"<br>{caseDetail}" +
                                                      "<br><br>For kind information please<br><br>Regards<br>IT WRLDC");
                }

                return(RedirectToAction(nameof(Index)).WithSuccess("Issue Editing done"));
            }
            var userList = await _context.Users.ToListAsync();

            ViewData["userId"] = new SelectList(userList, nameof(IdentityUser.Id), nameof(IdentityUser.UserName));
            return(View(vm));
        }
        public async Task <IActionResult> Create(ReportingCaseCreateVM vm)
        {
            if (ModelState.IsValid)
            {
                // create a new case object
                ReportingCase newCase = new ReportingCase()
                {
                    DownTime = vm.DownTime
                };

                // add issue created by Information
                newCase.CreatedById = _userManager.GetUserId(User);
                // add case items from vm
                List <ReportingCaseItem> caseItems = new List <ReportingCaseItem>();
                for (int caseTemplIter = 0; caseTemplIter < vm.CaseItems.Count; caseTemplIter++)
                {
                    CaseItemTemplate caseItemTemplate = vm.CaseItems[caseTemplIter];
                    string           resp             = vm.Responses[caseTemplIter];
                    if (caseItemTemplate.ResponseType == ResponseType.ChoicesWithText)
                    {
                        resp = vm.ChoiceTexts[caseTemplIter] ?? resp;
                    }
                    ReportingCaseItem caseItem = new ReportingCaseItem()
                    {
                        SerialNum    = caseItemTemplate.SerialNum,
                        Question     = caseItemTemplate.Question,
                        ResponseType = caseItemTemplate.ResponseType,
                        Response     = resp
                    };
                    caseItems.Add(caseItem);
                }
                newCase.CaseItems = caseItems;

                // Getting Attachment
                IFormFile attachment = vm.Attachment;
                // Saving attachment on Server
                if (attachment != null && attachment.Length > 0)
                {
                    // create a new filename with timestamp
                    string attachmentPath = $"{DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss")}_{Guid.NewGuid()}{Path.GetExtension(attachment.FileName)}";
                    string filePath       = Path.Combine(_folderPaths.AttachmentsFolder, attachmentPath);
                    using (var fileStream = new FileStream(filePath, FileMode.Create))
                    {
                        attachment.CopyTo(fileStream);
                        newCase.AttachmentName = attachment.FileName;
                        newCase.AttachmentPath = attachmentPath;
                    }
                }
                _context.Add(newCase);
                int numInserted = await _context.SaveChangesAsync();

                if (numInserted >= 1)
                {
                    _logger.LogInformation("New Case created");
                    // insert each concerned agency
                    if (!string.IsNullOrWhiteSpace(vm.ConcernedAgencyId))
                    {
                        string caseDetail = String.Join("<br>", newCase.CaseItems.Select(ci => $"{ci.Question} - {ci.Response}").ToArray());
                        foreach (string concAgId in vm.ConcernedAgencyId.Split(","))
                        {
                            IdentityUser user = await _context.Users.FindAsync(concAgId);

                            ReportingCaseConcerned concerned = new ReportingCaseConcerned()
                            {
                                ReportingCaseId = newCase.Id,
                                UserId          = user.Id
                            };
                            _context.Add(concerned);
                            numInserted = await _context.SaveChangesAsync();

                            if (numInserted == 1)
                            {
                                _logger.LogInformation("New Case Concerned agency created");
                                await _emailSender.SendEmailAsync($"{user.Email}",
                                                                  "New Issue alert",
                                                                  $"Sir/Madam,<br>You are being associated with a new issue with id <b>{newCase.Id}</b> in WRLDC issues portal." +
                                                                  "<br><br><b>Issue Details</b>" +
                                                                  $"<br>{caseDetail}" +
                                                                  "<br><br>For kind information please<br><br>Regards<br>IT WRLDC");
                            }
                            else
                            {
                                string msg = $"New Case Concerned agency not created as db returned num insertions as {numInserted}";
                                _logger.LogInformation(msg);
                                //todo create custom exception
                                throw new Exception(msg);
                            }
                        }
                        return(RedirectToAction(nameof(Index)).WithSuccess("New Issue created"));
                    }
                }
                else
                {
                    string msg = $"New Case not created as db returned num insertions as {numInserted}";
                    _logger.LogInformation(msg);
                    //todo create custom exception
                    throw new Exception(msg);
                }
            }
            return(View(vm));
        }