Integrate comments from a website into Jira ticket comments

Hello,

I’m working on integrating a support ticket website into JIRA. So far, creating a ticket on the website, also creates a ticket in JIRA. I managed to implement priorities and types. Creating a ticket with Low priority and type Task on the website, will create a corresponding ticket in Jira. The issue that I am having now is figuring out how to import the comments from the website and display them as comments on the actual Jira ticket.

For the application, the languages used are C# and MSSQL.
Here is how I implemented the priority and type:

IJiraIntegrationService:

Task<List> GetPriorityList();
IssuePriority GetIssuePriority(int id);

JiraIntegrationService:

public Issue CreateIssue(Ticket ticket)
{
viewModel.Priority = this.GetIssuePriority(ticket.TicketPriorityTypeId);
}

// TicketPriorityTypeId is a table in the database where I have the corresponding ids for each priority (Low, Medium, High, etc)

I implemented Type the same way here: viewModel.Type = this.GetIssueType(ticket.TicketTypeId);

In the same file, I have:

public Issue GetJiraIssueModel(JiraTicketViewModel viewModel)
{

var issueModel = new Issue(this.JiraClient, this.JiraProjectCode)
{
Summary = summary,
Assignee = viewModel.Assignee,
Description = viewModel.Description,
Type = viewModel.Type,
Priority = viewModel.Priority,

public async Task<List> GetPriorityList()
{
var priorityList = new List();

        var jiraPriorities = await this.JiraClient.Priorities.GetPrioritiesAsync();
        DataSet prismPrioritiesDs = this.GetPrismPriorities();
        int ticketPriorityTypeId = 1;
        foreach (IssuePriority jiraPriority in jiraPriorities)
        {
            foreach (DataRow row in prismPrioritiesDs.Tables[0].Rows)
            {
                if (row["JiraId"].ToString() == jiraPriority.Id)
                {
                    ticketPriorityTypeId = Convert.ToInt32(row["TicketPriorityTypeId"]);
                    break;
                }
            }
            priorityList.Add(new TicketPriorityTypeJira
            {
                TicketPriorityTypeId = ticketPriorityTypeId,
                DisplayText = jiraPriority.Name,
                IsActive = true,
                IsNew = false
            });
        }
        return priorityList;
    }

private DataSet GetThePriorities()
{

        var db = this.GetDatabase();
        string sqlCommand = "usp_TicketPriorityTypes_GetAll";
        DbCommand dbCommandWrapper = db.GetStoredProcCommand(sqlCommand);
        return db.ExecuteDataSet(dbCommandWrapper);
    }

public IssuePriority GetIssuePriority(int id)
{
IssuePriority priority = null;
DataSet thePrioritiesDs = this.GetThePriorities();
string jiraPriorityId = “1”;

        foreach (DataRow row in thePrioritiesDs.Tables[0].Rows)
        {
            if (Convert.ToInt32(row["TicketPriorityTypeId"]) == id)
            {
                jiraPriorityId = row["JiraId"].ToString();
                break;
            }
        }
        this.JiraClient.Priorities.GetPrioritiesAsync()
            .ContinueWith(ca =>
            {
                priority = ca.Result
                    .Where(p => p.Id == jiraPriorityId)
                    .FirstOrDefault();
            }).Wait();
        return priority;
    }

JiraTicketViewModel:

public class JiraTicketViewModel
{
public JiraTicketViewModel() { }

    public JiraTicketViewModel(Issue issue)
    {
        this.Summary = issue.Summary;
        this.Assignee = issue.Assignee;
        this.Description = issue.Description;
        this.Project = issue.Project;
        this.Priority = issue.Priority;

where Issue comes from the Jira API. (namespace Atlassian.Jira)

So type and priority are implemented identically. But for the comments, I am having issues. First of all, there is no “Comment” in the API:

public ProjectVersionCollection AffectsVersions { get; }
//
// Summary:
// Person to whom the issue is currently assigned
public string Assignee { get; set; }
//
// Summary:
// The components associated with this issue
[JqlFieldNameAttribute(“component”)]
public ProjectComponentCollection Components { get; }
//
// Summary:
// Time and date on which this issue was entered into JIRA
public DateTime? Created { get; }
//
// Summary:
// The custom fields associated with this issue
public CustomFieldValueCollection CustomFields { get; }
//
// Summary:
// Detailed description of the issue
[JqlContainsEqualityAttribute]
public string Description { get; set; }
//
// Summary:
// Date by which this issue is scheduled to be completed
public DateTime? DueDate { get; set; }
//
// Summary:
// Hardware or software environment to which the issue relates
[JqlContainsEqualityAttribute]
public string Environment { get; set; }
//
// Summary:
// The versions in which this issue is fixed
[JqlFieldNameAttribute(“FixVersion”)]
public ProjectVersionCollection FixVersions { get; }
//
// Summary:
// The JIRA server that created this issue
public Jira Jira { get; }
//
// Summary:
// Gets the internal identifier assigned by JIRA.
public string JiraIdentifier { get; }
//
// Summary:
// Unique identifier for this issue
public ComparableString Key { get; }
//
// Summary:
// The labels assigned to this issue.
public IssueLabelCollection Labels { get; }
//
// Summary:
// The parent key if this issue is a subtask.
//
// Remarks:
// Only available if issue was retrieved using REST API.
public string ParentIssueKey { get; }
//
// Summary:
// Importance of the issue in relation to other issues
public IssuePriority Priority { get; set; }
//
// Summary:
// Parent project to which the issue belongs
public string Project { get; }
//
// Summary:
// Person who entered the issue into the system
public string Reporter { get; set; }
//
// Summary:
// Record of the issue’s resolution, if the issue has been resolved or closed
public IssueResolution Resolution { get; set; }
//
// Summary:
// Time and date on which this issue was resolved.
//
// Remarks:
// Only available if issue was retrieved using REST API, use GetResolutionDate method
// for SOAP clients.
public DateTime? ResolutionDate { get; }
//
// Summary:
// Gets the security level set on the issue.
public IssueSecurityLevel SecurityLevel { get; }
//
// Summary:
// The stage the issue is currently at in its lifecycle.
public IssueStatus Status { get; }
//
// Summary:
// Brief one-line summary of the issue
[JqlContainsEqualityAttribute]
public string Summary { get; set; }
//
// Summary:
// The type of the issue
[RemoteFieldNameAttribute(“issuetype”)]
public IssueType Type { get; set; }
//
// Summary:
// Time and date on which this issue was last edited
public DateTime? Updated { get; }
//
// Summary:
// Number of votes the issue has
public long? Votes { get; set; }

    //
    // Summary:
    //     Add one or more attachments to this issue.
    //
    // Parameters:
    //   attachments:
    //     Attachment objects that describe the files to upload.
    public void AddAttachment(params UploadAttachmentInfo[] attachments);
    //
    // Summary:
    //     Add one or more attachments to this issue
    //
    // Parameters:
    //   filePaths:
    //     Full paths of files to upload
    public void AddAttachment(params string[] filePaths);
    //
    // Summary:
    //     Add an attachment to this issue
    //
    // Parameters:
    //   name:
    //     Attachment name with extension
    //
    //   data:
    //     Attachment data
    public void AddAttachment(string name, byte[] data);
    //
    // Summary:
    //     Add one or more attachments to this issue.
    //
    // Parameters:
    //   attachments:
    //     Attachment objects that describe the files to upload.
    //
    //   token:
    //     Cancellation token for this operation.
    public Task AddAttachmentAsync(UploadAttachmentInfo[] attachments, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Add a comment to this issue.
    //
    // Parameters:
    //   comment:
    //     Comment object to add.
    //
    //   token:
    //     Cancellation token for this operation.
    public Task AddCommentAsync(Comment comment, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Add a comment to this issue.
    //
    // Parameters:
    //   comment:
    //     Comment text to add.
    public Task AddCommentAsync(string comment, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Adds a user to the watchers of the issue.
    //
    // Parameters:
    //   username:
    //     Username of the user to add.
    //
    //   token:
    //     Cancellation token for this operation.
    public Task AddWatcherAsync(string username, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Adds a worklog to this issue.
    //
    // Parameters:
    //   worklog:
    //     The worklog instance to add
    //
    //   worklogStrategy:
    //     How to handle the remaining estimate, defaults to AutoAdjustRemainingEstimate
    //
    //   newEstimate:
    //     New estimate (only used if worklogStrategy set to NewRemainingEstimate)
    //
    //   token:
    //     Cancellation token for this operation.
    //
    // Returns:
    //     Worklog as constructed by server
    public Task<Worklog> AddWorklogAsync(Worklog worklog, WorklogStrategy worklogStrategy = WorklogStrategy.AutoAdjustRemainingEstimate, string newEstimate = null, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Adds a worklog to this issue.
    //
    // Parameters:
    //   timespent:
    //     Specifies a time duration in JIRA duration format, representing the time spent
    //     working on the worklog
    //
    //   worklogStrategy:
    //     How to handle the remaining estimate, defaults to AutoAdjustRemainingEstimate
    //
    //   newEstimate:
    //     New estimate (only used if worklogStrategy set to NewRemainingEstimate)
    //
    // Returns:
    //     Worklog as constructed by server
    public Task<Worklog> AddWorklogAsync(string timespent, WorklogStrategy worklogStrategy = WorklogStrategy.AutoAdjustRemainingEstimate, string newEstimate = null, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Removes an attachment from this issue.
    //
    // Parameters:
    //   attachment:
    //     Attachment to remove.
    //
    //   token:
    //     Cancellation token for this operation.
    public Task DeleteAttachmentAsync(Attachment attachment, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Removes a user from the watchers of the issue.
    //
    // Parameters:
    //   username:
    //     Username of the user to add.
    //
    //   token:
    //     Cancellation token for this operation.
    public Task DeleteWatcherAsync(string username, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Deletes the given worklog from the issue and updates the remaining estimate field.
    //
    // Parameters:
    //   worklog:
    //     The worklog to remove.
    //
    //   worklogStrategy:
    //     How to handle the remaining estimate, defaults to AutoAdjustRemainingEstimate.
    //
    //   newEstimate:
    //     New estimate (only used if worklogStrategy set to NewRemainingEstimate)
    //
    //   token:
    //     Cancellation token for this operation.
    public Task DeleteWorklogAsync(Worklog worklog, WorklogStrategy worklogStrategy = WorklogStrategy.AutoAdjustRemainingEstimate, string newEstimate = null, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Retrieve attachment metadata from server for this issue
    public Task<IEnumerable<Attachment>> GetAttachmentsAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Gets the workflow actions that the issue can be transitioned to.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IEnumerable<JiraNamedEntity>> GetAvailableActionsAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Retrieve change logs from server for this issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IEnumerable<IssueChangeLog>> GetChangeLogsAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Get the comments for this issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IEnumerable<Comment>> GetCommentsAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Gets a dictionary with issue field names as keys and their metadata as values.
    public Task<IDictionary<string, IssueFieldEditMetadata>> GetIssueFieldsEditMetadataAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Gets the issue links associated with this issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IEnumerable<IssueLink>> GetIssueLinksAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Retrieve the labels from server for this issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    [Obsolete("Use Issue.Labels instead.")]
    public Task<string[]> GetLabelsAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Get the comments for this issue.
    //
    // Parameters:
    //   maxComments:
    //     Maximum number of comments to retrieve.
    //
    //   startAt:
    //     Index of the first comment to return (0-based).
    //
    //   token:
    //     Cancellation token for this operation.
    public Task<IPagedQueryResult<Comment>> GetPagedCommentsAsync(int? maxComments = default(int?), int startAt = 0, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Returns the issues that are marked as sub tasks of this issue.
    //
    // Parameters:
    //   maxIssues:
    //     Maximum number of issues to retrieve.
    //
    //   startAt:
    //     Index of the first issue to return (0-based).
    //
    //   token:
    //     Cancellation token for this operation.
    public Task<IPagedQueryResult<Issue>> GetSubTasksAsync(int? maxIssues = default(int?), int startAt = 0, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Gets time tracking information for this issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IssueTimeTrackingData> GetTimeTrackingDataAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Gets the users that are watching the issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IEnumerable<JiraUser>> GetWatchersAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Retrieve worklogs for this issue.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    public Task<IEnumerable<Worklog>> GetWorklogsAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Creates a link between this issue and the issue specified.
    //
    // Parameters:
    //   inwardIssueKey:
    //     Key of the issue to link.
    //
    //   linkName:
    //     Name of the issue link type.
    //
    //   comment:
    //     Comment to add to this issue.
    //
    //   token:
    //     Cancellation token for this operation.
    public Task LinkToIssueAsync(string inwardIssueKey, string linkName, string comment = null, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Updates all fields from server.
    public void Refresh();
    //
    // Summary:
    //     Updates all fields from server.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    [AsyncStateMachine(typeof(<RefreshAsync>d__119))]
    public Task RefreshAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Saves field changes to server.
    public void SaveChanges();
    //
    // Summary:
    //     Saves field changes to server.
    //
    // Parameters:
    //   token:
    //     Cancellation token for this operation.
    [AsyncStateMachine(typeof(<SaveChangesAsync>d__94))]
    public Task<Issue> SaveChangesAsync(CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Sets the labels of this issue.
    //
    // Parameters:
    //   labels:
    //     The list of labels to set on the issue
    [Obsolete("Modify the Issue.Labels collection and call Issue.SaveChanges to update the labels field.")]
    public Task SetLabelsAsync(params string[] labels);
    //
    // Summary:
    //     Sets the labels of this issue.
    //
    // Parameters:
    //   labels:
    //     The list of labels to set on the issue
    //
    //   token:
    //     Cancellation token for this operation.
    [Obsolete("Modify the Issue.Labels collection and call Issue.SaveChanges to update the labels field.")]
    public Task SetLabelsAsync(string[] labels, CancellationToken token = default(CancellationToken));
    //
    // Summary:
    //     Transition an issue through a workflow action.
    //
    // Parameters:
    //   actionName:
    //     The workflow action to transition to.
    //
    //   additionalUpdates:
    //     Additional updates to perform when transitioning the issue.
    //
    //   token:
    //     Cancellation token for this operation.
    [AsyncStateMachine(typeof(<WorkflowTransitionAsync>d__97))]
    public Task WorkflowTransitionAsync(string actionName, WorkflowTransitionUpdates additionalUpdates = null, CancellationToken token = default(CancellationToken));
}

}

The only similiar thing is GetCommentsAsync, but I can’t figure out how to use it. Can anyone help me? I’m really stuck.

I was hoping there would be a simple “Comment” method that I could use in the same way Type and Priority works. How should I approach this ?

Hi @adriann.muresan,

Have you tried looking into CommentsManager API or via REST API ?

Cheers,
Anne Calantog

I am also working on the same issue but still cant find the right solution from any where but am reading an article that is related to this issue and hopeful that it will give me some guidance you can see here.