Jira rest api, add attachment with transition - jira

In jira rest api, we are working with transition api.
By posting on /rest/api/2/issue/{issueIdOrKey}/transitions url with transition id and comments and other fields, we are able to post comments and other fields with state transition.
{
"fields" : {"summary": "Test update 5"},
"transition": { "id": "4"},
"update": {
"comment": [
{
"add": {
"body": "It is time to finish this task"
}
}
]
}
}
Recently we came to know that jira has validation for attachments as well. Means I need to add attachment if I do transition. We are in search of how to add attachment during transition using rest api.
Any help would be really appreciated.
Thanks in advance.

Not sure if it would work during transitions, but here's how to add attachments.
https://docs.atlassian.com/jira/REST/latest/#d2e88
I had to make 2 calls -- first to create the issue and then another POST call to update it with the screenshot as there is no way to add attachments in the create call at all.

I am Not sure about adding attachements with transition(I had never done), but I think can be clubbed. Here is the code to just add an attachment to JIRA, You can use Transition API of JRJC and apply/add some logic in below code to get work done.
Follow link [Listing All JIRA Transitions via API
for updating status based on transition, Hope you may get something from here too.
public void addAttachment(IssueRestClient issueRestClient,
VersionOne versionOne, Issue issue, Epics epic) {
try {
URI attachmentsUri = new URI(
applicationProperties.get(Constants.JIRAURL)
+ "/rest/api/2/issue/" + issue.getKey()
+ "/attachments");
Iterable<Attachment> attachments = issue.getAttachments();
Set<String> existingAttachments = new TreeSet<String>();
String _jiraUser = applicationProperties.get(Constants.JIRAUSER);
String _jiraPwd = applicationProperties.get(Constants.JIRAPWD);
String auth = new String(Base64.encode(_jiraUser + ":" + _jiraPwd));
Set<String> files = new TreeSet<String>();
for (Attachment attachment : attachments) {
for (VAttachements vAttachement : epic
.getAttachement()) {
files.add(vAttachement.getFileName());
}
existingAttachments.add(attachment.getFilename());
}
for (VAttachements vAttachement : epic.getvAttachement()) {
if (!(existingAttachments.contains(vAttachement.getFileName()))) {
Promise<Void> attachmentResult = issueRestClient
.addAttachment(attachmentsUri,
vAttachement.getInputStream(),
vAttachement.getFileName());
attachmentResult.claim();
Constants.REPORT.info(attachmentResult.isDone());
}
}
for (Attachment attachment : attachments) {
for (String checkAttachment : existingAttachments) {
if (!files.contains(checkAttachment))
deleteJiraAttachment(attachment, auth, issue,
checkAttachment);
}
}
} catch (Exception e) {
Constants.ERROR.info(Level.INFO, e);
}
}
-Here Epics is a POJO class which contains attachments to be added in Jira, through getter/ setter method.
private void deleteJiraAttachment(Attachment attachment, String auth,
Issue issue, String jiraFilename) {
URI attachmentURL = attachment.getSelf();
int status;
try {
if (jiraFilename.equalsIgnoreCase(attachment.getFilename())) {
status = invokeDeleteMethod(auth, String.valueOf(attachmentURL));
if (status == 204) {
Constants.REPORT.info("Attachment deleted from Issue"
+ issue.getKey());
} else if (status == 403) {
System.out
.println("attachments for Issue\t "
+ issue.getKey()
+ " is disabled or you don't have permission to remove");
} else if (status == 404) {
Constants.REPORT.info("No attachment is not found for"
+ issue.getKey());
}
}
} catch (AuthenticationException | ClientHandlerException e) {
Constants.ERROR.info(Level.INFO, e);
}
}
private static int invokeDeleteMethod(String auth, String url)
throws AuthenticationException, ClientHandlerException {
Client client = Client.create();
WebResource webResource = client.resource(url);
ClientResponse response = webResource
.header("Authorization", "Basic " + auth)
.type("application/json").accept("application/json")
.delete(ClientResponse.class);
int statusCode = response.getStatus();
if (statusCode == 401) {
throw new AuthenticationException("Invalid Username or Password");
}
return statusCode;

Related

Calling an ASP.Net web api from a ASP.Net MVC web app. MVC web client is not building the URL properly so getting not found

When I run my web api method using Postman passing in my URL, it works fine - it returns the value of '5' which I expect since the call returns just a single integer. Also at the very bottom I include another method of my web api that I run using Postman and it too works just fine.
http://localhost:56224/api/profileandblog/validatelogin/DemoUser1/DemoUser1Password/169.254.102.60/
However, in the client - an Asp.Net MVC method, when building the URL, it is DROPPING the "/api/profileandblog" part. Note: I'm using "attribute routing" in the web api.
Here is the Asp.Net MVC method to call the web api:
I stop it on this line so I can see the error details: if (result1.IsSuccessStatusCode)
It's INCORRECTLY building the URL as: http://localhost:56224/validatelogin/DemoUser1/DemoUser1Password/169.254.102.60/
It's dropping the: "/api/profileandblog" part that should follow 56224.
So it give's me the Not found.
Why does it drop it? It has the localhost:56224 correct.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SignIn(SignInViewModel signInViewModel)
{
int returnedApiValue = 0;
User returnedApiUser = new User();
DateTime currentDateTime = DateTime.Now;
string hostName = Dns.GetHostName();
string myIpAddress = Dns.GetHostEntry(hostName).AddressList[2].ToString();
try
{
if (!this.IsCaptchaValid("Captcha is not valid"))
{
ViewBag.errormessage = "Error: captcha entered is not valid.";
}
else
{
if (!string.IsNullOrEmpty(signInViewModel.Username) && !string.IsNullOrEmpty(signInViewModel.Password))
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:56224/api/profileandblog");
string restOfUrl = "/validatelogin/" + signInViewModel.Username + "/" + signInViewModel.Password + "/" + myIpAddress + "/";
// Call the web api to validate the sign in.
// Sends back a -1(failure), -2(validation issue) or the UserId(success) via an OUTPUT parameter.
var responseTask1 = client.GetAsync(restOfUrl);
responseTask1.Wait();
var result1 = responseTask1.Result;
if (result1.IsSuccessStatusCode)
{
var readTask1 = result1.Content.ReadAsAsync<string>();
readTask1.Wait();
returnedApiValue = Convert.ToInt32(readTask1.Result);
if (returnedApiValue == -2)
{
ViewBag.errormessage = "You entered an invalid user name and/or password";
}
else
{
// I have the 'user id'.
// Continue processing...
}
}
else
{
ModelState.AddModelError(string.Empty, "Server error on signing in. 'validatelogin'. Please contact the administrator.");
}
}
}
}
return View(signInViewModel);
}
catch (Exception)
{
throw;
}
}
Per the suggestion about not having headers, I used another tutorial (https://www.c-sharpcorner.com/article/consuming-asp-net-web-api-rest-service-in-asp-net-mvc-using-http-client/) and it has the code for defining the headers. But it is coded slightly different - using async Task<> on the method definition. I was not using async in my prior version.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SignIn(SignInViewModel signInViewModel)
{
int returnedApiValue = 0;
User returnedApiUser = new User();
DateTime currentDateTime = DateTime.Now;
string hostName = Dns.GetHostName();
string myIpAddress = Dns.GetHostEntry(hostName).AddressList[2].ToString();
try
{
if (!this.IsCaptchaValid("Captcha is not valid"))
{
ViewBag.errormessage = "Error: captcha entered is not valid.";
}
else
{
if (!string.IsNullOrEmpty(signInViewModel.Username) && !string.IsNullOrEmpty(signInViewModel.Password))
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:56224/api/profileandblog");
string restOfUrl = "/validatelogin/" + signInViewModel.Username + "/" + signInViewModel.Password + "/" + myIpAddress + "/";
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Call the web api to validate the sign in.
// Sends back a -1(failure), -2(validation issue) or the UserId(success) via an OUTPUT parameter.
HttpResponseMessage result1 = await client.GetAsync(restOfUrl);
if (result1.IsSuccessStatusCode)
{
var readTask1 = result1.Content.ReadAsAsync<string>();
readTask1.Wait();
returnedApiValue = Convert.ToInt32(readTask1.Result);
if (returnedApiValue == -2)
{
ViewBag.errormessage = "You entered an invalid user name and/or password";
}
else
{
// I have the 'user id'.
// Do other processing....
}
}
else
{
ModelState.AddModelError(string.Empty, "Server error on signing in. 'validatelogin'. Please contact the administrator.");
}
}
}
}
return View(signInViewModel);
}
catch (Exception)
{
throw;
}
}
It now has a header but still NOT building the URL properly as it is not including the "/api/profileandblog" part.
Here is the web api and the method being called:
namespace GbngWebApi2.Controllers
{
[RoutePrefix("api/profileandblog")]
public class WebApi2Controller : ApiController
{
[HttpGet]
[Route("validatelogin/{userName}/{userPassword}/{ipAddress}/")]
public IHttpActionResult ValidateLogin(string userName, string userPassword, string ipAddress)
{
try
{
IHttpActionResult httpActionResult;
HttpResponseMessage httpResponseMessage;
int returnValue = 0;
// Will either be a valid 'user id" or a -2 indicating a validation issue.
returnValue = dataaccesslayer.ValidateLogin(userName, userPassword, ipAddress);
httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, returnValue);
httpActionResult = ResponseMessage(httpResponseMessage);
return httpActionResult;
}
catch (Exception)
{
throw;
}
}
}
}
Here's the network tab of the client browser before I hit the button to fire of the Asp.Net MVC method.
The network tab of the client browser after I hit the button to fire of the Asp.Net MVC method and it fails.
Here's another example of Postman executing another method of my api just fine.
I got it to work by setting this as: client.BaseAddress = new Uri("localhost:56224"); and setting the string restOfUrl = "/api/profileandblog/validatesignin/" + signInViewModel.Username + "/" + signInViewModel.Password + "/" + myIpAddress + "/";

SignalR in MVC skewing Application Insights

We just started using SignalR in an MVC application and now we're getting a bunch of alerts due to high average response time. I suspect this to be misleading as the application isn't experiencing performance degradation. It appears that SignalR uses this URL to make a connection. This url not a controller/action of the project and just the built in SignalR code in the js file. jquery.signalR-2.2.1.js is the file. I suspect that it is just leaving the websocket connection open while they are on this page and it's skewing our numbers. Is this accurate? If so, is there a way to filter it out of the application insights?
Here is the counter. Is this the expected behavior?
Here is the signalR jquery code where it builds it's url:
// BUG #2953: The url needs to be same otherwise it will cause a memory leak
getUrl: function (connection, transport, reconnecting, poll, ajaxPost) {
/// <summary>Gets the url for making a GET based connect request</summary>
var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
url = baseUrl + connection.appRelativeUrl,
qs = "transport=" + transport;
if (!ajaxPost && connection.groupsToken) {
qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken);
}
if (!reconnecting) {
url += "/connect";
} else {
if (poll) {
// longPolling transport specific
url += "/poll";
} else {
url += "/reconnect";
}
if (!ajaxPost && connection.messageId) {
qs += "&messageId=" + window.encodeURIComponent(connection.messageId);
}
}
url += "?" + qs;
url = transportLogic.prepareQueryString(connection, url);
if (!ajaxPost) {
url += "&tid=" + Math.floor(Math.random() * 11);
}
return url;
},
I fixed this by following the instructions on https://learn.microsoft.com/en-us/azure/application-insights/app-insights-api-filtering-sampling:
Update your ApplicationInsights Nuget package to 2.0.0 or later.
Create a class implementing ITelemetryProcessor:
public class UnwantedTelemetryFilter : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
public UnwantedTelemetryFilter(ITelemetryProcessor next)
{
this.Next = next;
}
public void Process(ITelemetry item)
{
var request = item as RequestTelemetry;
if (request != null && request.Name != null)
if (request.Name.Contains("signalr"))
return;
// Send everything else:
this.Next.Process(item);
}
}
Add the processor to your Application_Start() in Global.asax.cs:
var builder = TelemetryConfiguration.Active.TelemetryProcessorChainBuilder;
builder.Use((next) => new UnwantedTelemetryFilter(next));
builder.Build();
if the calls are coming from the C# part of the app, the easiest way is to write a custom telemetry processor:
https://learn.microsoft.com/en-us/azure/application-insights/app-insights-api-filtering-sampling
public void Process(ITelemetry item)
{
var request = item as RequestTelemetry;
if (request != null && request.[some field here].Equals("[some signalr specific check here]", StringComparison.OrdinalIgnoreCase))
{
// To filter out an item, just terminate the chain:
return;
}
// Send everything else:
this.Next.Process(item);
}
and use that to explicitly filter out the signalr calls from being sent
or if the calls are coming from JS, then the telemetry initializer there does a similar thing to filter out telemetry if you return false in the initializer.

Create to database using web api

I am trying to insert a new entry in my database using web api. I have two web projects: one is a UI project where all the user interaction will occur and the other is a services project which will handle all interactions with my database.
Below is my post method that will take in form data for creating a new team.
// POST: Api/Team/Create
[HttpPost]
public ActionResult Create(Team team)
{
try
{
if (ModelState.IsValid)
{
HttpEndPointContext httpEndPoint = new HttpEndPointContext()
{
AuthenticationMethod = HttpAuthenticationMethods.None,
Ssl = false,
HttpMethod = HttpMethod.Post,
Path = "localhost:32173/api/team/",
QueryStrings = null,
PayloadData = SerializationHelper.Current.Serialize(team.ToString(), SerializationTypes.Xml)
};
IProcessResult result = HttpConnectionManager.Current.SendMessage(httpEndPoint);
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
And this is my method for dealing with my PayloadStream/PayloadData attribute in the above method:
private void StreamPayload(HttpWebRequest webRequest, HttpEndPointContext httpEndPointContext)
{
if (httpEndPointContext.HttpMethod == new HttpMethod("GET"))
return;
//TODO: FIX MAYBE .... sometimes we want to post body with GET.
//Stream vs string
if (httpEndPointContext.PayloadStream == null)
{
//Wrap with SOAP Envelope and method if defined in SoapDefinition
string data = httpEndPointContext.PayloadData ?? String.Empty;
if (httpEndPointContext.SoapDefinition != null)
{
//If parameters is set, clear existing payload data.
data = String.Empty;
if (httpEndPointContext.SoapDefinition.Parameters != null)
foreach (var parameter in httpEndPointContext.SoapDefinition.Parameters)
{
data += String.Format("<{0}>{1}</{0}>", parameter.Key, parameter.Value);
}
data = String.Format("<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>" +
"<s:Body><{0} xmlns='{2}'>" +
"{1}</{0}></s:Body></s:Envelope>",
httpEndPointContext.SoapDefinition.SoapMethod, data,httpEndPointContext.SoapDefinition.SoapGlobalKey);
}
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(data);
httpEndPointContext.PayloadStream = new MemoryStream(byteArray);
}
using (Stream requestStream = webRequest.GetRequestStream())
{
StreamHelper.Current.CopyStreams(httpEndPointContext.PayloadStream, requestStream);
requestStream.Close();
}
}
And the code for getting the server response. I'm currently getting an Internal Server (500) Error. Not sure why.
public IProcessResult SendMessage(HttpEndPointContext httpEndPointContext)
{
HttpWebRequest webRequest = CreateWebRequest(httpEndPointContext);
StreamPayload(webRequest, httpEndPointContext);
IProcessResult result = GetWebResponse(webRequest, httpEndPointContext);
return result;
}
private IProcessResult GetWebResponse(HttpWebRequest webRequest, HttpEndPointContext httpEndPointContext)
{
//Get Response
WebResponse response;
IProcessResult result = new ProcessResult(Statuses.Success);
try
{
response = webRequest.GetResponse();
}
catch (System.Net.WebException ex)
{
//Do exception handling. Still get the response for 500s etc.
result.Error.Exception = ex;
result.Status = Constants.Statuses.FailedUnknown;
result.ResponseCodeDescription = ex.Status.ToString();
result.ResponseCode = ex.Status.ToString();
result.Error.ErrorCode = ex.Status.ToString();
response = ex.Response;
//The error did not have any response, such as DNS lookup.
if (response == null)
return result;
}
try
{
//Get the response stream.
Stream responseData = response.GetResponseStream();
if (responseData == null)
throw new CoreException("No Response Data in GetWebResponse.",
"No Response Data in GetWebResponse. EndPoint:{0}", httpEndPointContext.ToString());
// Open the stream using a StreamReader for easy access.
var reader = new StreamReader(responseData);
// Read the content.
result.ResponseData = reader.ReadToEnd();
}
finally
{
response.Close();
}
result.ResponseCode = ((int)((HttpWebResponse)response).StatusCode).ToString();
result.ResponseCodeDescription = ((HttpWebResponse) response).StatusDescription;
return result;
}
And finally, my method for inserting to the database, found in my services project:
//POST api/controller/5
public IProcessResult Insert(Team team)
{
return TeamBusinessManager.Current.Insert(SecurityManager.Current.ConnectionContext, new Team());
}
I'm confused as to why I'm getting the 500 error. I'm not sure if it's the PayloadData attribute in my POST method or is it something wrong with my method in my services project.

calling a webservice from scheduled task agent class in windows phone 7.1

Can we call a webservice from the scheduled periodic task class firstly, if yes,
Am trying to call a webservice method with parameters in scheduled periodic task agent class in windows phone 7.1. am getting a null reference exception while calling the method though am passing the expected values to the parameters for the webmethod.
am retrieving the id from the isolated storage.
the following is my code.
protected override void OnInvoke(ScheduledTask task)
{
if (task is PeriodicTask)
{
string Name = IName;
string Desc = IDesc;
updateinfo(Name, Desc);
}
}
public void updateinfo(string name, string desc)
{
AppSettings tmpSettings = Tr.AppSettings.Load();
id = tmpSettings.myString;
if (name == "" && desc == "")
{
name = "No Data";
desc = "No Data";
}
tservice.UpdateLogAsync(id, name,desc);
tservice.UpdateLogCompleted += new EventHandler<STservice.UpdateLogCompletedEventArgs>(t_UpdateLogCompleted);
}
Someone please help me resolve the above issue.
I've done this before without a problem. The one thing you need to make sure of is that you wait until your async read processes have completed before you call NotifyComplete();.
Here's an example from one of my apps. I had to remove much of the logic, but it should show you how the flow goes. This uses a slightly modified version of WebClient where I added a Timeout, but the principles are the same with the service that you're calling... Don't call NotifyComplete() until the end of t_UpdateLogCompleted
Here's the example code:
private void UpdateTiles(ShellTile appTile)
{
try
{
var wc = new WebClientWithTimeout(new Uri("URI Removed")) { Timeout = TimeSpan.FromSeconds(30) };
wc.DownloadAsyncCompleted += (src, e) =>
{
try
{
//process response
}
catch (Exception ex)
{
// Handle exception
}
finally
{
FinishUp();
}
};
wc.StartReadRequestAsync();
}
private void FinishUp()
{
#if DEBUG
try
{
ScheduledActionService.LaunchForTest(_taskName, TimeSpan.FromSeconds(30));
System.Diagnostics.Debug.WriteLine("relaunching in 30 seconds");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
#endif
NotifyComplete();
}

How to handle add request in smack API

I use Smack API to write my Google talk Client . Now i need to handle add request for this .
I set SubscriptionMode to manual & now I have to registering a listener for presence packets but i don't know how !!
can any body help ?
I have not tried it yet, but I guess the below should work. If using the manual mode, a PacketListener should be registered that listens for Presence packets that have a type of Presence.Type.subscribe.
First set the roster:
Roster roster = connection.getRoster();
roster.setSubscriptionMode(Roster.SubscriptionMode.manual);
Then add a packet listner to the above connection, eg :
connection.addPacketListener(new SubscriptionListener(), new PacketFilter(){
public boolean accept(Packet packet) {
if(packet instanceof Presence)
if(((Presence)packet).getType().equals(Presence.Type.subscribe))
return true;
return false;
}});
The above code just returns true for all requests, But you can customize it i.e set it to true or false based on user GUI input.
public static void admitFriendsRequest() {
connection.getRoster().setSubscriptionMode(
Roster.SubscriptionMode.manual);
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet paramPacket) {
System.out.println("\n\n");
if (paramPacket instanceof Presence) {
Presence presence = (Presence) paramPacket;
String email = presence.getFrom();
System.out.println("chat invite status changed by user: : "
+ email + " calling listner");
System.out.println("presence: " + presence.getFrom()
+ "; type: " + presence.getType() + "; to: "
+ presence.getTo() + "; " + presence.toXML());
Roster roster = connection.getRoster();
for (RosterEntry rosterEntry : roster.getEntries()) {
System.out.println("jid: " + rosterEntry.getUser()
+ "; type: " + rosterEntry.getType()
+ "; status: " + rosterEntry.getStatus());
}
System.out.println("\n\n\n");
if (presence.getType().equals(Presence.Type.subscribe)) {
Presence newp = new Presence(Presence.Type.subscribed);
newp.setMode(Presence.Mode.available);
newp.setPriority(24);
newp.setTo(presence.getFrom());
connection.sendPacket(newp);
Presence subscription = new Presence(
Presence.Type.subscribe);
subscription.setTo(presence.getFrom());
connection.sendPacket(subscription);
} else if (presence.getType().equals(
Presence.Type.unsubscribe)) {
Presence newp = new Presence(Presence.Type.unsubscribed);
newp.setMode(Presence.Mode.available);
newp.setPriority(24);
newp.setTo(presence.getFrom());
connection.sendPacket(newp);
}
}
}
}, new PacketFilter() {
public boolean accept(Packet packet) {
if (packet instanceof Presence) {
Presence presence = (Presence) packet;
if (presence.getType().equals(Presence.Type.subscribed)
|| presence.getType().equals(
Presence.Type.subscribe)
|| presence.getType().equals(
Presence.Type.unsubscribed)
|| presence.getType().equals(
Presence.Type.unsubscribe)) {
return true;
}
}
return false;
}
});
connection.getRoster().addRosterListener(new RosterListener() {
public void presenceChanged(Presence presence) {
System.out.println(presence.getFrom() + "presenceChanged");
}
public void entriesUpdated(Collection<String> presence) {
System.out.println("entriesUpdated");
}
public void entriesDeleted(Collection<String> presence) {
System.out.println("entriesDeleted");
}
public void entriesAdded(Collection<String> presence) {
System.out.println("entriesAdded");
}
});
}

Resources