shiori/internal/webserver/handler-api-ext.go
Felipe Martin a60dbf3dc5
Run legacy API and new API at the same time. (#648)
* config: backwards comptabile dir

* remove duplicated frontend

* frontend: move assets to assets folder

* legacy routes handler in gin

* templates and asset in different embed

* new routes

* frontend routes serve old views

* added DTO for account object

* api auth calls legacy handler

* frontend: handle new error messages

* frontend: update urls

* frontend: login using new api

* updated frontend tests

* chore: remove debug route

* create shiori/gopher user if no owner is present

* server as default command

* serve -> server

* refactored database logic, allow database url

* removed unused configuration

* storage docs

* refactor cli to use cfg and deps

* check errors only in server

* log fatal instead of os exit

* dont default data directory to current dir

* fixed sqlite path

* trigger build on prs

* avoid releasing if lint/test fails

* pull request condition

* event -> event_name

* Get correct pull request number

* added workflow to delete dangling tags

* fix: nil error checking

* set gin mode first

* set gin mode before initialization

* fix logger

* allow version bump from custom ref

* Updated matrix link to workspace
2023-07-19 18:25:41 +02: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.Bookmark{}
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(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.Bookmark{}
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)
}