shiori/internal/webserver/handler-api-ext.go
Felipe Martin cc7c75116d
refactor: migrate bookmark static pages to new http server (#775)
* migrate bookmark content route to new http server

* new archive page

* remove unused go generate comment

* database mock

* utils cleanup

* unused var

* domains refactor and tests

* fixed secret key type

* redirect to login on ui errors

* fixed archive folder with storage domain

* webroot documentation

* some bookmark route tests

* fixed error in bookmark domain for non existant bookmarks

* centralice errors

* add coverage data to unittests

* added tests, refactor storage to use afero

* removed mock to avoid increasing complexity

* using deps to copy files around

* remove config usage (to deps)

* remove handler-ui file
2023-12-28 18:18:32 +01:00

152 lines
3.9 KiB
Go

package webserver
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
fp "path/filepath"
"strconv"
"github.com/go-shiori/shiori/internal/core"
"github.com/go-shiori/shiori/internal/model"
"github.com/julienschmidt/httprouter"
)
// ApiInsertViaExtension is handler for POST /api/bookmarks/ext
func (h *Handler) ApiInsertViaExtension(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
ctx := r.Context()
// Make sure session still valid
err := h.validateSession(r)
checkError(err)
// Decode request
request := model.BookmarkDTO{}
err = json.NewDecoder(r.Body).Decode(&request)
checkError(err)
// Clean up bookmark URL
request.URL, err = core.RemoveUTMParams(request.URL)
if err != nil {
panic(fmt.Errorf("failed to clean URL: %v", err))
}
// Check if bookmark already exists.
book, exist, err := h.DB.GetBookmark(ctx, 0, request.URL)
if err != nil {
panic(fmt.Errorf("failed to get bookmark, URL: %v", err))
}
// If it already exists, we need to set ID and tags.
if exist {
book.HTML = request.HTML
mapOldTags := map[string]model.Tag{}
for _, oldTag := range book.Tags {
mapOldTags[oldTag.Name] = oldTag
}
for _, newTag := range request.Tags {
if _, tagExist := mapOldTags[newTag.Name]; !tagExist {
book.Tags = append(book.Tags, newTag)
}
}
} else if request.Title == "" {
request.Title = request.URL
}
// Since we are using extension, the extension might send the HTML content
// so no need to download it again here. However, if it's empty, it might be not HTML file
// so we download it here.
var contentType string
var contentBuffer io.Reader
if request.HTML == "" {
contentBuffer, contentType, _ = core.DownloadBookmark(request.URL)
} else {
contentType = "text/html; charset=UTF-8"
contentBuffer = bytes.NewBufferString(request.HTML)
}
// Save the bookmark with whatever we already have downloaded
// since we need the ID in order to download the archive
// Only when old bookmark is not exists.
if !exist {
books, err := h.DB.SaveBookmarks(ctx, true, request)
if err != nil {
log.Printf("error saving bookmark before downloading content: %s", err)
return
}
book = books[0]
}
// At this point the web page already downloaded.
// Time to process it.
if contentBuffer != nil {
book.CreateArchive = true
request := core.ProcessRequest{
DataDir: h.DataDir,
Bookmark: book,
Content: contentBuffer,
ContentType: contentType,
}
var isFatalErr bool
book, isFatalErr, err = core.ProcessBookmark(h.dependencies, request)
if tmp, ok := contentBuffer.(io.ReadCloser); ok {
tmp.Close()
}
// If we can't process or update the saved bookmark, just log it and continue on with the
// request.
if err != nil && isFatalErr {
log.Printf("failed to process bookmark: %v", err)
} else if _, err := h.DB.SaveBookmarks(ctx, false, book); err != nil {
log.Printf("error saving bookmark after downloading content: %s", err)
}
}
// Return the new bookmark
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(&book)
checkError(err)
}
// ApiDeleteViaExtension is handler for DELETE /api/bookmark/ext
func (h *Handler) ApiDeleteViaExtension(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
ctx := r.Context()
// Make sure session still valid
err := h.validateSession(r)
checkError(err)
// Decode request
request := model.BookmarkDTO{}
err = json.NewDecoder(r.Body).Decode(&request)
checkError(err)
// Check if bookmark already exists.
book, exist, err := h.DB.GetBookmark(ctx, 0, request.URL)
checkError(err)
if exist {
// Delete bookmarks
err = h.DB.DeleteBookmarks(ctx, book.ID)
checkError(err)
// Delete thumbnail image and archives from local disk
strID := strconv.Itoa(book.ID)
imgPath := fp.Join(h.DataDir, "thumb", strID)
archivePath := fp.Join(h.DataDir, "archive", strID)
os.Remove(imgPath)
os.Remove(archivePath)
}
fmt.Fprint(w, 1)
}