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