I was asked to be able to get the API key of redmine using ruby at work. I saw the completion for the time being, so I will summarize it instead of my memorandum. The article was only created by a beginner programmer in the first year of working life who got a job as a programmer just by studying by himself, by repeating search and copy. If there is a person like me, I hope that this article alone will be a success.
I searched for it first, but couldn't find the corresponding description. It is assumed that the API key is received from the personal setting screen of redmine and entered in the code, so I could not find a way to get the API key programmatically. However, as a result of searching excluding the condition of ruby, I found the following article.
How to get various data from JavaScript of Redmine https://qiita.com/forenoonM/items/7f42701b2ea40353a820
This article describes how to get the API key using JavaScript. Roughly speaking, it's a method using scraping.
I see, scraping? Well, I'm ashamed to say that I didn't even know what scraping was. After all, I'm a beginner who just studied ruby by myself. So, I searched for a way to scrape with ruby and arrived at the following site.
[Understanding in 5 minutes] Explain the basics of scraping with Ruby! https://www.sejuku.net/blog/13230
This is the code created in this way
equire 'open-uri'
require 'nokogiri' #Used to get API key
url = "http://192.168.33.11/my/api_key"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
apikey = contents.search("div[@class='box']").search('pre')
puts apikey
Well, when I actually move it, it doesn't move. As a result of various investigations, I noticed that it stopped at the login screen.
That means you have to create a login process
So, as usual, I arrived at this page by searching.
Log in with Mechanize and scrape https://qiita.com/katsuyuki/items/1a78360988d96eec1d54
I understand it completely.
agent = Mechanize.new
agent.user_agent = 'Mac Safari'
agent.get("http://#{adress}/my/api_key") do |page|
response = page.form_with(:action => '/login') do |form|
formdata = {
:mail => mail,
:password => password,
}
form.field_with(:name => 'username').value = formdata[:mail]
form.field_with(:name => 'password').value = formdata[:password]
end.submit
end
url = "http://#{adress}/my/api_key"
html = agent.get("#{url}").content.toutf8
contents = Nokogiri::HTML(html, nil, 'utf-8')
apikey = contents.search("div[@class='box']").search('pre')
puts apikey
Only the additional part was extracted.
By the way, regarding # {adress}, "I am testing locally now, but after that I will also run it on the company redmine and the client redmine."
require 'yaml' #Used to read the config
set = YAML.load_file("config.yml")
puts set
adress = set["train"]["adress"]
puts adress
You can specify it by entering the address in config.yml like this.
result
> <pre>[APIkey]</pre>
This is no good.
stringkey = "#{apikey}"
stringkey.slice!("</pre>")
stringkey.slice!("<pre>")
puts "APIKey = #{stringkey}"
Immediately after adding this, the process of acquiring the API key is completed for the time being.
Actually, I was working on this first, but what if it wasn't the login screen? I don't know if that happens, but if it does, it will cause an error in the process of logging in.
page = RedmineController.new
pagetitle = page.Myaccount_access(adress)
puts "pagetitle = #{pagetitle}"
if pagetitle == "Personal Settings- redmine" then #Check if you are logged in
apikey = page.GetAPIkey(adress)
puts "APIKey = #{apikey}"
else
apikey = page.Login(adress,mail,password)
end
The title of the personal settings screen after login was "Personal settings --redmine", so I corresponded to this.
A class called RedmineContoroller is created here, and this class will be described later.
After this, I tried it with the company redmine and noticed. Our company's redmine is "Personal settings-[company name] redmine". As a result of checking, all the top pages etc. are "[company name] redmine". In other words, it seems to be a style of "Personal settings- [Page name]". Let's deal with it.
page = RedmineController.new
toptitle = page.toptitle(adress)
pagetitle = page.Myaccount_access(adress)
puts "pagetitle = #{pagetitle}"
if pagetitle == "Personal Settings- #{toptitle}" then #Check if you are logged in
apikey = page.GetAPIkey(adress)
puts "APIKey = #{apikey}"
else
apikey = page.Login(adress,mail,password)
end
It's like this. In other words, it is a strategy to grasp the top title first. Now, let's publish the class "RedmineController". Yes, if I don't introduce the toptitle method, it will be troublesome twice, so I introduced it.
class RedmineController
def toptitle(adress)
url = "http://#{adress}/"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
return contents.title
end
def Myaccount_access(adress)
url = "http://#{adress}/my/account"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
return contents.title
end
def Login(adress,mail,password)
agent = Mechanize.new
agent.user_agent = 'Mac Safari'
agent.get("http://#{adress}/my/api_key") do |page|
response = page.form_with(:action => '/login') do |form|
formdata = {
:mail => mail,
:password => password,
}
form.field_with(:name => 'username').value = formdata[:mail]
form.field_with(:name => 'password').value = formdata[:password]
end.submit
end
url = "http://#{adress}/my/api_key"
html = agent.get("#{url}").content.toutf8
contents = Nokogiri::HTML(html, nil, 'utf-8')
apikey = contents.search("div[@class='box']").search('pre')
stringkey = "#{apikey}"
stringkey.slice!("</pre>")
stringkey.slice!("<pre>")
puts "APIKey = #{stringkey}"
return stringkey
end
def GetAPIkey(adress)
url = "http://#{adress}/my/api_key"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
apikey = contents.search("div[@class='box']").search('pre')
stringkey = "#{apikey}"
stringkey.slice!("</pre>")
stringkey.slice!("<pre>")
puts "APIKey = #{stringkey}"
return stringkey
end
end
After that, it is necessary to create a process to do something using the API, so let's push the process to get the API key into the method.
class Getter
def APIKey_Getter(adress,mail,password)
page = RedmineController.new
toptitle = page.toptitle(adress)
pagetitle = page.Myaccount_access(adress)
puts "pagetitle = #{pagetitle}"
if pagetitle == "Personal Settings- #{toptitle}" then #Check if you are logged in
apikey = page.GetAPIkey(adress)
puts "APIKey = #{apikey}"
else
apikey = page.Login(adress,mail,password)
end
return apikey
end
By the way, after this, I am now adding methods to call various APIs to this getter class.
Completed with the above. The whole picture is like this.
require 'open-uri'
require 'nokogiri' #Used to get API key
require 'mechanize' #Use for login
require 'yaml' #Used to read the config
require 'io/console' #Used for the words of the pasoward
class RedmineController
def toptitle(adress)
url = "http://#{adress}/"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
return contents.title
end
def Myaccount_access(adress)
url = "http://#{adress}/my/account"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
return contents.title
end
def Login(adress,mail,password)
agent = Mechanize.new
agent.user_agent = 'Mac Safari'
agent.get("http://#{adress}/my/api_key") do |page|
response = page.form_with(:action => '/login') do |form|
formdata = {
:mail => mail,
:password => password,
}
form.field_with(:name => 'username').value = formdata[:mail]
form.field_with(:name => 'password').value = formdata[:password]
end.submit
end
url = "http://#{adress}/my/api_key"
html = agent.get("#{url}").content.toutf8
contents = Nokogiri::HTML(html, nil, 'utf-8')
apikey = contents.search("div[@class='box']").search('pre')
stringkey = "#{apikey}"
stringkey.slice!("</pre>")
stringkey.slice!("<pre>")
puts "APIKey = #{stringkey}"
return stringkey
end
def GetAPIkey(adress)
url = "http://#{adress}/my/api_key"
charset = nil
html = open(url) do |page|
charaset = page.charset
page.read
end
contents = Nokogiri::HTML.parse(html,nil,charset)
apikey = contents.search("div[@class='box']").search('pre')
stringkey = "#{apikey}"
stringkey.slice!("</pre>")
stringkey.slice!("<pre>")
puts "APIKey = #{stringkey}"
return stringkey
end
end
class Getter
def APIKey_Getter(adress,mail,password)
page = RedmineController.new
toptitle = page.toptitle(adress)
pagetitle = page.Myaccount_access(adress)
puts "pagetitle = #{pagetitle}"
if pagetitle == "Personal Settings- #{toptitle}" then #Check if you are logged in
apikey = page.GetAPIkey(adress)
puts "APIKey = #{apikey}"
else
apikey = page.Login(adress,mail,password)
end
return apikey
end
end
#Processing starts from here. Actually receive information by get or post with sinatra
puts "Please enter your account name"
mail = gets
mail.chomp!
puts "Please enter the password (not displayed but you can enter it)"
password = STDIN.noecho(&:gets)
password.chomp!
#Actually, it is not acquired using gets, but it is set for the time being. Eventually all this range disappears
set = YAML.load_file("config.yml")
puts set
adress = set["train"]["adress"]
puts adress
f = Getter.new
apikey = f.APIKey_Getter(adress,mail,password)
puts "APIKey = #{apikey}"
Excuse me for your disgrace.
Recommended Posts