From e98aa4875755cf1b9fc901b9ab69bea610c55e69 Mon Sep 17 00:00:00 2001 From: "OHASHI, Norikazu" Date: Fri, 28 Jan 2022 19:58:39 +0900 Subject: [PATCH] =?utf8?q?DataBase=20=E3=82=A2=E3=82=AF=E3=82=BB=E3=82=B9?= =?utf8?q?=E7=94=A8=E3=81=AE=E3=82=AF=E3=83=A9=E3=82=B9=E3=82=92=20Singlet?= =?utf8?q?on=20=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- sinatra/.rubocop.yml | 3 + sinatra/Gemfile | 4 +- sinatra/app/controllers/web_gui.rb | 136 ++-- sinatra/app/models/books_db.rb | 1074 ++++++++++++++-------------- sinatra/app/models/users_db.rb | 40 +- sinatra/config.ru | 3 + 6 files changed, 636 insertions(+), 624 deletions(-) diff --git a/sinatra/.rubocop.yml b/sinatra/.rubocop.yml index 01274a4..71da13c 100644 --- a/sinatra/.rubocop.yml +++ b/sinatra/.rubocop.yml @@ -40,3 +40,6 @@ Style/TrailingCommaInArrayLiteral: EnforcedStyleForMultiline: comma Style/TrailingCommaInHashLiteral: EnforcedStyleForMultiline: comma + +Bundler/OrderedGems: + Enabled: false diff --git a/sinatra/Gemfile b/sinatra/Gemfile index e8fd144..f09ca80 100644 --- a/sinatra/Gemfile +++ b/sinatra/Gemfile @@ -1,8 +1,8 @@ # frozen_string_literal: true -source "https://rubygems.org" +source 'https://rubygems.org' -git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } # gem "rails" diff --git a/sinatra/app/controllers/web_gui.rb b/sinatra/app/controllers/web_gui.rb index 6a768db..f6ee83b 100644 --- a/sinatra/app/controllers/web_gui.rb +++ b/sinatra/app/controllers/web_gui.rb @@ -40,6 +40,10 @@ class WebGui < Sinatra::Base :expire_after => 1200, :secret => 'change' + before do + @user_account = UserAccount.instance; + @book_manager = BookManager.instance; + end helpers do # ページIDを保存して、viewに渡す # @params [Symble] pageId 表示するページID @@ -152,7 +156,7 @@ class WebGui < Sinatra::Base begin # アカウント作成 - id = UserAccount.createAccount(name, full_name, email, passwd) + id = @user_account.createAccount(name, full_name, email, passwd) session[:userId] = id redirect to('/user_home') rescue UserAccount::AlreadyInstanceError @@ -175,7 +179,7 @@ class WebGui < Sinatra::Base begin # パスワードチェック - id = UserAccount.checkPasswd(name, passwd) + id = @user_account.checkPasswd(name, passwd) session[:userId] = id redirect to('/user_home') rescue UserAccount::NotFoundInstanceError, @@ -190,11 +194,11 @@ class WebGui < Sinatra::Base cache_control :public, :must_revalidate, :max_age => 30 id = session[:userId] checkSession(id) - user = UserAccount.getUser(id) + user = @user_account.getUser(id) @id = id @username = user.full_name - @is_admin = UserAccount.checkAdmin(id) - @newest_list = BookManager.newestListOfBooks(id, 5) + @is_admin = @user_account.checkAdmin(id) + @newest_list = @book_manager.newestListOfBooks(id, 5) goPage :user_home end @@ -205,8 +209,8 @@ class WebGui < Sinatra::Base id = session[:userId] checkSession(id) begin - user = UserAccount.getUser(id) - @is_admin = UserAccount.checkAdmin(id) + user = @user_account.getUser(id) + @is_admin = @user_account.checkAdmin(id) @admin_type = false @id = id @username = user.full_name @@ -227,15 +231,15 @@ class WebGui < Sinatra::Base id = session[:userId] edit_id = params[:editId] checkSession(id) - if !UserAccount.checkAdmin(id) + if !@user_account.checkAdmin(id) raise WebError.new(:status => 405, :message => '管理者アカウントでないと操作できません。') end begin - user = UserAccount.getUser(id) - edit_user = UserAccount.getUser(edit_id) + user = @user_account.getUser(id) + edit_user = @user_account.getUser(edit_id) @admin_type = true - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) @id = edit_id @username = user.full_name @editname = edit_user.full_name @@ -266,13 +270,13 @@ class WebGui < Sinatra::Base checkSession(id) begin if new_pass != '' - check_id = UserAccount.checkPasswd(name, try_pass) + check_id = @user_account.checkPasswd(name, try_pass) if check_id != id raise StandardError, 'アカウント名とIDが不正' end end params = { :passwd => new_pass, :full_name => full_name, :email => email } - UserAccount.updateUser(id, params) + @user_account.updateUser(id, params) redirect to('/user_home') rescue UserAccount::NotFoundInstanceError, UserAccount::AuthenticationError @@ -298,13 +302,13 @@ class WebGui < Sinatra::Base new_pass = params[:new_pass] checkSession(id) - if !UserAccount.checkAdmin(id) + if !@user_account.checkAdmin(id) raise WebError.new(:status => 405, :message => '管理者アカウントでないと操作できません。') end begin params = { :passwd => new_pass, :full_name => full_name, :email => email } - UserAccount.updateUser(edit_id, params) + @user_account.updateUser(edit_id, params) redirect to('/user_list') rescue UserAccount::NotFoundInstanceError, UserAccount::AuthenticationError @@ -322,15 +326,15 @@ class WebGui < Sinatra::Base book_update_f = false session[:book_update_f] = book_update_f checkSession(id) - if !UserAccount.checkAdmin(id) + if !@user_account.checkAdmin(id) raise WebError.new(:status => 405, :message => '管理者アカウントでないと操作できません。') end begin - user = UserAccount.getUser(id) - @user_list = UserAccount.getUserList(id) + user = @user_account.getUser(id) + @user_list = @user_account.getUserList(id) @username = user.full_name - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) rescue UserAccount::AuthenticationError raise WebError.new(:status => 405, :message => '管理者でしか利用できません。') end @@ -345,13 +349,13 @@ class WebGui < Sinatra::Base id = session[:userId] delete_id = params[:deleteId] checkSession(id) - if !UserAccount.checkAdmin(id) + if !@user_account.checkAdmin(id) raise WebError.new(:status => 405, :message => '管理者アカウントでないと操作できません。') end begin - user = UserAccount.getUser(id) - @delete_user = UserAccount.getUser(delete_id) + user = @user_account.getUser(id) + @delete_user = @user_account.getUser(delete_id) @username = user.full_name rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') @@ -367,13 +371,13 @@ class WebGui < Sinatra::Base id = session[:userId] delete_id = params[:deleteId] checkSession(id) - if !UserAccount.checkAdmin(id) + if !@user_account.checkAdmin(id) raise WebError.new(:status => 405, :message => '管理者アカウントでないと操作できません。') end begin - BookManager.deleteBookCollectOfUser(delete_id) - UserAccount.deleteUser(delete_id) + @book_manager.deleteBookCollectOfUser(delete_id) + @user_account.deleteUser(delete_id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') rescue UserAccount::AuthenticationError @@ -392,12 +396,12 @@ class WebGui < Sinatra::Base session[:book_update_f] = book_update_f checkSession(id) begin - user = UserAccount.getUser(id) + user = @user_account.getUser(id) @id = id @username = user.full_name @book_info = {} @update_f = book_update_f - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') end @@ -414,16 +418,16 @@ class WebGui < Sinatra::Base book_update_f = true session[:book_update_f] = book_update_f isbn = params[:isbn] - is_admin_books = UserAccount.checkAdmin(id) & session[:is_admin] + is_admin_books = @user_account.checkAdmin(id) & session[:is_admin] checkSession(id) begin - user = UserAccount.getUser(id) + user = @user_account.getUser(id) @id = id @username = user.full_name - @book_info = is_admin_books ? BookManager.getBook(isbn) : - BookManager.getBookCollect(isbn, id) + @book_info = is_admin_books ? @book_manager.getBook(isbn) : + @book_manager.getBookCollect(isbn, id) @update_f = book_update_f - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) @is_admin_books = is_admin_books rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') @@ -455,7 +459,7 @@ class WebGui < Sinatra::Base id = session[:userId] book_update_f = session[:book_update_f] checkSession(id) - is_admin_books = UserAccount.checkAdmin(id) & session[:is_admin] + is_admin_books = @user_account.checkAdmin(id) & session[:is_admin] # 書影の新規登録があるかを確認 image_f = !params[:cover_base64].nil? @@ -467,20 +471,20 @@ class WebGui < Sinatra::Base isbn = book_info[:isbn] # 書籍情報の更新 - if BookManager.isBook(isbn) + if @book_manager.isBook(isbn) book_info.delete(:isbn) - BookManager.updateBook(isbn, book_info) + @book_manager.updateBook(isbn, book_info) else - BookManager.createBook(book_info) + @book_manager.createBook(book_info) end cover_image = setBookImage(image_f, params, book_info[:cover_uri]) # 書影情報の更新 if !cover_image[:data].nil? - image_hash = BookManager.addBookCover(isbn, cover_image) + image_hash = @book_manager.addBookCover(isbn, cover_image) cover_uri = "/book_image/#{image_hash}" - BookManager.updateBook(isbn, :cover_uri => cover_uri) + @book_manager.updateBook(isbn, :cover_uri => cover_uri) end if !is_admin_books @@ -488,9 +492,9 @@ class WebGui < Sinatra::Base summary = params[:summary] book_rank = params[:book_rank] if book_update_f - BookManager.updateBookCollect(isbn, id, summary, book_rank) + @book_manager.updateBookCollect(isbn, id, summary, book_rank) else - BookManager.createBookCollect(isbn, id, summary, book_rank) + @book_manager.createBookCollect(isbn, id, summary, book_rank) end end rescue BookManager::NotFoundInstanceError, @@ -511,13 +515,13 @@ class WebGui < Sinatra::Base isbn = params[:isbn] begin - user = UserAccount.getUser(id) + user = @user_account.getUser(id) @id = id @username = user.full_name if !isbn.nil? && !isbn.empty? - @book_info = BookManager.searchISBN(isbn, id) + @book_info = @book_manager.searchISBN(isbn, id) end - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') rescue BookManager::AlreadyInstanceError @@ -544,7 +548,7 @@ class WebGui < Sinatra::Base checkSession(id) begin - user = UserAccount.getUser(id) + user = @user_account.getUser(id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') end @@ -552,7 +556,7 @@ class WebGui < Sinatra::Base @id = id @username = user.full_name @book_info = params - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) @update_f = session[:book_update_f] cover_image = getUploadData(params[:cover_file]) if !cover_image.nil? @@ -572,7 +576,7 @@ class WebGui < Sinatra::Base get '/book_image/:hash' do cache_control :public, :must_revalidate, :max_age => 30 image_hash = params[:hash] - book_cover = BookManager.getBookCover(image_hash) + book_cover = @book_manager.getBookCover(image_hash) status 200 headers \ @@ -593,13 +597,13 @@ class WebGui < Sinatra::Base checkSession(id) begin - user = UserAccount.getUser(id) - is_admin_books = UserAccount.checkAdmin(id) & session[:is_admin] + user = @user_account.getUser(id) + is_admin_books = @user_account.checkAdmin(id) & session[:is_admin] @id = id @username = user.full_name - @book_info = is_admin_books ? BookManager.getBook(isbn) : - BookManager.getBookCollect(isbn, id) - @is_admin = UserAccount.checkAdmin(id) + @book_info = is_admin_books ? @book_manager.getBook(isbn) : + @book_manager.getBookCollect(isbn, id) + @is_admin = @user_account.checkAdmin(id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') rescue BookManager::NotFoundInstanceError @@ -692,11 +696,11 @@ class WebGui < Sinatra::Base list_status = session[:list_status] checkSession(id) begin - user = UserAccount.getUser(id) - is_admin_books = UserAccount.checkAdmin(id) & session[:is_admin] + user = @user_account.getUser(id) + is_admin_books = @user_account.checkAdmin(id) & session[:is_admin] @id = id @username = user.full_name - @is_admin = UserAccount.checkAdmin(id) + @is_admin = @user_account.checkAdmin(id) @is_admin_books = is_admin_books rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') @@ -704,10 +708,12 @@ class WebGui < Sinatra::Base position = list_status[:position] find_status = list_status[:find_status] @book_list, @full_size = is_admin_books ? - BookManager.narrowBooks(position[:start], - position[:step], find_status) : - BookManager.narrowBookOfId(id, position[:start], - position[:step], find_status) + @book_manager.narrowBooks(position[:start], + position[:step], + find_status) : + @book_manager.narrowBookOfId(id, position[:start], + position[:step], + find_status) @start = position[:start] @step = position[:step] @find_status = find_status @@ -728,13 +734,13 @@ class WebGui < Sinatra::Base isbn = params[:isbn] checkSession(id) begin - user = UserAccount.getUser(id) - is_admin_books = UserAccount.checkAdmin(id) & session[:is_admin] + user = @user_account.getUser(id) + is_admin_books = @user_account.checkAdmin(id) & session[:is_admin] @id = id @username = user.full_name - @book_info = is_admin_books ? BookManager.getBook(isbn) : - BookManager.getBookCollect(isbn, id) - @is_admin = UserAccount.checkAdmin(id) + @book_info = is_admin_books ? @book_manager.getBook(isbn) : + @book_manager.getBookCollect(isbn, id) + @is_admin = @user_account.checkAdmin(id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') rescue BookManager::NotFoundInstanceError @@ -750,10 +756,10 @@ class WebGui < Sinatra::Base get '/book_delete/result/:isbn' do cache_control :public, :must_revalidate, :max_age => 30 id = session[:userId] - is_admin_books = UserAccount.checkAdmin(id) & session[:is_admin] + is_admin_books = @user_account.checkAdmin(id) & session[:is_admin] isbn = params[:isbn] begin - is_admin_books ? BookManager.deleteBook(isbn) : + is_admin_books ? @book_manager.deleteBook(isbn) : BookManager.deleteBookCollect(isbn, id) rescue UserAccount::NotFoundInstanceError raise WebError.new(:status => 404, :message => 'ユーザ情報が存在しません。') diff --git a/sinatra/app/models/books_db.rb b/sinatra/app/models/books_db.rb index 903452d..85e7d0b 100644 --- a/sinatra/app/models/books_db.rb +++ b/sinatra/app/models/books_db.rb @@ -10,6 +10,7 @@ require 'httpclient' require 'json' require 'rexml/document' require 'digest/sha2' +require 'singleton' # DB設定ファイルの読み込み db_config = File.join(File.dirname(__FILE__), 'database.yml') @@ -66,6 +67,8 @@ end # ユーザ管理 class BookManager + include Singleton + # 対象の書籍情報がすでに存在している class AlreadyInstanceError < StandardError end @@ -96,683 +99,678 @@ class BookManager # 国立国会図書館 から取得 SEARCH_ON_NDL = 4 - # ISBNの文字列から "-" を削除 - # @param [String] isbn 処理対象のISBN - # @return [String] 変換後のISBN - def self.toIsbn(isbn) - if isbn.kind_of?(String) - return isbn.gsub(/-/, '') + # 書影情報登録 + # @param [String] isbn 画像を登録するISBN + # @param [Hash] cover_image 書影の画像データとフォーマット + + def addBookCover(isbn, cover_image) + cover = cover_image[:data] + mime_type = cover_image[:mime_type] + key_hash = Digest::SHA256.hexdigest(cover) + book_cover = BookCover.find_by(:isbn => isbn) + if !book_cover.nil? && !book_cover.destroy + raise DbAccessError end - return isbn + book_cover = BookCover.new + book_cover.key_hash = key_hash + book_cover.isbn = isbn + book_cover.mime_type = mime_type + book_cover.cover = cover + book_cover.create_at = DateTime.now + book_cover.update_at = DateTime.now + if !book_cover.save + raise DbAccessError + end + + return key_hash end - # 蔵書テーブルから ISBN の蔵書情報を削除 - # @param [String] isbn 処理対象のISBN - def self.deleteBookOfCollection(isbn) - colections = BookCollection.where(:isbn => isbn) - BookCollection.transcation do - colections.each do |item| - item.destroy! - end + # 書影イメージを取得 + # @param [String] key_hash 書影イメージのハッシュ + # @return [BookCover] 書影情報 + def getBookCover(key_hash) + book_cover = BookCover.find_by(:key_hash => key_hash) + if book_cover.nil? + raise NotFoundInstanceError end - rescue StandardError - raise DbAccessError + + return book_cover end - # ISBNから書籍情報検索してハッシュで返却 - # @param [String] isbn - # @return [Hash] 書籍情報 - def self.getHashOfBooks(isbn) - book = Book.find_by(:isbn => isbn) - if book.nil? - return nil + # 書影イメージの削除 + # @param [String] isbn_str 削除対象のISBN + def deleteBookCover(isbn_str) + isbn = toIsbn(isbn_str) + book_cover = BookCover.find_by(:isbn => isbn) + if book_cover + raise NotFoundInstanceError + end + if !book_cover.destroy + raise DbAccessError end + end - book_hash = { - :search_type => SEARCH_ON_BOOKS, - :isbn => book.isbn, - :title => book.title, - :subtitle => book.subtitle, - :volume => book.volume, - :series => book.series, - :author => book.author, - :original_author => book.original_author, - :illustrator => book.illustrator, - :translator => book.translator, - :supervisor => book.supervisor, - :publisher => book.publisher, - :pubdate => book.pubdate, - :cover_uri => book.cover_uri - } - return book_hash + # 書籍存在チェック(ISBN) + # @param [String] isbn_str 探索対象のISBN + # @return [Boolean] 対象書籍の有無を確認 + def isBook(isbn_str) + isbn = toIsbn(isbn_str) + book = Book.find_by(:isbn => isbn) + return !book.nil? end - # 書影のURLを国立図書館のAPIより取得する。 - # @param [String] isbn 対象のISBN - # @return [String] 取得したURI - def self.getCover(isbn) - cover_uri = "https://iss.ndl.go.jp/thumbnail/#{isbn}" - client = HTTPClient.new - res = client.get(cover_uri) + # 書籍探索(ISBN) + # @param [String] isbn_str 探索対象のISBN + # @param [Integer] user_id 探索対象のユーザID + # @return [Hash] 書籍情報 + def searchISBN(isbn_str, user_id) + isbn = toIsbn(isbn_str) + collection = BookCollection.find_by(:isbn => isbn, :user_id => user_id) + if !collection.nil? + # ユーザが保持しているのですでにあることを例外で通知 + raise AlreadyInstanceError + end - if res.status == 200 - return cover_uri - else - return nil + book_info = getHashOfBooks(isbn) + if book_info.nil? + book_info = getHashOfOpenBD(isbn) + end + if book_info.nil? + book_info = getHashOfNDL(isbn) + end + if book_info.nil? + book_info = getHashOfGBS(isbn) + end + if book_info.nil? + book_info = { :isbn => isbn } end + + return book_info end - # 著者種別から各関係者ハッシュのキーを取得 - # @param [String] job 著者種別 - # @return [Symbol] ハッシュキー - def self.getParsonKey(job) - case job - when '著', '著者', '作者', '作' - key = :author - when 'イラスト', '画', '作画' - key = :illustrator - when '翻訳', '訳' - key = :translator - when '原著', '原' - key = :original_author - when '監修', '監' - key = :supervisor - else - key = :author + # 書籍情報の登録 + # @param [Hash] book_info 書籍情報のハッシュ + def createBook(book_info) + isbn = book_info[:isbn] + if !Book.find_by(:isbn => isbn).nil? + raise AlreadyInstanceError end - return key - end - # openBDの著者情報から各関係者ハッシュを作成 - # @param [String] parsons 著者情報 - # @return [Hash] 関係者ハッシュ - def self.getParsonsFromOpenBD(parsons) - parsons_hash = {} - parsons.split(' ').each do |item| - name, job = item.split('/') - key = getParsonKey(job) - if parsons_hash[key].nil? || parsons_hash[key].empty? - parsons_hash[key] = name + book = Book.new + book_info.each do |key, value| + if key == :pubdate + book.pubdate = Date.parse(value) else - parsons_hash[key] += ", #{name}" + method = "#{key}=" + book.send(method, value) end end - return parsons_hash - end - # ISBNからopenBDを検索してハッシュで返却 - # @param [String] isbn - # @return [Hash] 書籍情報 - def self.getHashOfOpenBD(isbn) - client = HTTPClient.new - res = client.get('http://api.openbd.jp/v1/get', :isbn => isbn) - if res.status != HTTP::Status::OK - raise FailedGetInstance + # 登録日時の設定 + book.create_at = DateTime.now + book.update_at = DateTime.now + if !book.save + raise DbAccessError end + end - books = JSON.parse(res.body) - - if books.size > 1 - raise FailedGetInstance + # 書籍情報取得 + # @param [String] isbn_str 取得対象のISBN + # @return [Book] + def getBook(isbn_str) + isbn = toIsbn(isbn_str) + book = Book.find_by(:isbn => isbn) + if book.nil? + # 対象の書籍情報がなかった。 + raise NotFoundInstanceError end - if books.empty? - return nil - end + return book + end - if books[0].nil? - return nil + # 書籍情報の変更 + # @param [String] isbn_str + # @param [Hash] columns 変更するカラムと値のハッシュ + def updateBook(isbn_str, columns) + isbn = toIsbn(isbn_str) + book = Book.find_by(:isbn => isbn) + change_f = false + if book.nil? + raise NotFoundInstanceError end - book = books[0]['summary'] - parsons = getParsonsFromOpenBD(book['author']) - book_hash = { - :search_type => SEARCH_ON_OPENBD, - :isbn => book['isbn'], - :title => book['title'], - :volume => book['volume'], - :series => book['series'], - :author => parsons[:author], - :original_author => parsons[:original_author], - :translator => parsons[:translator], - :supervisor => parsons[:supervisor], - :illustrator => parsons[:illustrator], - :publisher => book['publisher'], - :pubdate => book['pubdate'], - :cover_uri => book['cover'].nil? || book['cover'].empty? ? getCover(isbn) : book['cover'] - } - return book_hash - end + columns.each do |key, value| + # 値がない、値が空文字の場合は対象としない。 + next if value.nil? + next if value == book.send(key) - # 国立国会図書館の著者情報から各関係者ハッシュを作成 - # @param [String] parsons 著者情報 - # @return [Hash] 関係者ハッシュ - def self.getParsonsFromNDL(parsons) - parsons_hash = {} - parsons.each do |item| - split_data = item.split(' ') - name = split_data[0...split_data.size - 1].join(' ') - job = split_data[split_data.size - 1] - key = getParsonKey(job) - if parsons_hash[key].nil? || parsons_hash[key].empty? - parsons_hash[key] = name + if key == :pubdate + book.pubdate = Date.parse(value) else - parsons_hash[key] += ", #{name}" + method = "#{key}=" + book.send(method, value) + end + change_f = true + end + + # 更新内容の適用 + if change_f + book.update_at = DateTime.now + if !book.save + raise DbAccessError end end - return parsons_hash end - # ISBNから国立図書館を検索してハッシュで返却 - # @param [String] isbn - # @return [Hash] 書籍情報 - def self.getHashOfNDL(isbn) - client = HTTPClient.new - res = client.get('https://iss.ndl.go.jp/api/sru', - { 'operation' => 'searchRetrieve', - 'query' => "isbn=#{isbn}", - 'recordSchema' => 'dcndl' }) - if res.status != HTTP::Status::OK - raise FailedGetInstance - end + # + # 書籍情報検索 + # @param [Hash] find_keys 検索キー情報 + # @return [Array] 検索結果 + def findBook(find_keys) + books = Book.all - library_param = REXML::Document.new(res.body) - book_num = library_param.elements['//searchRetrieveResponse/numberOfRecords'].text.to_i - if book_num < 1 - return nil + if find_keys.nil? + return books end - element_str = library_param.elements["//searchRetrieveResponse/records/record[#{book_num}]/recordData"].text - book_xml = REXML::Document.new(element_str) - book = book_xml.elements['//rdf:RDF/dcndl:BibResource/'] - creators = [] - book.elements.each('dc:creator') do |item| - creators << item.text + find_keys.each do |key, value| + if books.nil? + break + end + + if value =~ %r{^/(.+)/$} + reg_value = Regexp.last_match[1] + books = books.with_regexp(key, reg_value) + else + books = books.where(key => value) + end end - parsons = getParsonsFromNDL(creators) - book_hash = { - :search_type => SEARCH_ON_NDL, - :isbn => isbn, - :title => book.elements['dcterms:title'].nil? ? nil : book.elements['dcterms:title'].text, - :volume => book.elements['dcndl:volume/rdf:Description/rdf:value'].nil? ? nil : - book.elements['dcndl:volume/rdf:Description/rdf:value'].text.gsub(/[^\d]/, '').to_i, - :series => book.elements['dcndl:seriesTitle/rdf:Description/rdf:value'].nil? ? nil : - book.elements['dcndl:seriesTitle/rdf:Description/rdf:value'].text, - :author => parsons[:author], - :original_author => parsons[:original_author], - :translator => parsons[:translator], - :supervisor => parsons[:supervisor], - :illustrator => parsons[:illustrator], - :publisher => book.elements['dcterms:publisher/foaf:Agent/foaf:name'].nil? ? nil : - book.elements['dcterms:publisher/foaf:Agent/foaf:name'].text, - :pubdate => book.elements['dcterms:date'].nil? ? nil : book.elements['dcterms:date'].text.gsub('.', '-'), - :cover_uri => getCover(isbn) - } - return book_hash + return books end - # ISBNからGoogleBooksを検索してハッシュで返却 - # @param [String] isbn - # @return [Hash] 書籍情報 - def self.getHashOfGBS(isbn) - client = HTTPClient.new - res = client.get('https://www.googleapis.com/books/v1/volumes', :q => "isbn:#{isbn}") - if res.status != HTTP::Status::OK - raise FailedGetInstance + # 書籍情報の削除 + # @param [String] isbn_str 削除対象のISBN + def deleteBook(isbn_str) + isbn = toIsbn(isbn_str) + book = Book.find_by(:isbn => isbn) + if book.nil? + # 対象の書籍情報がなかった。 + raise NotFoundInstanceError end - books = JSON.parse(res.body) - - if books['totalItems'] > 1 - raise FailedGetInstance - end + # 蔵書情報から該当する書籍を削除 + deleteBookOfCollection(isbn) - if books['totalItems'] < 1 - return nil + # 書影情報を削除 + cover = BookCover.find_by(:isbn => isbn) + if !cover.nil? && !cover.destroy + raise DbAccessError end - if books['items'].nil? || books['items'][0].nil? - return nil + # 書籍情報を削除 + if !book.destroy + raise DbAccessError end - - book = books['items'][0]['volumeInfo'] - book_hash = { - :search_type => SEARCH_ON_GBS, - :isbn => isbn, - :title => book['title'], - :volume => book['volume'], - :series => nil, - :author => book['authors'].join(', '), - :original_author => nil, - :translator => nil, - :supervisor => nil, - :illustrator => nil, - :publisher => book['publisher'], - :pubdate => book['publishedDate'], - :cover_uri => book['imageLinks'].nil? ? getCover(isbn) : book['imageLinks']['thumbnail'] - } - return book_hash end - # 各ユーザ用の書籍情報を作成 - # @param [Book] book 書籍情報 - # @param [BookCollection] book_collect 蔵書情報 - # @return [Hash] 書籍情報 - def self.createBookHash(book, book_collect) - { - :isbn => book[:isbn], - :title => book[:title], - :subtitle => book[:subtitle], - :volume => book[:volume], - :series => book[:series], - :author => book[:author], - :original_author => book[:original_author], - :translator => book[:translator], - :supervisor => book[:supervisor], - :illustrator => book[:illustrator], - :publisher => book[:publisher], - :pubdate => book[:pubdate], - :cover_uri => book[:cover_uri], - :summary => book_collect[:summary], - :book_rank => book_collect[:book_rank] - } + # 全書籍取得 + # @param [Integer] start 表示開始位置 + # @param [Integer] step 表示数 + # @param [Hash] find_keys 検索対象 + # @return [Array] 絞り込んだ書籍情報 + def narrowBooks(start, step, find_keys) + return narrowBookList(Book.all, + start, step, find_keys) end - private_class_method :toIsbn, :deleteBookOfCollection, - :getHashOfBooks, :getParsonKey, :getCover, - :getParsonsFromOpenBD, :getHashOfOpenBD, - :getParsonsFromNDL, :getHashOfNDL, - :getHashOfGBS, :createBookHash + # ユーザでの絞り込み + # @param [Integer] user_id ユーザID + # @param [Integer] start 表示開始位置 + # @param [Integer] step 表示数 + # @param [Hash] find_keys 検索対象 + # @return [Array] 絞り込んだ書籍情報 + def narrowBookOfId(user_id, start, step, find_keys) + # ユーザに関連する書籍の一覧を取得する。 + return narrowBookList(BookFull.where(:user_id => user_id), + start, step, find_keys) + end - # 書影情報登録 - # @param [String] isbn 画像を登録するISBN - # @param [Hash] cover_image 書影の画像データとフォーマット + # 指定範囲の書籍一覧を取得 + # @param [Array] find_books 探索の一覧 + # @param [Integer] start 表示開始位置 + # @param [Integer] step 表示数 + # @param [Hash] find_keys 検索対象 + # @return [Array] 絞り込んだ書籍情報 + def narrowBookList(find_books, start, step, find_keys) + # 条件に合う書籍を検索 + find_keys&.each do |key, value| + if find_books.nil? + break + end - def self.addBookCover(isbn, cover_image) - cover = cover_image[:data] - mime_type = cover_image[:mime_type] - key_hash = Digest::SHA256.hexdigest(cover) - book_cover = BookCover.find_by(:isbn => isbn) - if !book_cover.nil? && !book_cover.destroy - raise DbAccessError + if key == :image_unregist + # 書影の有無を確認するための検索 + find_books = find_books.where(:cover_uri => nil) + elsif value =~ %r{^/(.+)/$} + # 通常の要素の正規表現検索 + reg_value = Regexp.last_match[1] + find_books = find_books.with_regexp(key, reg_value) + else + # 通常の要素の全マッチ検索 + find_books = find_books.where(key => value) + end end - book_cover = BookCover.new - book_cover.key_hash = key_hash - book_cover.isbn = isbn - book_cover.mime_type = mime_type - book_cover.cover = cover - book_cover.create_at = DateTime.now - book_cover.update_at = DateTime.now - if !book_cover.save - raise DbAccessError - end + # タイトルと巻数でソート + find_books = find_books.order(:title).order(:volume) - return key_hash + # 表示対象を抽出 + narrow_books = find_books.limit(step).offset(start) + return narrow_books, find_books.size end - # 書影イメージを取得 - # @param [String] key_hash 書影イメージのハッシュ - # @return [BookCover] 書影情報 - def self.getBookCover(key_hash) - book_cover = BookCover.find_by(:key_hash => key_hash) - if book_cover.nil? + # 蔵書情報の取得 + # @param [String] isbn_str 取得対象のISBN + # @param [Integer] user_id 取得対象のユーザID + # @return [Array] 絞り込んだ書籍情報 + def getBookCollect(isbn_str, user_id) + isbn = toIsbn(isbn_str) + book = Book.find_by(:isbn => isbn) + if book.nil? raise NotFoundInstanceError end - return book_cover + book_collect = BookCollection.find_by(:isbn => isbn, :user_id => user_id) + if book_collect.nil? + raise NotFoundInstanceError + end + + return createBookHash(book, book_collect) end - # 書影イメージの削除 - # @param [String] isbn_str 削除対象のISBN - def self.deleteBookCover(isbn_str) - isbn = toIsbn(isbn_str) - book_cover = BookCover.find_by(:isbn => isbn) - if book_cover + # 蔵書情報を登録 + # @param [String] isbn 登録するISBN + # @param [Integer] user_id 登録対象のユーザID + # @param [String] summary ユーザ毎の紹介分 + # @param [string] book_rank ユーザの評価 + # @return [BookCollection] 蔵書情報 + def createBookCollect(isbn, user_id, summary, book_rank) + if !BookCollection.find_by(:isbn => isbn, :user_id => user_id).nil? raise NotFoundInstanceError end - if !book_cover.destroy + + book_collect = BookCollection.new + book_collect.isbn = isbn + book_collect.user_id = user_id + if !summary.nil? && !summary.empty? + book_collect.summary = summary + end + + book_collect.book_rank = book_rank + book_collect.create_at = DateTime.now + book_collect.update_at = DateTime.now + + if !book_collect.save raise DbAccessError end end - # 書籍存在チェック(ISBN) - # @param [String] isbn_str 探索対象のISBN - # @return [Boolean] 対象書籍の有無を確認 - def self.isBook(isbn_str) + # 蔵書情報の変更 + # @param [String] isbn_str 変更対象のISBN + # @param [Integer] user_id 変更対象のユーザID + # @param [String] summary ユーザ毎の紹介分 + # @param [string] book_rank ユーザの評価 + def updateBookCollect(isbn_str, user_id, summary, book_rank) isbn = toIsbn(isbn_str) - book = Book.find_by(:isbn => isbn) - return !book.nil? - end + book_collect = BookCollection.find_by(:isbn => isbn, :user_id => user_id) + change_f = false + if book_collect.nil? + raise NotFoundInstanceError + end - # 書籍探索(ISBN) - # @param [String] isbn_str 探索対象のISBN - # @param [Integer] user_id 探索対象のユーザID - # @return [Hash] 書籍情報 - def self.searchISBN(isbn_str, user_id) - isbn = toIsbn(isbn_str) - collection = BookCollection.find_by(:isbn => isbn, :user_id => user_id) - if !collection.nil? - # ユーザが保持しているのですでにあることを例外で通知 - raise AlreadyInstanceError - end - - book_info = getHashOfBooks(isbn) - if book_info.nil? - book_info = getHashOfOpenBD(isbn) - end - if book_info.nil? - book_info = getHashOfNDL(isbn) - end - if book_info.nil? - book_info = getHashOfGBS(isbn) - end - if book_info.nil? - book_info = { :isbn => isbn } + if !summary.nil? && (summary != book_collect.summary) + # 値が異なれば更新 + book_collect.summary = summary + change_f = true end - return book_info - end - - # 書籍情報の登録 - # @param [Hash] book_info 書籍情報のハッシュ - def self.createBook(book_info) - isbn = book_info[:isbn] - if !Book.find_by(:isbn => isbn).nil? - raise AlreadyInstanceError + if book_rank != book_collect.book_rank + # 値が異なれば更新 + book_collect.book_rank = book_rank + change_f = true end - book = Book.new - book_info.each do |key, value| - if key == :pubdate - book.pubdate = Date.parse(value) - else - method = "#{key}=" - book.send(method, value) + # 更新内容の適用 + if change_f + book_collect.update_at = DateTime.now + if !book_collect.save + raise DbAccesError end end - - # 登録日時の設定 - book.create_at = DateTime.now - book.update_at = DateTime.now - if !book.save - raise DbAccessError - end end - # 書籍情報取得 - # @param [String] isbn_str 取得対象のISBN - # @return [Book] - def self.getBook(isbn_str) - isbn = toIsbn(isbn_str) - book = Book.find_by(:isbn => isbn) - if book.nil? - # 対象の書籍情報がなかった。 - raise NotFoundInstanceError + # 蔵書の新規登録リスト取得 + # @param [Integer] user_id 取得対象のユーザID + # @param [Integer] num 件数 + # @return [Array] 取得した書籍情報 + def newestListOfBooks(user_id, num) + books = [] + book_collects = BookCollection.where(:user_id => user_id) + .order(:create_at => :desc).first(num) + book_collects.each do |item| + book = Book.find_by(:isbn => item.isbn) + books.push(book) end - - return book + return books end - # 書籍情報の変更 - # @param [String] isbn_str - # @param [Hash] columns 変更するカラムと値のハッシュ - def self.updateBook(isbn_str, columns) + # 蔵書情報の削除 + # @param [String] isbn_str 削除対象のISBN + # @param [Integer] user_id 削除対象のユーザID + def deleteBookCollect(isbn_str, user_id) isbn = toIsbn(isbn_str) - book = Book.find_by(:isbn => isbn) - change_f = false - if book.nil? + book_collect = BookCollection.find_by(:isbn => isbn, :user_id => user_id) + if book_collect.nil? raise NotFoundInstanceError end - - columns.each do |key, value| - # 値がない、値が空文字の場合は対象としない。 - next if value.nil? - next if value == book.send(key) - - if key == :pubdate - book.pubdate = Date.parse(value) - else - method = "#{key}=" - book.send(method, value) - end - change_f = true + if !book_collect.destroy + raise DbAccessError end + end - # 更新内容の適用 - if change_f - book.update_at = DateTime.now - if !book.save + # 蔵書情報の削除 (ユーザ所有をすべて削除) + # @param [Integer] user_id 削除対象のユーザID + def deleteBookCollectOfUser(user_id) + book_collects = BookCollection.where(:user_id => user_id) + book_collects.each do |book_collect| + if !book_collect.destroy raise DbAccessError end end end - # - # 書籍情報検索 - # @param [Hash] find_keys 検索キー情報 - # @return [Array] 検索結果 - def self.findBook(find_keys) - books = Book.all - - if find_keys.nil? - return books + private + # ISBNの文字列から "-" を削除 + # @param [String] isbn 処理対象のISBN + # @return [String] 変換後のISBN + def toIsbn(isbn) + if isbn.kind_of?(String) + return isbn.gsub(/-/, '') end - find_keys.each do |key, value| - if books.nil? - break - end + return isbn + end - if value =~ %r{^/(.+)/$} - reg_value = Regexp.last_match[1] - books = books.with_regexp(key, reg_value) - else - books = books.where(key => value) + # 蔵書テーブルから ISBN の蔵書情報を削除 + # @param [String] isbn 処理対象のISBN + def deleteBookOfCollection(isbn) + colections = BookCollection.where(:isbn => isbn) + BookCollection.transcation do + colections.each do |item| + item.destroy! end end - return books + rescue StandardError + raise DbAccessError end - # 書籍情報の削除 - # @param [String] isbn_str 削除対象のISBN - def self.deleteBook(isbn_str) - isbn = toIsbn(isbn_str) + # ISBNから書籍情報検索してハッシュで返却 + # @param [String] isbn + # @return [Hash] 書籍情報 + def getHashOfBooks(isbn) book = Book.find_by(:isbn => isbn) if book.nil? - # 対象の書籍情報がなかった。 - raise NotFoundInstanceError + return nil end - # 蔵書情報から該当する書籍を削除 - deleteBookOfCollection(isbn) + book_hash = { + :search_type => SEARCH_ON_BOOKS, + :isbn => book.isbn, + :title => book.title, + :subtitle => book.subtitle, + :volume => book.volume, + :series => book.series, + :author => book.author, + :original_author => book.original_author, + :illustrator => book.illustrator, + :translator => book.translator, + :supervisor => book.supervisor, + :publisher => book.publisher, + :pubdate => book.pubdate, + :cover_uri => book.cover_uri + } + return book_hash + end - # 書影情報を削除 - cover = BookCover.find_by(:isbn => isbn) - if !cover.nil? && !cover.destroy - raise DbAccessError - end + # 書影のURLを国立図書館のAPIより取得する。 + # @param [String] isbn 対象のISBN + # @return [String] 取得したURI + def getCover(isbn) + cover_uri = "https://iss.ndl.go.jp/thumbnail/#{isbn}" + client = HTTPClient.new + res = client.get(cover_uri) - # 書籍情報を削除 - if !book.destroy - raise DbAccessError + if res.status == 200 + return cover_uri + else + return nil end end - # 全書籍取得 - # @param [Integer] start 表示開始位置 - # @param [Integer] step 表示数 - # @param [Hash] find_keys 検索対象 - # @return [Array] 絞り込んだ書籍情報 - def self.narrowBooks(start, step, find_keys) - return narrowBookList(Book.all, - start, step, find_keys) - end - - # ユーザでの絞り込み - # @param [Integer] user_id ユーザID - # @param [Integer] start 表示開始位置 - # @param [Integer] step 表示数 - # @param [Hash] find_keys 検索対象 - # @return [Array] 絞り込んだ書籍情報 - def self.narrowBookOfId(user_id, start, step, find_keys) - # ユーザに関連する書籍の一覧を取得する。 - return narrowBookList(BookFull.where(:user_id => user_id), - start, step, find_keys) + # 著者種別から各関係者ハッシュのキーを取得 + # @param [String] job 著者種別 + # @return [Symbol] ハッシュキー + def getParsonKey(job) + case job + when '著', '著者', '作者', '作' + key = :author + when 'イラスト', '画', '作画' + key = :illustrator + when '翻訳', '訳' + key = :translator + when '原著', '原' + key = :original_author + when '監修', '監' + key = :supervisor + else + key = :author + end + return key end - # 指定範囲の書籍一覧を取得 - # @param [Array] find_books 探索の一覧 - # @param [Integer] start 表示開始位置 - # @param [Integer] step 表示数 - # @param [Hash] find_keys 検索対象 - # @return [Array] 絞り込んだ書籍情報 - def self.narrowBookList(find_books, start, step, find_keys) - # 条件に合う書籍を検索 - find_keys&.each do |key, value| - if find_books.nil? - break - end - - if key == :image_unregist - # 書影の有無を確認するための検索 - find_books = find_books.where(:cover_uri => nil) - elsif value =~ %r{^/(.+)/$} - # 通常の要素の正規表現検索 - reg_value = Regexp.last_match[1] - find_books = find_books.with_regexp(key, reg_value) + # openBDの著者情報から各関係者ハッシュを作成 + # @param [String] parsons 著者情報 + # @return [Hash] 関係者ハッシュ + def getParsonsFromOpenBD(parsons) + parsons_hash = {} + parsons.split(' ').each do |item| + name, job = item.split('/') + key = getParsonKey(job) + if parsons_hash[key].nil? || parsons_hash[key].empty? + parsons_hash[key] = name else - # 通常の要素の全マッチ検索 - find_books = find_books.where(key => value) + parsons_hash[key] += ", #{name}" end end - - # タイトルと巻数でソート - find_books = find_books.order(:title).order(:volume) - - # 表示対象を抽出 - narrow_books = find_books.limit(step).offset(start) - return narrow_books, find_books.size + return parsons_hash end - # 蔵書情報の取得 - # @param [String] isbn_str 取得対象のISBN - # @param [Integer] user_id 取得対象のユーザID - # @return [Array] 絞り込んだ書籍情報 - def self.getBookCollect(isbn_str, user_id) - isbn = toIsbn(isbn_str) - book = Book.find_by(:isbn => isbn) - if book.nil? - raise NotFoundInstanceError + # ISBNからopenBDを検索してハッシュで返却 + # @param [String] isbn + # @return [Hash] 書籍情報 + def getHashOfOpenBD(isbn) + client = HTTPClient.new + res = client.get('http://api.openbd.jp/v1/get', :isbn => isbn) + if res.status != HTTP::Status::OK + raise FailedGetInstance end - book_collect = BookCollection.find_by(:isbn => isbn, :user_id => user_id) - if book_collect.nil? - raise NotFoundInstanceError - end + books = JSON.parse(res.body) - return createBookHash(book, book_collect) - end + if books.size > 1 + raise FailedGetInstance + end - # 蔵書情報を登録 - # @param [String] isbn 登録するISBN - # @param [Integer] user_id 登録対象のユーザID - # @param [String] summary ユーザ毎の紹介分 - # @param [string] book_rank ユーザの評価 - # @return [BookCollection] 蔵書情報 - def self.createBookCollect(isbn, user_id, summary, book_rank) - if !BookCollection.find_by(:isbn => isbn, :user_id => user_id).nil? - raise NotFoundInstanceError + if books.empty? + return nil end - book_collect = BookCollection.new - book_collect.isbn = isbn - book_collect.user_id = user_id - if !summary.nil? && !summary.empty? - book_collect.summary = summary + if books[0].nil? + return nil end - book_collect.book_rank = book_rank - book_collect.create_at = DateTime.now - book_collect.update_at = DateTime.now + book = books[0]['summary'] + parsons = getParsonsFromOpenBD(book['author']) + book_hash = { + :search_type => SEARCH_ON_OPENBD, + :isbn => book['isbn'], + :title => book['title'], + :volume => book['volume'], + :series => book['series'], + :author => parsons[:author], + :original_author => parsons[:original_author], + :translator => parsons[:translator], + :supervisor => parsons[:supervisor], + :illustrator => parsons[:illustrator], + :publisher => book['publisher'], + :pubdate => book['pubdate'], + :cover_uri => book['cover'].nil? || book['cover'].empty? ? getCover(isbn) : book['cover'] + } + return book_hash + end - if !book_collect.save - raise DbAccessError + # 国立国会図書館の著者情報から各関係者ハッシュを作成 + # @param [String] parsons 著者情報 + # @return [Hash] 関係者ハッシュ + def getParsonsFromNDL(parsons) + parsons_hash = {} + parsons.each do |item| + split_data = item.split(' ') + name = split_data[0...split_data.size - 1].join(' ') + job = split_data[split_data.size - 1] + key = getParsonKey(job) + if parsons_hash[key].nil? || parsons_hash[key].empty? + parsons_hash[key] = name + else + parsons_hash[key] += ", #{name}" + end end + return parsons_hash end - # 蔵書情報の変更 - # @param [String] isbn_str 変更対象のISBN - # @param [Integer] user_id 変更対象のユーザID - # @param [String] summary ユーザ毎の紹介分 - # @param [string] book_rank ユーザの評価 - def self.updateBookCollect(isbn_str, user_id, summary, book_rank) - isbn = toIsbn(isbn_str) - book_collect = BookCollection.find_by(:isbn => isbn, :user_id => user_id) - change_f = false - if book_collect.nil? - raise NotFoundInstanceError + # ISBNから国立図書館を検索してハッシュで返却 + # @param [String] isbn + # @return [Hash] 書籍情報 + def getHashOfNDL(isbn) + client = HTTPClient.new + res = client.get('https://iss.ndl.go.jp/api/sru', + { 'operation' => 'searchRetrieve', + 'query' => "isbn=#{isbn}", + 'recordSchema' => 'dcndl' }) + if res.status != HTTP::Status::OK + raise FailedGetInstance end - if !summary.nil? && (summary != book_collect.summary) - # 値が異なれば更新 - book_collect.summary = summary - change_f = true + library_param = REXML::Document.new(res.body) + book_num = library_param.elements['//searchRetrieveResponse/numberOfRecords'].text.to_i + if book_num < 1 + return nil end - if book_rank != book_collect.book_rank - # 値が異なれば更新 - book_collect.book_rank = book_rank - change_f = true + element_str = library_param.elements["//searchRetrieveResponse/records/record[#{book_num}]/recordData"].text + book_xml = REXML::Document.new(element_str) + book = book_xml.elements['//rdf:RDF/dcndl:BibResource/'] + creators = [] + book.elements.each('dc:creator') do |item| + creators << item.text end + parsons = getParsonsFromNDL(creators) + book_hash = { + :search_type => SEARCH_ON_NDL, + :isbn => isbn, + :title => book.elements['dcterms:title'].nil? ? nil : book.elements['dcterms:title'].text, + :volume => book.elements['dcndl:volume/rdf:Description/rdf:value'].nil? ? nil : + book.elements['dcndl:volume/rdf:Description/rdf:value'].text.gsub(/[^\d]/, '').to_i, + :series => book.elements['dcndl:seriesTitle/rdf:Description/rdf:value'].nil? ? nil : + book.elements['dcndl:seriesTitle/rdf:Description/rdf:value'].text, + :author => parsons[:author], + :original_author => parsons[:original_author], + :translator => parsons[:translator], + :supervisor => parsons[:supervisor], + :illustrator => parsons[:illustrator], + :publisher => book.elements['dcterms:publisher/foaf:Agent/foaf:name'].nil? ? nil : + book.elements['dcterms:publisher/foaf:Agent/foaf:name'].text, + :pubdate => book.elements['dcterms:date'].nil? ? nil : book.elements['dcterms:date'].text.gsub('.', '-'), + :cover_uri => getCover(isbn) + } + return book_hash + end - # 更新内容の適用 - if change_f - book_collect.update_at = DateTime.now - if !book_collect.save - raise DbAccesError - end + # ISBNからGoogleBooksを検索してハッシュで返却 + # @param [String] isbn + # @return [Hash] 書籍情報 + def getHashOfGBS(isbn) + client = HTTPClient.new + res = client.get('https://www.googleapis.com/books/v1/volumes', :q => "isbn:#{isbn}") + if res.status != HTTP::Status::OK + raise FailedGetInstance end - end - # 蔵書の新規登録リスト取得 - # @param [Integer] user_id 取得対象のユーザID - # @param [Integer] num 件数 - # @return [Array] 取得した書籍情報 - def self.newestListOfBooks(user_id, num) - books = [] - book_collects = BookCollection.where(:user_id => user_id) - .order(:create_at => :desc).first(num) - book_collects.each do |item| - book = Book.find_by(:isbn => item.isbn) - books.push(book) + books = JSON.parse(res.body) + + if books['totalItems'] > 1 + raise FailedGetInstance end - return books - end - # 蔵書情報の削除 - # @param [String] isbn_str 削除対象のISBN - # @param [Integer] user_id 削除対象のユーザID - def self.deleteBookCollect(isbn_str, user_id) - isbn = toIsbn(isbn_str) - book_collect = BookCollection.find_by(:isbn => isbn, :user_id => user_id) - if book_collect.nil? - raise NotFoundInstanceError + if books['totalItems'] < 1 + return nil end - if !book_collect.destroy - raise DbAccessError + + if books['items'].nil? || books['items'][0].nil? + return nil end + + book = books['items'][0]['volumeInfo'] + book_hash = { + :search_type => SEARCH_ON_GBS, + :isbn => isbn, + :title => book['title'], + :volume => book['volume'], + :series => nil, + :author => book['authors'].join(', '), + :original_author => nil, + :translator => nil, + :supervisor => nil, + :illustrator => nil, + :publisher => book['publisher'], + :pubdate => book['publishedDate'], + :cover_uri => book['imageLinks'].nil? ? getCover(isbn) : book['imageLinks']['thumbnail'] + } + return book_hash end - # 蔵書情報の削除 (ユーザ所有をすべて削除) - # @param [Integer] user_id 削除対象のユーザID - def self.deleteBookCollectOfUser(user_id) - book_collects = BookCollection.where(:user_id => user_id) - book_collects.each do |book_collect| - if !book_collect.destroy - raise DbAccessError - end - end + # 各ユーザ用の書籍情報を作成 + # @param [Book] book 書籍情報 + # @param [BookCollection] book_collect 蔵書情報 + # @return [Hash] 書籍情報 + def createBookHash(book, book_collect) + { + :isbn => book[:isbn], + :title => book[:title], + :subtitle => book[:subtitle], + :volume => book[:volume], + :series => book[:series], + :author => book[:author], + :original_author => book[:original_author], + :translator => book[:translator], + :supervisor => book[:supervisor], + :illustrator => book[:illustrator], + :publisher => book[:publisher], + :pubdate => book[:pubdate], + :cover_uri => book[:cover_uri], + :summary => book_collect[:summary], + :book_rank => book_collect[:book_rank] + } end end diff --git a/sinatra/app/models/users_db.rb b/sinatra/app/models/users_db.rb index d22cc74..6fc53d6 100644 --- a/sinatra/app/models/users_db.rb +++ b/sinatra/app/models/users_db.rb @@ -35,6 +35,7 @@ end # ユーザ管理 class UserAccount + include Singleton # ユーザ認証エラー class AuthenticationError < StandardError end @@ -51,23 +52,12 @@ class UserAccount class DbAccessError < StandardError end - # SALT と Password Hash を生成する - # @param [String] passwd パスワード - # @return [String, String] SALT, パスワードハッシュ - def self.makeHash(passwd) - passwd_salt = BCrypt::Engine.generate_salt - passwd_hash = BCrypt::Engine.hash_secret(passwd, passwd_salt) - - return passwd_salt, passwd_hash - end - - private_class_method :makeHash - + # ユーザが管理者であるかをチェック # @param [Integer] id チェック対象ユーザID # @return [Boolean] true: 管理者 # @return [Boolean] false: 管理者ではない - def self.checkAdmin(id) + def checkAdmin(id) user = User.find_by(:user_id => id) if user.nil? return false @@ -83,7 +73,7 @@ class UserAccount # @param [String] passwd パスワード # @return [Integer] 採番されたユーザID # @raise [AlreadyInstanceError] すでにユーザ情報を登録済み - def self.createAccount(name, full_name, email, passwd) + def createAccount(name, full_name, email, passwd) # ユーザの有無をチェック if !User.find_by(:user_name => name).nil? raise AlreadyInstanceError @@ -115,7 +105,7 @@ class UserAccount # @return [Integer] 認証されたユーザID # @raise [NotFoundInstanceError] ユーザ情報の取得に失敗 # @raise [AuthenticationError] 認証失敗 - def self.checkPasswd(name, passwd) + def checkPasswd(name, passwd) user = User.find_by(:user_name => name) # ユーザの有無をチェック @@ -138,7 +128,7 @@ class UserAccount # @param [Integer] id 対象ユーザID # @return [User] ユーザ情報 # @raise [NotFoundInstanceError] ユーザ情報の取得に失敗 - def self.getUser(id) + def getUser(id) user = User.find_by(:user_id => id) if user.nil? raise NotFoundInstanceError @@ -151,7 +141,7 @@ class UserAccount # @param [Integer] id 取得対象ユーザID # @return [Array] 全ユーザ情報の一覧 # @raise [AuthenticationError] ユーザ権限不正 - def self.getUserList(id) + def getUserList(id) if !checkAdmin(id) raise AuthenticationError end @@ -162,7 +152,7 @@ class UserAccount # ユーザ情報の変更 # @param [Integer] id 変更対象のユーザID # @param [Hash] columns 変更するカラムと値のハッシュ - def self.updateUser(id, columns) + def updateUser(id, columns) user = User.find_by(:user_id => id) change_f = false if user.nil? @@ -198,7 +188,7 @@ class UserAccount # ユーザ情報の削除 # @param [Integer] id 削除対象のユーザID - def self.deleteUser(id) + def deleteUser(id) user = User.find_by(:user_id => id) if user.nil? raise NotFoundInstanceError @@ -207,4 +197,16 @@ class UserAccount raise DbAccessError end end + + private + # SALT と Password Hash を生成する + # @param [String] passwd パスワード + # @return [String, String] SALT, パスワードハッシュ + def makeHash(passwd) + passwd_salt = BCrypt::Engine.generate_salt + passwd_hash = BCrypt::Engine.hash_secret(passwd, passwd_salt) + + return passwd_salt, passwd_hash + end + end diff --git a/sinatra/config.ru b/sinatra/config.ru index 4e4bd52..a83794f 100644 --- a/sinatra/config.ru +++ b/sinatra/config.ru @@ -1,3 +1,6 @@ +# coding: utf-8 +# frozen_string_literal: true + require 'sinatra' require './start' -- 2.19.2