I am using the BCXAPI for .net and I am trying to get a list of people for a project but this doesn't seem to be available in the API.
I found documentation that shows it's possible:
GET /projects/#{project_id}/people.xml
but I was hoping not to have to break pattern and stick with using the api.
Can someone validate my suspicion that this can't be done with the BCXAPI?
I have been trying to piece together bits and pieces from different articels and I'm trying this approach:
var basecampProjects = s.GetProjects(a.Id);
foreach (var proj in basecampProjects)
{
var client = new RestClient()
{
BaseUrl = new Uri("https://basecamp.com/" + a.Id + "/api/v1/projects/" + proj.Id + "/people.json/")
};
client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(AccessToken.access_token);
var request = new RestRequest(Method.GET);
request.RequestFormat = DataFormat.Json;
request.AddHeader("User-Agent", "PicoDev (trevor#l9digitalstrategies.com)");
request.AddHeader("Content-type", "application/json");
request.AddHeader("charset", "utf - 8");
request.AddHeader("Authorization", AccessToken.access_token);
request.AddParameter("client_id", clientId);
request.AddParameter("client_secret", clientSecret);
var result = client.Execute(request);
string jsonResult = result.Content;
}
But I am getting a "not found" result. Is this not available anymore or am I just making a mistake in my call?
Ok so I found out that this is possible using the BCXAPI, here is how I implemented it api documentation here
var accounts = s.GetAccounts();
foreach (var a in accounts.accounts)
{
try
{
var basecampProjects = s.GetProjects(a.Id);
foreach (var proj in basecampProjects)
{
var accesses = s.GetAccessesForProject(a.Id, proj.Id);
}
}
catch (Exception ex)
{
}
}
Related
how can i get a signal that my external agenda in my own app needs to be updated when there is a new event been made. at this moment my code looks like this but i can't retrieve a new event from google calendar. what do i do wrong.
public async Task<List<EventModel>> GetAllEventsAsync()
{
var refresToken = RetrieveRefreshTokenAndRevoke.RefreshToken();
if (refresToken == "ok")
{
var tokens = JObject.Parse(System.IO.File.ReadAllText(ConstantJsonFileLink.TOKEN));
RestClient restClient = new RestClient(new Uri("https://www.googleapis.com/calendar/v3/calendars/primary/events"));
RestRequest restRequest = new RestRequest(Method.GET);
restRequest.AddQueryParameter("key", $"{ApiKey}");
restRequest.AddHeader("Authorization", "Bearer " + tokens["access_token"]);
restRequest.AddHeader("Accept", "application/json");
try
{
var response = await restClient.ExecuteAsync(restRequest);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
JObject calendarEvents = JObject.Parse(response.Content);
var allEvents = calendarEvents["items"].ToObject<List<EventModel>>();
return allEvents;
}
}
catch (Exception ex)
{
throw new Exception("Coulden't connect to google agenda.");
}
}
return null;
}
There are two ways to find out if there were changes to any events in your google calendar.
The first and less robust solution woudl be polling. You could run an events.list every five minutes or so and check for changes.
The second option would be to listen for changes by setting up a watch and listing for push notifications the way this works is you set up a web end point on your system that listens for calls from Google calendar. In the event a change is made to any of your events Google will notify this endpoint on your server and you will then know that you need to make a new call to the api to get any updates.
public Watch WatchEventAsync()
{
var refresToken = RetrieveRefreshTokenAndRevoke.RefreshToken();
if (refresToken == "ok")
{
var tokens = JObject.Parse(System.IO.File.ReadAllText(ConstantJsonFileLink.TOKEN));
var restClient = new RestClient();
var restRequest = new RestRequest();
restClient.BaseUrl = new System.Uri("https://www.googleapis.com/calendar/v3/calendars/Primary/events/watch");
Watch watch = new Watch();
watch.Id = CalendarId;
watch.Token = refresToken;
watch.Type = "webhook";
watch.Params = new Watch.Param { Ttl = "604800" };
var model = JsonConvert.SerializeObject(watch, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
restRequest.AddQueryParameter("key", $"{ApiKeys}");
restRequest.AddHeader("Authorization", "Bearer " + tokens["access_token"]);
restRequest.AddHeader("Accept", "application/json");
restRequest.AddHeader("Content-Type", "application/json; charset=utf-8");
restRequest.AddParameter("application/json", model, ParameterType.RequestBody);
try
{
var restResponse = restClient.Post(restRequest);
if (restResponse.StatusCode == System.Net.HttpStatusCode.OK)
{
JObject watchEvents = JObject.Parse(restResponse.Content);
return watchEvents.ToObject<Watch>();
}
}
catch (Exception ex)
{
throw new Exception("Coulden't Create an event in google agenda.");
}
}
return null;
}
// I have this for the moment
I've been troubleshooting this for days now but still no luck.
I'm trying to send parameters to an API link provided by Microsoft O365 Power Automate, this API requires a customer number, company code, and posting date and in return, it will send me a table with the list of items that have the same customer number, company code, and posting date. When I'm doing testing in Postman the sends status code 200, but when using VS and my code it always returns a status code 400.
SoaController.cs
[HttpPost]
public async Task<IActionResult> Index(string company, string customer, string asof)
{
using (var client = new HttpClient())
{
SoaParams soaParams = new SoaParams
{
Posting_Date = asof,
Company_Code = company,
Customer_Number = customer
};
var SoaJson = JsonConvert.SerializeObject(soaParams);
var buffer = Encoding.UTF8.GetBytes(SoaJson);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.BaseAddress = new Uri(SD.ApiUri);
var response = await client.PostAsync(SD.ApiUri, byteContent);
if (response.IsSuccessStatusCode)
{
return RedirectToAction(nameof(Success), Json(response));
}
else
{
return RedirectToAction(nameof(Failed), Json(response));
}
}
}
The below image shows that the parameters needed are correct.
But it's SuccessStatusCode always returns false
I use a code provided by PostMan that look like this:
public List<BapiOpenItemDto> GetResponse(SoaParams soaParams, string uri)
{
var SoaJson = JsonConvert.SerializeObject(soaParams);
var client = new RestClient(uri);
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "[\r\n" + SoaJson + "\r\n]\r\n", ParameterType.RequestBody);
IRestResponse<List<BapiOpenItemDto>> response = client.Execute<List<BapiOpenItemDto>>(request);
return response.Data;
}
and its working now.
I'm working with Jira REST APIs with visual studio (c#) with help of Atlassian.NET SDK and trying to build such model:
search for ticket with Project, issue summary and status;
If issue is found, then I want to change its status from “To Do” to “Done”;
If there are no issues found, then do nothing.
Search functionality works good, the problem is with changing its status. Here’s my code:
static async System.Threading.Tasks.Task Main(string[] args)
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; //TLS 1.2
try
{
// Connection to JIRA using REST client
var jira = Jira.CreateRestClient("https://XXX.atlassian.net", "user", "token");
// LINQ syntax for retrieving issues
var issue = (from i in jira.Issues.Queryable
where i.Project == "QA" && i.Summary == "Summary" && i.Status == "To Do"
orderby i.Created
select i).First();
await issue.SaveChangesAsync();
string ticketid = issue.Key.Value;
string ticketsummary = issue.Summary;
string ticketkey = issue.JiraIdentifier;
//Updating found issue
var closeticket = await jira.Issues.GetIssueAsync(ticketid);
closeticket.Status = "Done";
await closeticket.SaveChangesAsync();
}
catch (Exception ex) { /*Result: SUCCESS [no issues found]*/ }
}
With this code I’m trying to search in project “QA”, where issue summary is “Summary” and status is “To Do”. Then I want to close its Status from “To Do” to “Done”. But I’m getting error on line closeticket.Status = "Done"; with text:
Error CS0200 Property or indexer 'Issue.Status' cannot be assigned to -- it is read only
Please give me some suggestions or I’m about to hang myself…
Thank you in advance.
EDIT:
I forgot to mention that I also tried to do the status changing case with help of httpclient. But there's a problem, when I connect to issue transitions, it returns error with statuscode 404.
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;
handler.Proxy = new WebProxy("https://XXX.atlassian.net", true, null, CredentialCache.DefaultNetworkCredentials);
// need to pass a valid username + password to JIRA
var jiraCredentials = UTF8Encoding.UTF8.GetBytes("user:token");
var httpClient = new HttpClient(handler);
httpClient.MaxResponseContentBufferSize = int.MaxValue;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(jiraCredentials));
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string transitionURL = "https://XXX.atlassian.net" + "/rest/api/2/issue/" + "QA-10" + "/transitions?expand=transitions.fields";
string jsonString = "{ \"update\":{},\"transition\": { \"id\": \"" + "31" + "\"}, \"fields\": { } }";
var sContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
var httpClientt = new HttpClient();
HttpResponseMessage transitionResponse = httpClientt.PostAsync(transitionURL, sContent).Result;
httpClient.Dispose();
After a deep research, I have finally reached the right way which is http request.
If there's anybody suffering with problem, here's a code:
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://XXX.atlassian.net/rest/api/2/issue/TST-4/transitions?expand=transitions.fields"))
{
var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes("user:token"));
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
request.Content = new StringContent("{\"transition\":{\"id\":\"31\"}}");
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await httpClient.SendAsync(request);
}
}
I have a bot running on http://localhost:3978/api/messages.
Instead of debugging it using an emulator, can I go about using a http post request to the messaging endpoint of the bot?
If so, how do I go about doing it?
I am using c# microsoft bot framework, and I am new to this application.
I do not want to use any channels or DirectLine api, just using Httpclient.
You can do this with C# using code similar to below. Note that you would have to construct an Activity to send by setting the appropriate properties for your needs, which is not included in this code.
//make a call to get an auth token
string token;
using (var client = new WebClient())
{
var values = new NameValueCollection();
values["grant_type"] = "client_credentials";
values["client_id"] = "YOUR APP ID";
values["client_secret"] = "NcOXRwb51joibEfzUuNE04u";
values["scope"] = "YOUR APP ID/.default";
var response =
client.UploadValues("https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token", values);
var responseString = Encoding.Default.GetString(response);
var result = JsonConvert.DeserializeObject<ResponseObject>(responseString);
token = result.access_token;
}
//you will need to adjust this value for your project.
//this example for a proxy project so the service url here is
//just an arbitrary endpoint I was using to send activities to
activity.ServiceUrl = "http://localhost:4643/api/return";
var jsonActivityAltered = JsonConvert.SerializeObject(activity);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/json");
client.Headers.Add("Authorization", $"Bearer {token}");
try
{
var btmResponse = client.UploadString("http://localhost:3971/api/messages", jsonActivityAltered);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
Have you tried using something like postman? (it's free and easy to use)
https://www.getpostman.com/
You can also write scripts in postman
otherwise you can just go to the endpoint of your API in the browser
http://localhost:3978/api/
I see you mentioned you wanted to make a console application.
You could do that. I'd suggest using postman though.
Here is an example of sending a file as well as some querystring data and Authentication using a Bearer token.
Sorry it may not be exact. Had to do a bit of copy pasting/deleting from some code examples if have
using (HttpClient client = new HttpClient())
{
JObject jsonModel = new JObject();
client.BaseAddress = new Uri("http://localhost:3978/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken);
using (var multipartFormDataContent = new MultipartFormDataContent())
{
var values = new[]
{
new KeyValuePair<string, string>("firstname", lastname),
new KeyValuePair<string, string>("lastname", lastname),
new KeyValuePair<string, string>("payloadFile", FileName)
};
foreach (var keyValuePair in values)
{
multipartFormDataContent.Add(new StringContent(keyValuePair.Value),
String.Format("\"{0}\"", keyValuePair.Key));
}
ByteArrayContent fileContent = new ByteArrayContent(File.ReadAllBytes(HttpContext.Current.Server.MapPath("~/uploads/output/" + FileName)));
string FullxmlString = File.ReadAllText(Path.Combine(HttpContext.Current.Server.MapPath("~/uploads/output/" + FileName)));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("payloadFile") { FileName = "payloadFile" };
multipartFormDataContent.Add(fileContent);
HttpResponseMessage response = client.PostAsync("api/message", multipartFormDataContent).Result;
string returnString = response.Content.ToString();
using (HttpContent content = response.Content)
{
string res = "";
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
}
}
}
I am using postman and making an api post request where I am adding body with x-www-form-urlencoded key/values and it works fine in postman.
The issue arrises when I try it from c# using RestSharp package.
I have tried the following code below but not getting the response. I get "BadRequest" invalid_client error.
public class ClientConfig {
public string client_id { get; set; } = "value here";
public string grant_type { get; set; } = "value here";
public string client_secret { get; set; } = "value here";
public string scope { get; set; } = "value here";
public string response_type { get; set; } = "value here";
}
public void GetResponse() {
var client = new RestClient("api-url-here");
var req = new RestRequest("endpoint-here",Method.POST);
var config = new ClientConfig();//values to pass in request
req.AddHeader("Content-Type","application/x-www-form-urlencoded");
req.AddParameter("application/x-www-form-urlencoded",config,ParameterType.RequestBody);
var res = client.Execute(req);
return;
}
//Also tried this
req.AddParameter("client_id",config.client_id,"application/x-www-form-urlencoded",ParameterType.RequestBody);
req.AddParameter("grant_type",config.grant_type,"application/x-www-form-urlencoded",ParameterType.RequestBody);
req.AddParameter("client_secret",config.client_secret,"application/x-www-form-urlencoded",ParameterType.RequestBody);
req.AddParameter("scope",config.scope,ParameterType.RequestBody);
req.AddParameter("response_type",config.response_type,"application/x-www-form-urlencoded",ParameterType.RequestBody);
//tried this too
var client = new RestClient("url-here");
var req = new RestRequest("endpointhere",Method.POST);
var config = new ClientConfig();
req.AddBody(config);
var res = client.Execute(req);
this working for me, it was generator from postman
var token = new TokenValidation()
{
app_id = CloudConfigurationManager.GetSetting("appId"),
secret = CloudConfigurationManager.GetSetting("secret"),
grant_type = CloudConfigurationManager.GetSetting("grant_type"),
Username = CloudConfigurationManager.GetSetting("Username"),
Password = CloudConfigurationManager.GetSetting("Password"),
};
var client = new RestClient($"{xxx}{tokenEndPoint}");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", $"app_id={token.app_id}&secret={token.secret}&grant_type={token.grant_type}&Username={token.Username}&Password={token.Password}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine("Access Token cannot obtain, process terminate");
return null;
}
var tokenResponse = JsonConvert.DeserializeObject<TokenValidationResponse>(response.Content);
I personally find this way to work better for me when sending Form-UrlEncoded data.
public void GetResponse() {
var client = new RestClient("api-url-here");
var req = new RestRequest("endpoint-here",Method.POST);
var config = new ClientConfig();//values to pass in request
// Content type is not required when adding parameters this way
// This will also automatically UrlEncode the values
req.AddParameter("client_id",config.client_id, ParameterType.GetOrPost);
req.AddParameter("grant_type",config.grant_type, ParameterType.GetOrPost);
req.AddParameter("client_secret",config.client_secret, ParameterType.GetOrPost);
req.AddParameter("scope",config.scope, ParameterType.GetOrPost);
req.AddParameter("response_type",config.response_type, ParameterType.GetOrPost);
var res = client.Execute(req);
return;
}
Details on this parameter type can be found here:
https://github.com/restsharp/RestSharp/wiki/ParameterTypes-for-RestRequest#getorpost
Personally, I found AddObject() method quite useful, and cleaner when you have so many parameters to add.
public void GetResponse() {
var client = new RestClient("api-url-here");
var req = new RestRequest("endpoint-here",Method.POST);
var config = new ClientConfig();//values to pass in request
req.AddHeader("Content-Type","application/x-www-form-urlencoded");
req.AddObject(config);
var res = client.Execute(req);
return res;
}
If it worked on postman, you can just press the code button on the right hand side. This will provide a working example in multiple languages. It is the button above the information icon. I would post a screenshot of it, but I don't have 10 reputation to do so.
i have found this good for my scenario , it is working perfect,
var client = new RestClient("https://test.salesforce.com/services/oauth2/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=password&client_id=3MVG9U_dUptXGpYKew7P.oPwrIsvowP_K4CsnkxHJIEOUJzW0XBUUY3o12bLDasjeIPGVobvBZo8TNFcCY6J3&client_secret=3189542819149073716&username=integraciones%40lamarina.com.mx.dev&password=2Password!4iwZvMQKVAwkYyJRy50JlAHk", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine("Response.StatusCode: " + response.StatusCode);
Console.WriteLine("Response.Content: " + response.Content);
Console.WriteLine("Response.ErrorMessage: " + response.ErrorMessage);
https://dotnetfiddle.net/J64FR5
in my case this is what worked
req.AddParameter("client_id", "unigen-corporation", ParameterType.HttpHeader);
req.AddParameter("grant_type", "client_credentials", ParameterType.GetOrPost);
If you've copied the code from the postman, try removing the following:
request.AlwaysMultipartFormData = true;
In my case after removing this line code worked.
var client1 = new RestClient(URI);
var request1 = new RestRequest(Method.POST);
request1.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request1.AddParameter("client_id", "XX");
request1.AddParameter("client_secret", "XX");
request1.AddParameter("grant_type", "XX");
request1.AddParameter("role", "XX");
IRestResponse response1 = client1.Execute(request1);
System.Console.WriteLine(response1.Content);
Add parameters according to your needs. This work fine!
for my code, this works perfect.
// extention function for object->formed data body string
public static string toFormDataBodyString(this object src)
{
var res = new List<string>();
foreach (var key in src.GetType().GetProperties())
{
res.Add($"{key.Name}={src.GetType().GetProperty(key.Name)?.GetValue(src)}");
}
return string.Join("&", res);
}
//--------------------------------------
var data = new {
param1 = xxxx,
param2 = xxxx
}
var translateReq = new RestRequest("url_here")
.AddHeader("Content-Type", "application/x-www-form-urlencoded")
.AddParameter("application/x-www-form-urlencoded", data.toFormDataBodyString(), ParameterType.RequestBody);