Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ensure bookmark files are correctly downloaded before deleting current ones #683

Merged
merged 37 commits into from
Aug 20, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7aa37d2
generate ebook get dstPath
Monirzadeh Jul 28, 2023
91937b3
Archive and ebook can recover if download faild
Monirzadeh Jul 28, 2023
c12e3f2
recover thumb if download faild
Monirzadeh Aug 5, 2023
379a3ba
thumb image create just if image processing is sucssesful
Monirzadeh Aug 5, 2023
42afd23
create epub in tmp if it sucssesful copy to destination
Monirzadeh Aug 5, 2023
624a746
archive file create in tmp if it successful move to destination
Monirzadeh Aug 5, 2023
2ec8e5e
move to destination as function
Monirzadeh Aug 5, 2023
44b9a13
update ebook download api and remove .epub from file name
Monirzadeh Aug 5, 2023
622ff9d
report faild item to user
Monirzadeh Aug 5, 2023
bf31c3b
not show dialog if error not happen
Monirzadeh Aug 5, 2023
658c80f
update thumbnail based on last status of bookmark fix #524
Monirzadeh Aug 5, 2023
87b6861
better warning massage
Monirzadeh Aug 6, 2023
c54da26
tmpFile without .epub
Monirzadeh Aug 6, 2023
0a752e1
MoveToDestination change to MoveFileToDestination
Monirzadeh Aug 6, 2023
89c04d6
return .epub
Monirzadeh Aug 6, 2023
2b489ea
log if downloadBookImage return error
Monirzadeh Aug 6, 2023
3588119
fix bug remove imgPath just if download last image be unsuccessful
Monirzadeh Aug 6, 2023
81703cb
update old unit test
Monirzadeh Aug 6, 2023
e56ef8f
add processing.go unit test
Monirzadeh Aug 6, 2023
947eefa
small massage for report failded item to the user
Monirzadeh Aug 6, 2023
757599f
add some more unit test and samplefile
Monirzadeh Aug 7, 2023
d33384a
use sample image in unit test
Monirzadeh Aug 7, 2023
d1a6412
use local sample file and unit test not need internet connection anymore
Monirzadeh Aug 7, 2023
a44caad
update error to user and log that too
Monirzadeh Aug 12, 2023
612c439
add more comment
Monirzadeh Aug 12, 2023
9a42103
update comment
Monirzadeh Aug 12, 2023
55bb071
change variable name parentDir to dstDir
Monirzadeh Aug 14, 2023
3da6206
more simpler error handling
Monirzadeh Aug 14, 2023
1630092
remove unneeded defer
Monirzadeh Aug 14, 2023
afba6ff
remvoe unneeded epubWriter.Close()
Monirzadeh Aug 14, 2023
17f984d
more readable unit test in processing
Monirzadeh Aug 14, 2023
bf95321
more readable unit test for ebooks
Monirzadeh Aug 14, 2023
7f26e3f
delete all defer os.RemoveAll from unit tests
Monirzadeh Aug 14, 2023
9341e4d
Merge branch 'master' into cache-recovery
Monirzadeh Aug 14, 2023
cdf6fab
Better comment
Monirzadeh Aug 20, 2023
587340b
Better Error output
Monirzadeh Aug 20, 2023
3003099
fix err.String() method
Monirzadeh Aug 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions internal/core/ebook.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import (
"github.com/pkg/errors"
)

// this function get request and a destination path and will create an epub file in dstPath from that request
// dstPath should be incouded file name with '.epub'
// it will return a bookmark model and err
// bookmark model later use for update UI shiori based on this function be sucssesful or not
Monirzadeh marked this conversation as resolved.
Show resolved Hide resolved
func GenerateEbook(req ProcessRequest, dstPath string) (book model.Bookmark, err error) {
Monirzadeh marked this conversation as resolved.
Show resolved Hide resolved
// variable for store generated html code
var html string
Expand All @@ -27,6 +31,7 @@ func GenerateEbook(req ProcessRequest, dstPath string) (book model.Bookmark, err
return book, errors.New("bookmark ID is not valid")
}

// get current state of bookmark
// cheak archive and thumb
strID := strconv.Itoa(book.ID)

Expand All @@ -41,6 +46,8 @@ func GenerateEbook(req ProcessRequest, dstPath string) (book model.Bookmark, err
book.HasArchive = true
}

// this function create ebook from reader mode of bookmark so
// we can't create ebook from PDF so we return error here if bookmark is a pdf
contentType := req.ContentType
if strings.Contains(contentType, "application/pdf") {
return book, errors.New("can't create ebook for pdf")
Expand All @@ -51,12 +58,10 @@ func GenerateEbook(req ProcessRequest, dstPath string) (book model.Bookmark, err
if err != nil {
return book, errors.Wrap(err, "can't create temporary EPUB file")
}
defer tmpFile.Close()
defer os.Remove(tmpFile.Name())
Monirzadeh marked this conversation as resolved.
Show resolved Hide resolved

// Create zip archive
epubWriter := zip.NewWriter(tmpFile)
defer epubWriter.Close()

// Create the mimetype file
mimetypeWriter, err := epubWriter.Create("mimetype")
Expand Down Expand Up @@ -226,7 +231,7 @@ img {
return book, errors.Wrap(err, "can't open temporary EPUB file")
}
defer tmpFile.Close()

// if everitings go well we start move ebook to dstPath
err = MoveFileToDestination(dstPath, tmpFile)
if err != nil {
return book, errors.Wrap(err, "failed move ebook to destination")
Expand Down
325 changes: 159 additions & 166 deletions internal/core/ebook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,172 +11,165 @@ import (
"github.com/stretchr/testify/assert"
)

func TestGenerateEbook_ValidBookmarkID_ReturnsBookmarkWithHasEbookTrue(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)
parentDir := t.TempDir()
defer os.RemoveAll(parentDir)

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
Title: "Example Bookmark",
HTML: "<html><body>Example HTML</body></html>",
HasEbook: false,
},
DataDir: parentDir,
ContentType: "text/html",
}

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))

assert.True(t, bookmark.HasEbook)
assert.NoError(t, err)
}

func TestGenerateEbook_InvalidBookmarkID_ReturnsError(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)
mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 0,
HasEbook: false,
},
DataDir: tempDir,
ContentType: "text/html",
}

bookmark, err := core.GenerateEbook(mockRequest, tempDir)

assert.Equal(t, model.Bookmark{
ID: 0,
HasEbook: false,
}, bookmark)
assert.Error(t, err)
}

func TestGenerateEbook_ValidBookmarkID_EbookExist_EbookExist_ReturnWithHasEbookTrue(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)
parentDir := t.TempDir()
defer os.RemoveAll(parentDir)

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: parentDir,
ContentType: "text/html",
}
// Create the ebook directory
ebookDir := fp.Join(mockRequest.DataDir, "ebook")
err := os.MkdirAll(ebookDir, os.ModePerm)
if err != nil {
t.Fatal(err)
}
// Create the ebook file
ebookfile := fp.Join(mockRequest.DataDir, "ebook", fmt.Sprintf("%d.epub", mockRequest.Bookmark.ID))
file, err := os.Create(ebookfile)
if err != nil {
t.Fatal(err)
}
defer file.Close()

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))

assert.True(t, bookmark.HasEbook)
assert.NoError(t, err)
}

func TestGenerateEbook_ValidBookmarkID_EbookExist_ImagePathExist_ReturnWithHasEbookTrue(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)
parentDir := t.TempDir()
defer os.RemoveAll(parentDir)

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: parentDir,
ContentType: "text/html",
}
// Create the image directory
imageDir := fp.Join(mockRequest.DataDir, "thumb")
err := os.MkdirAll(imageDir, os.ModePerm)
if err != nil {
t.Fatal(err)
}
// Create the image file
imagePath := fp.Join(mockRequest.DataDir, "thumb", fmt.Sprintf("%d", mockRequest.Bookmark.ID))
file, err := os.Create(imagePath)
if err != nil {
t.Fatal(err)
}
defer file.Close()

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))
expectedimagePath := "/bookmark/1/thumb"
if expectedimagePath != bookmark.ImageURL {
t.Errorf("Expected imageURL %s, but got %s", bookmark.ImageURL, expectedimagePath)
}
assert.True(t, bookmark.HasEbook)
assert.NoError(t, err)
}

func TestGenerateEbook_ValidBookmarkID_EbookExist_ReturnWithHasArchiveTrue(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)
parentDir := t.TempDir()
defer os.RemoveAll(parentDir)

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: parentDir,
ContentType: "text/html",
}
// Create the archive directory
archiveDir := fp.Join(mockRequest.DataDir, "archive")
err := os.MkdirAll(archiveDir, os.ModePerm)
if err != nil {
t.Fatal(err)
}
// Create the archive file
archivePath := fp.Join(mockRequest.DataDir, "archive", fmt.Sprintf("%d", mockRequest.Bookmark.ID))
file, err := os.Create(archivePath)
if err != nil {
t.Fatal(err)
}
defer file.Close()

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))
assert.True(t, bookmark.HasArchive)
assert.NoError(t, err)
}

func TestGenerateEbook_ValidBookmarkID_RetuenError_PDF(t *testing.T) {
tempDir := t.TempDir()
defer os.RemoveAll(tempDir)

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: tempDir,
ContentType: "application/pdf",
}

bookmark, err := core.GenerateEbook(mockRequest, tempDir)

assert.False(t, bookmark.HasEbook)
assert.Error(t, err)
assert.Contains(t, err.Error(), "can't create ebook for pdf")
func TestGenerateEbook(t *testing.T) {
t.Run("Successful ebook generate", func(t *testing.T) {
t.Run("valid bookmarkId that return HasEbook true", func(t *testing.T) {
// test cae
tempDir := t.TempDir()
dstDir := t.TempDir()

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
Title: "Example Bookmark",
HTML: "<html><body>Example HTML</body></html>",
HasEbook: false,
},
DataDir: dstDir,
ContentType: "text/html",
}

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))

assert.True(t, bookmark.HasEbook)
assert.NoError(t, err)
})
t.Run("ebook generate with valid BookmarkID EbookExist ImagePathExist ReturnWithHasEbookTrue", func(t *testing.T) {
tempDir := t.TempDir()
dstDir := t.TempDir()

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: dstDir,
ContentType: "text/html",
}
// Create the image directory
imageDir := fp.Join(mockRequest.DataDir, "thumb")
err := os.MkdirAll(imageDir, os.ModePerm)
if err != nil {
t.Fatal(err)
}
// Create the image file
imagePath := fp.Join(mockRequest.DataDir, "thumb", fmt.Sprintf("%d", mockRequest.Bookmark.ID))
file, err := os.Create(imagePath)
if err != nil {
t.Fatal(err)
}
defer file.Close()

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))
expectedimagePath := "/bookmark/1/thumb"
if expectedimagePath != bookmark.ImageURL {
t.Errorf("Expected imageURL %s, but got %s", bookmark.ImageURL, expectedimagePath)
}
assert.True(t, bookmark.HasEbook)
assert.NoError(t, err)
})
t.Run("generate ebook valid BookmarkID EbookExist Returnh HasArchive True", func(t *testing.T) {

tempDir := t.TempDir()
dstDir := t.TempDir()

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: dstDir,
ContentType: "text/html",
}
// Create the archive directory
archiveDir := fp.Join(mockRequest.DataDir, "archive")
err := os.MkdirAll(archiveDir, os.ModePerm)
if err != nil {
t.Fatal(err)
}
// Create the archive file
archivePath := fp.Join(mockRequest.DataDir, "archive", fmt.Sprintf("%d", mockRequest.Bookmark.ID))
file, err := os.Create(archivePath)
if err != nil {
t.Fatal(err)
}
defer file.Close()

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))
assert.True(t, bookmark.HasArchive)
assert.NoError(t, err)
})
})
t.Run("specific ebook generate case", func(t *testing.T) {
t.Run("unvalid bookmarkId that return Error", func(t *testing.T) {
tempDir := t.TempDir()
mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 0,
HasEbook: false,
},
DataDir: tempDir,
ContentType: "text/html",
}

bookmark, err := core.GenerateEbook(mockRequest, tempDir)

assert.Equal(t, model.Bookmark{
ID: 0,
HasEbook: false,
}, bookmark)
assert.Error(t, err)
})
t.Run("ebook exist return HasEbook true", func(t *testing.T) {
tempDir := t.TempDir()
dstDir := t.TempDir()

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: dstDir,
ContentType: "text/html",
}
// Create the ebook directory
ebookDir := fp.Join(mockRequest.DataDir, "ebook")
err := os.MkdirAll(ebookDir, os.ModePerm)
if err != nil {
t.Fatal(err)
}
// Create the ebook file
ebookfile := fp.Join(mockRequest.DataDir, "ebook", fmt.Sprintf("%d.epub", mockRequest.Bookmark.ID))
file, err := os.Create(ebookfile)
if err != nil {
t.Fatal(err)
}
defer file.Close()

bookmark, err := core.GenerateEbook(mockRequest, fp.Join(tempDir, "1"))

assert.True(t, bookmark.HasEbook)
assert.NoError(t, err)
})
t.Run("generate ebook valid BookmarkID RetuenError for PDF file", func(t *testing.T) {
tempDir := t.TempDir()

mockRequest := core.ProcessRequest{
Bookmark: model.Bookmark{
ID: 1,
HasEbook: false,
},
DataDir: tempDir,
ContentType: "application/pdf",
}

bookmark, err := core.GenerateEbook(mockRequest, tempDir)

assert.False(t, bookmark.HasEbook)
assert.Error(t, err)
assert.Contains(t, err.Error(), "can't create ebook for pdf")
})
})
}

// Add more unit tests for other scenarios that missing specialy
Expand Down
Loading