Calendar V3 Broke and I have no idea why - ruby-on-rails

I'm using the following code and it worked but all of a sudden it is not working. I have another method that gets free busy using the same auth and everything is working fine. Below is my method as well as the console log.
def createEvent(title, event_description, mentor, mentee, start_time, end_time)
calendar_api = Google::Apis::CalendarV3::CalendarService.new
calendar_api.authorization = #auth
event = Google::Apis::CalendarV3::Event.new(
summary: title,
description: event_description,
start: {
date_time: start_time.iso8601,
time_zone: 'Etc/UTC',
},
end: {
date_time: end_time.iso8601,
time_zone: 'Etc/UTC',
},
attendees: [
{email: mentor},
{email: mentee},
],
reminders: {
use_default: true,
},
)
calendar_api.insert_event('primary', event)
end
The console error I am getting is as shown
Sending HTTP post https://www.googleapis.com/calendar/v3/calendars/primary/events?
400
#<Hurley::Response POST https://www.googleapis.com/calendar/v3/calendars/primary/events == 400 (276 bytes) 300ms>
Caught error invalid
Error - #<Google::Apis::ClientError: invalid>

As suggested here, try putting a breakpoint in a debug session to know where the error was coming from. Also, the warning will be solved if you upgrade to 3.0 or turn off deprecations using Representable.deprecations = false. You may also check these references: https://github.com/google/google-api-ruby-client/issues/407 and https://github.com/trailblazer/representable/issues/195

Related

ZendeskApi.Tickets.CreateTicket throws 401 despite "Anybody can submit tickets" is enabled

I have a Trial subscription and I'm using ZendeskApi.Tickets.CreateTicket(ticket) to create a new ticket; Anybody can submit tickets is Enabled. It works when I create a ticket with requester.email that is a registered user, but I'm getting the below error when I try to create a ticket with a Requester who is not a user. Tips on what I'm doing wrong?
The remote server returned an error: (401) Unauthorized.Error content: {"error":"Couldn't authenticate you"}
Resource String: tickets.json +
Body: {
"ticket": {
"subject": "Subject",
"comment": {
"body": "Message test body",
"public": false
},
"requester": {
"email": "wendellj#gmail.com"
},
"is_public": false
}
For anonymous user you should use this api end point: https://developer.zendesk.com/rest_api/docs/core/requests#create-request
This is used to create requests in zendesk when user is not registered with user and it doesn't need authentication header as well. See
To make anonymous requests:
Omit the authorization header.
Include a requester object in the request object.

Google auth for YouTube doesn't work in Rails

I'm using Rails 5.1.1 an yt gem 0.28
I used official gem docs (link is above).
Also these docs Github
And tried to check myself with this tutorial on SitePoint
If you check comments below the SP's tutorial - there was the same issue but yt owner removed Issues so I can't use it.
Gem seems to be working fine. At least when I place:
video = Yt::Video.new id: 'BPNYv0vd78A'
in video_controllers.rb and then ask for video.description, it answers with description. So lets put a tick here.
And I cofigured YT as it was said:
Yt.configure do |config|
config.log_level = :debug
config.client_id = "[my_client_id].apps.googleusercontent.com"
config.client_secret = "[my_secret_key]"
config.api_key = '[my_api_key]'
end
I copied values from google_oauth2, so if there it's OK, it must be OK here as well.
But when I try to use anything involving authentification something very strange happens.
FIRST PART - access token
According to the manual, if I have access token I can just:
account = Yt::Account.new access_token: 'ya29.[authenticating_user_token]'
account.email
Here goes the message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid Credentials"
}
}
Also it offers curl command to simulate this action:
curl -X GET -H "content-length: 0" -H "user-agent: Yt::Request (gzip)" -H "authorization: Bearer ya29.[authenticating_user_token]" -H "host: www.googleapis.com" "https://www.googleapis.com/oauth2/v2/userinfo?key=[my_api_key]"
authenticating_user_token is the same as I get from google auth json like user.auth_hash["credentials"]["token"]
my_api_key is the same key from Google Developers Console.
When I requested account's value through byebug, it gave me:
#<Yt::Models::Account:0x000000051473f0 #access_token="ya29.[authenticating_user_token]", #refresh_token=nil, #device_code=nil, #expires_at=nil, #authorization_code=nil, #redirect_uri=nil, #force=nil, #scopes=nil, #authentication=nil>
The first question that stays without answer: "Why it uses api key if docs say all I need is access_token?"
SECOND PART refresh_token
Actually, after the fiasco with access token I thought that it might be that
"credentials"=>{"token"=>"ya29.[authenticating_user_token]",
"expires"=>true,
"expires_at"=>1518443279}
is the mysterious refresh token!
It gave me the same 'Invalid Credentials'
So I modified videos_controller.rb:
account = Yt::Account.new(refresh_token: user.auth_hash["credentials"]["token"],
expires_at: user.auth_hash["credentials"]["expires_at"],
expires: user.auth_hash["credentials"]["expires"])
This time with byebug I got account's value:
#<Yt::Models::Account:0x00000007a6e5a8 #access_token=nil, #refresh_token="ya29.[you know_what]", #device_code=nil, #expires_at=1518443279, #authorization_code=nil, #redirect_uri=nil, #force=nil, #scopes=nil, #authentication=nil, #user_infos=#<Yt::Collections::UserInfos:0x00000007a305a0 #parent=#<Yt::Models::Account:0x00000007a6e5a8 ...>, #auth=#<Yt::Models::Account:0x00000007a6e5a8 ...>, #page_token=nil, #last_index=0, #items=[]>, #refreshed_authentications=#<Yt::Collections::Authentications:0x007ff0080054b0 #parent=#<Yt::Models::Account:0x00000007a6e5a8 ...>, #auth=#<Yt::Models::Account:0x00000007a6e5a8 ...>, #auth_params={:client_id=>"[my_client_id].apps.googleusercontent.com", :client_secret=>"[my_client_secret]", :refresh_token=>"[you_know_what]", :grant_type=>:refresh_token}, #page_token=nil, #last_index=1, #items=[], #where_params={}>>
And requesting account.email:
*** Yt::Errors::Unauthorized Exception: A request to YouTube API was sent without a valid authentication:
{}
You can retry the same request manually by running:
nil
And the second question: "Was it refresh token or not?"
In YouTube account I have a working channel so it couldn't be a reason.
I would appreciate any help! If you have any app working with YouTube, please share the link to Github, so I could figure out what's wrong with my app!
Well, that's embarssing - nobody even tried to help...
Still I found the source of errors.
So the token from auth["credentials"]["token"] is access token.
My problems came because I didn't specify :scope in config/initializers/device.rb
It should be:
config.omniauth :google_oauth2, "[client_id_from_google_developers_console].apps.googleusercontent.com", "[key_from_google_developers_console]", scope: 'userinfo.profile, userinfo.email, youtube'
Also I noticed the error comes when a token expires, so you should do something like begin-rescue thing to update user's token time-to-time.
btn-group
use this class for the button div like <div class="btn-group"></div>
and apply
btn-group button:hover {
background-color: #3e8e41;
}
.btn-group:after {
content: "";
clear: both;
display: table;
}
.btn-group button:not(:last-child) {
border-right: none;
}

Rails: How to add a video call when creating a new Event through Google Calendar API

I am using the typheous gem to create a new Event through the Google Calendar API (V3). The response returns 200 and a Calendar Event is created. My question, is there a way to always create the Event with a video-call attached as well?
response = Typhoeus::Request.new(
"https://www.googleapis.com/calendar/v3/calendars/calendarId/events",
method: :post,
body: {
start: {
dateTime: Time.parse(split_time_range[0])
},
end: {
dateTime: Time.parse(split_time_range[1])
},
attendees: [
{
email: "#{ENV["my_email"]}"
}
],
summary: "New Meeting"
}.to_json,
params: {access_token: session[:google_calendar_access_token], calendarId: "primary", sendNotifications: true},
headers: {"Content-Type": "application/json"}
).run
The Google Calendar event body does have a field called HangoutsLink
hangoutLink string An absolute link to the Google+ hangout associated with this event. Read-only.
As you can see this field is read only. I would try and send it when you are creating your event but i am not sure its something you can set with the API.
There is an issue logged for this Calendar API: Hangout not being added automatically to event when creating using the API. I have not been able to find the "automatically create a video call to a created event" setting which they speak of but its an old issue this may have been removed.

Rails: Pretty print JSON without overkill

I'm using the below code to display an unauthorized message in JSON:
def render_unauthorized
# Displays the Unauthorized message since the user did
# not pass proper authentication parameters.
self.headers['WWW-Authenticate'] = 'Token realm="API"'
render json: {
error: {
type: "unauthorized",
message: "This page cannot be accessed without a valid API key."
}
}, status: 401
end
Which outputs:
{"error":{"type":"unauthorized","message":"This page cannot be accessed without a valid API key."}}
So my question is this: Is there a way to pretty print this message (WITHOUT putting it in a separate view and using some 3rd party gem).
Edit: What is pretty print?
Properly spaced, and well .. pretty. Here's the output I'd like to see:
{
"error": {
"type": "unauthorized",
"message": "This page cannot be accessed without a valid API key."
}
}
Solution
Using #emaillenin's answer below worked. For the record, here's what the final code looks like (since he hadn't included the whole thing):
def render_unauthorized
# Displays the Unauthorized message since the user did
# not pass proper authentication parameters.
self.headers['WWW-Authenticate'] = 'Token realm="API"'
render json: JSON.pretty_generate({ # <-- Here it is :')
error: {
type: "unauthorized",
message: "This page cannot be accessed without a valid API key."
}
}), status: 401
end
Use this helper method built into JSON.
JSON.pretty_generate
I just tried and it works:
> str = '{"error":{"type":"unauthorized","message":"This page cannot be accessed without a valid API key."}}'
> JSON.pretty_generate(JSON.parse(str))
=> "{\n \"error\": {\n \"type\": \"unauthorized\",\n \"message\": \"This page cannot be accessed without a valid API key.\"\n }\n}"
If you (like I) find that the pretty_generate option built into Ruby's JSON library is not "pretty" enough, I recommend my own NeatJSON gem for your formatting.
To use it gem install neatjson and then use JSON.neat_generate instead of JSON.pretty_generate.
Like Ruby's pp it will keep objects and arrays on one line when they fit, but wrap to multiple as needed. For example:
{
"navigation.createroute.poi":[
{"text":"Lay in a course to the Hilton","params":{"poi":"Hilton"}},
{"text":"Take me to the airport","params":{"poi":"airport"}},
{"text":"Let's go to IHOP","params":{"poi":"IHOP"}},
{"text":"Show me how to get to The Med","params":{"poi":"The Med"}},
{"text":"Create a route to Arby's","params":{"poi":"Arby's"}},
{
"text":"Go to the Hilton by the Airport",
"params":{"poi":"Hilton","location":"Airport"}
},
{
"text":"Take me to the Fry's in Fresno",
"params":{"poi":"Fry's","location":"Fresno"}
}
],
"navigation.eta":[
{"text":"When will we get there?"},
{"text":"When will I arrive?"},
{"text":"What time will I get to the destination?"},
{"text":"What time will I reach the destination?"},
{"text":"What time will it be when I arrive?"}
]
}
It also supports a variety of formatting options to further customize your output. For example, how many spaces before/after colons? Before/after commas? Inside the brackets of arrays and objects? Do you want to sort the keys of your object? Do you want the colons to all be lined up?
Using the aligned option would allow your output to look like this:
{
"error": {
"type" : "unauthorized",
"message" : "This page cannot be accessed without a valid API key."
}
}

422 error when creating a ticket in Zendesk

I am developping an app in ASP.NET MVC5 using Zendesk_v2 (uploaded using a nuget package). I have admin rights for subdomain easynext.zendesk.com.
Here is my code for creating a ticket:
private static string requestUri = "https://easynext.zendesk.com/api/v2/tickets.json";
private static string _username = "gbalasel#easynext.be";
private static string _password = "MYPASSWORD";
private static ZendeskApi apiZendesk = new ZendeskApi(requestUri, _username, _password, "");
private void CréerTicketZendesk() {
var myTicket = apiZendesk.Tickets.CreateTicket(new Ticket()
{
Subject = "test ticket",
Priority = TicketPriorities.Low
});
}
This code sends me a 422 Unprocessable Entity error.
I have also made a test account for a client in Zendesk and the method works fine, the ticket is created in Zendesk and I also receive it in my email account.
Status 422 is most likely caused by a semantic error on your part. In my experience, ZD can return 422 most often in two situations:
When trying to PUT an update to a ticket whose status is closed. In that case, you need to create a new ticket or a follow-up ticket, if possible.
Setting an invalid value on some attribute of the ticket object or sub-object of the ticket. This can be particularly tedious to debug, as the ZD response doesn't usually tell you which attribute has an invalid value. You should check all the integer values that you are setting on the ticket. E.g., I've been burned by using the Group IDs from my production Zendesk while developing on the Sandbox System (they most likely have entirely different IDs for everything, including custom fields, groups, users, etc.).
If you are creating new tickets via POST, be sure to check all the values you are setting, as per my second bullet point above.
This telling you that you have not formed a request that it can handle; the destination script exists (otherwise you'd see a 404), the request is being handled (otherwise you'd get a 400 error) and it's been encoded correctly (or you'd get a 415 error) but the actual instruction can't be carried out.
take a look on this for more info.
Error List
just to add to the solution if anyone encounters the same problem.
requester_id is mandatory while posting the ticket json.
A sample ticket json -
{
"ticket": {
"subject": "My printer is on fire!",
"requester_id": 123,
"assignee_id": 456,
"type": "incident",
"subject": "Help, my printer is on fire!",
"description": "The fire is very colorful.",
"priority": "High",
"status": "open",
"custom_fields": [
{
"id": 111, // custom field ID
"value": "500.23"
}
]
}
}
Thanks
Yeah I run today to the same problem and solved it. The problem is that you need a comment and body part inside the ticket structure.
So this is how it could look like (in PHP):
$ticket = [
'group_id' => '35135',
'title' => 'Title',
'subject' => 'Subject',
'type' => 'ticket',
'comment' => ['body' => 'Comment text.'],
'priority' => 'normal',
'ticket_form_id' => '454524',
'custom_fields' => [
'51325351' => 'test',
],
];
Take a look on here:
https://developer.zendesk.com/rest_api/docs/core/tickets
I had an issue with the Zendesk API throwing a 422 when I was attempting to create a ticket. All parameters were correct, the problem was that the assignee for which the ticket was created for did not belong to the group.
I found this error by looking at the request response by using FIDDLER.
Adding this here in case someone else runs into this issue. For me the ticket formatting was correct, but the requester was suspended:
Error Result:
{
"error": "RecordInvalid",
"description": "Record validation errors",
"details": {
"requester": [{
"description": "Requester: jkraft is suspended."
}]
}
}
Follow these instructions to unsuspend a user: https://support.zendesk.com/hc/en-us/articles/4408835668634-How-do-I-unsuspend-access-for-a-user-
I hope this is helpful to tell whether or not you are receiving the HTTP 422 because the ticket was already closed or if its because you were trying to do something like edit a field with invald params:
If you log the response object from zendesk for the failed http 422, you can look at the response object and check its configs. In my example it was:
response: {
status: 422,
statusText: 'Unprocessable Entity',
headers: {
date: 'Wed, 01 Feb 2023 17:48:00 GMT',
'content-type': 'application/json; charset=utf-8',
'content-length': '145',
connection: 'close',
'x-zendesk-api-version': 'v2',
'x-zendesk-application-version': 'v15375',
'x-frame-options': 'SAMEORIGIN',
'zendesk-rate-limit-tickets-update': 'total=100; remaining=99; resets=60',
'x-rate-limit': '700',
'rate-limit': '700',
'x-rate-limit-remaining': '699',
'rate-limit-remaining': '699',
'rate-limit-reset': '60',
'strict-transport-security': 'max-age=31536000;',
'cache-control': 'no-cache',
'x-zendesk-origin-server': 'classic-app-server-5b7bb5f96b-2bngr',
'set-cookie': [Array],
'x-request-id': '792c83f6384a5f9a-SMF, 792c83f6384a5f9a-SMF',
'x-runtime': '0.086818',
'x-zendesk-zorg': 'yes',
'cf-cache-status': 'DYNAMIC',
'report-to': '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=mwQlS2H5vr2L4HJeTbyCvhjJbRJIwwhO%2FjJFw1z5cpIkak9Oke5GtqcaWsrzIF9gnYxTnkiPAFpkBgprHoXcr2yi%2FvA7grLEoQvXeHhsSmzOnu2LslqRDbzYeeMhRRtQwIrE0uLhrZJxTzlo%2FIfcKZ4%3D"}],"group":"cf-nel","max_age":604800}',
nel: '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}',
server: 'cloudflare',
'cf-ray': '792c83f6384a5f9a-SMF'
},
config: {
transitional: [Object],
adapter: [Function: httpAdapter],
transformRequest: [Array],
transformResponse: [Array],
timeout: 10000,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus],
headers: [Object],
baseURL: 'https://***.zendesk.com/',
method: 'put',
url: '/api/v2/tickets/69519.json',
data: '{"ticket":{"status":"open","comment":{"html_body":"Follow-up Notes: \\n<p><br></p>","public":false}}}'
},
If you will notice, the 'url' and 'data' properties of the config object in my case proved I was hitting the correct api endpoint and I was also providing the correctly formatted payload. This led me to pull the tickets status and confirm it was closed, which was the source reason for the 422 response.

Resources