--- /dev/null
+# coding: utf-8
+# 書籍系DBアクセス処理
+# @author OHASHI, Norikazu
+
+require 'active_record'
+require 'mysql2'
+require 'httpclient'
+require 'json'
+require 'digest/sha2'
+
+# DB設定ファイルの読み込み
+db_config = File.join(File.dirname(__FILE__), 'database.yml')
+ActiveRecord::Base.configurations = YAML.load_file(db_config)
+ActiveRecord::Base.establish_connection(:development)
+
+#書籍情報
+class Book < ActiveRecord::Base
+ # 正規表現によるレコード探索
+ # @param [Symbol] key カラム名
+ # @param [String] pattern 正規表現パターン
+ # @return [Array<User>] 対象となるユーザ一覧
+ def self.with_regexp(key, pattern)
+ column = columns_hash[key.to_s].name
+ where("`#{table_name}`.`#{column}` REGEXP ?", pattern)
+ end
+end
+
+#蔵書情報
+class BookCollection < ActiveRecord::Base
+ # 正規表現によるレコード探索
+ # @param [Symbol] key カラム名
+ # @param [String] pattern 正規表現パターン
+ # @return [Array<User>] 対象となるユーザ一覧
+ def self.with_regexp(key, pattern)
+ column = columns_hash[key.to_s].name
+ where("`#{table_name}`.`#{column}` REGEXP ?", pattern)
+ end
+end
+
+#書影情報
+class BookCover < ActiveRecord::Base
+ # 正規表現によるレコード探索
+ # @param [Symbol] key カラム名
+ # @param [String] pattern 正規表現パターン
+ # @return [Array<User>] 対象となるユーザ一覧
+ def self.with_regexp(key, pattern)
+ column = columns_hash[key.to_s].name
+ where("`#{table_name}`.`#{column}` REGEXP ?", pattern)
+ end
+end
+
+# ユーザ管理
+class BookManager
+
+ # 対象の書籍情報がすでに存在している
+ class AlreadyInstanceError < StandardError
+ end
+
+ # 対象の書籍情報が存在していない
+ class NotFoundInstanceError < StandardError
+ end
+
+ # DBアクセス失敗
+ class DbAccessError < StandardError
+ end
+
+ # データ取得に失敗
+ class FailedGetInstance < StandardError
+ end
+ # 定数定義
+
+ # 探索対象
+ # 書籍情報から取得
+ SEARCH_ON_BOOKS = 1
+
+ # openBDから取得
+ SEARCH_ON_OPENBD = 2
+
+ # ISBNの文字列から "-" を削除
+ # @param [String] isbn 処理対象のISBN
+ # @return [String] 変換後のISBN
+ def self.toIsbn(isbn)
+ if isbn.kind_of?(String)
+ return isbn.gsub(/-/, "")
+ end
+ return isbn
+ end
+
+ # 蔵書テーブルから ISBN の蔵書情報を削除
+ # @param [String] isbn 処理対象のISBN
+ def self.deleteBookOfCollection(isbn)
+ begin
+ colections = BookCollection.where(isbn: isbn)
+ BookCollection.transcation do
+ colections.each do |item|
+ item.destroy!
+ end
+ end
+ rescue
+ raise DbAccessError
+ end
+ end
+
+
+ # ISBNから書籍情報検索してハッシュで返却
+ # @param [String] isbn
+ # @return [Hash] 書籍情報
+ def self.getHashOfBooks(book)
+ book = Book.find_by(isbn: isbn)
+ if (book == nil)
+ return nil
+ end
+ book_hash = {
+ search_type: SEARCH_ON_BOOKS,
+ isbn: book.isbn,
+ title: book.title,
+ volume: book.volume,
+ series: book.series,
+ author: book.author,
+ orignal_author: book.orignal_author,
+ illustrator: book.illustrator,
+ translator: book.translator,
+ supervisor: book.supervisor,
+ publisher: book.publisher,
+ pubdate: book.pubdate,
+ cover_uri: book.cover
+ }
+ return book_hash
+ end
+
+ # openBDの著者情報から各関係者ハッシュを作成
+ # @param [String] parsons 著者情報
+ # @return [Hash] 関係者ハッシュ
+ def self.getParsons(parsons)
+ parsons_hash = {}
+ parsons.split(" ").each do |item|
+ name, jobs = item.split("/")
+ case jobs
+ when "著", "著者", "作者", "作" then
+ key = :author
+ when "イラスト", "画", "作画" then
+ key = :illustrator
+ when "翻訳", "訳" then
+ key = :translator
+ when "原著", "原" then
+ key = :orignal_author
+ when "監修", "監" then
+ key = :supervisor
+ else
+ key = :author
+ end
+ if ( parsons_hash[key] == nil || parsons_hash[key] = "")
+ parsons_hash[key] = name
+ else
+ parsons_hash[key] += ", " + name
+ end
+ end
+ return parsons_hash
+ end
+
+ # ISBNからopenBDを検索してハッシュで返却
+ # @param [String] isbn
+ # @return [Hash] 書籍情報
+ def self.getHashOfOpenBD(book)
+ client = HTTPClient.new
+ res = client.get("http://api.openbd.jp/v1/get", isbn: isbn)
+ books = JSON.perse(res.body)
+
+ if (books.size > 1)
+ raise FailedGetInstance
+ end
+ if (books.size < 1)
+ return nil
+ end
+ book = books[0]["summary"]
+ parsons = getParsons(book["author"])
+ book_hash = {
+ search_type: SEARCH_ON_OPENBD,
+ isbn: book["isbn"],
+ title: book["title"],
+ volume: book["volume"],
+ series: book["series"],
+ author: parsons[:author],
+ orignal_author: parsons[:orignal_author],
+ translator: parsons[:translator],
+ supervisor: parsons[:supervisor],
+ illustrator: book[:illustrator],
+ publisher: book["publisher"],
+ pubdate: book["pubdate"],
+ cover_uri: book["cover"]
+ }
+ return book_hash
+ end
+
+ # 各ユーザ用の書籍情報を作成
+ # @param [Book] book 書籍情報
+ # @param [BookCollection] book_collect 蔵書情報
+ # @return [Hash] 書籍情報
+ def createBookHash(book, book_collect)
+ {
+ isbn: book[:isbn],
+ title: book[:title],
+ volume: book[:volume],
+ series: book[:series],
+ author: book[:author],
+ orignal_author: book[:orignal_author],
+ translator: book[:translator],
+ supervisor: book[:supervisor],
+ illustrator: book[:illustrator],
+ publisher: book[:publisher],
+ pubdate: book[:pubdate],
+ cover_uri: book[:cover],
+ summary: book_collect[:summary],
+ rank: book_collect[:rank]
+ }
+ end
+
+ private_class_method :toIsbn, :deleteBookOfCollection,
+ :getHashOfBooks, :getParsons, :getHashOfOpenBD,
+ :createBookHash
+
+ # 書影情報登録
+ # @param [String] isbn 画像を登録するISBN
+ # @param [Hash] cover_image 書影の画像データとフォーマット
+
+ def self.addBookCover(isbn, cover_image)
+ cover = cover_image[:data]
+ mime_type = cover_image[:mime_type]
+ key_hash = Digest::SHA256.hexdigest(cover)
+
+ if (BookCover.find_by(isbn: isbn) != nil)
+ raise AlreadyInstanceError
+ 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 (not book_cover.save)
+ raise DbAccessError
+ end
+ return key_hash
+
+ end
+
+ # 書影イメージを取得
+ # @param [String] key_hash 書影イメージのハッシュ
+ # @return [BookCover] 書影情報
+ def self.getBookCover(key_hash)
+ book_cover = BookCover.find_by(key_hash: key_hash)
+ if (book_cover)
+ raise NotFoundInstanceError
+ end
+ return book_cover
+ 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)
+ raise NotFoundInstanceError
+ end
+ if (not book_cover.destroy)
+ raise DbAccessError
+ end
+ end
+
+ # 書籍探索(ISBN)
+ # @param [String] isbn_str 探索対象のISBN
+ # @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
+ return book_info
+ end
+
+ # 書籍情報の登録
+ # @param [Hash] 書籍情報のハッシュ
+ def self.createBook(book_info)
+ isbn = book_info[:isbn]
+ if (Book.find_by(isbn: isbn) != nil)
+ raise AlreadyInstanceError
+ end
+ book = Book.new
+ book_info.each do |key, value|
+ if (key == :cover_image)
+ # 書影のイメージはここでは設定しない
+ next
+ end
+ if (key == :cover_uri)
+ # 書影にはURIのキーを登録
+ book.cover = value
+ else
+ # その他のステータスはそのまま登録
+ method = key.to_s + "="
+ book.send(method, value)
+ end
+ end
+
+ # 登録日時の設定
+ book.create_at = DateTime.now
+ book.update_at = DateTime.now
+ if (not 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)
+ if (book == nil)
+ # 対象の書籍情報がなかった。
+ raise NotFoundInstanceError
+ end
+ return book
+ end
+
+ # 書籍情報の変更
+ # @param [String] isbn_str
+ # @param [Hash] columns 変更するカラムと値のハッシュ
+ def self.updateBook(id, columns)
+ isbn = toIsbn(isbn_str)
+ book = Book.find_by(isbn: isbn)
+ change_f = false
+ if (book == nil)
+ raise NotFoundInstanceError
+ end
+
+ columns.each do |key, value|
+ if ((value == nil) || (value == ""))
+ # 値がない、値が空文字の場合は対象としない。
+ next
+ end
+ if (key == :cover_uri)
+ method = "cover="
+ else
+ method = key.to_s + "="
+ end
+ if (value != book.send(method.chop))
+ book.send(method, value)
+ change_f = true
+ end
+ end
+
+ # 更新内容の適用
+ if (change_f)
+ book.update_at = DateTime.now
+ if (book.save)
+ raise DbAccessError
+ end
+ end
+ end
+
+ #
+ # 書籍情報検索
+ # @param [Hash] find_keys 検索キー情報
+ # @return [Array<Book>] 検索結果
+ def self.findBook(find_keys)
+
+ books = Book.all
+ find_keys.each do |key, value|
+ if (books == nil)
+ break
+ end
+ if (value =~ /^\/(.+)\/$/)
+ books = books.with_regexp(key, value)
+ else
+ books = books.where(key => value)
+ end
+ end
+ return books
+ end
+
+ # 書籍情報の削除
+ # @param [String] isbn_str 削除対象のISBN
+ def self.deleteBook(isbn_str)
+ isbn = toIsbn(isbn_str)
+ book = Book.find_by(isbn: isbn)
+ if (book == nil)
+ # 対象の書籍情報がなかった。
+ raise NotFoundInstanceError
+ end
+
+ # 蔵書情報から該当する書籍を削除
+ deleteBookOfCollection(isbn)
+
+ # 書影情報を削除
+ cover = BookCover.find_by(isbn: isbn)
+ if (cover != nil)
+ if (not cover.destroy)
+ raise DbAccessError
+ end
+ end
+
+ # 書籍情報を削除
+ if (not book.destroy)
+ raise DbAccessError
+ end
+ end
+
+ # ユーザでの絞り込み
+ # @param [Integer] user_id ユーザID
+ # @param [Arrray<Book>] books 絞り込み対象の書籍情報一覧
+ # @return [Array<Hash>] 絞り込んだ書籍情報
+ def narrowBookOfId(user_id, books)
+ narrow_books=Array.new
+ books.each do |book|
+ book_collect = BookCollection.find_by(user_id: user_id, isbn: book.isbn)
+ if (book_collect != nil)
+ narrow_book = createBookHash(book, book_collect)
+ narrow_books.push(narrow_book)
+ end
+ end
+ return narrow_books
+ end
+
+ #蔵書情報の取得
+ # @param [String] isbn_str 取得対象のISBN
+ # @param [Integer] user_id 取得対象のユーザID
+ # @param [Arrray<Book>] books 絞り込み対象の書籍情報一覧
+ # @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
+ 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 登録するISBN
+ #@param [Integer] user_id 登録対象のユーザID
+ #@param [String] summary ユーザ毎の紹介分
+ #@param [Integer] rank ユーザの評価
+ #@return [BookCollection] 蔵書情報
+ def createBookCollect(isbn, user_id, summary, rank)
+ if (BookCollection.find_by(isbn: isbn, user_id: user_id) != nil)
+ raise NotFoundInstanceError
+ end
+ book_collect = BookCollection.new
+ book_collect.isbn = isbn
+ book_collect.user_id = user_id
+ book_collect.summary = summary
+ book_collect.rank = rank
+ book_collect.create_at = DateTime.now
+ book_collect.update_at = DateTime.now
+ if (not book_collect.save)
+ raise DbAccessError
+ end
+ end
+
+ # 蔵書情報の変更
+ # @param [String] isbn_str 変更対象のISBN
+ # @param [Integer] user_id 変更対象のユーザID
+ # @param [Hash] columns 変更するカラムと値のハッシュ
+ def self.updateBookCollect(isbn_str, user_id, columns)
+ isbn = toIsbn(isbn_str)
+ book_collect = BookCollection.find_by(isbn: isbn, user_id: user_id )
+ change_f = false
+ if (book_collect == nil)
+ raise NotFoundInstanceError
+ end
+
+ columns.each do |key, value|
+ if ((value == nil) || (value == ""))
+ # 値がない、値が空文字の場合は対象としない。
+ next
+ end
+ if (value != book_collect.send(key))
+ # 値が異なれば更新
+ method = key.to_s + "="
+ book_collect.send(method, value)
+ change_f = true
+ end
+ end
+
+ # 更新内容の適用
+ if (change_f)
+ user.update_at = DateTime.now
+ if (user.save)
+ raise DbAccessError
+ end
+ end
+ end
+
+ # 蔵書情報の削除
+ # @param [String] isbn_str 削除対象のISBN
+ # @param [Integer] user_id 削除対象のユーザID
+ def self.deleteUser(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
+ end
+ if (not book_collect.destroy)
+ raise DbAccessError
+ end
+ end
+
+end