// GET: Tickets public ActionResult Index(string scope) { // First, get this user... UserRolesHelper helper = new UserRolesHelper(); var userId = helper.GetCurrentUserId(); // Do this in every GET action... ViewBag.UserModel = ProjectsHelper.LoadUserModel(); if (string.IsNullOrEmpty(scope)) scope = "My"; ViewBag.Scope = scope; CheckCookies(); DateTimeOffset now = DateTimeOffset.UtcNow; DateTimeOffset start, end; switch (scope) { case "My": // Need to track all places where User could be attached to a ticket: // - as PM (then follow ticket chain) // - as Developer (follow ticket chain) // - as ticket creator // - as ticket commenter var myTickets = db.Users.Find(userId).TicketsAssigned .Union(db.Users.Find(userId).TicketsOwned); return View(myTickets.ToList()); case "All": // Come here for all tickets var allTickets = db.Tickets.Include(t => t.AssignedToDev).Include(t => t.OwnerUser).Include(t => t.Project).Include(t => t.SkillRequired).Include(t => t.TicketPriority).Include(t => t.TicketStatus).Include(t => t.TicketType); return View(allTickets.ToList()); case "NotAssigned": // Come here for all not yet assigned var notTickets = db.Tickets .Where(tic => tic.AssignedToDevId == null) .Include(t => t.AssignedToDev).Include(t => t.OwnerUser).Include(t => t.Project).Include(t => t.SkillRequired).Include(t => t.TicketPriority).Include(t => t.TicketStatus).Include(t => t.TicketType); return View(notTickets.ToList()); case "Problem": // Come here for tickets that don't look right (i.e., not assigned by status too low) DateTimeOffset oneYear = DateTimeOffset.UtcNow.AddYears(-1); var problems = db.Tickets .Where(tic => (tic.TicketStatus.Step <= 30 && tic.AssignedToDevId != null) || (tic.TicketStatus.Step >= 40 && tic.AssignedToDevId == null) || tic.DueDate == DateTimeOffset.MinValue || tic.HoursToComplete == 0 || tic.DueDate <= oneYear || tic.TicketStatusId == (int)TS.Status.Deferred || tic.TicketStatusId == (int)TS.Status.UnableToReproduce) .OrderByDescending(tic => tic.TicketStatusId).ThenBy(tic => tic.Id); return View(problems.ToList()); case "MyNew": var newTickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.TicketStatusId == (int)TS.Status.AssignedToDev); return View(newTickets.ToList()); case "MyDue7": end = now.AddDays(7); var due7Tickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.TicketStatusId != (int)TS.Status.Resolved && t.DueDate >= now && t.DueDate < end); return View(due7Tickets.ToList()); case "MyDue24": end = now.AddDays(1); var due24Tickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.TicketStatusId != (int)TS.Status.Resolved && t.DueDate >= now && t.DueDate < end); return View(due24Tickets.ToList()); case "MyDue30": end = now.AddDays(30); var due30Tickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.TicketStatusId != (int)TS.Status.Resolved && t.DueDate >= now && t.DueDate < end); return View(due30Tickets.ToList()); case "MyOverdue": start = now.AddDays(-1); var overdueTickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.DueDate >= start && t.DueDate < now); return View(overdueTickets.ToList()); case "MyInDevelopment": var devTickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.TicketStatusId == (int)TS.Status.InDevelopment); return View(devTickets.ToList()); case "MyTesting": var testingTickets = db.Tickets .Where(t => t.AssignedToDevId == userId && t.TicketStatusId >= (int)TS.Status.ReadyToTest && t.TicketStatusId != (int)TS.Status.Resolved); return View(testingTickets.ToList()); case "Resolved": // This is for Admin to see which tickets might have been accidentally resolved too early // Allows for them to be adjusted var resolvedTickets = db.Tickets .Where(t => t.TicketStatusId == (int)TS.Status.Resolved); return View(resolvedTickets.ToList()); default: // For all other scopes, come here var tickets = db.Tickets .Where(tic => tic.TicketStatus.Name == scope) .Include(t => t.AssignedToDev).Include(t => t.OwnerUser).Include(t => t.Project).Include(t => t.SkillRequired).Include(t => t.TicketPriority).Include(t => t.TicketStatus).Include(t => t.TicketType); return View(tickets.ToList()); } }
public ActionResult Edit([Bind(Include = "Id,ProjectId,TicketTypeId,TicketPriorityId,TicketStatusId,AssignedToDevId,SkillRequiredId,Title,Created,Description,DueDate,HoursToComplete")] Ticket ticket, string submit) { CheckCookies(); if (ModelState.IsValid) { Ticket origTicket = db.Tickets.Find(ticket.Id); // Check each field to see if changed. If so, copy new value to origTicket and create TicketHistory // But first, remember the current Developer... string origDevId = origTicket.AssignedToDevId; if (submit == "Ready for Testing") { // Update status... origTicket.TicketStatusId = (int)TS.Status.ReadyToTest; } // WasChanged updates all the fields, origTicket is new version... DateTimeOffset dtChanged = ticket.WasChanged(db, origTicket); // If the current user is not the assigned Dev, need to send notification // Get current user... var helper = new UserRolesHelper(); if (ticket.AssignedToDevId != helper.GetCurrentUserId()) TicketNotification.Notify(db, origTicket, dtChanged, TicketNotification.EType.TicketModified); if (dtChanged != DateTimeOffset.MinValue) { origTicket.SetUpdated(dtChanged); db.Entry(origTicket).State = EntityState.Modified; db.SaveChanges(); // Need to see if the Assigned Dev was changed... if so, send out // one notification to previous Dev, two notifications to new Dev if (origTicket.AssignedToDevId != origDevId) { // Remember the current Dev, swap vars in order to remove... string newDevId = origTicket.AssignedToDevId; origTicket.AssignedToDevId = origDevId; TicketNotification.Notify(db, origTicket, origTicket.Updated.Value, TicketNotification.EType.RemovedFromTicket); // And now reset to correct new Dev and issue notifications origTicket.AssignedToDevId = newDevId; TicketNotification.Notify(db, origTicket, origTicket.Updated.Value, TicketNotification.EType.AssignedToTicket); TicketNotification.Notify(db, origTicket, origTicket.Updated.Value, TicketNotification.EType.TicketModified); } } return RedirectToAction("Index", new { scope = "My" }); } // Do this in every GET action... ViewBag.UserModel = ProjectsHelper.LoadUserModel(); ViewBag.AssignedToDevId = new SelectList(db.Users, "Id", "FirstName", ticket.AssignedToDevId); ViewBag.OwnerUserId = new SelectList(db.Users, "Id", "FirstName", ticket.OwnerUserId); ViewBag.ProjectId = new SelectList(db.Projects, "Id", "Name", ticket.ProjectId); ViewBag.SkillRequiredId = new SelectList(db.SkillLevels, "Id", "Name", ticket.SkillRequiredId); ViewBag.TicketPriorityId = new SelectList(db.TicketPriorities, "Id", "Name", ticket.TicketPriorityId); ViewBag.TicketStatusId = new SelectList(db.TicketStatuses, "Id", "Name", ticket.TicketStatusId); ViewBag.TicketTypeId = new SelectList(db.TicketTypes, "Id", "Name", ticket.TicketTypeId); return View(ticket); }
// GET: Tickets/Edit/5 public ActionResult Edit(int? id) { CheckCookies(); // Do this in every GET action... var uModel = ProjectsHelper.LoadUserModel(); ViewBag.UserModel = uModel; if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Ticket ticket = db.Tickets.Find(id); if (ticket == null) { return HttpNotFound(); } UserRolesHelper helper = new UserRolesHelper(); var userId = helper.GetCurrentUserId(); var roles = helper.ListUserRoles(userId); // If Admin, allow to select Developer when creating the ticket if (uModel.IsAdmin || uModel.IsPM) { var roleDev = db.Roles.FirstOrDefault(r => r.Name == R.Developer); ViewBag.CanAssignDeveloper = true; if (roleDev != null) { var dev = new SelectList(db.Users .Where(d => d.Roles.Any(r => r.RoleId == roleDev.Id)), "Id", "UserName", ticket.AssignedToDevId); ViewBag.AssignedToDevId = dev; } else ViewBag.AssignedToDevId = Enumerable.Empty<SelectListItem>(); } else { ViewBag.AssignedToDevId = Enumerable.Empty<SelectListItem>(); ViewBag.CanAssignDeveloper = false; } ViewBag.OwnerUserId = new SelectList(db.Users, "Id", "FirstName", ticket.OwnerUserId); ViewBag.ProjectId = new SelectList(db.Projects, "Id", "Name", ticket.ProjectId); ViewBag.SkillRequiredId = new SelectList(db.SkillLevels, "Id", "Name", ticket.SkillRequiredId); ViewBag.TicketPriorityId = new SelectList(db.TicketPriorities, "Id", "Name", ticket.TicketPriorityId); ViewBag.TicketStatusId = new SelectList(db.TicketStatuses, "Id", "Name", ticket.TicketStatusId); ViewBag.TicketTypeId = new SelectList(db.TicketTypes, "Id", "Name", ticket.TicketTypeId); return View(ticket); }
// GET: TicketNotifications public ActionResult Index(string scope) { ViewBag.UserModel = ProjectsHelper.LoadUserModel(); ViewBag.Scope = scope ?? "My"; // First, get this user... UserRolesHelper helper = new UserRolesHelper(); var userId = helper.GetCurrentUserId(); switch (scope) { case "My": // Now get My notifications... var My = db.TicketNotifications.Where(n => n.UserId == userId) .OrderBy(n => n.HasBeenRead).ThenByDescending(n => n.Created); return View(My.ToList()); case "All": var All = db.TicketNotifications.Include(t => t.Ticket).Include(t => t.User) .OrderBy(n => n.HasBeenRead).ThenByDescending(n => n.Created); return View(All.ToList()); case "MyAssignedToTicket": var MyAssignedToTicket = db.TicketNotifications .Where(n => n.UserId == userId && n.Type == TicketNotification.EType.AssignedToTicket); return View(MyAssignedToTicket.ToList()); case "MyRemovedFromTicket": var MyRemovedFromTicket = db.TicketNotifications .Where(n => n.UserId == userId && n.Type == TicketNotification.EType.RemovedFromTicket); return View(MyRemovedFromTicket.ToList()); case "MyTicketModified": var MyTicketModified = db.TicketNotifications .Where(n => n.UserId == userId && n.Type == TicketNotification.EType.TicketModified); return View(MyTicketModified.ToList()); case "MyComments": var MyComments = db.TicketNotifications .Where(n => n.UserId == userId && (n.Type == TicketNotification.EType.CommentCreated || n.Type == TicketNotification.EType.CommentDeleted || n.Type == TicketNotification.EType.CommentModified)); return View(MyComments.ToList()); case "MyAttachments": var MyAttachments = db.TicketNotifications .Where(n => n.UserId == userId && (n.Type == TicketNotification.EType.AttachmentCreated || n.Type == TicketNotification.EType.AttachmentDeleted || n.Type == TicketNotification.EType.AttachmentModified)); return View(MyAttachments.ToList()); default: // A normal type without "My" in front TicketNotification.EType type = TicketNotification.EType.AssignedToTicket; bool gotIt = Enum.TryParse<TicketNotification.EType>(scope, out type); if (gotIt) { var ticketNotifications = db.TicketNotifications.Where(n => n.Type == type); return View(ticketNotifications.ToList()); } else { var noneHere = db.TicketNotifications.Where(n => n.TicketId == -1); return View(noneHere.ToList()); } } }
private int AddNewTickets() { // Process each row, create new user int nTickets = 0; int row; string[] colData; string Creator, Dev, Name, Desc; row = Start - 1; UserRolesHelper helper = new UserRolesHelper(); var statuses = db.TicketStatuses.ToList(); var priorities = db.TicketPriorities.ToList(); var types = db.TicketTypes.ToList(); var skills = db.SkillLevels.ToList(); bool devOk = false; // Set to true if validated and ready to add to ticket // Use same time stamp for all tickets DateTimeOffset now = DateTimeOffset.UtcNow; // First, make sure all needed columns are present if (HeadingOffsets[(int)H.T_Title] < 0 || HeadingOffsets[(int)H.T_Description] < 0) { Section.LogErr(db, "Ticket on row " + (row + 1) + " is missing a column " + "(Title and Description are required) -- cannot process any Tickets"); return 0; } while (++row < (Count + Start)) { if (Source[row][0] != ';') { // Valid row to process, so get columns // // DON'T TRIM THE ROW!! If it's trimmed, the column positions will NOT line up with // what is expected, resulting in a crash! // colData = Source[row].Split('\t'); // These rules must be followed: // [] Title and Description must be non-empty // [] No uniqueness test -- OK to enter tickets with same Title/Description(??) // [] Developer must be in database // [] Developer must be in Developer role // [] TicketCreator must be in database // [] If ProjectTitle/Description cannot be found, leave as null // [] Parse DateCreated - default is Now // [] Parse DueDate - default is Now + 1 day // [] Parse HoursToComplete - default is 1 // [] Parse Type, Priority, Status, Skill - default is 1 // - load all values from db, find the match, if not found use default // // If rules not followed, show error and skip Ticket ticket = new Ticket(); ticket.Title = colData[HeadingOffsets[(int)H.T_Title]]; ticket.Description = colData[HeadingOffsets[(int)H.T_Description]]; Dev = colData[HeadingOffsets[(int)H.T_AssignedDeveloperUserName]]; Creator = colData[HeadingOffsets[(int)H.T_TicketCreatorUserName]]; ApplicationUser user = null; // Test column requirements now... if (ticket.Title.Length == 0 || ticket.Description.Length == 0) { Section.LogErr(db, "Ticket on row " + (row + 1) + " needs both a Title and a Description -- will be skipped"); continue; } // Validate Developer user = db.Users.FirstOrDefault(u => u.UserName == Dev); if (user == null) { if (Dev != "") Section.LogAlert(db, "DeveloperUser on row " + (row + 1) + " has UserName [" + Dev + "] not in database -- leaving field blank, will continue"); } else { // Dev is in database, now check role if (!helper.IsUserInRole(user.Id, R.Developer)) { Section.LogErr(db, "Ticket on row " + (row + 1) + " has AssignedDeveloper [" + user.UserName + "] not in 'Developer' role -- leaving field blank, will continue"); } else { devOk = true; // Flags us to create Notification if/when ticket added to table ticket.AssignedToDevId = user.Id; } } // Validate Creator user = db.Users.FirstOrDefault(u => u.UserName == Creator); if (user == null) { Section.LogAlert(db, "TicketCreator on row " + (row + 1) + " has UserName [" + Dev + "] not in database -- using name of current user for this Ticket"); ticket.OwnerUserId = helper.GetCurrentUserId(); } else { ticket.OwnerUserId = user.Id; } // Validate Project -- if not found, leave as null Name = colData[HeadingOffsets[(int)H.T_ProjectName]]; Desc = colData[HeadingOffsets[(int)H.T_ProjectDescription]]; var project = db.Projects.FirstOrDefault(p => p.Name == Name && p.Description == Desc); if (project != null) ticket.ProjectId = project.Id; else { if (Name != "" && Desc != "") Section.LogAlert(db, "Ticket on row " + (row + 1) + " has project not found in Projects table -- setting to null, will continue"); } // Check HoursToComplete int num; int.TryParse(colData[HeadingOffsets[(int)H.T_HoursToComplete]], out num); ticket.HoursToComplete = num < 1 ? 1 : num; // Parse Dates... DateTimeOffset date; DateTimeOffset.TryParse(colData[HeadingOffsets[(int)H.T_DateCreated]], out date); if (date == DateTimeOffset.MinValue) { ticket.Created = ticket.MostRecentUpdate = now; Section.LogAlert(db, "Ticket on row " + (row + 1) + " had invalid DateCreated -- using today's date"); } else ticket.Created = date; DateTimeOffset.TryParse(colData[HeadingOffsets[(int)H.T_DueDate]], out date); if (date == DateTimeOffset.MinValue) { ticket.DueDate = now.AddDays(10); Section.LogAlert(db, "Ticket on row " + (row + 1) + " had invalid DueDate -- set default date to 10 days from now"); } else ticket.DueDate = date; // Validate Type, Priority, Status, Skill -- set to 1 as default // Type string type = colData[HeadingOffsets[(int)H.T_TicketType]].ToUpper(); var tempType = types.Where(t => t.Name.ToUpper().Contains(type)); if (tempType.Count() == 1) ticket.TicketTypeId = tempType.ElementAt(0).Id; else { // Set to default, issue alert if invalid type specified ticket.TicketTypeId = 1; if (type != "") Section.LogAlert(db, "Ticket on row " + (row + 1) + " had invalid TicketType -- set to Bug"); } // Priority string priority = colData[HeadingOffsets[(int)H.T_TicketPriority]].ToUpper(); var tempPriority = priorities.Where(t => t.Name.ToUpper().Contains(priority)); if (tempPriority.Count() == 1) ticket.TicketPriorityId = tempPriority.ElementAt(0).Id; else { // Set to default, issue alert if invalid type specified ticket.TicketPriorityId = 3; if (type != "") Section.LogAlert(db, "Ticket on row " + (row + 1) + " had invalid TicketPriority -- set to Essential"); } // Status string status = colData[HeadingOffsets[(int)H.T_TicketStatus]].ToUpper(); var tempStatus = statuses.Where(t => t.Name.ToUpper().Contains(status)); if (tempStatus.Count() == 1) ticket.TicketStatusId = tempStatus.ElementAt(0).Id; else { // Set to default, issue alert if invalid type specified ticket.TicketStatusId = 1; if (type != "") Section.LogAlert(db, "Ticket on row " + (row + 1) + " had invalid TicketStatus -- set to New"); } // Skill string skill = colData[HeadingOffsets[(int)H.T_SkillRequired]].ToUpper(); var tempSkill = skills.Where(s => s.Name.ToUpper().Contains(skill)); if (tempSkill.Count() == 1) ticket.SkillRequiredId = tempSkill.ElementAt(0).Id; else { // Set to default, issue alert if invalid type specified ticket.SkillRequiredId = 1; if (type != "") Section.LogAlert(db, "Ticket on row " + (row + 1) + " had invalid SkillRequired -- set to Junior"); } // Last check... if ticket.StatusId is "New" and a developer is assigned, change to "AssignedToDev" if (ticket.AssignedToDev != null && ticket.TicketStatusId == (int)TS.Status.New) { Section.LogAlert(db, "Ticket on row " + (row + 1) + " has assigned developer -- set to AssignedToDev"); ticket.TicketStatusId = (int)TS.Status.AssignedToDev; } // We can add the Ticket now db.Tickets.Add(ticket); db.SaveChanges(); if (devOk) ticket.NotifyNewTicket(db); LogSuccess(db, "Added Ticket from row " + (row + 1)); nTickets++; } } return nTickets; }
public ActionResult SelectRole(string MyRole) { // Strip out any extra portion... MyRole = MyRole.Replace(" (default)", ""); // User has selected a role, so make it active ApplicationDbContext db = new ApplicationDbContext(); UserRolesHelper helper = new UserRolesHelper(); var user = db.Users.Find(helper.GetCurrentUserId()); user.ActiveRole = MyRole; db.Entry(user).State = EntityState.Modified; db.SaveChanges(); // Do this in every GET action... ViewBag.UserModel = ProjectsHelper.LoadUserModel(); return RedirectToAction("Dashboard"); }