DataBase アクセス用のクラスを Singleton に変更
authorOHASHI, Norikazu <katz@neko-mori.sakura.ne.jp>
Fri, 28 Jan 2022 10:58:39 +0000 (19:58 +0900)
committerOHASHI, Norikazu <katz@neko-mori.sakura.ne.jp>
Fri, 28 Jan 2022 10:58:39 +0000 (19:58 +0900)
sinatra/.rubocop.yml
sinatra/Gemfile
sinatra/app/controllers/web_gui.rb
sinatra/app/models/books_db.rb
sinatra/app/models/users_db.rb
sinatra/config.ru

index 01274a4..71da13c 100644 (file)
@@ -40,3 +40,6 @@ Style/TrailingCommaInArrayLiteral:
   EnforcedStyleForMultiline: comma
 Style/TrailingCommaInHashLiteral:
   EnforcedStyleForMultiline: comma
+
+Bundler/OrderedGems:
+  Enabled: false
index e8fd144..f09ca80 100644 (file)
@@ -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"
 
index 6a768db..f6ee83b 100644 (file)
@@ -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 => 'ユーザ情報が存在しません。')
index 903452d..85e7d0b 100644 (file)
@@ -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<Book>]  検索結果
+  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<Hash>] 絞り込んだ書籍情報
+  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<Hash>] 絞り込んだ書籍情報
+  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<Books>] find_books 探索の一覧
+  # @param [Integer] start 表示開始位置
+  # @param [Integer] step 表示数
+  # @param [Hash]  find_keys 検索対象
+  # @return [Array<Hash>] 絞り込んだ書籍情報
+  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<Hash>] 絞り込んだ書籍情報
+  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<Book>] 取得した書籍情報
+  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<Book>]  検索結果
-  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<Hash>] 絞り込んだ書籍情報
-  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<Hash>] 絞り込んだ書籍情報
-  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<Books>] find_books 探索の一覧
-  # @param [Integer] start 表示開始位置
-  # @param [Integer] step 表示数
-  # @param [Hash]  find_keys 検索対象
-  # @return [Array<Hash>] 絞り込んだ書籍情報
-  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<Hash>] 絞り込んだ書籍情報
-  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
 
-  # è\94µæ\9b¸æ\83\85å ±ã\81®å¤\89æ\9b´
-  # @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ã\81\8bã\82\89å\9b½ç«\8bå\9b³æ\9b¸é¤¨ã\82\92æ¤\9cç´¢ã\81\97ã\81¦ã\83\8fã\83\83ã\82·ã\83¥ã\81§è¿\94å\8d´
+  # @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<Book>] 取得した書籍情報
-  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
index d22cc74..6fc53d6 100644 (file)
@@ -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<User>] 全ユーザ情報の一覧
   # @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
index 4e4bd52..a83794f 100644 (file)
@@ -1,3 +1,6 @@
+# coding: utf-8
+# frozen_string_literal: true
+
 require 'sinatra'
 require './start'