# Buggy code
def get_metadata(book):
    download_urls = []
    for book_data in book.data:
        if book_data.format not in KOBO_FORMATS:
            continue
        for kobo_format in KOBO_FORMATS[book_data.format]:
            # log.debug('Id: %s, Format: %s' % (book.id, kobo_format))
            download_urls.append(
                {
                    "Format": kobo_format,
                    "Size": book_data.uncompressed_size,
                    "Url": get_download_url_for_book(book, book_data.format),
                    # The Kobo forma accepts platforms: (Generic, Android)
                    "Platform": "Generic",
                    # "DrmType": "None", # Not required
                }
            )

    book_uuid = book.uuid
    metadata = {
        "Categories": [
            "00000000-0000-0000-0000-000000000001",
        ],
        "Contributors": get_author(book),
        "CoverImageId": book_uuid,
        "CrossRevisionId": book_uuid,
        "CurrentDisplayPrice": {"CurrencyCode": "USD", "TotalAmount": 0},
        "CurrentLoveDisplayPrice": {"TotalAmount": 0},
        "Description": get_description(book),
        "DownloadUrls": download_urls,
        "EntitlementId": book_uuid,
        "ExternalIds": [],
        "Genre": "00000000-0000-0000-0000-000000000001",
        "IsEligibleForKoboLove": False,
        "IsInternetArchive": False,
        "IsPreOrder": False,
        "IsSocialEnabled": True,
        "Language": "en",
        "PhoneticPronunciations": {},
        # TODO: Fix book.pubdate to return a datetime object so that we can easily
        # convert it to the format Kobo devices expect.
        "PublicationDate": book.pubdate,
        "Publisher": {
            "Imprint": "",
            "Name": get_publisher(book),
        },
        "RevisionId": book_uuid,
        "Title": book.title,
        "WorkId": book_uuid,
    }

    if get_series(book):
        if sys.version_info < (3, 0):
            name = get_series(book).encode("utf-8")
        else:
            name = get_series(book)
        metadata["Series"] = {
            "Name": get_series(book),
            "Number": book.series_index,  # ToDo Check int() ?
            "NumberFloat": float(book.series_index),
            # Get a deterministic id based on the series name.
            "Id": uuid.uuid3(uuid.NAMESPACE_DNS, name),
        }

    return metadata


# Traceback (AttributeError)
[2020-05-13 09:25:49,687]  INFO {cps.kobo:132} Kobo library sync request received.
[2020-05-13 09:25:49,687] DEBUG {cps.kobo:134} Kobo: Received unproxied request, changed request port to server port
[2020-05-13 09:25:49,737] ERROR {cps:1892} Exception on /kobo/token*******/v1/library/sync [GET]
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/usr/lib/python2.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/lib/python2.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/lib/python2.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/lib/python2.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/calibre-web/app/cps/kobo_auth.py", line 112, in inner
return f(*args, **kwargs)
File "/calibre-web/app/cps/web.py", line 237, in inner
return f(*args, **kwargs)
File "/calibre-web/app/cps/kobo.py", line 190, in HandleSyncRequest
entitlement["ReadingState"] = get_kobo_reading_state_response(book, kobo_reading_state)
File "/calibre-web/app/cps/kobo.py", line 729, in get_kobo_reading_state_response
"StatusInfo": get_status_info_response(kobo_reading_state.book_read_link),
File "/calibre-web/app/cps/kobo.py", line 737, in get_status_info_response
"LastModified": convert_to_kobo_timestamp_string(book_read.last_modified),
File "/calibre-web/app/cps/kobo.py", line 124, in convert_to_kobo_timestamp_string
return timestamp.strftime("%Y-%m-%dT%H:%M:%SZ")
AttributeError: 'NoneType' object has no attribute 'strftime'

# Fixed code
def get_metadata(book):
    download_urls = []
    for book_data in book.data:
        if book_data.format not in KOBO_FORMATS:
            continue
        for kobo_format in KOBO_FORMATS[book_data.format]:
            # log.debug('Id: %s, Format: %s' % (book.id, kobo_format))
            download_urls.append(
                {
                    "Format": kobo_format,
                    "Size": book_data.uncompressed_size,
                    "Url": get_download_url_for_book(book, book_data.format),
                    # The Kobo forma accepts platforms: (Generic, Android)
                    "Platform": "Generic",
                    # "DrmType": "None", # Not required
                }
            )

    book_uuid = book.uuid
    metadata = {
        "Categories": [
            "00000000-0000-0000-0000-000000000001",
        ],
        "Contributors": get_author(book),
        "CoverImageId": book_uuid,
        "CrossRevisionId": book_uuid,
        "CurrentDisplayPrice": {"CurrencyCode": "USD", "TotalAmount": 0},
        "CurrentLoveDisplayPrice": {"TotalAmount": 0},
        "Description": get_description(book),
        "DownloadUrls": download_urls,
        "EntitlementId": book_uuid,
        "ExternalIds": [],
        "Genre": "00000000-0000-0000-0000-000000000001",
        "IsEligibleForKoboLove": False,
        "IsInternetArchive": False,
        "IsPreOrder": False,
        "IsSocialEnabled": True,
        "Language": "en",
        "PhoneticPronunciations": {},
        # TODO: Fix book.pubdate to return a datetime object so that we can easily
        # convert it to the format Kobo devices expect.
        "PublicationDate": book.pubdate,
        "Publisher": {
            "Imprint": "",
            "Name": get_publisher(book),
        },
        "RevisionId": book_uuid,
        "Title": book.title,
        "WorkId": book_uuid,
    }

    if get_series(book):
        if sys.version_info < (3, 0):
            name = get_series(book).encode("utf-8")
        else:
            name = get_series(book)
        metadata["Series"] = {
            "Name": get_series(book),
            "Number": get_seriesindex(book),  # ToDo Check int() ?
            "NumberFloat": float(get_seriesindex(book)),
            # Get a deterministic id based on the series name.
            "Id": uuid.uuid3(uuid.NAMESPACE_DNS, name),
        }

    return metadata