예제 #1
0
def get_arealib():
    fieldName = ["area", "pref", "city", "library"]
    fieldValue = list(map(lambda x: request.args.get(x), fieldName))
    args = request.args
    level = int(args.get("level"))
    logger.debug(args)
    items = list()

    if level == 1:
        items = PREFECTURES[args.get("area")]

    elif level == 2:
        filters = [
            ("pref", "==", args.get("pref"))
        ]
        resp = db.library.filter(filters)
        # city names
        items = list(set(map(lambda x: x["city"], resp.values())))

    elif level == 3:
        filters = [
            ("pref", "==", args.get("pref")),
            ("city", "==", args.get("city"))
        ]
        # library info
        items = list(db.library.filter(filters).values())

    elif level == 4:
        # register the library
        pass

    return jsonify({"items": items}), 200
예제 #2
0
def put_library():
    """
    Create favorite library on record. It must be unique on one user record.
    """
    body = request.get_json()
    id_token = body.get("idToken")
    libid = body.get("libid")
    logger.info(body)
    document, status_code = get_resource(resource_name="ALL", id_token=id_token)

    if status_code == 200:
        registered_favolib = document["favolib"]
        registered_libid = list(map(lambda favolib: favolib["libid"], registered_favolib))

        if libid in registered_libid:
            # 406: not acceptable
            return jsonify({"status": 406, "message": "This library is already registered."}), 406
        else:
            libinfo = db.library.find(libid)

            lib_doc = dict()
            lib_doc["timestamp"] = int(time.time())
            lib_doc["formal"] = libinfo["formal"]
            lib_doc["libid"] = libinfo["libid"]
            lib_doc["systemid"] = libinfo["systemid"]

            logger.debug(f"additional favorite library: {lib_doc}")
            document["favolib"].append(lib_doc)

            resource, status_code = create_resource(document, id_token)
            return jsonify(resource), status_code

    else:
        return jsonify({"status": 500, "message": "api server error"}), 500
예제 #3
0
def add_bookmark(event=None):
    """
    Register new bookmark at specified user.

    Parameters
    ----------
    event: LINE event
        LINE event

    Returns
    -------
    status: str
        Return status string.

    Raises
    ------
    UserNotFound
        Raises UserNotFound if user is not registered.
    DuplicateBookError
        Raises DuplicateLibraryError if new book is already registered.
    """

    bookmeta = record.bookmeta
    book_doc = record.book_doc
    status = ""
    userid = event.source.user_id if event else "testid"
    hashed_userid = sha256(userid.encode()).hexdigest()

    postback_data = event.postback.data.replace(
        "'", '"')  # replace single quotation to double
    waitingbook = json.loads(postback_data)

    if db.user.find(hashed_userid) is None:
        raise UserNotFound

    user_doc = db.user.find(hashed_userid)
    bookmark = user_doc["bookmark"]
    logger.debug(f"registared bookmarks: {bookmark}")

    if waitingbook["isbn"] in list(
            map(lambda x: x["bookmeta"]["isbn"], bookmark)):
        raise DuplicateBookError

    bookmeta["title"] = waitingbook["title"]
    bookmeta["author"] = waitingbook["author"]
    bookmeta["isbn"] = waitingbook["isbn"]
    book_doc["timestamp"] = int(time.time())
    book_doc["bookmeta"] = bookmeta
    logger.debug(f"addtional book marks: {book_doc}")

    bookmark.append(book_doc)
    user_doc["bookmark"] = bookmark
    db.user.set(hashed_userid, user_doc)  # update bookmarks
    logger.info(f"{bookmark} is registared")
    status = "本が登録されました"

    return status
예제 #4
0
def img2isbn(img):
    try:
        barcodes = list(
            map(lambda barcode: str(barcode[0].decode("utf-8")),
                decode(Image.open(img))))  # detect multiple barcodes
        isbn = list(
            filter(lambda barcode: barcode[0] == "9", barcodes)
        )[0]  # use the first detected barcode which starts with 9 as detected isbn
        logger.debug(f"detected barcodes: {barcodes}")

    except (OSError, IndexError):
        raise IsbnNotFound

    else:
        return isbn
예제 #5
0
def create_resource(resource, id_token=None):
    id_token = id_token or os.getenv("DEFAULT_HASHED_USERId")
    try:
        response = get_profile(id_token)
        userid = response["sub"]

        hashed_useid = sha256(userid.encode()).hexdigest()
        logger.debug(hashed_useid)
        db.user.set(hashed_useid, resource)

        return {"status": 200}, 200

    except Exception as e:
        logger.info(f"undefined error: {e}")

        return {"status": 500, "message": str(e)}, 500
예제 #6
0
def followevent(event=None):
    user_doc = record.user  # copy the record to save user information
    userid = event.source.user_id if event else "testid"
    hashed_userid = sha256(userid.encode()).hexdigest()

    user_doc["userid"] = hashed_userid
    user_doc["context"] = ""
    user_doc["options"] = {
        "calil": True,
        "google": False,
        "honto": False,
        "amazon": True,
        "rakuten": False,
        "yodobashi": False,
        "yahoo": False,
        "mercari": True,
        "rakuma": False,
        "paypayfleamarket": False
    }

    status = ""
    try:
        logger.debug(user_doc)
        if db.user.find(hashed_userid):
            raise DuplicateUserError

        db.user.set(hashed_userid, user_doc)
        logger.info("Successed in registaring new follower!")
        status = """登録ありがとうございます。\nメニューにて"Help"を参照してください。"""

    except DuplicateUserError:
        logger.info("This user is already registared.")
        status = "This user is already registared"

    except Exception as e:
        logger.info("Faild to registaring new follower!")
        logger.info(e)
        status = "Fail"

    finally:
        if event:
            line_bot_api.reply_message(
                event.reply_token,
                messages=TextSendMessage(text=status)
            )

    return status
예제 #7
0
def put_options():
    """
    Create favorite library on record. It must be unique on one user record.
    """
    body = request.get_json()
    id_token = body.get("idToken")
    options = body.get("items")
    logger.info(body)
    document, status_code = get_resource(resource_name="ALL", id_token=id_token)

    if status_code == 200:
        registered_options = document["options"]
        for key, val in options.items():
            registered_options[key] = val

        document["options"] = registered_options
        logger.debug(document)
        resource, status_code = create_resource(document, id_token)

        return jsonify(resource), status_code

    else:
        return jsonify({"status": 500, "message": "api server error"}), 500
예제 #8
0
def add_history(event=None, bookdoc=None):
    """
    Register new history at specified user.

    Parameters
    ----------
    event: LINE event
        LINE event
    libinfo: dict
        New library book document.

    Returns
    -------
    None

    Raises
    ------
    None
    """

    userid = event.source.user_id if event else "testid"
    hashed_userid = sha256(userid.encode()).hexdigest()
    user_doc = db.user.find(hashed_userid)
    history = user_doc["history"]

    try:
        logger.debug(f"hashed userid: {hashed_userid}, history: {history}")

        history.append(bookdoc)
        logger.debug(f"registaring history: {bookdoc}")

        user_doc["history"] = history
        db.user.set(hashed_userid, user_doc)  # update history
        logger.debug(f"successed in registaring history")

    except Exception as e:
        logger.info(e)
예제 #9
0
def get_option():
    title = ""
    isbn = ""
    idToken = request.args.get("idToken")
    resource, status_code = get_resource("options", idToken)

    links_names = {
        # "calil": {
        #    "link": f"https://calil.jp/book/{isbn}",
        #    "displayName": "詳細"
        #},
        "google": {
            "link": f"https://www.google.com/search?q={isbn}",
            "displayName": "Google"
        },
        "honto": {
            "link": f"https://honto.jp/netstore/search_10{title}.html",
            "displayName": "honto"
        },
        "amazon": {
            "link": f"https://amazon.co.jp/s?k={title}",
            "displayName": "Amazon"
        },
        "rakuten": {
            "link": f"https://search.rakuten.co.jp/search/mall/{title}/",
            "displayName": "楽天"
        },
        "yodobashi": {
            "link": f"https://www.yodobashi.com/category/81001/?word={isbn}",
            "displayName": "ヨドバシドットコム"
        },
        "yahoo": {
            "link": f"https://shopping.yahoo.co.jp/search?&p={title}",
            "displayName": "ヤフーショッピング"
        },
        "mercari": {
            "link":
            f"https://www.mercari.com/jp/search/?keyword={title}&category_root=5",
            "displayName": "メルカリ"
        },
        "rakuma": {
            "link": f"https://fril.jp/s?query={title}&category_id=733",
            "displayName": "ラクマ"
        },
        "paypayfleamarket": {
            "link":
            f"https://paypayfleamarket.yahoo.co.jp/search/{title}?categoryIds=10002",
            "displayName": "PayPayフリマ"
        },
    }
    display_name = {
        key: values["displayName"]
        for key, values in links_names.items()
    }

    resource["items"].pop("calil")
    res = {
        "items": {
            "options": resource["items"],
            "displayName": display_name
        }
    }
    logger.debug(res)

    return jsonify(res), status_code
예제 #10
0
def bookmeta(book_doc, hashed_userid):
    """
    Create from book_doc to flexbox and return it.

    Parameters
    ----------
    book_doc: dict
        Book status.

    Returns
    -------
    flex_message: dict
        Flex message style dict.

    Raises
    ------
    None

    See also
    --------
    flaskr.models.record.book_doc
    """

    meta = book_doc["bookmeta"]
    flex_bookmeta = deepcopy(flexbox.bookmeta)
    bookmeta = deepcopy(record.bookmeta)

    # variable of meta contains too much information, so bookmeta is less than it.
    bookmeta["isbn"] = meta["isbn"]
    bookmeta["title"] = meta["title"]
    bookmeta["author"] = meta["author"]

    # key: {size: text size, weight: text weight, prefix: prefix of bookmeta[key]}
    order = {
        "title": {"size": "xl", "weight": "bold"},
        "subtitle": {"size": "lg"},
        "author": {"prefix": "著者: "},
        "publisher": {"prefix": "出版社: "},
        "publishdate": {"prefix": "出版日: "},
        "page": {"prefix": "ページ数: "}
    }

    for key in order:
        # some meta[key] are "" (not specified)
        if meta[key]:
            minitext = deepcopy(flexbox.minitext)
            minitext["text"] = order[key].get("prefix", "") + meta[key]
            minitext["size"] = order[key].get("size", "md")
            minitext["weight"] = order[key].get("weight", "regular")
            flex_bookmeta["body"]["contents"].append(deepcopy(minitext))

    # if None, then use an image from irasutoya
    flex_bookmeta["hero"]["url"] = meta["image"] if meta["image"] else "https://4.bp.blogspot.com/-2t-ECy35d50/UPzH73UAg3I/AAAAAAAAKz4/OJZ0yCVaRbU/s1600/book.png"

    buttons = list()
    options = add_links(hashed_userid, meta["title"], meta["isbn"])
    for name, link in options:
        logger.debug(link)
        button = {
            "type": "button",
            "style": "link",
            "action": {
                "type": "uri",
                "label": name,
                "uri": link
            }
        }
        buttons.append(button)

    button = {
        "type": "button",
        "style": "link",
        "action": {
            "type": "postback",
            "label": "ブックマークに登録する",
            "data": f"{bookmeta}"
        },
    }

    buttons.append(button)
    flex_bookmeta["footer"]["contents"] = buttons

    flex_message = FlexSendMessage(
        alt_text="book information",
        contents=flex_bookmeta
    )


    return flex_message
예제 #11
0
def bookstatus(bookstatus):
    """
    Create from bookstatus to flexbox and return it.

    Parameters
    ----------
    bookstatus: list
       List of bookstatus which is searched in different libraries.

    Returns
    -------
    flex_message: dict
        Carousel flex message.
    Raises
    ------
    BookNotFound
        There is no information in calil website.
    """

    flexboxes = []
    for status, systemid in bookstatus:
        flex_bookstatus = deepcopy(flexbox.flex_bookstatus)
        try:
            flex_bookstatus["hero"]["url"] = "https://3.bp.blogspot.com/-FJiaJ8gidCs/Ugsu-rSFw0I/AAAAAAAAXNA/JFiIUoxggW4/s800/book_tate.png"
            """
            if os.path.exists(f"./flaskr/static/images/library/{systemid}.jpg"):
                flex_bookstatus["hero"]["url"] = f"/static/images/library/{systemid}.jpg"
            else:
                flex_bookstatus["hero"]["url"] = "https://3.bp.blogspot.com/-FJiaJ8gidCs/Ugsu-rSFw0I/AAAAAAAAXNA/JFiIUoxggW4/s800/book_tate.png"
            """

            library = db.library.filter("systemid", "==", systemid)
            libid = list(library.keys())[0]
            minitext = deepcopy(flexbox.minitext)
            systemname = library[libid]["systemname"]

            # both reserveurl and libkey are None
            if (status.get("reserveurl") and status.get("libkey")) is False:
                minitext["text"] = f"{systemname}: 在書"
                flex_bookstatus["body"]["contents"].append(minitext)

            else:
                minitext["text"] = systemname
                minitext["size"] = "lg"
                minitext["weight"] = "bold"
                flex_bookstatus["body"]["contents"].append(minitext)

            if status.get("libkey"):
                text = ""
                keylist = status["libkey"].keys()

                # status depends on libraries
                minitext = deepcopy(flexbox.minitext)
                for libkey in keylist:
                    # short = library[libid]["short"] if library else libkey
                    state = status["libkey"][libkey]
                    text += f"{libkey}: {state}\n"

                minitext["text"] = text
                flex_bookstatus["body"]["contents"].append(minitext)

            if status.get("reserveurl"):
                button = deepcopy(flexbox.button)
                button["action"]["uri"] = status["reserveurl"]
                flex_bookstatus["footer"]["contents"].append(button)

            logger.debug(flex_bookstatus)
            flexboxes.append(flex_bookstatus)

        except KeyError:
            pass

        except Exception as e:
            logger.info(e)

    if len(flexboxes) == 1:
        flex_message = FlexSendMessage(
            alt_text='book status information',
            contents=flexboxes[0]
        )
    else:
        carousel = {
            "type": "carousel",
            "contents": flexboxes
        }

        flex_message = FlexSendMessage(
            alt_text='book status information',
            contents=carousel
        )

    return flex_message
예제 #12
0
def compact_bookmeta(isbn):
    """
    Create from isbn to flexbox and return it.

    Parameters
    ----------
    isbn: str
        The isbn which openbd does not much information.

    Returns
    -------
    flex_message: dict
        Normal flex message.

    Raises
    ------
    BookNotFound
        There is no information in calil website.
    """

    # scrape from calil web site, not api
    url = f"https://calil.jp/book/{isbn}"
    title_xpath = '//*[@id="ccontent"]/div/div[1]/div[2]/div/div[2]/h1'
    author_xpath = '//*[@id="ccontent"]/div/div[1]/div[2]/div/div[2]/p/a'
    rq = requests.get(url)
    status_code = rq.status_code

    if status_code == 200:
        minitext = deepcopy(flexbox.minitext)
        flex_bookmeta = deepcopy(flexbox.bookmeta)
        bookmeta = deepcopy(record.bookmeta)

        tree = html.fromstring(rq.content)
        title = tree.xpath(title_xpath)[0].text.replace(
            " ", "").replace("\n", "")
        author = tree.xpath(author_xpath)[0].text.replace(
            " ", "").replace("\n", "")

        bookmeta["isbn"] = isbn
        bookmeta["title"] = title
        bookmeta["author"] = author

        minitext["text"] = title
        minitext["size"] = "xl"
        flex_bookmeta["body"]["contents"].append(minitext)

        content = list()
        content.append({
            "type": "button",
            "style": "link",
            "action": {
                "type": "uri",
                "label": "詳細",
                "uri": "https://calil.jp/book/{isbn}"
            }
        })

        content.append({
            "type": "button",
            "style": "link",
            "action": {
                "type": "postback",
                "label": "ブックマークに登録する",
                "data": bookmeta
            },
        })

        flex_bookmeta["footer"]["contents"] = content
        logger.debug(flex_bookmeta)

        flex_message = FlexSendMessage(
            alt_text='book information',
            contents=flex_bookmeta
        )

        return (bookmeta, flex_message)

    else:
        raise BookNotFound
예제 #13
0
def isbn2message(event, isbn):
    """
    Create from isbn to message and send it.

    Parameters
    ----------
    event: LINE event
        LINE event
    isbn: str
        The isbn which a user input.

    Returns
    -------
    None

    Raises
    ------
    None
    """

    userid = event.source.user_id if event else "testid"
    hashed_userid = sha256(userid.encode()).hexdigest()
    favolib = db.user.find(hashed_userid)["favolib"]
    logger.debug(favolib)
    bookstatus = []

    try:
        bookdoc = call_api.openbd(isbn)
        if bookdoc:
            flex_message = send.bookmeta(bookdoc, hashed_userid)
            add.history(event, bookdoc)

        else:
            bookdoc, flex_message = send.compact_bookmeta(isbn)
            add.history(event, bookdoc)

        line_bot_api.push_message(event.source.user_id, messages=flex_message)

        for library in favolib:
            try:
                bookstatus.append(
                    (call_api.calil(isbn,
                                    library["systemid"]), library["systemid"]))
            except BookNotFound:
                pass

        if bookstatus:
            # When you cannot get book meta information from google books api, you pass NoneType to this function.
            flex_message = send.bookstatus(bookstatus)
            line_bot_api.reply_message(event.reply_token,
                                       messages=flex_message)
            event = None

        else:
            raise BookNotFound

    except MetadataNotFound:
        pass

    except BookNotFound:
        logger.info("book not found")
        status = "book not found"

    except Exception as e:
        logger.info(e)
        status = "Fail"

    finally:
        # A message is already sent, event is None.
        if event:
            flexcontent = flexbox.notfound
            flexcontent["body"]["contents"][0]["text"] = status
            line_bot_api.reply_message(event.reply_token,
                                       messages=FlexSendMessage(
                                           alt_text=status,
                                           contents=flexcontent))
예제 #14
0
def openbd(isbn):
    """
    Call openbd api and return book meta data.

    Parameters
    ----------
    isbn: str
        The isbn of a book users want to know the status. It is 13 digits.

    Returns
    -------
    book_doc: dict
        Return book_doc with status of the book specified with isbn at the library doen with systemid.

    Raises
    ------
    UserNotFound
        Raises UserNotFound if user is not registered.
    DuplicateBookError
        Raises DuplicateLibraryError if new book is already registered.
    BookNotFound
        None of keys are found in calil api response or some unexpected exception is occured.

    See also
    --------
    flaskr.models.record.bookmeta
    flaskr.models.record.book_doc
    """

    url = f"https://api.openbd.jp/v1/get?isbn={isbn}"
    bookmeta = record.bookmeta
    book_doc = record.book_doc

    try:
        bookmeta["isbn"] = isbn
        # resourse path at the response
        # keyname: {path: path to resource, name: replace keyname to this name for easily understanding}
        necessary_keys = {
            "TitleText": {
                "path":
                "onix/DescriptiveDetail/TitleDetail/TitleElement/TitleText/content",
                "name": "title"
            },
            "Subtitle": {
                "path":
                "onix/DescriptiveDetail/TitleDetail/TitleElement/Subtitle/content",
                "name": "subtitle"
            },
            "PersonName": {
                "path":
                "onix/DescriptiveDetail/Contributor/0/PersonName/content",
                "name": "author"
            },
            "ExtentValue": {
                "path": "onix/DescriptiveDetail/Extent/0/ExtentValue",
                "name": "page"
            },
            "ResourceLink": {
                "path":
                "onix/CollateralDetail/SupportingResource/0/ResourceVersion/0/ResourceLink",
                "name": "image"
            },
            "ImprintName": {
                "path": "onix/PublishingDetail/Imprint/ImprintName",
                "name": "publisher"
            },
            "Date": {
                "path": "onix/PublishingDetail/PublishingDate/0/Date",
                "name": "publishdate"
            }
        }

        openbd = requests.get(url).json()[0]
        contain_keylist = get_keys(openbd, [])
        for key in necessary_keys.keys():
            if key in contain_keylist:
                content = find_resource(openbd, necessary_keys[key]["path"], 0)
            else:
                content = ""
            bookmeta[necessary_keys[key]["name"]] = content
        book_doc["timestamp"] = int(time.time())
        book_doc["bookmeta"] = bookmeta
        logger.debug(book_doc)

    except Exception as e:
        book_doc = ""
        logger.info(e)

    finally:
        return book_doc
예제 #15
0
def calil(isbn, systemid):
    """
    Call calil api and return book status.

    Parameters
    ----------
    isbn: str
        The isbn of a book users want to know the status. It is 13 digits.
    sytemid:
        The systemid of a library where users want to know the book status.

    Returns
    -------
    book_doc: dict
        Return book_doc with status of the book specified with isbn at the library doen with systemid.

    Raises
    ------
    BookNotFound
        None of keys are found in calil api response or some unexpected exception is occured.

    See also
    --------
    flaskr.models.record.book_doc
    """

    url = "http://api.calil.jp/check?&format=json&callback=no&appkey={" + os.getenv(
        "CALIL_API_KEY") + "}"
    queries = f"&isbn={isbn}&systemid={systemid}"
    # bookquery = json.loads(requests.get(url+queries).text)
    bookquery = requests.get(url + queries).json()
    """
    Response example
    {"session": "ea5e50999e96d1cd4361f6e1892ff4da", "books": {"9784873117836": {"Univ_Aizu": {"status": "Cache", "reserveurl": "https://libeopsv.u-aizu.ac.jp/gate?module=search&path=detail.do&method=detail&bibId=1000014556&bsCls=0", "libkey": {"4大": "貸出中"}}}}, "continue": 0}
    '"""
    logger.debug(bookquery)

    try:
        # When status is running, you have to wait a few seconds for detail information.
        cnt = 0
        # Call api again and again. If 10 times called, break
        while (bookquery["continue"] == 1 and cnt < 10):
            time.sleep(1)
            # Call by session
            queries = f"&session={bookquery['session']}"
            #bookquery = json.loads(requests.get(url+queries).text)
            bookquery = requests.get(url + queries).json()
            logger.debug(f"session: {bookquery}")
            cnt += 1

        bookstatus = {}
        found = False
        bookquery_isbn = bookquery["books"][isbn]
        # If one or more keys are found, return bookstatus.
        for query_systemid in bookquery_isbn.keys():
            reserveurl = bookquery_isbn[query_systemid].get("reserveurl")
            libkey = bookquery_isbn[query_systemid].get("libkey")
            if reserveurl or libkey:
                found = True
                bookstatus = ({
                    "systemid": query_systemid,
                    "reserveurl": reserveurl,
                    "libkey": libkey
                })

        # If none of keys are found, raise BookNotFound.
        if found is False:
            raise BookNotFound

    except Exception as e:
        logger.info(e)
        raise BookNotFound

    else:
        logger.debug(f"bookstatus: {bookstatus}")
        return bookstatus
예제 #16
0
def add_favoilib(event=None, libinfo=None):
    """
    Register new library at specified user.

    Parameters
    ----------
    event: LINE event
        LINE event
    libinfo: dict
        New library information.

    Returns
    -------
    status: str
        Return status string.

    Raises
    ------
    UserNotFound
        Raises UserNotFound if user is not registered.
    DuplicateLibraryError
        Raises DuplicateLibraryError if new library is already registered.

    """

    lib_doc = record.library
    status = ""
    userid = event.source.user_id if event else "testid"
    hashed_userid = sha256(userid.encode()).hexdigest()
    logger.debug(event)

    # test code
    # libinfo  = {"formal": "会津大学附属図書館", "systemid": "Univ_Aizu"}
    if libinfo is None:
        libinfo = {
            "formal": "会津大学附属図書館",
            "systemid": "Univ_Aizu",
            "libid": "104688"
        }

    # confirmation of uniquness of the user
    if db.user.find(hashed_userid) is None:
        logger.info("user not found")
        raise UserNotFound

    user_doc = db.user.find(hashed_userid)
    favolib = user_doc["favolib"]
    logger.debug(f"registered favorite libraries: {favolib}")

    if libinfo["libid"] in list(map(lambda x: x["libid"], favolib)):
        raise DuplicateLibraryError

    # get info of one library from db
    libinfo = db.library.find(libinfo["libid"])
    # make favorite library doc
    lib_doc["timestamp"] = int(time.time())
    lib_doc["formal"] = libinfo["formal"]
    lib_doc["libid"] = libinfo["libid"]
    lib_doc["systemid"] = libinfo["systemid"]
    logger.debug(f"additional favorite library: {lib_doc}")

    favolib.append(lib_doc)
    user_doc["favolib"] = favolib
    db.user.set(hashed_userid, user_doc)  # update favorite library
    logger.info(f"{favolib} is registared")
    status = "success"

    return status