/// <summary> /// Deletes the issue notification. /// </summary> /// <param name="notification">The issue notification to delete.</param> /// <returns></returns> public static bool Delete(IssueNotification notification) { if (notification == null) throw new ArgumentNullException("notification"); if (notification.IssueId <= Globals.NEW_ID) throw (new ArgumentOutOfRangeException("notification", "The issue id for the notification is not valid")); if (string.IsNullOrEmpty(notification.NotificationUsername)) throw (new ArgumentOutOfRangeException("notification", "The user name for the notification cannot be null or empty")); return DataProviderManager.Provider.DeleteIssueNotification(notification.IssueId, notification.NotificationUsername); }
/// <summary> /// Admin Notification List edit Remove Button /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void btnDelNot_Click(object sender, EventArgs e) { if (lstNotificationUsers.SelectedItem == null) return; var notify = new IssueNotification { IssueId = IssueId, NotificationUsername = lstNotificationUsers.SelectedItem.Value }; IssueNotificationManager.Delete(notify); BindNotifications(); }
/// <summary> /// Creates the new issue notification. /// </summary> /// <param name="newNotification">The new notification.</param> /// <returns></returns> public override int CreateNewIssueNotification(IssueNotification newNotification) { // Validate Parameters if (newNotification == null) throw (new ArgumentNullException("newNotification")); try { using (var sqlCmd = new SqlCommand()) { AddParamToSqlCmd(sqlCmd, "@ReturnValue", SqlDbType.Int, 0, ParameterDirection.ReturnValue, null); AddParamToSqlCmd(sqlCmd, "@IssueId", SqlDbType.Int, 0, ParameterDirection.Input, newNotification.IssueId); AddParamToSqlCmd(sqlCmd, "@NotificationUserName", SqlDbType.NText, 255, ParameterDirection.Input, newNotification.NotificationUsername); SetCommandType(sqlCmd, CommandType.StoredProcedure, SP_ISSUENOTIFICATION_CREATE); ExecuteScalarCmd(sqlCmd); return ((int)sqlCmd.Parameters["@ReturnValue"].Value); } } catch (Exception ex) { throw ProcessException(ex); } }
/// <summary> /// Saves the issue. /// </summary> /// <returns></returns> private bool SaveIssue() { decimal estimation; decimal.TryParse(txtEstimation.Text.Trim(), out estimation); var dueDate = DueDatePicker.SelectedValue ?? DateTime.MinValue; var issue = new Issue { AffectedMilestoneId = DropAffectedMilestone.SelectedValue, AffectedMilestoneImageUrl = string.Empty, AffectedMilestoneName = DropAffectedMilestone.SelectedText, AssignedDisplayName = DropAssignedTo.SelectedText, AssignedUserId = Guid.Empty, AssignedUserName = DropAssignedTo.SelectedValue, CategoryId = DropCategory.SelectedValue, CategoryName = DropCategory.SelectedText, CreatorDisplayName = Security.GetDisplayName(), CreatorUserId = Guid.Empty, CreatorUserName = Security.GetUserName(), DateCreated = DateTime.Now, Description = DescriptionHtmlEditor.Text.Trim(), Disabled = false, DueDate = dueDate, Estimation = estimation, Id = 0, IsClosed = false, IssueTypeId = DropIssueType.SelectedValue, IssueTypeName = DropIssueType.SelectedText, IssueTypeImageUrl = string.Empty, LastUpdate = DateTime.Now, LastUpdateDisplayName = Security.GetDisplayName(), LastUpdateUserName = Security.GetUserName(), MilestoneDueDate = null, MilestoneId = DropMilestone.SelectedValue, MilestoneImageUrl = string.Empty, MilestoneName = DropMilestone.SelectedText, OwnerDisplayName = DropOwned.SelectedText, OwnerUserId = Guid.Empty, OwnerUserName = DropOwned.SelectedValue, PriorityId = DropPriority.SelectedValue, PriorityImageUrl = string.Empty, PriorityName = DropPriority.SelectedText, Progress = Convert.ToInt32(ProgressSlider.Text), ProjectCode = string.Empty, ProjectId = ProjectId, ProjectName = string.Empty, ResolutionId = DropResolution.SelectedValue, ResolutionImageUrl = string.Empty, ResolutionName = DropResolution.SelectedText, StatusId = DropStatus.SelectedValue, StatusImageUrl = string.Empty, StatusName = DropStatus.SelectedText, Title = Server.HtmlEncode(TitleTextBox.Text), TimeLogged = 0, Visibility = chkPrivate.Checked ? 1 : 0, Votes = 0 }; if (!IssueManager.SaveOrUpdate(issue)) { Message1.ShowErrorMessage(Resources.Exceptions.SaveIssueError); return false; } if (!CustomFieldManager.SaveCustomFieldValues(issue.Id, ctlCustomFields.Values, true)) { Message1.ShowErrorMessage(Resources.Exceptions.SaveCustomFieldValuesError); return false; } IssueId = issue.Id; //add attachment if present. if (AspUploadFile.HasFile) { // get the current file var uploadFile = AspUploadFile.PostedFile; string inValidReason; var validFile = IssueAttachmentManager.IsValidFile(uploadFile.FileName, out inValidReason); if (validFile) { if (uploadFile.ContentLength > 0) { byte[] fileBytes; using (var input = uploadFile.InputStream) { fileBytes = new byte[uploadFile.ContentLength]; input.Read(fileBytes, 0, uploadFile.ContentLength); } var issueAttachment = new IssueAttachment { Id = Globals.NEW_ID, Attachment = fileBytes, Description = AttachmentDescription.Text.Trim(), DateCreated = DateTime.Now, ContentType = uploadFile.ContentType, CreatorDisplayName = string.Empty, CreatorUserName = Security.GetUserName(), FileName = uploadFile.FileName, IssueId = issue.Id, Size = fileBytes.Length }; if (!IssueAttachmentManager.SaveOrUpdate(issueAttachment)) { Message1.ShowErrorMessage(string.Format(GetGlobalResourceObject("Exceptions", "SaveAttachmentError").ToString(), uploadFile.FileName)); } } } else { Message1.ShowErrorMessage(inValidReason); return false; } } //create a vote for the new issue var vote = new IssueVote { IssueId = issue.Id, VoteUsername = Security.GetUserName() }; if (!IssueVoteManager.SaveOrUpdate(vote)) { Message1.ShowErrorMessage(Resources.Exceptions.SaveIssueVoteError); return false; } if (chkNotifyOwner.Checked && !string.IsNullOrEmpty(issue.OwnerUserName)) { var oUser = UserManager.GetUser(issue.OwnerUserName); if (oUser != null) { var notify = new IssueNotification { IssueId = issue.Id, NotificationUsername = oUser.UserName }; IssueNotificationManager.SaveOrUpdate(notify); } } if (chkNotifyAssignedTo.Checked && !string.IsNullOrEmpty(issue.AssignedUserName)) { var oUser = UserManager.GetUser(issue.AssignedUserName); if (oUser != null) { var notify = new IssueNotification { IssueId = issue.Id, NotificationUsername = oUser.UserName }; IssueNotificationManager.SaveOrUpdate(notify); } } //send issue notifications IssueNotificationManager.SendIssueAddNotifications(issue.Id); return true; }
// IssueNotifications public abstract int CreateNewIssueNotification(IssueNotification newNotification);
/// <summary> /// Saves the issue /// </summary> /// <param name="entity">The issue to save.</param> /// <returns></returns> public static bool SaveOrUpdate(Issue entity) { if (entity == null) throw new ArgumentNullException("entity"); if (entity.ProjectId <= Globals.NEW_ID) throw (new ArgumentException("The issue project id is invalid")); if (string.IsNullOrEmpty(entity.Title)) throw (new ArgumentException("The issue title cannot be empty or null")); try { if (entity.Id <= Globals.NEW_ID) { var tempId = DataProviderManager.Provider.CreateNewIssue(entity); if (tempId > 0) { entity.Id = tempId; return true; } return false; } else { //existing issue var issueChanges = GetIssueChanges(GetById(entity.Id), entity); DataProviderManager.Provider.UpdateIssue(entity); UpdateHistory(issueChanges); IssueNotificationManager.SendIssueNotifications(entity.Id, issueChanges); if (entity.SendNewAssigneeNotification) { //add this user to notifications and send them a notification var notification = new IssueNotification() { IssueId = entity.Id, NotificationUsername = entity.AssignedUserName }; IssueNotificationManager.SaveOrUpdate(notification); IssueNotificationManager.SendNewAssigneeNotification(notification); } return true; } } catch(Exception ex) { Log.Error(LoggingManager.GetErrorMessageResource("SaveIssueError"), ex); return false; } return false; }
/// <summary> /// Saves the issue /// </summary> /// <param name="entity">The issue to save.</param> /// <returns></returns> public static bool SaveOrUpdate(Issue entity) { if (entity == null) throw new ArgumentNullException("entity"); if (entity.ProjectId <= Globals.NEW_ID) throw (new ArgumentException("The issue project id is invalid")); if (string.IsNullOrEmpty(entity.Title)) throw (new ArgumentException("The issue title cannot be empty or null")); if (entity.Id <= Globals.NEW_ID) { var tempId = DataProviderManager.Provider.CreateNewIssue(entity); if (tempId > 0) { entity.Id = tempId; //add vote var vote = new IssueVote { IssueId = entity.Id, VoteUsername = entity.CreatorUserName }; IssueVoteManager.SaveOrUpdate(vote); //TOOD: handle adding an attachment for new issue. //send notifications for add issue IssueNotificationManager.SendIssueAddNotifications(entity.Id); return true; } return false; } var issueChanges = GetIssueChanges(GetById(entity.Id), entity); if (issueChanges.Count > 0) { var result = DataProviderManager.Provider.UpdateIssue(entity); if (result) { UpdateHistory(issueChanges); IssueNotificationManager.SendIssueNotifications(entity.Id, issueChanges); if (entity.SendNewAssigneeNotification) { //add this user to notifications and send them a notification var notification = new IssueNotification() { IssueId = entity.Id, NotificationUsername = entity.AssignedUserName }; IssueNotificationManager.SaveOrUpdate(notification); IssueNotificationManager.SendNewAssigneeNotification(notification); } } return result; } return true; }
/// <summary> /// Handles the Click event of the btnReceiveNotifications control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param> protected void btnReceiveNotifications_Click(object sender, EventArgs e) { var notify = new IssueNotification { IssueId = IssueId, NotificationUsername = Page.User.Identity.Name}; IssueNotificationManager.SaveOrUpdate(notify); BindNotifications(); }
/// <summary> /// Handles the Click event of the btnDontRecieveNotfictaions control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param> protected void btnDontRecieveNotfictaions_Click(object sender, EventArgs e) { var notify = new IssueNotification { IssueId = IssueId, NotificationUsername = Page.User.Identity.Name }; IssueNotificationManager.Delete(notify); BindNotifications(); }
/// <summary> /// Send notifications for the new issue /// </summary> /// <param name="issue">The issue generated from the email</param> void SendNotifications(Issue issue) { if (issue == null) { return; } List<DefaultValue> defValues = IssueManager.GetDefaultIssueTypeByProjectId(issue.ProjectId); DefaultValue selectedValue = defValues.FirstOrDefault(); if (selectedValue != null) { if (selectedValue.OwnedByNotify) { var oUser = UserManager.GetUser(issue.OwnerUserName); if (oUser != null) { var notify = new IssueNotification { IssueId = issue.Id, NotificationUsername = oUser.UserName }; IssueNotificationManager.SaveOrUpdate(notify); } } if (selectedValue.AssignedToNotify) { var oUser = UserManager.GetUser(issue.AssignedUserName); if (oUser != null) { var notify = new IssueNotification { IssueId = issue.Id, NotificationUsername = oUser.UserName }; IssueNotificationManager.SaveOrUpdate(notify); } } } //send issue notifications IssueNotificationManager.SendIssueAddNotifications(issue.Id); }
/// <summary> /// Sends an email to the user that is assigned to the issue /// </summary> /// <param name="notification"></param> public static void SendNewAssigneeNotification(IssueNotification notification) { if (notification == null) throw (new ArgumentNullException("notification")); if (notification.IssueId <= Globals.NEW_ID) throw (new ArgumentOutOfRangeException("notification", "The issue id is not valid for this notification")); // TODO - create this via dependency injection at some point. IMailDeliveryService mailService = new SmtpMailDeliveryService(); var issue = DataProviderManager.Provider.GetIssueById(notification.IssueId); var emailFormatType = HostSettingManager.Get(HostSettingNames.SMTPEMailFormat, EmailFormatType.Text); // data for template var data = new Dictionary<string, object> { { "Issue", issue } }; var emailFormatKey = (emailFormatType == EmailFormatType.Text) ? "" : "HTML"; const string subjectKey = "NewAssigneeSubject"; var bodyKey = string.Concat("NewAssignee", emailFormatKey); var nc = new CultureNotificationContent().LoadContent(notification.NotificationCulture, subjectKey, bodyKey); try { //send notifications to everyone except who changed it. if (notification.NotificationUsername.ToLower() == Security.GetUserName().ToLower()) return; var user = UserManager.GetUser(notification.NotificationUsername); // skip to the next user if this user is not approved if (!user.IsApproved) return; // skip to next user if this user doesn't have notifications enabled. if (!new WebProfile().GetProfile(user.UserName).ReceiveEmailNotifications) return; var emailSubject = nc.CultureContents .First(p => p.ContentKey == subjectKey) .FormatContent(issue.FullId); var bodyContent = nc.CultureContents .First(p => p.ContentKey == bodyKey) .TransformContent(data); var message = new MailMessage { Subject = emailSubject, Body = bodyContent, IsBodyHtml = true }; mailService.Send(user.Email, message, notification.IssueId); } catch (Exception ex) { ProcessException(ex); } }
/// <summary> /// Saves the issue /// </summary> /// <param name="entity">The issue to save.</param> /// <returns></returns> public static bool SaveOrUpdate(Issue entity) { if (entity == null) throw new ArgumentNullException("entity"); if (entity.ProjectId <= Globals.NEW_ID) throw (new ArgumentException("The issue project id is invalid")); if (string.IsNullOrEmpty(entity.Title)) throw (new ArgumentException("The issue title cannot be empty or null")); try { if (entity.Id <= Globals.NEW_ID) { var tempId = DataProviderManager.Provider.CreateNewIssue(entity); if (tempId > 0) { entity.Id = tempId; return true; } return false; } // this is here due to issue with updating the issue from the Mailbox reader // to fix the inline images. we don't have an http context so we are limited to what we can // do from here. in any case the mailbox reader is creating and updating concurrently so // we are not missing anything. if (HttpContext.Current != null) { //existing issue entity.LastUpdate = DateTime.Now; entity.LastUpdateUserName = Security.GetUserName(); var issueChanges = GetIssueChanges(GetById(entity.Id), entity); DataProviderManager.Provider.UpdateIssue(entity); UpdateHistory(issueChanges); IssueNotificationManager.SendIssueNotifications(entity.Id, issueChanges); if (entity.SendNewAssigneeNotification) { //add this user to notifications and send them a notification var notification = new IssueNotification { IssueId = entity.Id, NotificationUsername = entity.AssignedUserName, NotificationCulture = string.Empty }; var profile = new WebProfile().GetProfile(entity.AssignedUserName); if (profile != null && !string.IsNullOrWhiteSpace(profile.PreferredLocale)) { notification.NotificationCulture = profile.PreferredLocale; } IssueNotificationManager.SaveOrUpdate(notification); IssueNotificationManager.SendNewAssigneeNotification(notification); } } else { DataProviderManager.Provider.UpdateIssue(entity); } return true; } catch (Exception ex) { Log.Error(LoggingManager.GetErrorMessageResource("SaveIssueError"), ex); return false; } }
/// <summary> /// Saves the issue. /// </summary> /// <returns></returns> private bool SaveIssue() { decimal estimation; decimal.TryParse(txtEstimation.Text.Trim(), out estimation); var dueDate = DueDatePicker.SelectedValue == null ? DateTime.MinValue : (DateTime)DueDatePicker.SelectedValue; var isNewIssue = (IssueId <= 0); // WARNING: DO NOT ENCODE THE HTMLEDITOR TEXT. // It expects raw input. So pass through a raw string. // This is a potential XSS vector as the Issue Class should // handle sanitizing the input and checking that its input is HtmlEncoded // (ie no < or > characters), not the IssueDetail.aspx.cs var issue = new Issue { AffectedMilestoneId = DropAffectedMilestone.SelectedValue, AffectedMilestoneImageUrl = string.Empty, AffectedMilestoneName = DropAffectedMilestone.SelectedText, AssignedDisplayName = DropAssignedTo.SelectedText, AssignedUserId = Guid.Empty, AssignedUserName = DropAssignedTo.SelectedValue, CategoryId = DropCategory.SelectedValue, CategoryName = DropCategory.SelectedText, CreatorDisplayName = Security.GetDisplayName(), CreatorUserId = Guid.Empty, CreatorUserName = Security.GetUserName(), DateCreated = DateTime.Now, Description = DescriptionHtmlEditor.Text.Trim(), Disabled = false, DueDate = dueDate, Estimation = estimation, Id = IssueId, IsClosed = false, IssueTypeId = DropIssueType.SelectedValue, IssueTypeName = DropIssueType.SelectedText, IssueTypeImageUrl = string.Empty, LastUpdate = DateTime.Now, LastUpdateDisplayName = Security.GetDisplayName(), LastUpdateUserName = Security.GetUserName(), MilestoneDueDate = null, MilestoneId = DropMilestone.SelectedValue, MilestoneImageUrl = string.Empty, MilestoneName = DropMilestone.SelectedText, OwnerDisplayName = DropOwned.SelectedText, OwnerUserId = Guid.Empty, OwnerUserName = DropOwned.SelectedValue, PriorityId = DropPriority.SelectedValue, PriorityImageUrl = string.Empty, PriorityName = DropPriority.SelectedText, Progress = Convert.ToInt32(ProgressSlider.Text), ProjectCode = string.Empty, ProjectId = ProjectId, ProjectName = string.Empty, ResolutionId = DropResolution.SelectedValue, ResolutionImageUrl = string.Empty, ResolutionName = DropResolution.SelectedText, StatusId = DropStatus.SelectedValue, StatusImageUrl = string.Empty, StatusName = DropStatus.SelectedText, Title = Server.HtmlEncode(TitleTextBox.Text), TimeLogged = 0, Visibility = chkPrivate.Checked ? 1 : 0, Votes = 0 }; if (!IssueManager.SaveOrUpdate(issue)) { Message1.ShowErrorMessage(Resources.Exceptions.SaveIssueError); return false; } IssueId = issue.Id; if (!CustomFieldManager.SaveCustomFieldValues(IssueId, ctlCustomFields.Values)) { Message1.ShowErrorMessage(Resources.Exceptions.SaveCustomFieldValuesError); return false; } //if new issue check if notify owner and assigned is checked. if (isNewIssue) { //add attachment if present. if (AspUploadFile.HasFile) { // get the current file var uploadFile = AspUploadFile.PostedFile; string inValidReason; var validFile = IssueAttachmentManager.IsValidFile(uploadFile.FileName, out inValidReason); if (validFile) { if (uploadFile.ContentLength > 0) { byte[] fileBytes; using (var input = uploadFile.InputStream) { fileBytes = new byte[uploadFile.ContentLength]; input.Read(fileBytes, 0, uploadFile.ContentLength); } var issueAttachment = new IssueAttachment { Id = Globals.NEW_ID, Attachment = fileBytes, Description = AttachmentDescription.Text.Trim(), DateCreated = DateTime.Now, ContentType = uploadFile.ContentType, CreatorDisplayName = string.Empty, CreatorUserName = Security.GetUserName(), FileName = uploadFile.FileName, IssueId = IssueId, Size = fileBytes.Length }; if (!IssueAttachmentManager.SaveOrUpdate(issueAttachment)) { Message1.ShowErrorMessage(string.Format(GetGlobalResourceObject("Exceptions", "SaveAttachmentError").ToString(), uploadFile.FileName)); } } } else { Message1.ShowErrorMessage(inValidReason); return false; } } //create a vote for the new issue var vote = new IssueVote { IssueId = IssueId, VoteUsername = Security.GetUserName() }; if (!IssueVoteManager.SaveOrUpdate(vote)) { Message1.ShowErrorMessage(Resources.Exceptions.SaveIssueVoteError); return false; } if (chkNotifyOwner.Checked && !string.IsNullOrEmpty(issue.OwnerUserName)) { var oUser = UserManager.GetUser(issue.OwnerUserName); if (oUser != null) { var notify = new IssueNotification { IssueId = IssueId, NotificationUsername = oUser.UserName }; IssueNotificationManager.SaveOrUpdate(notify); } } if (chkNotifyAssignedTo.Checked && !string.IsNullOrEmpty(issue.AssignedUserName)) { var oUser = UserManager.GetUser(issue.AssignedUserName); if (oUser != null) { var notify = new IssueNotification { IssueId = IssueId, NotificationUsername = oUser.UserName }; IssueNotificationManager.SaveOrUpdate(notify); } } // add all users subscribed at the project level to the issue level IEnumerable<ProjectNotification> subscriptions = ProjectNotificationManager.GetByProjectId(ProjectId); foreach (ProjectNotification sub in subscriptions) { IssueNotificationManager.SaveOrUpdate(new IssueNotification() { IssueId = IssueId, NotificationUsername = sub.NotificationUsername }); } //send issue notifications IssueNotificationManager.SendIssueAddNotifications(IssueId); } return true; }
/// <summary> /// Sends an email to the user that is assigned to the issue /// </summary> /// <param name="notification"></param> public static void SendNewAssigneeNotification(IssueNotification notification) { if (notification == null) throw (new ArgumentNullException("notification")); if (notification.IssueId <= Globals.NEW_ID) throw (new ArgumentOutOfRangeException("notification", "The issue id is not valid for this notification")); var issue = DataProviderManager.Provider.GetIssueById(notification.IssueId); var emailFormatType = HostSettingManager.Get(HostSettingNames.SMTPEMailFormat, EmailFormatType.Text); //load template var template = NotificationManager.Instance.LoadEmailNotificationTemplate("NewAssignee", emailFormatType); var data = new Dictionary<string, object> {{"Issue", issue}}; template = NotificationManager.GenerateNotificationContent(template, data); var subject = NotificationManager.Instance.LoadNotificationTemplate("NewAssigneeSubject"); try { var context = new NotificationContext { BodyText = template, EmailFormatType = emailFormatType, Subject = String.Format(subject, issue.FullId), UserDisplayName = UserManager.GetUserDisplayName(notification.NotificationUsername), Username = notification.NotificationUsername }; NotificationManager.Instance.SendNotification(context); } catch (Exception ex) { ProcessException(ex); } }