Enumerating settable parameters - ruby

I successfully setup a connection to my Rally project, but am not able to programatically set the "Submitted By" field when opening defects. I am misnaming the parameter, or it is not settable via the REST API. Any help on querying modifiable parameters, link to attribute names, or code to set the "Submitted By" parameter would be greatly appreciated.
My goal is to have a webpage where folks submit defects or stories, along with their email, and use that to populate their username in the "Submitted By" field. My current setup can open Stories and Defects but only anonymously since the second to last line has no effect.
I am using the Ruby API and the following is the ruby code that gets invoked when a user clicks on a button on the main page, which redirects them to localhost:4567/rally_defect where Sinatra is listening.
require 'rubygems'
require 'rally_rest_api'
require 'sinatra'
custom_headers = CustomHttpHeader.new
custom_headers.name = 'Mail 2 Rally'
custom_headers.version = '0.1'
custom_headers.vendor = 'Rally Software'
rally_server = 'https://rally1.rallydev.com/slm'
rally_username = <insert rally username>
rally_pwd = <insert rally password>
rally = RallyRestAPI.new(:base_url => rally_server,
:username => rally_username,
:password => rally_pwd,
:http_headers => custom_headers)
get '/rally_defect' do
rally.create(:defect, :name => "Test Defect",
:description => "This is a test",
:SubmittedBy => "test")
end

If you're getting started building this integration, I'd strongly recommend using rally_api instead of rally_rest_api.
rally_rest_api is in the process of being deprecated for a number of issues around performance and stability. There won't be any further development on rally_rest_api moving forward.
You can find documentation on rally_api here:
https://developer.help.rallydev.com/ruby-toolkit-rally-rest-api-json
rally_api does require Ruby 1.9.2 or higher.
rally_api's syntax is quite similar to rally_rest_api. The rally_api version of what you're attempting above would look something like the code sample below. Note that any "set-able" parameter can be set simply by including its name in the object hash and setting that to a value.
The best place to look for the Rally Webservices API object model, including Artifact attributes, allowed values, and whether they are write-able is the Webservices API documentation:
https://rally1.rallydev.com/slm/doc/webservice
When an attribute of a Rally Artifact is itself a Rally Object like a User, for example, either lookup the Object in Rally first (the example below does this), or, set the value to the REST URL reference to the object in Rally. For instance, if you know that user#company.com has ObjectID 12345678910 in Rally, then you can do:
user_ref = "/user/12345678910"
new_defect["SubmittedBy"] = user_ref
The code below shows the way to do a lookup into Rally to get the User object, given an email-formatted UserID, since I'm assuming you'll probably need to accomodate multiple different users.
require 'rubygems'
require 'rally_api'
require 'sinatra'
#Setting custom headers
headers = RallyAPI::CustomHttpHeader.new()
headers.name = 'Mail 2 Rally'
headers.vendor = "My Company"
headers.version = "0.1"
# Rally credentials
rally_username = <insert rally username>
rally_pwd = <insert rally password>
rally_server = 'https://rally1.rallydev.com/slm'
# Rally REST API config
config = {:base_url => rally_server}
config[:username] = rally_username
config[:password] = rally_pwd
config[:workspace] = "Workspace Name"
config[:project] = "Project Name"
config[:headers] = headers #from RallyAPI::CustomHttpHeader.new()
# New up rally connection config
#rally = RallyAPI::RallyRestJson.new(config)
# Lookup UserID for SubmittedBY
submitted_by_user_id = "user#company.com"
user_query = RallyAPI::RallyQuery.new()
user_query.type = :user
user_query.fetch = "ObjectID,UserName,DisplayName"
user_query.order = "UserName Asc"
user_query.query_string = "(UserName = \"#{submitted_by_user_id}\")"
# Query for user
user_query_results = #rally.find(user_query)
submitted_by_user = user_query_results.first
# Create the Defect
new_defect = {}
new_defect["Name"] = "Test Defect"
new_defect["Description"] = "This is a test"
new_defect["SubmittedBy"] = submitted_by_user
new_defect_create_result = #rally.create(:defect, new_defect)
puts "New Defect created FormattedID: #{new_defect_create_result.FormattedID}"

Related

Google Analytics Reporting v4 with streams instead of views

I've just created a new Google Analytics property and it now defaults to data streams instead of views.
I had some code that was fetching reports through the API that I now need to updated to work with those data streams instead of views since there are not views anymore.
I've looked in the docs but i don't see anything related to data streams, anybody knows how this is done now?
Here's my current code that works with a view ID (I'm using the ruby google-api-client gem):
VIEW_ID = "XXXXXX"
SCOPE = 'https://www.googleapis.com/auth/analytics.readonly'
client = AnalyticsReportingService.new
#server to server auth mechanism using a service account
#creds = ServiceAccountCredentials.make_creds({:json_key_io => File.open('account.json'), :scope => SCOPE})
#creds.sub = "myserviceaccount#example.iam.gserviceaccount.com"
client.authorization = #creds
#metrics
metric_views = Metric.new
metric_views.expression = "ga:pageviews"
metric_unique_views = Metric.new
metric_unique_views.expression = "ga:uniquePageviews"
#dimensions
dimension = Dimension.new
dimension.name = "ga:hostname"
#range
range = DateRange.new
range.start_date = start_date
range.end_date = end_date
#sort
orderby = OrderBy.new
orderby.field_name = "ga:pageviews"
orderby.sort_order = 'DESCENDING'
rr = ReportRequest.new
rr.view_id = VIEW_ID
rr.metrics = [metric_views, metric_unique_views]
rr.dimensions = [dimension]
rr.date_ranges = [range]
rr.order_bys = [orderby]
grr = GetReportsRequest.new
grr.report_requests = [rr]
response = client.batch_get_reports(grr)
I would expect that there would be a stream_id property on the ReportRequest object that I could use instead of the view_id but that's not the case.
Your existing code uses the Google Analytics Reporting api to extract data from a Universal analytics account.
Your new Google analytics property is a Google Analytics GA4 account. To extract data from that you need to use the Google analytics data api These are two completely different systems. You will not be able to just port it.
You can find info on the new api and new library here: Ruby Client for the Google Analytics Data API
$ gem install google-analytics-data
Thanks to Linda's answer i was able to get it working, here's the same code ported to the data API, it might end up being useful to someone:
client = Google::Analytics::Data.analytics_data do |config|
config.credentials = "account.json"
end
metric_views = Google::Analytics::Data::V1beta::Metric.new(name: "screenPageViews")
metric_unique_views = Google::Analytics::Data::V1beta::Metric.new(name: "totalUsers")
dimension = Google::Analytics::Data::V1beta::Dimension.new(name: "hostName")
range = Google::Analytics::Data::V1beta::DateRange.new(start_date: start_date, end_date: end_date)
order_dim = Google::Analytics::Data::V1beta::OrderBy::DimensionOrderBy.new(dimension_name: "screenPageViews")
orderby = Google::Analytics::Data::V1beta::OrderBy.new(desc: true, dimension: order_dim)
request = Google::Analytics::Data::V1beta::RunReportRequest.new(
property: "properties/#{PROPERTY_ID}",
metrics: [metric_views, metric_unique_views],
dimensions: [dimension],
date_ranges: [range],
order_bys: [orderby]
)
response = client.run_report request

Save Google Cloud Speech API operation(job) object to retrieve results later

I'm struggling to use the Google Cloud Speech Api with the ruby client (v0.22.2).
I can execute long running jobs and can get results if I use
job.wait_until_done!
but this locks up a server for what can be a long period of time.
According to the API docs, all I really need is the operation name(id).
Is there any way of creating a job object from the operation name and retrieving it that way?
I can't seem to create a functional new job object such as to use the id from #grpc_op
What I want to do is something like:
speech = Google::Cloud::Speech.new(auth_credentials)
job = speech.recognize_job file, options
saved_job = job.to_json #Or some element of that object such that I can retrieve it.
Later, I want to do something like....
job_object = Google::Cloud::Speech::Job.new(saved_job)
job.reload!
job.done?
job.results
Really hoping that makes sense to somebody.
Struggling quite a bit with google's ruby clients on the basis that everything seems to be translated into objects which are much more complex than the ones required to use the API.
Is there some trick that I'm missing here?
You can monkey-patch this functionality to the version you are using, but I would advise upgrading to google-cloud-speech 0.24.0 or later. With those more current versions you can use Operation#id and Project#operation to accomplish this.
require "google/cloud/speech"
speech = Google::Cloud::Speech.new
audio = speech.audio "path/to/audio.raw",
encoding: :linear16,
language: "en-US",
sample_rate: 16000
op = audio.process
# get the operation's id
id = op.id #=> "1234567890"
# construct a new operation object from the id
op2 = speech.operation id
# verify the jobs are the same
op.id == op2.id #=> true
op2.done? #=> false
op2.wait_until_done!
op2.done? #=> true
results = op2.results
Update Since you can't upgrade, you can monkey-patch this functionality to an older-version using the workaround described in GoogleCloudPlatform/google-cloud-ruby#1214:
require "google/cloud/speech"
# Add monkey-patches
module Google
Module Cloud
Module Speech
class Job
def id
#grpc.name
end
end
class Project
def job id
Job.from_grpc(OpenStruct.new(name: id), speech.service).refresh!
end
end
end
end
end
# Use the new monkey-patched methods
speech = Google::Cloud::Speech.new
audio = speech.audio "path/to/audio.raw",
encoding: :linear16,
language: "en-US",
sample_rate: 16000
job = audio.recognize_job
# get the job's id
id = job.id #=> "1234567890"
# construct a new operation object from the id
job2 = speech.job id
# verify the jobs are the same
job.id == job2.id #=> true
job2.done? #=> false
job2.wait_until_done!
job2.done? #=> true
results = job2.results
Ok. Have a very ugly way of solving the issue.
Get the id of the Operation from the job object
operation_id = job.grpc.grpc_op.name
Get an access token to manually use the RestAPI
json_key_io = StringIO.new(ENV["GOOGLE_CLOUD_SPEECH_JSON_KEY"])
authorisation = Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io:json_key_io,
scope:"https://www.googleapis.com/auth/cloud-platform"
)
token = authorisation.fetch_access_token!
Make an api call to retrieve the operation details.
This will return with a "done" => true parameter, once results are in and will display the results. If "done" => true isn't there then you'll have to poll again later until it is.
HTTParty.get(
"https://speech.googleapis.com/v1/operations/#{operation_id}",
headers: {"Authorization" => "Bearer #{token['access_token']}"}
)
There must be a better way of doing that. Seems such an obvious use case for the speech API.
Anyone from google in the house who can explain a much simpler/cleaner way of doing it?

How to display linkedin profile information in Rails

I'm working on an app that will have a linkedin sign in button. Once the user signs in using their linkedin in username and password. I want to display their information on the home page.
Currently I'm using 'omniauth', 'omniauth-linkedin-oauth2' to authenticate the user.
The person working on this before me completed the authentication process but I can't understand how to display the users info. The authentication was implemented by following RailsCast #235 & #236 Omniauth Part 1 and 2.
This is the omniauth.rb file.
Rails.application.config.middleware.use OmniAuth::Builder do
provider :linkedin, 'LINKEDIN_KEY', 'LINKEDIN_SECRET', :scope => 'r_fullprofile r_emailaddress r_network', :fields => ['id', 'email-address', 'first-name', 'last-name']
end
I want to display all the fields from the omniauth.rb file.
I understand its a really silly issue but I'm really new to Ruby on Rails so I'd greatly appreciate it if someone can guide me through the process.
Based on the Authentications Controller in Part 2
You can get the fields from the omniauth hash:
omniauth = request.env["omniauth.auth"]
first_name = omniauth[:info][:first_name]
last_name = omniauth[:info][:last_name]
summary = omniauth[:extra][:raw_info][:summary]
headline = omniauth[:extra][:raw_info][:headline]
image = omniauth[:info][:image]
email = omniauth[:info][:email]
token = omniauth[:credentials][:token]
secret = omniauth[:credentials][:secret]
profile_url = omniauth[:info][:urls][:public_profile]
Those are the basic info you need from the authentication hash, if you need more data, you can use the following gem (using the user's token):
gem 'linkedin-oauth2', '~> 0.1.1'

Reporting in Microsoft AdCenter (Sandbox) - RoR

I am using AdCenter API for my RoR application. I searched a lot on Internet to find example of ruby code to fetch account performance report using API, But didn't get.. Now I have written following code but submitGenerateReport returns nil
Here is my code.
report_request = AccountPerformanceReportRequest.new
start_date = 10.days.ago.strftime("%Y-%m-%d")
end_date = Time.zone.now.strftime("%Y-%m-%d")
scope = AccountReportScope.new
scope.accountIds = [AppConfig.adcenter['accountId']]
# Specify the format of the report.
report_request.format = 'Xml'
report_request.returnOnlyCompleteData = false
report_request.language = 'English'
report_request.reportName = "My Account Report"
report_request.aggregation = 'Daily'
report_request.time = ReportTime.new(start_date, end_date)
report_request.columns = %w[ AccountName AccountName GregorianDate CurrentMaxCpc Impressions Clicks ]
report_request.scope = scope
report_request.filter = nil
report = SubmitGenerateReportRequest.new(report_request)
# Returns nil
puts response = svc.submitGenerateReport(report)
I have campaigns, adgroups as well as ads in specified account.
Can anyone please guide me where I am wrong or give some example of reporting adcenter through api using ruby?
Thanks in advance
Got the solution...
The time was not in right format so, start time and end time was unrecognisable in soap request. SOAP debugging helped me a lot..

Ruby: Dynamically defining classes based on user input

I'm creating a library in Ruby that allows the user to access an external API. That API can be accessed via either a SOAP or a REST API. I would like to support both.
I've started by defining the necessary objects in different modules. For example:
soap_connecton = Library::Soap::Connection.new(username, password)
response = soap_connection.create Library::Soap::LibraryObject.new(type, data, etc)
puts response.class # Library::Soap::Response
rest_connecton = Library::Rest::Connection.new(username, password)
response = rest_connection.create Library::Rest::LibraryObject.new(type, data, etc)
puts response.class # Library::Rest::Response
What I would like to do is allow the user to specify that they only wish to use one of the APIs, perhaps something like this:
Library::Modes.set_mode(Library::Modes::Rest)
rest_connection = Library::Connection.new(username, password)
response = rest_connection.create Library::LibraryObject.new(type, data, etc)
puts response.class # Library::Response
However, I have not yet discovered a way to dynamically set, for example, Library::Connection based on the input to Library::Modes.set_mode. What would be the best way to implement this functionality?
Murphy's law prevails; find an answer right after posting the question to Stack Overflow.
This code seems to have worked for me:
module Library
class Modes
Rest = 1
Soap = 2
def self.set_mode(mode)
case mode
when Rest
Library.const_set "Connection", Class.new(Library::Rest::Connection)
Library.const_set "LibraryObject", Class.new(Library::Rest::LibraryObject)
when Soap
Library.const_set "Connection", Class.new(Library::Soap::Connection)
Library.const_set "LibraryObject", Class.new(Library::Soap::LibraryObject)
else
throw "#{mode.to_s} is not a valid Library::Mode"
end
end
end
end
A quick test:
Library::Modes.set_mode(Library::Modes::Rest)
puts Library::Connection.class == Library::Rest::Connection.class # true
c = Library::Connection.new(username, password)

Resources