From 2736661bfcf6b472da8fa06202cb0f5f92013180 Mon Sep 17 00:00:00 2001 From: Mustafa Ali Mutlu Date: Sat, 25 Jan 2020 19:28:13 +0300 Subject: [PATCH] [fix, plugin] Evernote exporter only writes one documents clippings when txt export used, rest is ignored (#5774) fixes #3690 --- plugins/evernote.koplugin/main.lua | 54 ++++++++----- spec/unit/evernote_plugin_main_spec.lua | 102 ++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 spec/unit/evernote_plugin_main_spec.lua diff --git a/plugins/evernote.koplugin/main.lua b/plugins/evernote.koplugin/main.lua index 69551d0da..6b03c429b 100644 --- a/plugins/evernote.koplugin/main.lua +++ b/plugins/evernote.koplugin/main.lua @@ -6,7 +6,6 @@ local NetworkMgr = require("ui/network/manager") local DataStorage = require("datastorage") local DocSettings = require("docsettings") local UIManager = require("ui/uimanager") -local ConfirmBox = require("ui/widget/confirmbox") local Screen = require("device").screen local util = require("ffi/util") local Device = require("device") @@ -309,13 +308,9 @@ For more information, please visit https://github.com/koreader/koreader/wiki/Eve text = _("Purge history records"), callback = function() self.config:purge() - UIManager:show(ConfirmBox:new{ - text = _("History records have been purged.\nAll notes will be exported again next time.\nWould you like to remove the existing KOReaderClipping.txt file to avoid duplication?\nRecords will be appended to KOReaderClipping.txt instead of being overwritten."), - ok_text = _("Remove file"), - ok_callback = function() - os.remove(self.text_clipping_file) - end, - cancel_text = _("Keep file"), + UIManager:show(InfoMessage:new{ + text = _("History records have been purged.\nAll notes will be exported again next time.\n"), + timeout = 2, }) end } @@ -484,6 +479,23 @@ function EvernoteExporter:updateMyClippings(clippings, new_clippings) return clippings end +--[[-- +Parses highlights and calls exporter functions. + +Entry point for exporting highlights. User interface calls this function. +Parses current document and documents from history, passes them to exportClippings(). +Highlight: Highlighted text or image in document, stored in "highlights" table in +documents sidecar file. Parser uses this table. If highlight._._.text field is empty parser uses +highlight._._.pboxes field to get an image instead. +Bookmarks: Data in bookmark explorer. Stored in "bookmarks" table of documents sidecar file. Every +field in bookmarks._ has "text" and "notes" fields When user edits a highlight or "renames" bookmark, +text field is created or updated. Parser looks to bookmarks._.text field for edited notes. bookmarks._.notes isn't used for exporting operations. +https://github.com/koreader/koreader/blob/605f6026bbf37856ee54741b8a0697337ca50039/plugins/evernote.koplugin/clip.lua#L229 +Clippings: Parsed form of highlights, stored in clipboard/evernote.sdr/metadata.sdr.lua +for all documents. Used only for exporting bookmarks. Internal highlight or bookmark functions +does not usew this table. +Booknotes: Every table in clippings table. clippings = {"title" = booknotes} +--]] function EvernoteExporter:exportAllNotes() -- Flush highlights of current document. if not self:isDocless() then @@ -518,6 +530,7 @@ function EvernoteExporter:exportClippings(clippings) elseif self.html_export then exported_stamp= "html" elseif self.txt_export then + os.remove(self.text_clipping_file) exported_stamp = "txt" elseif self.joplin_export then exported_stamp = "joplin" @@ -544,7 +557,8 @@ function EvernoteExporter:exportClippings(clippings) end -- check if booknotes are exported in this notebook -- so that booknotes will still be exported after switching user account - if booknotes.exported[exported_stamp] ~= true then + --Don't respect exported_stamp on txt export since it isn't possible to delete(update) prior clippings. + if booknotes.exported[exported_stamp] ~= true or self.txt_export then local ok, err if self.html_export then ok, err = pcall(self.exportBooknotesToHTML, self, title, booknotes) @@ -639,7 +653,6 @@ end function EvernoteExporter:exportBooknotesToTXT(title, booknotes) -- Use wide_space to avoid crengine to treat it specially. local wide_space = "\227\128\128" - local file_modification = lfs.attributes(self.text_clipping_file, "modification") or 0 local file = io.open(self.text_clipping_file, "a") if file then file:write(title .. "\n" .. wide_space .. "\n") @@ -648,19 +661,16 @@ function EvernoteExporter:exportBooknotesToTXT(title, booknotes) file:write(wide_space .. chapter.title .. "\n" .. wide_space .. "\n") end for _ignore2, clipping in ipairs(chapter) do - -- If this clipping has already been exported, we ignore it. - if clipping.time >= file_modification then - file:write(wide_space .. wide_space .. - T(_("-- Page: %1, added on %2\n"), - clipping.page, os.date("%c", clipping.time))) - if clipping.text then - file:write(clipping.text) - end - if clipping.image then - file:write(_("")) - end - file:write("\n-=-=-=-=-=-\n") + file:write(wide_space .. wide_space .. + T(_("-- Page: %1, added on %2\n"), + clipping.page, os.date("%c", clipping.time))) + if clipping.text then + file:write(clipping.text) + end + if clipping.image then + file:write(_("")) end + file:write("\n-=-=-=-=-=-\n") end end diff --git a/spec/unit/evernote_plugin_main_spec.lua b/spec/unit/evernote_plugin_main_spec.lua new file mode 100644 index 000000000..d9288198e --- /dev/null +++ b/spec/unit/evernote_plugin_main_spec.lua @@ -0,0 +1,102 @@ +describe("Evernote plugin module", function() + local readerui, match + local sample_clippings, sample_epub + local DocumentRegistry + setup(function() + require("commonrequire") + match = require("luassert.match") + local ReaderUI = require("apps/reader/readerui") + DocumentRegistry = require("document/documentregistry") + sample_epub = "spec/front/unit/data/juliet.epub" + readerui = ReaderUI:new{ + document = DocumentRegistry:openDocument(sample_epub), + } + + sample_clippings = { + ["Title1"] = { + [1] = { + [1] = { + ["page"] = 6, + ["time"] = 1578946897, + ["sort"] = "highlight", + ["text"] = "Some important stuff 1" + } + }, + [2] = { + [1] = { + ["page"] = 13, + ["time"] = 1578946903, + ["sort"] = "highlight", + ["text"] = "Some important stuff 2" + } + }, + ["file"] = "path/to/title1", + ["exported"] = { + ["txt"] = true, + ["html"] = true, + }, + ["title"] = "Title1" + }, + ["Title2"] = { + [1] = { + [1] = { + ["page"] = 233, + ["time"] = 1578946918, + ["sort"] = "highlight", + ["text"] = "Some important stuff 3" + } + }, + [2] = { + [1] = { + ["page"] = 237, + ["time"] = 1578947501, + ["sort"] = "highlight", + ["text"] = "", + ["image"] = { + ["hash"] = "cb7b40a63afc89f0aa452f2b655877e6", + ["png"] = "Binary Encoding of image" + }, + } + }, + ["file"] = "path/to/title2", + ["exported"] = { + }, + ["title"] = "Title2" + }, + } + + end) + + it("should write clippings to txt file", function () + local file_mock = mock( { + write = function() return end, + close = function() return end + }) + local old_io = _G.io + _G.io = mock({ + open = function(file, mode) + if file == readerui.evernote.text_clipping_file then + return file_mock + else + return old_io.open(file, mode) + end + end + }) + + readerui.evernote:exportBooknotesToTXT("Title1", sample_clippings.Title1) + assert.spy(io.open).was.called() + assert.spy(file_mock.write).was.called_with(match.is_ref(file_mock), "Some important stuff 1") + _G.io = old_io + + end) + + it("should not export booknotes with exported_stamp", function() + readerui.evernote.html_export = true + stub(readerui.evernote, "exportBooknotesToHTML") + readerui.evernote:exportClippings(sample_clippings) + assert.stub(readerui.evernote.exportBooknotesToHTML).was_called_with(match.is_truthy(), "Title2", match.is_truthy()) + assert.stub(readerui.evernote.exportBooknotesToHTML).was_not_called_with(match.is_truthy(), "Title1", match.is_truthy()) + end) + + +end) \ No newline at end of file