From 2374d856712b8315aec2605975aa48bd37398105 Mon Sep 17 00:00:00 2001 From: Pierre Leroux Date: Thu, 7 Sep 2023 09:08:06 +0200 Subject: [PATCH] refactor(API): switch lcp (renew,return,unlock) to redux-saga logic delete LCP API (FIxes #1992) --- src/common/api/api.type.ts | 2 - src/common/api/interface/lcpApi.interface.ts | 18 --- src/common/api/methodApi.type.ts | 4 +- src/common/api/moduleApi.type.ts | 4 +- src/common/redux/actions/lcp/index.ts | 6 + .../actions/lcp/renewPublicationLicense.ts | 29 +++++ .../redux/actions/lcp/returnPublication.ts | 29 +++++ .../lcp/unlockPublicationWithPassphrase.ts | 32 +++++ src/main/api/lcp.ts | 112 ----------------- src/main/di.ts | 4 - src/main/redux/middleware/sync.ts | 2 + src/main/redux/sagas/index.ts | 4 + src/main/redux/sagas/lcp.ts | 119 ++++++++++++++++++ .../components/dialog/LcpAuthentication.tsx | 23 ++-- .../components/dialog/RenewLsdConfirm.tsx | 23 ++-- .../components/dialog/ReturnLsdConfirm.tsx | 24 ++-- src/renderer/library/redux/middleware/sync.ts | 6 +- src/renderer/reader/redux/middleware/sync.ts | 6 +- 18 files changed, 272 insertions(+), 175 deletions(-) delete mode 100644 src/common/api/interface/lcpApi.interface.ts create mode 100644 src/common/redux/actions/lcp/renewPublicationLicense.ts create mode 100644 src/common/redux/actions/lcp/returnPublication.ts create mode 100644 src/common/redux/actions/lcp/unlockPublicationWithPassphrase.ts delete mode 100644 src/main/api/lcp.ts create mode 100644 src/main/redux/sagas/lcp.ts diff --git a/src/common/api/api.type.ts b/src/common/api/api.type.ts index 52f8cbf45..f58bb656c 100644 --- a/src/common/api/api.type.ts +++ b/src/common/api/api.type.ts @@ -6,7 +6,6 @@ // ==LICENSE-END== import { ICatalogModuleApi } from "./interface/catalog.interface"; -import { ILcpModuleApi } from "./interface/lcpApi.interface"; import { IOpdsModuleApi } from "./interface/opdsApi.interface"; import { IApiappModuleApi } from "./interface/apiappApi.interface"; import { IHttpBrowserModuleApi } from "./interface/httpBrowser.interface"; @@ -14,7 +13,6 @@ import { IPublicationModuleApi } from "./interface/publicationApi.interface"; export type TApiMethod = ICatalogModuleApi & - ILcpModuleApi & IOpdsModuleApi & IApiappModuleApi & IHttpBrowserModuleApi & diff --git a/src/common/api/interface/lcpApi.interface.ts b/src/common/api/interface/lcpApi.interface.ts deleted file mode 100644 index c42deba5a..000000000 --- a/src/common/api/interface/lcpApi.interface.ts +++ /dev/null @@ -1,18 +0,0 @@ -// ==LICENSE-BEGIN== -// Copyright 2017 European Digital Reading Lab. All rights reserved. -// Licensed to the Readium Foundation under one or more contributor license agreements. -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file exposed on Github (readium) in the project repository. -// ==LICENSE-END== - -export interface ILcpApi { - renewPublicationLicense: (publicationIdentifier: string) => Promise; - returnPublication: (publicationIdentifier: string) => Promise; - unlockPublicationWithPassphrase: (passphrase: string, publicationViewIdentifer: string) => Promise; -} - -export interface ILcpModuleApi { - "lcp/renewPublicationLicense": ILcpApi["renewPublicationLicense"]; - "lcp/returnPublication": ILcpApi["returnPublication"]; - "lcp/unlockPublicationWithPassphrase": ILcpApi["unlockPublicationWithPassphrase"]; -} diff --git a/src/common/api/methodApi.type.ts b/src/common/api/methodApi.type.ts index f3fb465aa..a7bd348c9 100644 --- a/src/common/api/methodApi.type.ts +++ b/src/common/api/methodApi.type.ts @@ -7,7 +7,6 @@ import { IHttpBrowserApi } from "./interface/httpBrowser.interface"; import { ICatalogApi } from "./interface/catalog.interface"; -import { ILcpApi } from "./interface/lcpApi.interface"; import { IOpdsApi } from "./interface/opdsApi.interface"; import { IPublicationApi } from "./interface/publicationApi.interface"; import { IApiappApi } from "./interface/apiappApi.interface"; @@ -17,5 +16,4 @@ export type TMethodApi = keyof IPublicationApi | keyof IOpdsApi | keyof IApiappApi | - keyof IHttpBrowserApi | - keyof ILcpApi + keyof IHttpBrowserApi diff --git a/src/common/api/moduleApi.type.ts b/src/common/api/moduleApi.type.ts index 133d8a84d..19004586d 100644 --- a/src/common/api/moduleApi.type.ts +++ b/src/common/api/moduleApi.type.ts @@ -11,11 +11,9 @@ type TPublicationApi = "publication"; type TOpdsApi = "opds"; type TApiappApi = "apiapp"; type THttpBrowserApi = "httpbrowser"; -type TLcpApi = "lcp"; export type TModuleApi = TCatalogApi | TPublicationApi | TOpdsApi | TApiappApi | - THttpBrowserApi | - TLcpApi + THttpBrowserApi diff --git a/src/common/redux/actions/lcp/index.ts b/src/common/redux/actions/lcp/index.ts index 5abe2969b..c8921afcb 100644 --- a/src/common/redux/actions/lcp/index.ts +++ b/src/common/redux/actions/lcp/index.ts @@ -6,7 +6,13 @@ // ==LICENSE-END== import * as userKeyCheckRequest from "./user-key-check-request"; +import * as renewPublicationLicense from "./renewPublicationLicense"; +import * as returnPublication from "./returnPublication"; +import * as unlockPublicationWithPassphrase from "./unlockPublicationWithPassphrase"; export { userKeyCheckRequest, + renewPublicationLicense, + returnPublication, + unlockPublicationWithPassphrase, }; diff --git a/src/common/redux/actions/lcp/renewPublicationLicense.ts b/src/common/redux/actions/lcp/renewPublicationLicense.ts new file mode 100644 index 000000000..385b3a74d --- /dev/null +++ b/src/common/redux/actions/lcp/renewPublicationLicense.ts @@ -0,0 +1,29 @@ +// ==LICENSE-BEGIN== +// Copyright 2017 European Digital Reading Lab. All rights reserved. +// Licensed to the Readium Foundation under one or more contributor license agreements. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file exposed on Github (readium) in the project repository. +// ==LICENSE-END== + +import { Action } from "readium-desktop/common/models/redux"; + +export const ID = "LCP_RENEW_PUBLICATION_LICENSE"; + +export interface Payload { + publicationIdentifier: string; +} + +export function build( + publicationIdentifier: string, +): + Action { + + return { + type: ID, + payload: { + publicationIdentifier, + }, + }; +} +build.toString = () => ID; // Redux StringableActionCreator +export type TAction = ReturnType; diff --git a/src/common/redux/actions/lcp/returnPublication.ts b/src/common/redux/actions/lcp/returnPublication.ts new file mode 100644 index 000000000..db772955d --- /dev/null +++ b/src/common/redux/actions/lcp/returnPublication.ts @@ -0,0 +1,29 @@ +// ==LICENSE-BEGIN== +// Copyright 2017 European Digital Reading Lab. All rights reserved. +// Licensed to the Readium Foundation under one or more contributor license agreements. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file exposed on Github (readium) in the project repository. +// ==LICENSE-END== + +import { Action } from "readium-desktop/common/models/redux"; + +export const ID = "LCP_RETURN_PUBLICATION"; + +export interface Payload { + publicationIdentifier: string; +} + +export function build( + publicationIdentifier: string, +): + Action { + + return { + type: ID, + payload: { + publicationIdentifier, + }, + }; +} +build.toString = () => ID; // Redux StringableActionCreator +export type TAction = ReturnType; diff --git a/src/common/redux/actions/lcp/unlockPublicationWithPassphrase.ts b/src/common/redux/actions/lcp/unlockPublicationWithPassphrase.ts new file mode 100644 index 000000000..672a91f66 --- /dev/null +++ b/src/common/redux/actions/lcp/unlockPublicationWithPassphrase.ts @@ -0,0 +1,32 @@ +// ==LICENSE-BEGIN== +// Copyright 2017 European Digital Reading Lab. All rights reserved. +// Licensed to the Readium Foundation under one or more contributor license agreements. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file exposed on Github (readium) in the project repository. +// ==LICENSE-END== + +import { Action } from "readium-desktop/common/models/redux"; + +export const ID = "LCP_UNLOCK_PUBLICATION_WITH_PASS"; + +export interface Payload { + publicationIdentifier: string; + passphrase: string; +} + +export function build( + publicationIdentifier: string, + passphrase: string, +): + Action { + + return { + type: ID, + payload: { + publicationIdentifier, + passphrase, + }, + }; +} +build.toString = () => ID; // Redux StringableActionCreator +export type TAction = ReturnType; diff --git a/src/main/api/lcp.ts b/src/main/api/lcp.ts deleted file mode 100644 index 48abe5768..000000000 --- a/src/main/api/lcp.ts +++ /dev/null @@ -1,112 +0,0 @@ -// ==LICENSE-BEGIN== -// Copyright 2017 European Digital Reading Lab. All rights reserved. -// Licensed to the Readium Foundation under one or more contributor license agreements. -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file exposed on Github (readium) in the project repository. -// ==LICENSE-END== - -import * as debug_ from "debug"; -import { inject, injectable } from "inversify"; -import { ILcpApi } from "readium-desktop/common/api/interface/lcpApi.interface"; -import { lcpActions } from "readium-desktop/common/redux/actions"; -import { readerActions } from "readium-desktop/common/redux/actions/"; -import { PublicationRepository } from "readium-desktop/main/db/repository/publication"; -import { diSymbolTable } from "readium-desktop/main/diSymbolTable"; -import { LcpManager } from "readium-desktop/main/services/lcp"; -import { type Store } from "redux"; - -import { PublicationViewConverter } from "../converter/publication"; -import { RootState } from "../redux/states"; - -const debug = debug_("readium-desktop:main:redux:sagas:streamer"); - -@injectable() -export class LcpApi implements ILcpApi { - @inject(diSymbolTable.store) - private readonly store!: Store; - - @inject(diSymbolTable["lcp-manager"]) - private readonly lcpManager!: LcpManager; - - @inject(diSymbolTable["publication-repository"]) - private readonly publicationRepository!: PublicationRepository; - - @inject(diSymbolTable["publication-view-converter"]) - private readonly publicationViewConverter!: PublicationViewConverter; - - public async renewPublicationLicense(publicationIdentifier: string): Promise { - const publicationDocument = await this.publicationRepository.get( - publicationIdentifier, - ); - await this.lcpManager.renewPublicationLicense(publicationDocument); - } - - public async returnPublication(publicationIdentifier: string): Promise { - const publicationDocument = await this.publicationRepository.get( - publicationIdentifier, - ); - await this.lcpManager.returnPublication(publicationDocument); - } - - public async unlockPublicationWithPassphrase(passphrase: string, publicationViewIdentifer: string): Promise { - - const publicationDocument = await this.publicationRepository.get( - publicationViewIdentifer, - ); - try { - // TODO: improve this horrible returned union type! - const unlockPublicationRes: string | number | null | undefined = - await this.lcpManager.unlockPublication(publicationDocument, passphrase); - - if (typeof unlockPublicationRes !== "undefined") { - const message = - // unlockPublicationRes === 11 ? - // this.translator.translate("publication.expiredLcp") : - this.lcpManager.convertUnlockPublicationResultToString(unlockPublicationRes); - debug(message); - - // import { TaJsonDeserialize } from "@r2-lcp-js/serializable"; - // import { Publication as R2Publication } from "@r2-shared-js/models/publication"; - // tslint:disable-next-line: max-line-length - // const r2PublicationStr = Buffer.from(publicationView.r2PublicationBase64, "base64").toString("utf-8"); - // const r2PublicationJson = JSON.parse(r2PublicationStr); - // const r2Publication = TaJsonDeserialize(r2PublicationJson, R2Publication); - - // const epubPath = this.publicationStorage.getPublicationEpubPath(publicationView.identifier); - // const r2Publication = await this.streamer.loadOrGetCachedPublication(epubPath); - - const publicationView = await this.publicationViewConverter.convertDocumentToView(publicationDocument); - if (!publicationView.lcp) { - debug("LCP !!?"); - return; - } - - // !r2Publication?.LCP?.Encryption?.UserKey?.TextHint - if (!publicationView.lcp.textHint) { - debug("LCP TextHint !!?"); - publicationView.lcp.textHint = ""; - } - - try { - // will call API.unlockPublicationWithPassphrase() again - const action = lcpActions.userKeyCheckRequest.build( - publicationView, - publicationView.lcp.textHint, // r2Publication.LCP.Encryption.UserKey.TextHint, - publicationView.lcp.urlHint, - message, - ); - this.store.dispatch(action); - return; - } catch (error) { - debug(error); - return; - } - } - } catch (err) { - debug(err); - return; - } - - this.store.dispatch(readerActions.openRequest.build(publicationViewIdentifer)); - } -} diff --git a/src/main/di.ts b/src/main/di.ts index 4065c8cc3..ed5930087 100644 --- a/src/main/di.ts +++ b/src/main/di.ts @@ -15,7 +15,6 @@ import * as path from "path"; import { Translator } from "readium-desktop/common/services/translator"; import { ok } from "readium-desktop/common/utils/assert"; import { CatalogApi } from "readium-desktop/main/api/catalog"; -import { LcpApi } from "readium-desktop/main/api/lcp"; import { LocatorViewConverter } from "readium-desktop/main/converter/locator"; import { OpdsFeedViewConverter } from "readium-desktop/main/converter/opds"; import { PublicationViewConverter } from "readium-desktop/main/converter/publication"; @@ -227,8 +226,6 @@ container.bind(diSymbolTable["opds-api"]).toConstantValue(opdsApi); container.bind(diSymbolTable["apiapp-api"]).toConstantValue(apiappApi); container.bind(diSymbolTable["httpbrowser-api"]).toConstantValue(httpBrowserApi); -container.bind(diSymbolTable["lcp-api"]).to(LcpApi).inSingletonScope(); - let libraryWin: BrowserWindow; const saveLibraryWindowInDi = @@ -279,7 +276,6 @@ interface IGet { (s: "opds-api"): typeof opdsApi; (s: "apiapp-api"): typeof apiappApi; (s: "httpbrowser-api"): typeof httpBrowserApi; - (s: "lcp-api"): LcpApi; (s: "saga-middleware"): SagaMiddleware; // minor overload type used in api.ts/LN32 (s: keyof typeof diSymbolTable): any; diff --git a/src/main/redux/middleware/sync.ts b/src/main/redux/middleware/sync.ts index 15fba895e..f9a9332fa 100644 --- a/src/main/redux/middleware/sync.ts +++ b/src/main/redux/middleware/sync.ts @@ -54,6 +54,8 @@ const SYNCHRONIZABLE_ACTIONS: string[] = [ authActions.cancel.ID, sessionActions.enable.ID, + + lcpActions.unlockPublicationWithPassphrase.ID, ]; export const reduxSyncMiddleware: Middleware diff --git a/src/main/redux/sagas/index.ts b/src/main/redux/sagas/index.ts index 88c4f2728..8d244f9a1 100644 --- a/src/main/redux/sagas/index.ts +++ b/src/main/redux/sagas/index.ts @@ -25,6 +25,7 @@ import * as reader from "./reader"; import * as streamer from "./streamer"; import * as win from "./win"; import * as telemetry from "./telemetry"; +import * as lcp from "./lcp"; // Logger const filename_ = "readium-desktop:main:saga:app"; @@ -95,6 +96,9 @@ export function* rootSaga() { // OPDS authentication flow yield auth.saga(); + // LCP saga + yield lcp.saga(); + // rehydrate shorcuts in redux yield put(keyboardActions.setShortcuts.build(keyboardShortcuts.getAll(), false)); diff --git a/src/main/redux/sagas/lcp.ts b/src/main/redux/sagas/lcp.ts new file mode 100644 index 000000000..68157d2f2 --- /dev/null +++ b/src/main/redux/sagas/lcp.ts @@ -0,0 +1,119 @@ +// ==LICENSE-BEGIN== +// Copyright 2017 European Digital Reading Lab. All rights reserved. +// Licensed to the Readium Foundation under one or more contributor license agreements. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file exposed on Github (readium) in the project repository. +// ==LICENSE-END== + +import * as debug_ from "debug"; +import { lcpActions, readerActions } from "readium-desktop/common/redux/actions"; +import { takeSpawnLeading } from "readium-desktop/common/redux/sagas/takeSpawnLeading"; +import { diMainGet } from "readium-desktop/main/di"; +import { error } from "readium-desktop/main/tools/error"; +// eslint-disable-next-line local-rules/typed-redux-saga-use-typed-effects +import { all } from "redux-saga/effects"; +import { call as callTyped, put as putTyped } from "typed-redux-saga/macro"; + +const filename_ = "readium-desktop:main:redux:sagas:lcp"; +const debug = debug_(filename_); + +function* renewPublicationLicense(action: lcpActions.renewPublicationLicense.TAction) { + const { publicationIdentifier } = action.payload; + const publicationRepository = diMainGet("publication-repository"); + const lcpManager = diMainGet("lcp-manager"); + const publicationDocument = yield* callTyped(() => publicationRepository.get( + publicationIdentifier, + )); + yield* callTyped(() => lcpManager.renewPublicationLicense(publicationDocument)); +} + +function* returnPublication(action: lcpActions.returnPublication.TAction) { + const { publicationIdentifier } = action.payload; + const publicationRepository = diMainGet("publication-repository"); + const lcpManager = diMainGet("lcp-manager"); + const publicationDocument = yield* callTyped(() => publicationRepository.get( + publicationIdentifier, + )); + yield* callTyped(() => lcpManager.returnPublication(publicationDocument)); +} + +function* unlockPublicationWithPassphrase(action: lcpActions.unlockPublicationWithPassphrase.TAction) { + const { publicationIdentifier, passphrase } = action.payload; + const publicationRepository = diMainGet("publication-repository"); + const lcpManager = diMainGet("lcp-manager"); + const publicationViewConverter = diMainGet("publication-view-converter"); + const publicationDocument = yield* callTyped(() => publicationRepository.get( + publicationIdentifier, + )); + + debug("UnlockPublication", publicationIdentifier, "with", passphrase); + try { + // TODO: improve this horrible returned union type! + const unlockPublicationRes: string | number | null | undefined = + yield* callTyped(() => lcpManager.unlockPublication(publicationDocument, passphrase)); + + debug(unlockPublicationRes, "'undefined' means OKay the publication is decrypted, Well Done !"); + if (typeof unlockPublicationRes !== "undefined") { + const message = + // unlockPublicationRes === 11 ? + // this.translator.translate("publication.expiredLcp") : + yield* callTyped(() => lcpManager.convertUnlockPublicationResultToString(unlockPublicationRes)); + debug(message); + + // import { TaJsonDeserialize } from "@r2-lcp-js/serializable"; + // import { Publication as R2Publication } from "@r2-shared-js/models/publication"; + // tslint:disable-next-line: max-line-length + // const r2PublicationStr = Buffer.from(publicationView.r2PublicationBase64, "base64").toString("utf-8"); + // const r2PublicationJson = JSON.parse(r2PublicationStr); + // const r2Publication = TaJsonDeserialize(r2PublicationJson, R2Publication); + + // const epubPath = this.publicationStorage.getPublicationEpubPath(publicationView.identifier); + // const r2Publication = await this.streamer.loadOrGetCachedPublication(epubPath); + + const publicationView = yield* callTyped(() => publicationViewConverter.convertDocumentToView(publicationDocument)); + if (!publicationView.lcp) { + debug("LCP !!?"); + return; + } + + // !r2Publication?.LCP?.Encryption?.UserKey?.TextHint + if (!publicationView.lcp.textHint) { + debug("LCP TextHint !!?"); + publicationView.lcp.textHint = ""; + } + + yield* putTyped(lcpActions.userKeyCheckRequest.build( + publicationView, + publicationView.lcp.textHint, // r2Publication.LCP.Encryption.UserKey.TextHint, + publicationView.lcp.urlHint, + message, + )); + return ; // do not open the reader in bottom + } + } catch (err) { + debug(err); + return; + } + + yield* putTyped(readerActions.openRequest.build(publicationIdentifier)); +} + +export function saga() { + return all([ + takeSpawnLeading( + lcpActions.renewPublicationLicense.ID, + renewPublicationLicense, + (e) => error(filename_ + ":renewPublicationLicense", e), + ), + takeSpawnLeading( + lcpActions.returnPublication.ID, + returnPublication, + (e) => error(filename_ + ":returnPublication", e), + ), + takeSpawnLeading( + lcpActions.unlockPublicationWithPassphrase.ID, + unlockPublicationWithPassphrase, + (e) => error(filename_ + ":unlockPublicationWithPassphrase", e), + ), + ]); +} diff --git a/src/renderer/library/components/dialog/LcpAuthentication.tsx b/src/renderer/library/components/dialog/LcpAuthentication.tsx index 5c56bafd8..39513ff09 100644 --- a/src/renderer/library/components/dialog/LcpAuthentication.tsx +++ b/src/renderer/library/components/dialog/LcpAuthentication.tsx @@ -14,9 +14,10 @@ import Dialog from "readium-desktop/renderer/common/components/dialog/Dialog"; import { TranslatorProps, withTranslator, } from "readium-desktop/renderer/common/components/hoc/translator"; -import { apiAction } from "readium-desktop/renderer/library/apiAction"; import { ILibraryRootState } from "readium-desktop/renderer/library/redux/states"; import { TChangeEventOnInput } from "readium-desktop/typings/react"; +import { TDispatch } from "readium-desktop/typings/redux"; +import { lcpActions } from "readium-desktop/common/redux/actions"; // eslint-disable-next-line @typescript-eslint/no-empty-interface interface IBaseProps extends TranslatorProps { @@ -26,7 +27,7 @@ interface IBaseProps extends TranslatorProps { // ReturnType // ReturnType // eslint-disable-next-line @typescript-eslint/no-empty-interface -interface IProps extends IBaseProps, ReturnType { +interface IProps extends IBaseProps, ReturnType, ReturnType { } interface IState { @@ -109,14 +110,8 @@ export class LCPAuthentication extends React.Component { if (!this.state.password) { return; } - apiAction("lcp/unlockPublicationWithPassphrase", - this.state.password, - this.props.publicationView.identifier, - ).catch((error) => { - console.error("Error lcp/unlockPublicationWithPassphrase", error); - }); + this.props.unlockPublication(this.props.publicationView.identifier, this.state.password); }; - } const mapStateToProps = (state: ILibraryRootState, _props: IBaseProps) => ({ @@ -125,4 +120,12 @@ const mapStateToProps = (state: ILibraryRootState, _props: IBaseProps) => ({ }, ...state.dialog.data as DialogType[DialogTypeName.LcpAuthentication], }); -export default connect(mapStateToProps)(withTranslator(LCPAuthentication)); +const mapDispatchToProps = (dispatch: TDispatch, _props: IBaseProps) => { + return { + unlockPublication: (id: string, pass: string) => { + dispatch(lcpActions.unlockPublicationWithPassphrase.build(id, pass)); + }, + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(withTranslator(LCPAuthentication)); diff --git a/src/renderer/library/components/dialog/RenewLsdConfirm.tsx b/src/renderer/library/components/dialog/RenewLsdConfirm.tsx index 23e015195..7d6594335 100644 --- a/src/renderer/library/components/dialog/RenewLsdConfirm.tsx +++ b/src/renderer/library/components/dialog/RenewLsdConfirm.tsx @@ -8,13 +8,14 @@ import * as React from "react"; import { connect } from "react-redux"; import { DialogType, DialogTypeName } from "readium-desktop/common/models/dialog"; +import { lcpActions } from "readium-desktop/common/redux/actions"; import * as stylesGlobal from "readium-desktop/renderer/assets/styles/global.css"; import Dialog from "readium-desktop/renderer/common/components/dialog/Dialog"; import { TranslatorProps, withTranslator, } from "readium-desktop/renderer/common/components/hoc/translator"; -import { apiAction } from "readium-desktop/renderer/library/apiAction"; import { ILibraryRootState } from "readium-desktop/renderer/library/redux/states"; +import { TDispatch } from "readium-desktop/typings/redux"; // eslint-disable-next-line @typescript-eslint/no-empty-interface interface IBaseProps extends TranslatorProps { @@ -24,7 +25,7 @@ interface IBaseProps extends TranslatorProps { // ReturnType // ReturnType // eslint-disable-next-line @typescript-eslint/no-empty-interface -interface IProps extends IBaseProps, ReturnType { +interface IProps extends IBaseProps, ReturnType, ReturnType { } class RenewLsdConfirm extends React.Component { @@ -42,7 +43,7 @@ class RenewLsdConfirm extends React.Component { return ( this.props.renewLsdConfirm(this.props.publicationView.identifier)} submitButtonDisabled={false} shouldOkRefEnabled={true} submitButtonTitle={this.props.__("dialog.yes")} @@ -55,12 +56,6 @@ class RenewLsdConfirm extends React.Component { ); } - - private renew = () => { - apiAction("lcp/renewPublicationLicense", this.props.publicationView.identifier).catch((error) => { - console.error("Error API lcp/renewPublicationLicense", error); - }); - }; } const mapStateToProps = (state: ILibraryRootState, _props: IBaseProps) => ({ @@ -69,4 +64,12 @@ const mapStateToProps = (state: ILibraryRootState, _props: IBaseProps) => ({ }, ...state.dialog.data as DialogType[DialogTypeName.LsdRenewConfirm], }); -export default connect(mapStateToProps)(withTranslator(RenewLsdConfirm)); +const mapDispatchToProps = (dispatch: TDispatch, _props: IBaseProps) => { + return { + renewLsdConfirm: (publicationId: string) => { + dispatch(lcpActions.renewPublicationLicense.build(publicationId)); + }, + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(withTranslator(RenewLsdConfirm)); diff --git a/src/renderer/library/components/dialog/ReturnLsdConfirm.tsx b/src/renderer/library/components/dialog/ReturnLsdConfirm.tsx index 0acb305d1..de91f3330 100644 --- a/src/renderer/library/components/dialog/ReturnLsdConfirm.tsx +++ b/src/renderer/library/components/dialog/ReturnLsdConfirm.tsx @@ -8,13 +8,14 @@ import * as React from "react"; import { connect } from "react-redux"; import { DialogType, DialogTypeName } from "readium-desktop/common/models/dialog"; +import { lcpActions } from "readium-desktop/common/redux/actions"; import * as stylesGlobal from "readium-desktop/renderer/assets/styles/global.css"; import Dialog from "readium-desktop/renderer/common/components/dialog/Dialog"; import { TranslatorProps, withTranslator, } from "readium-desktop/renderer/common/components/hoc/translator"; -import { apiAction } from "readium-desktop/renderer/library/apiAction"; import { ILibraryRootState } from "readium-desktop/renderer/library/redux/states"; +import { TDispatch } from "readium-desktop/typings/redux"; // eslint-disable-next-line @typescript-eslint/no-empty-interface interface IBaseProps extends TranslatorProps { @@ -24,7 +25,7 @@ interface IBaseProps extends TranslatorProps { // ReturnType // ReturnType // eslint-disable-next-line @typescript-eslint/no-empty-interface -interface IProps extends IBaseProps, ReturnType { +interface IProps extends IBaseProps, ReturnType, ReturnType { } class LsdReturnConfirm extends React.Component { @@ -42,7 +43,7 @@ class LsdReturnConfirm extends React.Component { return ( this.props.returnPublication(this.props.publicationView.identifier)} submitButtonDisabled={false} submitButtonTitle={this.props.__("dialog.yes")} shouldOkRefEnabled={true} @@ -55,13 +56,6 @@ class LsdReturnConfirm extends React.Component { ); } - - private remove = () => { - apiAction("lcp/returnPublication", this.props.publicationView.identifier) - .catch((error) => { - console.error("Error API lcp/returnPublication", error); - }); - }; } const mapStateToProps = (state: ILibraryRootState, _props: IBaseProps) => ({ @@ -70,4 +64,12 @@ const mapStateToProps = (state: ILibraryRootState, _props: IBaseProps) => ({ }, ...state.dialog.data as DialogType[DialogTypeName.LsdReturnConfirm], }); -export default connect(mapStateToProps)(withTranslator(LsdReturnConfirm)); +const mapDispatchToProps = (dispatch: TDispatch, _props: IBaseProps) => { + return { + returnPublication: (publicationId: string) => { + dispatch(lcpActions.returnPublication.build(publicationId)); + }, + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(withTranslator(LsdReturnConfirm)); diff --git a/src/renderer/library/redux/middleware/sync.ts b/src/renderer/library/redux/middleware/sync.ts index e9f62a81f..081b29ac4 100644 --- a/src/renderer/library/redux/middleware/sync.ts +++ b/src/renderer/library/redux/middleware/sync.ts @@ -6,7 +6,7 @@ // ==LICENSE-END== import { - apiActions, authActions, downloadActions, i18nActions, keyboardActions, readerActions, sessionActions, + apiActions, authActions, downloadActions, i18nActions, keyboardActions, lcpActions, readerActions, sessionActions, } from "readium-desktop/common/redux/actions"; import { syncFactory } from "readium-desktop/renderer/common/redux/middleware/syncFactory"; @@ -33,6 +33,10 @@ const SYNCHRONIZABLE_ACTIONS: string[] = [ downloadActions.abort.ID, sessionActions.enable.ID, + + lcpActions.renewPublicationLicense.ID, + lcpActions.returnPublication.ID, + lcpActions.unlockPublicationWithPassphrase.ID, ]; export const reduxSyncMiddleware = syncFactory(SYNCHRONIZABLE_ACTIONS); diff --git a/src/renderer/reader/redux/middleware/sync.ts b/src/renderer/reader/redux/middleware/sync.ts index f0263d617..e84eeb9ca 100644 --- a/src/renderer/reader/redux/middleware/sync.ts +++ b/src/renderer/reader/redux/middleware/sync.ts @@ -6,7 +6,7 @@ // ==LICENSE-END== import { - apiActions, i18nActions, keyboardActions, readerActions, sessionActions, + apiActions, i18nActions, keyboardActions, lcpActions, readerActions, sessionActions, } from "readium-desktop/common/redux/actions"; import { syncFactory } from "readium-desktop/renderer/common/redux/middleware/syncFactory"; @@ -31,6 +31,10 @@ const SYNCHRONIZABLE_ACTIONS: string[] = [ keyboardActions.reloadShortcuts.ID, sessionActions.enable.ID, + + lcpActions.renewPublicationLicense.ID, + lcpActions.returnPublication.ID, + lcpActions.unlockPublicationWithPassphrase.ID, ]; export const reduxSyncMiddleware = syncFactory(SYNCHRONIZABLE_ACTIONS);