PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/smartlib/app/api.rb

https://bitbucket.org/thrabal/smartlib
Ruby | 724 lines | 625 code | 74 blank | 25 comment | 83 complexity | 98e210ed90443a43d26f03e9c2b04f8c MD5 | raw file
  1. # encoding:utf-8
  2. require 'smartlib/common'
  3. require 'open-uri'
  4. require 'rest_client'
  5. require 'nokogiri'
  6. require 'rest_client'
  7. require 'isbn'
  8. require 'faraday'
  9. module Smartlib
  10. module App
  11. class Api < Common
  12. set :views, 'lib/smartlib/views/email', 'lib/smartlib/views/api'
  13. ISSUES_URL = 'https://api.bitbucket.org/1.0/repositories/thrabal/sma' +
  14. 'rtlib/issues'
  15. URL_ALEPH = 'https://aleph.muni.cz/'
  16. COPY_URL = URL_ALEPH +
  17. 'F?func=find-b&find_code=SYS&local_base=MUB01&request=##&format=999'
  18. GOOGLE = 'http://books.google.com/books?bibkeys=ISBN' +
  19. '##&jscmd=viewapi'
  20. before do
  21. headers 'StatusCode' => '200'
  22. end
  23. helpers do
  24. def protected!
  25. return true if session.include?('session_api') &&
  26. self.class::get_person_by_session(session['session_api'])
  27. throw(unauthorized)
  28. end
  29. end
  30. # Search books
  31. get '/books/search' do
  32. #limits
  33. output = []
  34. limit = params.include?('limit') ? params['limit'].to_i : 20
  35. offset = params.include?('offset')? params['offset'].to_i : 0
  36. select, join, where = '', '', ''
  37. simple_error unless params.include?('query') &&
  38. params['query'] && !params['query'].empty?
  39. now = Time.now
  40. begin
  41. is = ISBN.valid?(params['query'].gsub('-', ''))
  42. raise StandardError, 'f' if is == false
  43. isbn = params['query'].gsub('-', '')
  44. add_books(
  45. DB[:books].filter(:isbn => ISBN.ten(isbn)).or(:isbn => ISBN.thirteen(isbn)), output
  46. )
  47. rescue StandardError => bang
  48. query = params['query'].tr(
  49. 'áäčďéěíĺľňóôőöŕšťúůűüýřžÁÄČĎÉĚÍĹĽŇÓÔŐÖŔŠŤÚŮŰÜÝŘŽ',
  50. 'aacdeeillnoooorstuuuuyrzAACDEEILLNOOOORSTUUUUYRZ'
  51. ).downcase
  52. again = true
  53. attempt = 0
  54. while again
  55. mode = "NATURAL LANGUAGE MODE"
  56. if attempt > 0
  57. mode = "BOOLEAN MODE"
  58. query = "*#{query}*" unless query =~ /\s+/
  59. query = "#{query}*" if query =~ /\s+/
  60. end
  61. attempt += 1
  62. # params contains specific libraries
  63. if params.include?('library')
  64. library = params['library'].gsub(/-[a-z]+,?/i, ',')
  65. select = ""
  66. join =
  67. " INNER JOIN `copies` ON (`copies`.`book_id` = `books`.`id`) " +
  68. " INNER JOIN `libraries` ON (`copies`.`library_id` = `libraries`.`id`)"
  69. library , where, counter = library.split(','), " AND (", 0
  70. library.each do |lib|
  71. or_ = counter == 0 ? '' : 'OR'
  72. counter += 1
  73. where += " #{or_} `libraries`.`library` LIKE '#{lib.strip}'"
  74. end
  75. where += ")"
  76. end
  77. # title search
  78. if !params.include?('type') || params['type'] && params['type'].eql?('title')
  79. output = add_books(
  80. DB["SELECT DISTINCT(`books`.`id`), `books`.`title`, `bo" +
  81. "oks`.`full_title`, `books`.`sysno`, `books`.`isbn`, `b" +
  82. "ooks`.`average_rating`, `books`.`cover_url`, `books`.`" +
  83. "preview_url` #{select} FROM `books` INNER JOIN `books_search`" +
  84. " ON (`books`.`id` = `books_search`.`book_id`) #{join}" +
  85. " WHERE MATCH (`books_search`.`search_title`) AGAINST (" +
  86. " '#{query}' IN #{mode} ) #{where} " +
  87. " LIMIT #{limit} OFFSET #{offset}"],
  88. output
  89. )
  90. end
  91. # complete search
  92. if (!params.include?('type') && (output.count < limit)) || (
  93. params.include?('type') && params['type'] && params['type'].eql?('author')
  94. )
  95. if (!params.include?('type') ||
  96. (params.include?('type') && !params['type'])) &&
  97. offset > 20
  98. count = DB["SELECT DISTINCT(COUNT(`id`)) as count FROM " +
  99. "`books_search` WHERE MATCH (`authors_search`." +
  100. "`search_name`) AGAINST ('#{query}' IN #{mode})"]
  101. offset = offset - count.first[:count]
  102. end
  103. books = DB["SELECT DISTINCT `books`.`id`,`books`.`title`, " +
  104. "`books`.`full_title`, `books`.`sysno`, `books`.`isbn`," +
  105. " `books`.`average_rating`, `books`.`cover_url`, `books" +
  106. "`.`preview_url` #{select} FROM `books` INNER JOIN `books_authors" +
  107. "` ON (`books`.`id` = `books_authors`.`book_id`) INNER " +
  108. "JOIN `authors_search` ON (`books_authors`.`author_id` " +
  109. "= `authors_search`.`author_id`) #{join} WHERE MATCH (" +
  110. "`authors_search`.`search_name`) AGAINST ('#{query}'" +
  111. " IN #{mode}) #{where}" +
  112. " LIMIT #{limit - output.count} OFFSET #{offset}"]
  113. output = add_books(books, output)
  114. end
  115. again = false if attempt > 1 || !output.empty?
  116. end
  117. end
  118. p "MySQL: #{query} #{(Time.now - now)}"
  119. my_json output
  120. end
  121. def add_books books, output
  122. books.each do |book|
  123. b = {
  124. 'sysno' => book[:sysno],
  125. 'title' => book[:title].gsub(' :', ': '),
  126. 'fullTitle' => book[:full_title] ? book[:full_title].gsub(' :', ': ') : '',
  127. 'authors' => get_authors(book[:id]),
  128. 'averageRating' => book[:average_rating],
  129. 'ratingCount' => get_rating_count(book[:id])
  130. }
  131. b.merge!(download_image(book))
  132. output << b
  133. end if books
  134. output
  135. end
  136. # Load book info
  137. get '/books' do
  138. # get book detail
  139. search = {}
  140. if params.include?('sysno') || params.include?('isbn')
  141. search[:sysno] = params['sysno'] if params.include? 'sysno'
  142. search[:isbn] = params['isbn'] if params.include? 'isbn'
  143. result = DB[:books].select(
  144. :books__id, :books__sysno, :books__full_title, :books__page_desc,
  145. :books__pages, :books__preview_url, :books__cover_url, :books__title,
  146. :publishers__publisher, :years__year, :languages__language,
  147. :page_types__page_type, :books__isbn
  148. ).join_table(:left, :publishers, :id => :books__publisher_id
  149. ).join_table(:left, :years, :id => :books__year_id
  150. ).join_table(:left, :page_types, :id => :books__page_type_id
  151. ).join_table(:left, :languages, :id => :books__language_id
  152. ).filter(search).first
  153. simple_error if search.empty?
  154. elsif params.include?('barcode')
  155. result = DB[:books].select(
  156. :books__id, :books__sysno, :books__full_title, :books__page_desc,
  157. :books__pages, :books__preview_url, :books__cover_url, :books__title,
  158. :publishers__publisher, :years__year, :languages__language,
  159. :page_types__page_type, :books__isbn
  160. ).join_table(:inner, :copies, :copies__book_id => :id
  161. ).join_table(:left, :publishers, :id => :books__publisher_id
  162. ).join_table(:left, :years, :id => :books__year_id
  163. ).join_table(:left, :page_types, :id => :books__page_type_id
  164. ).join_table(:left, :languages, :id => :books__language_id
  165. ).filter(:copies__barcode => params['barcode']).first
  166. end
  167. if result
  168. rslt = {
  169. 'sysno' => result[:sysno],
  170. 'isbn' => result[:isbn],
  171. 'title' => result[:title],
  172. 'fullTitle' => result[:full_title],
  173. 'publisher' => result[:publisher],
  174. 'publishedDate' => result[:year],
  175. 'language' => result[:language],
  176. 'pageCount' => result[:pages],
  177. 'pageType' => result[:page_type],
  178. 'pageDesc' => result[:page_desc],
  179. 'authors' => get_authors(result[:id]),
  180. }
  181. rslt.merge!(download_image(result))
  182. my_json rslt
  183. else
  184. not_found
  185. end
  186. end
  187. def get_authors id
  188. rslt = []
  189. authors = DB[:authors].select(:name, :author_type
  190. ).join_table(:inner, :books_authors, :author_id => :id
  191. ).join_table(:left, :author_types, :id => :author_type_id
  192. ).filter(
  193. :books_authors__book_id => id
  194. )
  195. authors.each do |author|
  196. rslt << {'type' => author[:author_type], 'name' => author[:name] }
  197. end if authors
  198. rslt
  199. end
  200. # Post new book review
  201. post '/books/:sysno/reviews' do
  202. simple_error unless
  203. params.include?('rating') || params.include?('text')
  204. params['rating'] = 5 if params['rating'].to_i > 5
  205. params['rating'] = 0 if params['rating'].to_i < 0
  206. person, device, temp = nil, nil, {}
  207. # user search
  208. if session[:session_api]
  209. person = self.class::get_person_by_session session[:session_api]
  210. elsif params.include?('device_id')
  211. device = DB[:devices].filter(:name => params['device_id']).first
  212. unless device
  213. device = DB[:devices].insert(:name => params['device_id'])
  214. device = DB[:devices].filter(:id => device).first
  215. end
  216. end
  217. simple_error unless person || device
  218. book = DB[:books].filter(:sysno => params['sysno']).first
  219. simple_error unless book
  220. rating = DB[:ratings].filter(:book_id => book[:id])
  221. rating = rating.and(:person_id => person[:id]) if person
  222. rating = rating.and(:device_id => device[:id]) if device
  223. rating = rating.first
  224. temp[:rating] = params['rating'] if params.include?('rating')
  225. temp[:review] = params['text'] if params.include?('text')
  226. temp[:person_id] = person[:id] if person && person[:id]
  227. temp[:device_id] = device[:id] if device && device[:id]
  228. temp[:time] = my_now
  229. if rating
  230. DB[:ratings].filter(:id => rating[:id]).update(temp)
  231. else
  232. temp[:book_id] = book[:id]
  233. DB[:ratings].insert(temp)
  234. end
  235. DB[:books].filter(:id => book[:id]).update(
  236. :average_rating => compute_rating(book)
  237. )
  238. ok
  239. end
  240. # Get actual rating
  241. get '/books/:sysno/reviews' do
  242. not_found unless params.include?('sysno') && params['sysno'] &&
  243. params['sysno'] =~ /\d+/
  244. limit = params.include?('limit') ? params['limit'].to_i : 20
  245. offset = params.include?('offset')? params['offset'].to_i : 0
  246. ratings = DB[:ratings].join_table(:inner, :books, :id => :book_id
  247. ).join_table(:inner, :people, :id => :ratings__person_id
  248. ).filter(:sysno => params['sysno']).limit(limit, offset)
  249. output = []
  250. ratings.each do |rating|
  251. output << {
  252. 'user' => get_person(rating),
  253. 'text' => rating[:review],
  254. 'rating' => rating[:rating],
  255. 'date' => rating[:time],
  256. }
  257. end
  258. my_json(output) if output
  259. end
  260. get '/books/:sysno/ratings' do
  261. ratings = DB[:ratings].select_more{:rating}.group_and_count(:rating).join_table(
  262. :inner, :books, :id => :book_id
  263. ).filter(:sysno => params['sysno'])
  264. output = {}
  265. ['0','0.5','1.0','1.5','2.5','2.5','3.5','3.5','4.5','4.5','5.0'].each{
  266. |i| output[i] = 0
  267. }
  268. ratings.each do |rating|
  269. output[rating[:rating]] = rating[:count]
  270. end
  271. return my_json output
  272. end
  273. # return json person
  274. def get_person person
  275. {
  276. 'firstName' => person[:first_name],
  277. 'lastName' => person[:surname],
  278. 'uco' => person[:username]
  279. } if person
  280. end
  281. post '/report' do
  282. simple_error unless
  283. params.include?('uco') &&
  284. params.include?('text') &&
  285. params.include?('type')
  286. params['type'] = 'bug' if params['type'].eql?('error')
  287. params['type'] = 'task' if params['type'].eql?('issue')
  288. backtrace = params.include?('backtrace') ?
  289. params['backtrace'] : ''
  290. begin
  291. RestClient::Request.new(
  292. 'method' => :post,
  293. 'url' => ISSUES_URL,
  294. 'user' => $CONFIG[:bitbucket_login],
  295. 'password' => $CONFIG[:bitbucket_passwd],
  296. 'accept' => :json,
  297. 'payload' => {
  298. 'title' => 'New issue: ' + params['uco'],
  299. 'kind' => params['type'],
  300. 'content' =>
  301. "User: #{params['uco']}
  302. Text:
  303. #{params['text']}" +
  304. "#{backtrace}"
  305. }).execute
  306. rescue => e
  307. p e.message
  308. simple_error
  309. end
  310. ok
  311. end
  312. get '/books/:sysno/details' do
  313. self.class::simple_error unless params.include? 'sysno'
  314. book = DB[:books].select(
  315. :books__id, :books__sysno, :books__pages, :books__isbn,
  316. :publishers__publisher, :years__year, :languages__language,
  317. :page_types__page_type, :books__isbn, :books__cover_url,
  318. :books__preview_url
  319. ).join_table(:left, :publishers, :id => :books__publisher_id
  320. ).join_table(:left, :years, :id => :books__year_id
  321. ).join_table(:left, :page_types, :id => :books__page_type_id
  322. ).join_table(:left, :languages, :id => :books__language_id
  323. ).filter(:sysno => params['sysno']).first
  324. return not_found unless book
  325. b = {
  326. 'publisher' => book[:publisher],
  327. 'publishedDate' => book[:year],
  328. 'isbn' => book[:isbn],
  329. 'language' => book[:language],
  330. 'pageType' => book[:page_type],
  331. 'pageCount' => book[:pages],
  332. }
  333. b.merge!(download_image(book))
  334. my_json b
  335. end
  336. get '/books/:sysno/copies' do
  337. simple_error unless params.include?('sysno') && params['sysno'] &&
  338. params['sysno'] =~ /\d+/
  339. copies, rslt = DB[:copies].select(
  340. :copies__signature, :copies__barcode, :copies__status,
  341. :copies__last_check, :books__id, :libraries__library,
  342. :cols__col, :copies__availability
  343. ).join_table(:inner, :books, :id => :book_id
  344. ).join_table(:left, :libraries, :id => :copies__library_id
  345. ).join_table(:left, :cols, :id => :copies__col_id
  346. ).filter(:books__sysno => params[:sysno]), []
  347. not_found unless copies
  348. copies.each{ |copy| rslt << get_copy(copy) }
  349. # no information or information older then 1 day
  350. if rslt.count > 0 && !rslt[0]['last_check'] || Time.parse(rslt[0]['last_check']).to_i+86400 < Time.now.to_i
  351. rslt = check_availability params['sysno'], rslt.map{|i| i['barcode'] }
  352. end
  353. my_json rslt
  354. end
  355. # get top or new ratings
  356. get '/books/list' do
  357. limit = params.include?('limit')? params['limit'].to_i : 20
  358. offset = params.include?('offset')? params['offset'].to_i : 0
  359. if params.include?('category')
  360. params['category'] = 'new' unless
  361. params[:category].eql?('new') || params[:category].eql?('top')
  362. else
  363. params['category'] = 'new'
  364. end
  365. if params['category'].eql?('new')
  366. books = DB[:books].select(:books__id, :books__sysno, :books__title, :books__full_title,
  367. :books__average_rating, :books__isbn, :books__cover_url, :books__preview_url
  368. ).select_more{count(:ratings__id)}.join_table(:inner, :ratings, :book_id => :id
  369. ).group(:books__id).reverse(:ratings__time).limit(limit, offset)
  370. elsif params['category'].eql?('top')
  371. books = DB[:books].select(:books__id, :books__sysno, :books__title, :books__full_title,
  372. :books__average_rating, :books__isbn, :books__cover_url, :books__preview_url
  373. ).select_more{count(:ratings__id)}.join_table(:inner, :ratings, :book_id => :id
  374. ).group(:books__id).reverse(:books__average_rating, :ratings__time).limit(limit, offset)
  375. end
  376. not_found unless books
  377. output = []
  378. books.each do |book|
  379. b = {
  380. 'sysno' => book[:sysno],
  381. 'title' => book[:title],
  382. 'fullTitle' => book[:full_title],
  383. 'authors' => get_authors(book[:id]),
  384. 'averageRating' => book[:average_rating],
  385. 'ratingCount' => book[:"count(`ratings`.`id`)"]
  386. }
  387. b.merge!(download_image(book))
  388. output << b
  389. end
  390. my_json output
  391. end
  392. def download_image book
  393. # download info from google books
  394. return {
  395. 'coverUrl' => nil,
  396. 'previewUrl' => nil,
  397. } if !book[:isbn] || (book[:cover_url] && book[:cover_url].eql?(''))
  398. new_book = {}
  399. unless book[:cover_url]
  400. # first try => google books
  401. new_book[:cover_url] = '' # default set
  402. result = download_preview_google book
  403. if result && result.count > 0
  404. key = result[result.keys[0]]
  405. new_book[:cover_url] = key['thumbnail_url'].gsub('zoom=5', 'zoom=1') if
  406. key.include?('thumbnail_url')
  407. new_book[:preview_url] = "#{key['preview_url']}#v=onepage&q&f=true" if
  408. key.include?('preview_url') && key['preview_url'] =~ /printsec=frontcover/i
  409. end
  410. if new_book[:cover_url].eql?('')
  411. request =
  412. "http://www.obalkyknih.cz/api/books?books=#{URI.encode(
  413. "[{ \"permalink\":\"test\", \"bibinfo\": {\"isbn\":\"#{book[:isbn]}\"}}]")}"
  414. result = RestClient.get request
  415. if result
  416. result = result =~ /\[(.+)\]/i ? Oj.load($1) : nil
  417. if result
  418. new_book[:cover_url] = result.include?('cover_medium_url') ?
  419. result['cover_medium_url'] : ""
  420. end
  421. end
  422. end
  423. DB[:books].filter(:id => book[:id]).update(new_book)
  424. book = DB[:books].filter(:id => book[:id]).first
  425. end
  426. {
  427. 'coverUrl' => book[:cover_url],
  428. 'previewUrl' => book[:preview_url],
  429. }
  430. end
  431. def download_preview_google book
  432. result = RestClient.get(GOOGLE.sub('##', URI.encode(book[:isbn])))
  433. result =~ /(\{.*\})/ ? Oj.load($1) : nil
  434. end
  435. get '/spec' do
  436. books = Book.where('cover_url' => "false")
  437. books.each do |book|
  438. book.cover_url = ""
  439. book.save
  440. end
  441. end
  442. # return rating by json
  443. def compute_rating book
  444. rating, counter = 0, 0
  445. books = DB[:ratings].filter(:book_id => book[:id])
  446. books.each do |book|
  447. if book[:rating]
  448. counter += 1
  449. rating = rating + book[:rating]
  450. end
  451. end
  452. if counter > 0
  453. rating = rating / counter
  454. rating.round(1)
  455. else
  456. rating = nil
  457. end
  458. if rating
  459. r_ = rating % 1
  460. rating += 1 - r_ if (r_ >= 0.75 && r_ < 1)
  461. rating += 0.5 - r_ if (r_ >= 0.25 && r_ < 0.5)
  462. rating -= r_ - 0.5 if (r_ > 0.5 && r_ < 0.75)
  463. rating -= r_ if (r_ > 0 && r_ < 0.25)
  464. end
  465. rating
  466. end
  467. # ---------------- USER FUNCTIONS -------------------
  468. # logout
  469. post '/user/logout' do
  470. protected!
  471. session['session_api'] = nil
  472. ok
  473. end
  474. # register new user
  475. post '/user/registration' do
  476. not_found unless params.include?('firstName') &&
  477. params.include?('lastName') &&
  478. params.include?('uco')
  479. simple_error 409 if
  480. DB[:people].filter(:username => params['uco'], :active => true).count > 0
  481. password = self.class::get_random_text 10
  482. person = DB[:people].insert(
  483. {
  484. 'first_name' => params['firstName'],
  485. 'surname' => params['lastName'],
  486. 'username' => params['uco'],
  487. 'email' => "#{params['uco']}@mail.muni.cz",
  488. 'password' => self.class::md5(password),
  489. 'active' => true,
  490. 'admin' => false
  491. }
  492. )
  493. person = DB[:people].filter(:id => person).first
  494. text = erb :registration, :locals => {
  495. :username => params['uco'],
  496. :password => password
  497. }
  498. self.class::send_email person[:email], 'SmartLib - registrace', text
  499. ok
  500. end
  501. # register new user
  502. get '/user/lostpassword' do
  503. not_found unless params.include?('uco')
  504. person = DB[:people].filter(
  505. :username => params['uco'], :active => true
  506. ).first
  507. simple_error 409 unless person
  508. password = self.class::get_random_text 10
  509. DB[:people].filter(:id => person[:id]).update(
  510. :temp_password => self.class::md5(password),
  511. :temp_password_time => my_now)
  512. text = erb :lost_password, :locals => {
  513. :username => params['uco'],
  514. :password => password
  515. }
  516. self.class::send_email person[:email], 'SmartLib - dočasné heslo', text
  517. ok
  518. end
  519. # change password
  520. post '/user/changepassword' do
  521. self.class::simple_error unless params.include?('uco') &&
  522. params.include?('oldPassword') && params.include?('newPassword')
  523. person = self.class::authenticate params['uco'], params['oldPassword']
  524. unauthorized unless person
  525. DB[:people].filter(:id => person[:id]
  526. ).update(:password => self.class::md5(params['newPassword']))
  527. ok
  528. end
  529. # authenticate!
  530. post '/user/authentication' do
  531. if session.include?('session_api')
  532. return self.class::get_person_by_session(session['session_api']) ?
  533. ok : unauthorized
  534. end
  535. unauthorized
  536. end
  537. # log person in
  538. post '/user/login' do
  539. simple_error unless params.include?('uco') && params.include?('password')
  540. if person = self.class::authenticate(params[:uco], params[:password])
  541. session_api = self.class::get_random_text 50
  542. DB[:people].filter(:id => person[:id]).update(:session_api => session_api)
  543. session['session_api'] = session_api
  544. return ok
  545. end
  546. session[:session_api] = nil
  547. unauthorized
  548. end
  549. get '/libraries' do
  550. libraries = DB[:libraries]
  551. output = []
  552. libraries.each do |library|
  553. output << {
  554. 'library' => library[:library]
  555. }
  556. end
  557. my_json output
  558. end
  559. def get_rating_count id
  560. DB[:ratings].filter(:book_id => id).count
  561. end
  562. get '/books/:sysno/check' do
  563. not_found unless params.include?('sysno') && params['sysno'] &&
  564. params['sysno'] =~ /\d+/
  565. book = DB[:books].filter(:sysno => params['sysno']).first
  566. not_found unless book && params.include?('barcodes')
  567. otpt, barcodes = [], params['barcodes'].split(',')
  568. my_json(check_availability(params['sysno'], barcodes))
  569. end
  570. def check_availability sysno, barcodes
  571. begin
  572. url, otpt = COPY_URL.sub('##', sysno), []
  573. doc = Nokogiri::HTML(RestClient.get(url))
  574. not_found unless doc
  575. url = doc.at_xpath('//a[contains(text(),"Všechny jednotky")]/@href') or not_found
  576. url = URL_ALEPH + url.content
  577. doc = Nokogiri::HTML(RestClient.get(url))
  578. not_found unless doc
  579. last = my_now
  580. barcodes.each do |barcode|
  581. copy = DB[:copies].filter(:barcode => barcode).first
  582. next unless copy
  583. find = doc.at_xpath('//span[contains(text(),"' +barcode+'")]')
  584. unless find
  585. otpt << {
  586. 'barcode' => barcode,
  587. 'status' => 404,
  588. 'last_check' => output_time(Time.now)
  589. }
  590. next
  591. end
  592. status = find.at_xpath('./../preceding-sibling::td[6]') || ''
  593. back = find.at_xpath('./../preceding-sibling::td[5]')
  594. back = back ? back.content : ''
  595. type = copy[:status] ? 'prs' : 'abs'
  596. if back =~ /\d+\-\d+\-\d+/
  597. DB[:copies].filter(:id => copy[:id]).update(
  598. :availability => false, :last_check => last
  599. )
  600. otpt << {
  601. 'barcode' => barcode,
  602. 'status' => false,
  603. 'type' => type,
  604. 'back' => back,
  605. 'last_check' => output_time(Time.parse(last))
  606. }
  607. else
  608. DB[:copies].filter(:id => copy[:id]).update(
  609. :availability => true, :last_check => last
  610. )
  611. otpt << {
  612. 'barcode' => barcode,
  613. 'status' => true,
  614. 'back' => back,
  615. 'type' => type,
  616. 'last_check' => output_time(Time.parse(last))
  617. }
  618. end
  619. end
  620. otpt
  621. rescue StandardError => bang
  622. p bang.message
  623. p bang.backtrace
  624. not_found
  625. end
  626. end
  627. def my_now
  628. Time.now.strftime('%Y-%m-%d %H:%M:%S')
  629. end
  630. def output_time time
  631. time.getutc.iso8601(0)
  632. end
  633. def get_copy copy
  634. last_check = copy[:last_check] ?
  635. output_time(copy[:last_check]) : nil
  636. {
  637. 'signature' => copy[:signature],
  638. 'barcode' => copy[:barcode],
  639. 'last_check' => last_check,
  640. 'status' => copy[:availability] ? true : false,
  641. 'col' => copy[:col],
  642. 'panel' => nil,
  643. 'library' => copy[:library],
  644. 'type' => copy[:status] && copy[:status].eql?('1') ?
  645. 'prs' : 'abs'
  646. }
  647. end
  648. end
  649. end
  650. end