|
53 | 53 | from core.model import DataSource, DeliveryMechanism, Loan, Patron, Representation |
54 | 54 | from core.util.http import RemoteIntegrationException |
55 | 55 | from core.util.opds_writer import OPDSFeed |
56 | | -from core.util.problem_detail import ProblemDetail |
| 56 | +from core.util.problem_detail import ProblemDetail, BaseProblemDetailException, ProblemDetail |
| 57 | +from core.exceptions import BaseError |
57 | 58 |
|
58 | 59 |
|
59 | 60 | class LoanController(CirculationManagerController): |
@@ -395,95 +396,33 @@ def fulfill( |
395 | 396 |
|
396 | 397 | try: |
397 | 398 | fulfillment = self.circulation.fulfill( |
398 | | - patron, |
| 399 | + patron, # type: ignore[arg-type] |
399 | 400 | credential, |
400 | 401 | requested_license_pool, |
401 | 402 | mechanism, |
402 | 403 | ) |
403 | | - except DeliveryMechanismConflict as e: |
404 | | - return DELIVERY_CONFLICT.detailed(str(e)) |
405 | | - except NoActiveLoan as e: |
406 | | - return NO_ACTIVE_LOAN.detailed( |
407 | | - _("Can't fulfill loan because you have no active loan for this book."), |
408 | | - status_code=e.status_code, |
409 | | - ) |
410 | | - except FormatNotAvailable as e: |
411 | | - return NO_ACCEPTABLE_FORMAT.with_debug(str(e), status_code=e.status_code) |
412 | | - except CannotFulfill as e: |
413 | | - return CANNOT_FULFILL.with_debug(str(e), status_code=e.status_code) |
414 | | - except DeliveryMechanismError as e: |
415 | | - return BAD_DELIVERY_MECHANISM.with_debug(str(e), status_code=e.status_code) |
416 | | - |
417 | | - # A subclass of FulfillmentInfo may want to bypass the whole |
418 | | - # response creation process. |
419 | | - response = fulfillment.as_response |
420 | | - |
421 | | - if response is not None: |
422 | | - print("fulfill response: ", response) |
423 | | - return response |
424 | | - |
425 | | - headers = dict() |
426 | | - encoding_header = dict() |
427 | | - if ( |
428 | | - fulfillment.data_source_name == DataSource.ENKI |
429 | | - and mechanism.delivery_mechanism.drm_scheme_media_type |
430 | | - == DeliveryMechanism.NO_DRM |
| 404 | + except (CirculationException, RemoteInitiatedServerError) as e: |
| 405 | + return e.problem_detail |
| 406 | + |
| 407 | + # TODO: This should really be turned into its own Fulfillment class, |
| 408 | + # so each integration can choose when to return a feed response like |
| 409 | + # this, and when to return a direct response. |
| 410 | + if mechanism.delivery_mechanism.is_streaming and isinstance( |
| 411 | + fulfillment, UrlFulfillment |
431 | 412 | ): |
432 | | - encoding_header["Accept-Encoding"] = "deflate" |
433 | | - |
434 | | - if mechanism.delivery_mechanism.is_streaming: |
435 | | - # If this is a streaming delivery mechanism, create an OPDS entry |
436 | | - # with a fulfillment link to the streaming reader url. |
437 | | - feed = OPDSAcquisitionFeed.single_entry_loans_feed( |
| 413 | + # If this is a streaming delivery mechanism (note: E-kirjasto does not stream), |
| 414 | + # create an OPDS entry with a fulfillment link to the streaming reader url. |
| 415 | + return OPDSAcquisitionFeed.single_entry_loans_feed( |
438 | 416 | self.circulation, loan, fulfillment=fulfillment |
439 | 417 | ) |
440 | | - if isinstance(feed, ProblemDetail): |
441 | | - print("problems") |
442 | | - # This should typically never happen, since we've gone through the entire fulfill workflow |
443 | | - # But for the sake of return-type completeness we are adding this here |
444 | | - return feed |
445 | | - if isinstance(feed, Response): |
446 | | - print("response") |
447 | | - return feed |
448 | | - else: |
449 | | - content = etree.tostring(feed) |
450 | | - status_code = 200 |
451 | | - headers["Content-Type"] = OPDSFeed.ACQUISITION_FEED_TYPE |
452 | | - elif fulfillment.content_link_redirect is True: |
453 | | - # The fulfillment API has asked us to not be a proxy and instead redirect the client directly |
454 | | - print(f"elif fulfillment.content_link_redirect is True:") |
455 | | - return redirect(fulfillment.content_link) |
456 | | - else: |
457 | | - content = fulfillment.content |
458 | | - if fulfillment.content_link: |
459 | | - print("if fulfillment.content_link: ", fulfillment.content_link) |
460 | | - # If we have a link to the content on a remote server, web clients may not |
461 | | - # be able to access it if the remote server does not support CORS requests. |
462 | | - |
463 | | - # If the pool is open access though, the web client can link directly to the |
464 | | - # file to download it, so it's safe to redirect. |
465 | | - if requested_license_pool.open_access: |
466 | | - print("if requested_license_pool.open_access:") |
467 | | - return redirect(fulfillment.content_link) |
468 | | - |
469 | | - # Otherwise, we need to fetch the content and return it instead |
470 | | - # of redirecting to it, since it may be downloaded through an |
471 | | - # indirect acquisition link. |
472 | | - try: |
473 | | - status_code, headers, content = do_get( |
474 | | - fulfillment.content_link, headers=encoding_header |
475 | | - ) |
476 | | - headers = dict(headers) |
477 | | - print(f"loanpy fulfill: code: {status_code}, headers: {headers}, fulfillment.content_link: {fulfillment.content_link}") |
478 | | - except RemoteIntegrationException as e: |
479 | | - return e.as_problem_detail_document(debug=False) |
480 | | - else: |
481 | | - status_code = 200 |
482 | | - if fulfillment.content_type: |
483 | | - headers["Content-Type"] = fulfillment.content_type |
484 | 418 |
|
485 | | - print(f"fulfill at end response: {response}, status: {status_code} headers: {headers}") |
486 | | - return Response(response=content, status=status_code, headers=headers) |
| 419 | + try: |
| 420 | + resp = fulfillment.response() |
| 421 | + print("response in loan: ", resp) |
| 422 | + return resp |
| 423 | + except BaseError as e: |
| 424 | + return e.problem_detail |
| 425 | + |
487 | 426 |
|
488 | 427 | def can_fulfill_without_loan(self, library, patron, pool, lpdm): |
489 | 428 | """Is it acceptable to fulfill the given LicensePoolDeliveryMechanism |
|
0 commit comments