diff --git a/assets/css/main.scss b/assets/css/main.scss
index addf5ce..2e0883a 100644
--- a/assets/css/main.scss
+++ b/assets/css/main.scss
@@ -31,24 +31,19 @@ $container-max-widths: (
font-size: 0.9rem;
}
-// Large editor
-//
-// Used for edit canvases which take up the entire window
+// Post form
-.large-editor {
+// Post edit page styling
+.post-edit-page {
height: 100vh;
}
-.large-editor main {
+.post-edit-page main {
display: flex;
flex-direction: column;
overflow: hidden;
}
-// Post form
-
-// Post edit page styling
-
.post-edit-page .post-form {
flex: 1;
display: flex;
diff --git a/assets/js/controllers/edit_upload.js b/assets/js/controllers/edit_upload.js
deleted file mode 100644
index 95cbb1e..0000000
--- a/assets/js/controllers/edit_upload.js
+++ /dev/null
@@ -1,233 +0,0 @@
-import feather from "feather-icons/dist/feather.js";
-import Handlebars from "handlebars";
-import {Controller} from "@hotwired/stimulus";
-
-Handlebars.registerHelper("submit_on", function (id, event) {
- return `data-action="${event}->edit-upload#updateProcessor" data-edit-upload-id-param="${id}"`
-});
-
-const processorFrame = Handlebars.compile(`
-
-`);
-
-const processorUIs = {
- "shadow": {
- label: "Shadow",
- template: Handlebars.compile(`
-
-
- `),
- },
- "resize": {
- label: "Resize",
- template: Handlebars.compile(`
-
- Width
-
-
-
- Height
-
-
- `),
- },
-};
-
-export default class UploadEditController extends Controller {
- static targets = ['processList', 'preview'];
- static values = {
- uploadId: Number,
- siteId: Number,
- };
-
- connect() {
- this._rebuildProcessList();
- this._createSession();
- }
-
- async addProcessor(ev) {
- ev.preventDefault();
- await this._addProcessor({
- type: "shadow"
- });
- }
-
- async removeProcessor(ev) {
- ev.preventDefault();
- let id = ev.params.id;
- await this._removeProcessor(id);
- }
-
- async saveUpload(ev) {
- ev.preventDefault();
- await this._save("replace");
- }
-
- async saveNewUpload(ev) {
- ev.preventDefault();
- await this._save("copy");
- }
-
- async updateProcessor(ev) {
- ev.preventDefault();
- let id = ev.params.id;
-
- let paramParentEl = ev.target.closest('[data-role="processor-params"]');
- let params = Object.fromEntries(new FormData(paramParentEl).entries());
-
- await this._updateProcessor(id, params);
- }
-
- _rebuildProcessList() {
- let el = this.processListTarget;
-
- if ((!this._state) || (!this._state.session) || (!this._state.session.processors)) {
- return;
- }
-
- el.innerHTML = "";
- for (let p of this._state.session.processors) {
- let ui = processorUIs[p.type];
- if (!ui) {
- continue;
- }
- let cardOuter = processorFrame({
- id: p.id,
- name: ui.label,
- props: ui.template(p),
- });
- el.innerHTML += cardOuter;
- }
-
- feather.replace();
- }
-
- async _createSession() {
- try {
- let resp = await fetch(`/sites/${this.siteIdValue}/imageedit/`, {
- method: 'POST',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- "base_upload": this.uploadIdValue,
- })
- });
-
- this._state = await resp.json();
-
- this._rebuildProcessList();
- this.previewTarget.src = this._state.preview_url;
- } catch (e) {
- console.error(e);
- }
- }
-
- async _addProcessor(processor) {
- try {
- let resp = await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}/processors`, {
- method: 'POST',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(processor)
- });
-
- this._state = await resp.json();
-
- this._rebuildProcessList();
- this.previewTarget.src = this._state.preview_url;
- } catch (e) {
- console.error(e);
- }
- }
-
- async _updateProcessor(processorID, params) {
- await this._doReturningState(async () => {
- return (await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}`, {
- method: 'PATCH',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- processor: {
- id: processorID,
- props: params,
- }
- })
- })).json();
- })
- }
-
-
- async _removeProcessor(processorID) {
- await this._doReturningState(async () => {
- return (await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}/processors/${processorID}`, {
- method: 'DELETE',
- })).json();
- })
- }
-
- async _save(mode) {
- if (!this._state || !this._state.session) {
- return;
- }
-
- try {
- let resp = await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}/save`, {
- method: 'POST',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({ mode })
- });
-
- if (!resp.ok) {
- console.error("Save failed:", resp.statusText);
- return;
- }
-
- let result = await resp.json();
- window.location.href = `/sites/${this.siteIdValue}/uploads/${result.upload_id}`;
- } catch (e) {
- console.error(e);
- }
- }
-
- async _doReturningState(fn) {
- try {
- this._state = await fn();
-
- this._rebuildProcessList();
- this.previewTarget.src = this._state.preview_url;
- } catch (e) {
- console.error(e);
- }
-
- }
-}
\ No newline at end of file
diff --git a/assets/js/controllers/postedit.js b/assets/js/controllers/postedit.js
index f800c44..71328e3 100644
--- a/assets/js/controllers/postedit.js
+++ b/assets/js/controllers/postedit.js
@@ -60,16 +60,6 @@ export default class PosteditController extends Controller {
try {
const formData = new FormData(this.element);
let data = Object.fromEntries(formData.entries());
-
- // Special handling for categories
- let categoryIDs = [];
- for (let i of formData.entries()) {
- if (i[0] === "category_ids") {
- categoryIDs.push(parseInt(i[1]))
- }
- }
-
- data["category_ids"] = categoryIDs;
data = {...data, action: action || 'save'};
const response = await fetch(this.element.getAttribute("action"), {
diff --git a/assets/js/main.js b/assets/js/main.js
index d3ff4c6..fcbe286 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -8,7 +8,6 @@ import LogoutController from "./controllers/logout";
import FirstRunController from "./controllers/firstrun";
import UploadController from "./controllers/upload";
import ShowUploadController from "./controllers/show_upload";
-import EditUploadController from "./controllers/edit_upload";
import PagelistController from "./controllers/pagelist";
window.Stimulus = Application.start()
@@ -19,7 +18,6 @@ Stimulus.register("logout", LogoutController);
Stimulus.register("first-run", FirstRunController);
Stimulus.register("upload", UploadController);
Stimulus.register("show-upload", ShowUploadController);
-Stimulus.register("edit-upload", EditUploadController);
Stimulus.register("pagelist", PagelistController);
feather.replace();
\ No newline at end of file
diff --git a/cmds/server.go b/cmds/server.go
index 29a8c2a..36e5923 100644
--- a/cmds/server.go
+++ b/cmds/server.go
@@ -111,11 +111,9 @@ Starting weiro without any arguments will start the server.
lh := handlers.LoginHandler{Config: cfg, AuthService: svcs.Auth}
ph := handlers.PostsHandler{PostService: svcs.Posts, CategoryService: svcs.Categories}
uh := handlers.UploadsHandler{UploadsService: svcs.Uploads}
- ieh := handlers.ImageEditHandlers{ImageEditService: svcs.ImageEdit}
ssh := handlers.SiteSettingsHandler{SiteService: svcs.Sites}
ch := handlers.CategoriesHandler{CategoryService: svcs.Categories}
pgh := handlers.PagesHandler{PageService: svcs.Pages}
- oih := handlers.ObsImportHandler{ObsImportService: svcs.ObsImport, ScratchDir: cfg.ScratchDir}
app.Get("/login", lh.Login)
app.Post("/login", lh.DoLogin)
@@ -151,21 +149,10 @@ Starting weiro without any arguments will start the server.
siteGroup.Post("/uploads/pending/:guid", uh.UploadPart)
siteGroup.Post("/uploads/pending/:guid/finalize", uh.UploadComplete)
siteGroup.Delete("/uploads/:uploadID", uh.Delete)
- siteGroup.Get("/uploads/:uploadID/edit", uh.Edit)
-
- siteGroup.Post("/imageedit", ieh.Create)
- siteGroup.Patch("/imageedit/:sessionID", ieh.PatchSession)
- siteGroup.Post("/imageedit/:sessionID/processors", ieh.AddProcessor)
- siteGroup.Delete("/imageedit/:sessionID/processors/:processorID", ieh.DeleteProcessor)
- siteGroup.Post("/imageedit/:sessionID/save", ieh.Save)
- siteGroup.Get("/imageedit/:sessionID/preview/:versionID", ieh.Preview)
siteGroup.Get("/settings", ssh.General)
siteGroup.Post("/settings", ssh.UpdateGeneral)
- siteGroup.Get("/import/obsidian", oih.Form)
- siteGroup.Post("/import/obsidian", oih.Upload)
-
siteGroup.Get("/categories", ch.Index)
siteGroup.Get("/categories/new", ch.New)
siteGroup.Get("/categories/:categoryID", ch.Edit)
diff --git a/handlers/imageedit.go b/handlers/imageedit.go
deleted file mode 100644
index 27a01b0..0000000
--- a/handlers/imageedit.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package handlers
-
-import (
- "bufio"
- "io"
- "log"
- "net/http"
-
- "github.com/gofiber/fiber/v3"
- "lmika.dev/lmika/weiro/models"
- "lmika.dev/lmika/weiro/services/imgedit"
-)
-
-type ImageEditHandlers struct {
- ImageEditService *imgedit.Service
-}
-
-type sessionResponse struct {
- Session *models.ImageEditSession `json:"session"`
- PreviewURL string `json:"preview_url"`
-}
-
-func (ieh ImageEditHandlers) Create(c fiber.Ctx) error {
- var req struct {
- BaseUploadID int64 `json:"base_upload"`
- }
-
- if err := c.Bind().JSON(&req); err != nil {
- return err
- }
-
- res, err := ieh.ImageEditService.NewSession(c.Context(), req.BaseUploadID)
- if err != nil {
- return err
- }
-
- var resp = sessionResponse{
- Session: res,
- PreviewURL: res.PreviewURL(),
- }
-
- return c.Status(http.StatusCreated).JSON(resp)
-}
-
-func (ieh ImageEditHandlers) Preview(c fiber.Ctx) error {
- log.Printf("Previewing image edit session %v/%v", c.Params("sessionID"), c.Params("versionID"))
- sessionID := c.Params("sessionID")
- versionID := c.Params("versionID")
-
- mimeTime, rw, err := ieh.ImageEditService.LoadImageVersion(c.Context(), sessionID, versionID)
- if err != nil {
- return err
- }
-
- c.Set("Content-Type", mimeTime)
- c.Status(http.StatusOK)
- return c.SendStreamWriter(func(w *bufio.Writer) {
- rw, err := rw()
- if err != nil {
- return
- }
- defer rw.Close()
-
- _, err = io.Copy(w, rw)
- if err != nil {
- return
- }
- })
-}
-
-func (ieh ImageEditHandlers) AddProcessor(c fiber.Ctx) error {
- sessionID := c.Params("sessionID")
- if sessionID == "" {
- log.Println("No session ID")
- return fiber.ErrBadRequest
- }
-
- var req imgedit.AddProcessorReq
- if err := c.Bind().Body(&req); err != nil {
- log.Printf("Failed to parse request body: %v", err)
- return fiber.ErrBadRequest
- }
-
- res, err := ieh.ImageEditService.AddProcessor(c.Context(), sessionID, req)
- if err != nil {
- return err
- }
-
- return c.Status(http.StatusOK).JSON(sessionResponse{
- Session: res,
- PreviewURL: res.PreviewURL(),
- })
-}
-
-func (ieh ImageEditHandlers) DeleteProcessor(c fiber.Ctx) error {
- sessionID := c.Params("sessionID")
- if sessionID == "" {
- return fiber.ErrBadRequest
- }
-
- processorID := c.Params("processorID")
- if processorID == "" {
- return fiber.ErrBadRequest
- }
-
- res, err := ieh.ImageEditService.DeleteProcessor(c.Context(), sessionID, processorID)
- if err != nil {
- return err
- }
-
- return c.Status(http.StatusOK).JSON(sessionResponse{
- Session: res,
- PreviewURL: res.PreviewURL(),
- })
-}
-
-func (ieh ImageEditHandlers) Save(c fiber.Ctx) error {
- sessionID := c.Params("sessionID")
- if sessionID == "" {
- return fiber.ErrBadRequest
- }
-
- var req struct {
- Mode string `json:"mode"`
- }
- if err := c.Bind().JSON(&req); err != nil {
- return fiber.ErrBadRequest
- }
-
- result, err := ieh.ImageEditService.Save(c.Context(), sessionID, req.Mode)
- if err != nil {
- return err
- }
-
- return c.Status(http.StatusOK).JSON(result)
-}
-
-func (ieh ImageEditHandlers) PatchSession(c fiber.Ctx) error {
- var req struct {
- UpdateProc *imgedit.UpdateProcessorReq `json:"processor"`
- }
-
- sessionID := c.Params("sessionID")
- if sessionID == "" {
- return fiber.ErrBadRequest
- }
-
- if err := c.Bind().Body(&req); err != nil {
- return err
- }
- log.Printf("Got request: %v", *req.UpdateProc)
-
- if req.UpdateProc != nil {
- res, err := ieh.ImageEditService.UpdateProcessor(c.Context(), sessionID, *req.UpdateProc)
- if err != nil {
- return err
- }
- return c.Status(http.StatusOK).JSON(sessionResponse{
- Session: res,
- PreviewURL: res.PreviewURL(),
- })
- }
-
- return fiber.ErrBadRequest
-}
diff --git a/handlers/index.go b/handlers/index.go
index 410c347..6062237 100644
--- a/handlers/index.go
+++ b/handlers/index.go
@@ -2,7 +2,6 @@ package handlers
import (
"fmt"
- "log"
"net/url"
"regexp"
@@ -38,13 +37,6 @@ func (h IndexHandler) Index(c fiber.Ctx) error {
}
}
- sess := session.FromContext(c)
- lastSiteID, ok := sess.Get("last_site_id").(int64)
- log.Printf("last site id: %v", lastSiteID)
- if ok {
- return c.Redirect().To(fmt.Sprintf("/sites/%v/posts", lastSiteID))
- }
-
site, err := h.SiteService.BestSite(c.Context(), user)
if err != nil {
return err
diff --git a/handlers/login.go b/handlers/login.go
index 34c1e96..30ed0b4 100644
--- a/handlers/login.go
+++ b/handlers/login.go
@@ -37,8 +37,9 @@ func (lh *LoginHandler) Logout(c fiber.Ctx) error {
func (lh *LoginHandler) DoLogin(c fiber.Ctx) error {
var req struct {
- Username string `form:"username"`
- Password string `form:"password"`
+ Username string `form:"username"`
+ Password string `form:"password"`
+ LoginChallenge string `form:"_login_challenge"`
}
if err := c.Bind().Body(&req); err != nil {
return c.Status(fiber.StatusBadRequest).SendString("Failed to parse request body")
@@ -50,6 +51,11 @@ func (lh *LoginHandler) DoLogin(c fiber.Ctx) error {
sess := session.FromContext(c)
+ challenge, _ := sess.Get("_login_challenge").(string)
+ if challenge != req.LoginChallenge {
+ return c.Redirect().To("/login")
+ }
+
user, err := lh.AuthService.Login(c.Context(), req.Username, req.Password)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString("Failed to login")
diff --git a/handlers/middleware/site.go b/handlers/middleware/site.go
index 1d3ddf2..6f47430 100644
--- a/handlers/middleware/site.go
+++ b/handlers/middleware/site.go
@@ -5,7 +5,6 @@ import (
"emperror.dev/errors"
"github.com/gofiber/fiber/v3"
- "github.com/gofiber/fiber/v3/middleware/session"
"lmika.dev/lmika/weiro/models"
"lmika.dev/lmika/weiro/providers/db"
"lmika.dev/lmika/weiro/services/sites"
@@ -42,9 +41,6 @@ func RequiresSite(sites *sites.Service) func(c fiber.Ctx) error {
}
c.Locals("allSites", sitesOwnedByUser)
- sess := session.FromContext(c)
- sess.Set("last_site_id", siteID)
-
if pubTargets, err := sites.BestPubTarget(c.Context(), site); err == nil {
c.Locals("pubTarget", pubTargets)
}
diff --git a/handlers/obsimport.go b/handlers/obsimport.go
deleted file mode 100644
index e20be77..0000000
--- a/handlers/obsimport.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package handlers
-
-import (
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/gofiber/fiber/v3"
- "lmika.dev/lmika/weiro/models"
- "lmika.dev/lmika/weiro/services/obsimport"
-)
-
-type ObsImportHandler struct {
- ObsImportService *obsimport.Service
- ScratchDir string
-}
-
-func (h ObsImportHandler) Form(c fiber.Ctx) error {
- return c.Render("obsimport/form", fiber.Map{})
-}
-
-func (h ObsImportHandler) Upload(c fiber.Ctx) error {
- site := c.Locals("site").(models.Site)
-
- fileHeader, err := c.FormFile("zipfile")
- if err != nil {
- return fiber.NewError(fiber.StatusBadRequest, "no file provided")
- }
-
- // Save uploaded file to scratch dir
- if err := os.MkdirAll(h.ScratchDir, 0755); err != nil {
- return err
- }
-
- dstPath := filepath.Join(h.ScratchDir, models.NewNanoID()+".zip")
- if err := c.SaveFile(fileHeader, dstPath); err != nil {
- return err
- }
- defer os.Remove(dstPath)
-
- result, err := h.ObsImportService.ImportZip(c.Context(), dstPath)
- if err != nil {
- return err
- }
-
- return c.Render("obsimport/result", fiber.Map{
- "result": result,
- "siteURL": fmt.Sprintf("/sites/%v/posts", site.ID),
- })
-}
diff --git a/handlers/posts.go b/handlers/posts.go
index 0e491aa..3326533 100644
--- a/handlers/posts.go
+++ b/handlers/posts.go
@@ -75,7 +75,7 @@ func (ph PostsHandler) New(c fiber.Ctx) error {
"post": p,
"categories": cats,
"selectedCategories": map[int64]bool{},
- "bodyClass": "large-editor",
+ "bodyClass": "post-edit-page",
})
}
@@ -116,7 +116,7 @@ func (ph PostsHandler) Edit(c fiber.Ctx) error {
"post": post,
"categories": cats,
"selectedCategories": selectedCategories,
- "bodyClass": "large-editor",
+ "bodyClass": "post-edit-page",
})
}))
}
diff --git a/handlers/uploads.go b/handlers/uploads.go
index 3553b09..fa2cb98 100644
--- a/handlers/uploads.go
+++ b/handlers/uploads.go
@@ -162,24 +162,3 @@ func (uh UploadsHandler) UploadComplete(c fiber.Ctx) error {
return c.Status(fiber.StatusAccepted).JSON(fiber.Map{})
}
-
-func (uh UploadsHandler) Edit(c fiber.Ctx) error {
- uploadIDStr := c.Params("uploadID")
- if uploadIDStr == "" {
- return fiber.ErrBadRequest
- }
- uploadID, err := strconv.ParseInt(uploadIDStr, 10, 64)
- if err != nil {
- return fiber.ErrBadRequest
- }
-
- upload, err := uh.UploadsService.FetchUpload(c.Context(), uploadID)
- if err != nil {
- return err
- }
-
- return c.Render("uploads/edit", fiber.Map{
- "upload": upload,
- "bodyClass": "large-editor",
- })
-}
diff --git a/models/errors.go b/models/errors.go
index 2c4ae68..3efadbc 100644
--- a/models/errors.go
+++ b/models/errors.go
@@ -8,4 +8,3 @@ var NotFoundError = errors.New("not found")
var SiteRequiredError = errors.New("site required")
var DeleteDebounceError = errors.New("permanent delete too soon, try again in a few seconds")
var SlugConflictError = errors.New("a record with this slug already exists")
-var UnsupportedImageFormat = errors.New("unsupported image format")
diff --git a/models/imgedit.go b/models/imgedit.go
deleted file mode 100644
index b954402..0000000
--- a/models/imgedit.go
+++ /dev/null
@@ -1,62 +0,0 @@
-package models
-
-import (
- "crypto/md5"
- "encoding/json"
- "fmt"
- "strings"
- "time"
-)
-
-type ImageEditSession struct {
- GUID string `json:"guid"`
- SiteID int64 `json:"siteId"`
- UserID int64 `json:"userId"`
- BaseUploadID int64 `json:"baseUploadId"`
- ImageExt string `json:"imageExt"`
- CreatedAt time.Time `json:"createdAt"`
- UpdatedAt time.Time `json:"updatedAt"`
- Processors []ImageEditProcessor `json:"processors"`
-}
-
-func (ieh ImageEditSession) PreviewURL() string {
- return fmt.Sprintf("/sites/%v/imageedit/%v/preview/%v", ieh.SiteID, ieh.GUID, ieh.Processors[len(ieh.Processors)-1].VersionID)
-}
-
-func (ieh *ImageEditSession) RecalcVersionIDs() {
- for i, p := range ieh.Processors {
- if i == 0 {
- p.SetVersionID("")
- } else {
- p.SetVersionID(ieh.Processors[i-1].VersionID)
- }
-
- ieh.Processors[i] = p
- }
-}
-
-type ImageEditProcessor struct {
- ID string `json:"id"`
- Type string `json:"type"`
- Props json.RawMessage `json:"props"`
-
- // VersionID is a unique hash of the particular processor. This includes the version ID of the previous processor,
- // thereby causing a change of one processor to affect the version IDs of processors down the line.
- VersionID string `json:"versionId"`
-}
-
-func (ieh *ImageEditProcessor) SetVersionID(previousVersionID string) {
- var sb strings.Builder
- sb.WriteString(ieh.ID)
- sb.WriteString("-")
- sb.WriteString(previousVersionID)
- sb.WriteString("-")
- sb.WriteString(ieh.Type)
- sb.WriteString("-")
- sb.WriteString(string(ieh.Props))
- ieh.VersionID = fmt.Sprintf("%x", md5.Sum([]byte(sb.String())))
-}
-
-type CopyUploadProps struct {
- UploadID int64 `json:"uploadId"`
-}
diff --git a/package-lock.json b/package-lock.json
index eadf529..2068fd3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,8 +8,7 @@
"@hotwired/stimulus": "^3.2.2",
"bootstrap": "^5.3.8",
"esbuild-sass-plugin": "^3.6.0",
- "feather-icons": "^4.29.2",
- "handlebars": "^4.7.8"
+ "feather-icons": "^4.29.2"
},
"devDependencies": {
"esbuild": "0.27.3"
@@ -893,27 +892,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/handlebars": {
- "version": "4.7.8",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
- "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.2",
- "source-map": "^0.6.1",
- "wordwrap": "^1.0.0"
- },
- "bin": {
- "handlebars": "bin/handlebars"
- },
- "engines": {
- "node": ">=0.4.7"
- },
- "optionalDependencies": {
- "uglify-js": "^3.1.4"
- }
- },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -980,21 +958,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
- "license": "MIT"
- },
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
@@ -1432,15 +1395,6 @@
"node": ">=14.0.0"
}
},
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -1508,31 +1462,12 @@
"license": "0BSD",
"peer": true
},
- "node_modules/uglify-js": {
- "version": "3.19.3",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
- "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
- "license": "BSD-2-Clause",
- "optional": true,
- "bin": {
- "uglifyjs": "bin/uglifyjs"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
"license": "MIT",
"peer": true
- },
- "node_modules/wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
- "license": "MIT"
}
}
}
diff --git a/package.json b/package.json
index 3455630..5a786ac 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,6 @@
"@hotwired/stimulus": "^3.2.2",
"bootstrap": "^5.3.8",
"esbuild-sass-plugin": "^3.6.0",
- "feather-icons": "^4.29.2",
- "handlebars": "^4.7.8"
+ "feather-icons": "^4.29.2"
}
}
diff --git a/providers/db/categories.go b/providers/db/categories.go
index 23a9e67..72fac94 100644
--- a/providers/db/categories.go
+++ b/providers/db/categories.go
@@ -82,8 +82,8 @@ func (db *Provider) SelectCategoriesOfPost(ctx context.Context, postID int64) ([
return cats, nil
}
-func (db *Provider) SelectPublishedPostsOfCategory(ctx context.Context, categoryID int64, pp PagingParams) ([]*models.Post, error) {
- rows, err := db.queries.SelectPublishedPostsOfCategory(ctx, sqlgen.SelectPublishedPostsOfCategoryParams{
+func (db *Provider) SelectPostsOfCategory(ctx context.Context, categoryID int64, pp PagingParams) ([]*models.Post, error) {
+ rows, err := db.queries.SelectPostsOfCategory(ctx, sqlgen.SelectPostsOfCategoryParams{
CategoryID: categoryID,
Limit: pp.Limit,
Offset: pp.Offset,
diff --git a/providers/db/gen/sqlgen/categories.sql.go b/providers/db/gen/sqlgen/categories.sql.go
index f6a291f..d5bc40d 100644
--- a/providers/db/gen/sqlgen/categories.sql.go
+++ b/providers/db/gen/sqlgen/categories.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: categories.sql
package sqlgen
@@ -227,7 +227,7 @@ func (q *Queries) SelectCategoryBySlugAndSite(ctx context.Context, arg SelectCat
return i, err
}
-const selectPublishedPostsOfCategory = `-- name: SelectPublishedPostsOfCategory :many
+const selectPostsOfCategory = `-- name: SelectPostsOfCategory :many
SELECT p.id, p.site_id, p.state, p.guid, p.title, p.body, p.slug, p.created_at, p.updated_at, p.published_at, p.deleted_at FROM posts p
INNER JOIN post_categories pc ON pc.post_id = p.id
WHERE pc.category_id = ? AND p.state = 0 AND p.deleted_at = 0
@@ -235,14 +235,14 @@ ORDER BY p.published_at DESC
LIMIT ? OFFSET ?
`
-type SelectPublishedPostsOfCategoryParams struct {
+type SelectPostsOfCategoryParams struct {
CategoryID int64
Limit int64
Offset int64
}
-func (q *Queries) SelectPublishedPostsOfCategory(ctx context.Context, arg SelectPublishedPostsOfCategoryParams) ([]Post, error) {
- rows, err := q.db.QueryContext(ctx, selectPublishedPostsOfCategory, arg.CategoryID, arg.Limit, arg.Offset)
+func (q *Queries) SelectPostsOfCategory(ctx context.Context, arg SelectPostsOfCategoryParams) ([]Post, error) {
+ rows, err := q.db.QueryContext(ctx, selectPostsOfCategory, arg.CategoryID, arg.Limit, arg.Offset)
if err != nil {
return nil, err
}
diff --git a/providers/db/gen/sqlgen/db.go b/providers/db/gen/sqlgen/db.go
index 7d9d9e7..8eab959 100644
--- a/providers/db/gen/sqlgen/db.go
+++ b/providers/db/gen/sqlgen/db.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
package sqlgen
diff --git a/providers/db/gen/sqlgen/models.go b/providers/db/gen/sqlgen/models.go
index 348c1ab..3df1193 100644
--- a/providers/db/gen/sqlgen/models.go
+++ b/providers/db/gen/sqlgen/models.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
package sqlgen
diff --git a/providers/db/gen/sqlgen/pages.sql.go b/providers/db/gen/sqlgen/pages.sql.go
index 7dd5105..1d53291 100644
--- a/providers/db/gen/sqlgen/pages.sql.go
+++ b/providers/db/gen/sqlgen/pages.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: pages.sql
package sqlgen
diff --git a/providers/db/gen/sqlgen/pending_uploads.sql.go b/providers/db/gen/sqlgen/pending_uploads.sql.go
index a831bbe..63eeb60 100644
--- a/providers/db/gen/sqlgen/pending_uploads.sql.go
+++ b/providers/db/gen/sqlgen/pending_uploads.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: pending_uploads.sql
package sqlgen
diff --git a/providers/db/gen/sqlgen/posts.sql.go b/providers/db/gen/sqlgen/posts.sql.go
index b1d3afb..ef3d170 100644
--- a/providers/db/gen/sqlgen/posts.sql.go
+++ b/providers/db/gen/sqlgen/posts.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: posts.sql
package sqlgen
@@ -200,54 +200,6 @@ func (q *Queries) SelectPostsOfSite(ctx context.Context, arg SelectPostsOfSitePa
return items, nil
}
-const selectPublishedPostsOfSite = `-- name: SelectPublishedPostsOfSite :many
-SELECT id, site_id, state, guid, title, body, slug, created_at, updated_at, published_at, deleted_at
-FROM posts
-WHERE site_id = ?1 AND state = 0 AND deleted_at = 0
-ORDER BY published_at DESC LIMIT ?3 OFFSET ?2
-`
-
-type SelectPublishedPostsOfSiteParams struct {
- SiteID int64
- Offset int64
- Limit int64
-}
-
-func (q *Queries) SelectPublishedPostsOfSite(ctx context.Context, arg SelectPublishedPostsOfSiteParams) ([]Post, error) {
- rows, err := q.db.QueryContext(ctx, selectPublishedPostsOfSite, arg.SiteID, arg.Offset, arg.Limit)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
- var items []Post
- for rows.Next() {
- var i Post
- if err := rows.Scan(
- &i.ID,
- &i.SiteID,
- &i.State,
- &i.Guid,
- &i.Title,
- &i.Body,
- &i.Slug,
- &i.CreatedAt,
- &i.UpdatedAt,
- &i.PublishedAt,
- &i.DeletedAt,
- ); err != nil {
- return nil, err
- }
- items = append(items, i)
- }
- if err := rows.Close(); err != nil {
- return nil, err
- }
- if err := rows.Err(); err != nil {
- return nil, err
- }
- return items, nil
-}
-
const softDeletePost = `-- name: SoftDeletePost :exec
UPDATE posts SET deleted_at = ? WHERE id = ?
`
diff --git a/providers/db/gen/sqlgen/pubtargets.sql.go b/providers/db/gen/sqlgen/pubtargets.sql.go
index cd5cfa6..69c09df 100644
--- a/providers/db/gen/sqlgen/pubtargets.sql.go
+++ b/providers/db/gen/sqlgen/pubtargets.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: pubtargets.sql
package sqlgen
diff --git a/providers/db/gen/sqlgen/sites.sql.go b/providers/db/gen/sqlgen/sites.sql.go
index 797eaad..80ccbc0 100644
--- a/providers/db/gen/sqlgen/sites.sql.go
+++ b/providers/db/gen/sqlgen/sites.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: sites.sql
package sqlgen
diff --git a/providers/db/gen/sqlgen/uploads.sql.go b/providers/db/gen/sqlgen/uploads.sql.go
index 7ad3828..189de2d 100644
--- a/providers/db/gen/sqlgen/uploads.sql.go
+++ b/providers/db/gen/sqlgen/uploads.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: uploads.sql
package sqlgen
@@ -18,7 +18,7 @@ func (q *Queries) DeleteUpload(ctx context.Context, id int64) error {
return err
}
-const insertUpload = `-- name: InsertUpload :one
+const insertUpload = `-- name: InsertUpload :exec
INSERT INTO uploads (
site_id,
guid,
@@ -43,8 +43,8 @@ type InsertUploadParams struct {
CreatedAt int64
}
-func (q *Queries) InsertUpload(ctx context.Context, arg InsertUploadParams) (int64, error) {
- row := q.db.QueryRowContext(ctx, insertUpload,
+func (q *Queries) InsertUpload(ctx context.Context, arg InsertUploadParams) error {
+ _, err := q.db.ExecContext(ctx, insertUpload,
arg.SiteID,
arg.Guid,
arg.MimeType,
@@ -54,9 +54,7 @@ func (q *Queries) InsertUpload(ctx context.Context, arg InsertUploadParams) (int
arg.Alt,
arg.CreatedAt,
)
- var id int64
- err := row.Scan(&id)
- return id, err
+ return err
}
const selectUploadByID = `-- name: SelectUploadByID :one
@@ -156,17 +154,3 @@ func (q *Queries) UpdateUpload(ctx context.Context, arg UpdateUploadParams) erro
_, err := q.db.ExecContext(ctx, updateUpload, arg.Alt, arg.ID)
return err
}
-
-const updateUploadFileSize = `-- name: UpdateUploadFileSize :exec
-UPDATE uploads SET file_size = ? WHERE id = ?
-`
-
-type UpdateUploadFileSizeParams struct {
- FileSize int64
- ID int64
-}
-
-func (q *Queries) UpdateUploadFileSize(ctx context.Context, arg UpdateUploadFileSizeParams) error {
- _, err := q.db.ExecContext(ctx, updateUploadFileSize, arg.FileSize, arg.ID)
- return err
-}
diff --git a/providers/db/gen/sqlgen/users.sql.go b/providers/db/gen/sqlgen/users.sql.go
index a70a3bf..6007589 100644
--- a/providers/db/gen/sqlgen/users.sql.go
+++ b/providers/db/gen/sqlgen/users.sql.go
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
-// sqlc v1.30.0
+// sqlc v1.28.0
// source: users.sql
package sqlgen
diff --git a/providers/db/posts.go b/providers/db/posts.go
index 3b86aaf..7f58d1a 100644
--- a/providers/db/posts.go
+++ b/providers/db/posts.go
@@ -47,23 +47,6 @@ func (db *Provider) SelectPostsOfSite(ctx context.Context, siteID int64, showDel
return posts, nil
}
-func (db *Provider) SelectPublishedPostsOfSite(ctx context.Context, siteID int64, pp PagingParams) ([]*models.Post, error) {
- rows, err := db.queries.SelectPublishedPostsOfSite(ctx, sqlgen.SelectPublishedPostsOfSiteParams{
- SiteID: siteID,
- Limit: pp.Limit,
- Offset: pp.Offset,
- })
- if err != nil {
- return nil, err
- }
-
- posts := make([]*models.Post, len(rows))
- for i, row := range rows {
- posts[i] = dbPostToPost(row)
- }
- return posts, nil
-}
-
func (db *Provider) SelectPost(ctx context.Context, postID int64) (*models.Post, error) {
row, err := db.queries.SelectPost(ctx, postID)
if err != nil {
diff --git a/providers/db/uploads.go b/providers/db/uploads.go
index b3033ab..006b7cc 100644
--- a/providers/db/uploads.go
+++ b/providers/db/uploads.go
@@ -44,7 +44,7 @@ func (db *Provider) SelectUploadBySiteIDAndSlug(ctx context.Context, siteID int6
func (db *Provider) SaveUpload(ctx context.Context, upload *models.Upload) error {
if upload.ID == 0 {
- newID, err := db.queries.InsertUpload(ctx, sqlgen.InsertUploadParams{
+ if err := db.queries.InsertUpload(ctx, sqlgen.InsertUploadParams{
SiteID: upload.SiteID,
Guid: upload.GUID,
MimeType: upload.MIMEType,
@@ -53,11 +53,9 @@ func (db *Provider) SaveUpload(ctx context.Context, upload *models.Upload) error
Slug: upload.Slug,
Alt: upload.Alt,
CreatedAt: upload.CreatedAt.Unix(),
- })
- if err != nil {
+ }); err != nil {
return err
}
- upload.ID = newID
return nil
}
@@ -67,13 +65,6 @@ func (db *Provider) SaveUpload(ctx context.Context, upload *models.Upload) error
})
}
-func (db *Provider) UpdateUploadFileSize(ctx context.Context, id int64, fileSize int64) error {
- return db.queries.UpdateUploadFileSize(ctx, sqlgen.UpdateUploadFileSizeParams{
- FileSize: fileSize,
- ID: id,
- })
-}
-
func (db *Provider) DeleteUpload(ctx context.Context, id int64) error {
return db.queries.DeleteUpload(ctx, id)
}
diff --git a/providers/markdown/renderer.go b/providers/markdown/renderer.go
index 828ba96..aedd184 100644
--- a/providers/markdown/renderer.go
+++ b/providers/markdown/renderer.go
@@ -22,7 +22,7 @@ type Renderer struct {
func NewRendererForUI() *Renderer {
mdParser := goldmark.New(
- goldmark.WithExtensions(extension.GFM, extension.Footnote),
+ goldmark.WithExtensions(extension.GFM),
goldmark.WithRendererOptions(
gm_html.WithUnsafe(),
),
@@ -48,7 +48,7 @@ func NewRendererForUI() *Renderer {
func NewRendererForSite() *Renderer {
mdParser := goldmark.New(
- goldmark.WithExtensions(extension.GFM, extension.Footnote),
+ goldmark.WithExtensions(extension.GFM),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
diff --git a/providers/sitebuilder/builder.go b/providers/sitebuilder/builder.go
index d0bf17b..71ce926 100644
--- a/providers/sitebuilder/builder.go
+++ b/providers/sitebuilder/builder.go
@@ -49,7 +49,6 @@ func New(site pubmodel.Site, opts Options) (*Builder, error) {
mdRenderer: markdown.NewRendererForSite(),
postMDProcessors: []postMDProcessor{
uploadAbsoluteURL,
- removeFootnoteHRs,
},
}, nil
}
diff --git a/providers/sitebuilder/processors.go b/providers/sitebuilder/processors.go
index 605d077..c699160 100644
--- a/providers/sitebuilder/processors.go
+++ b/providers/sitebuilder/processors.go
@@ -35,8 +35,3 @@ func uploadAbsoluteURL(site pubmodel.Site, dom *goquery.Document) error {
})
return nil
}
-
-func removeFootnoteHRs(site pubmodel.Site, dom *goquery.Document) error {
- dom.Find("div.footnotes > hr").Remove()
- return nil
-}
diff --git a/providers/uploadfiles/provider.go b/providers/uploadfiles/provider.go
index 610a6f9..2eb84e4 100644
--- a/providers/uploadfiles/provider.go
+++ b/providers/uploadfiles/provider.go
@@ -66,11 +66,6 @@ func copyFile(src, dst string) error {
return err
}
-func (p *Provider) ReplaceFile(site models.Site, up models.Upload, srcPath string) error {
- fullPath := p.uploadFileName(site, up)
- return copyFile(srcPath, fullPath)
-}
-
func (p *Provider) OpenUpload(site models.Site, up models.Upload) (io.ReadCloser, error) {
fullPath := p.uploadFileName(site, up)
return os.Open(fullPath)
diff --git a/services/imgedit/processing.go b/services/imgedit/processing.go
deleted file mode 100644
index ec84199..0000000
--- a/services/imgedit/processing.go
+++ /dev/null
@@ -1,171 +0,0 @@
-package imgedit
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "image"
- "image/color"
- "os"
- "path/filepath"
-
- "github.com/disintegration/imaging"
- "lmika.dev/lmika/weiro/models"
-)
-
-type imageProcessor struct {
- newParams func() any
- processImage func(ctx context.Context, srcImg image.Image, params any) (image.Image, error)
-}
-
-type shadowProcessorArgs struct {
- Color string `json:"color"`
- OffsetY int `json:"offset_y,string"`
-}
-
-var processors = map[string]imageProcessor{
- "shadow": {
- newParams: func() any {
- return &shadowProcessorArgs{
- Color: "#000000",
- OffsetY: 0,
- }
- },
- processImage: func(ctx context.Context, srcImg image.Image, params any) (image.Image, error) {
- p := params.(*shadowProcessorArgs)
-
- shadowColor, err := parseHexColor(p.Color)
- if err != nil {
- return nil, fmt.Errorf("invalid shadow color: %w", err)
- }
-
- shadow := makeBoxShadow(srcImg, shadowColor, 4, 10, p.OffsetY)
- composit := imaging.OverlayCenter(shadow, srcImg, 1.0)
- return composit, nil
- },
- },
-}
-
-func (s *Service) reprocess(ctx context.Context, session *models.ImageEditSession) (imageSource, error) {
- var img imageSource
-
- for _, p := range session.Processors {
- // Check if there's currently a cached image of this processor
- cachedImageFile := filepath.Join(s.scratchDir, session.GUID, fmt.Sprintf("%v.%v", p.VersionID, session.ImageExt))
- if s, err := os.Stat(cachedImageFile); err == nil && !s.IsDir() {
- img = fileImageSource(cachedImageFile)
- continue
- }
-
- // Need to process the image
- var srcImg image.Image
- if img != nil {
- var err error
- srcImg, err = img.image()
- if err != nil {
- return nil, err
- }
- }
-
- resImg, err := s.processImage(ctx, srcImg, p)
- if err != nil {
- return nil, err
- }
-
- // Cache the processed image
- if err := imaging.Save(resImg, cachedImageFile); err != nil {
- return nil, err
- }
- img = imageImageSource{resImg}
- }
-
- return img, nil
-}
-
-func (s *Service) processImage(ctx context.Context, srcImg image.Image, processor models.ImageEditProcessor) (image.Image, error) {
- switch processor.Type {
- case "copy-upload":
- var p models.CopyUploadProps
- if err := json.Unmarshal(processor.Props, &p); err != nil {
- return nil, err
- }
-
- _, rc, err := s.uploadService.OpenUpload(ctx, p.UploadID)
- if err != nil {
- return nil, err
- }
-
- f, err := rc()
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- return imaging.Decode(f)
- }
-
- proc, ok := processors[processor.Type]
- if !ok {
- return nil, fmt.Errorf("unknown processor type: %v", processor.Type)
- }
-
- paramType := proc.newParams()
- if err := json.Unmarshal(processor.Props, paramType); err != nil {
- return nil, err
- }
- return proc.processImage(ctx, srcImg, paramType)
-}
-
-type imageSource interface {
- image() (image.Image, error)
-}
-
-type fileImageSource string
-
-func (f fileImageSource) image() (image.Image, error) {
- return imaging.Open(string(f))
-}
-
-type imageImageSource struct {
- img image.Image
-}
-
-func (i imageImageSource) image() (image.Image, error) {
- return i.img, nil
-}
-
-func parseHexColor(s string) (color.Color, error) {
- // Remove leading hash if present
- if len(s) > 0 && s[0] == '#' {
- s = s[1:]
- }
-
- // Parse based on length
- var r, g, b, a uint8
- switch len(s) {
- case 6:
- // RGB format
- var rgb uint32
- if _, err := fmt.Sscanf(s, "%06x", &rgb); err != nil {
- return nil, fmt.Errorf("invalid hex color format: %w", err)
- }
- r = uint8((rgb >> 16) & 0xFF)
- g = uint8((rgb >> 8) & 0xFF)
- b = uint8(rgb & 0xFF)
- a = 0xFF
- case 8:
- // RGBA format
- var rgba uint32
- if _, err := fmt.Sscanf(s, "%08x", &rgba); err != nil {
- return nil, fmt.Errorf("invalid hex color format: %w", err)
- }
- r = uint8((rgba >> 24) & 0xFF)
- g = uint8((rgba >> 16) & 0xFF)
- b = uint8((rgba >> 8) & 0xFF)
- a = uint8(rgba & 0xFF)
- default:
- return nil, fmt.Errorf("invalid hex color length: expected 6 or 8 characters, got %d", len(s))
- }
-
- return color.RGBA{R: r, G: g, B: b, A: a}, nil
-}
diff --git a/services/imgedit/service.go b/services/imgedit/service.go
deleted file mode 100644
index 926633c..0000000
--- a/services/imgedit/service.go
+++ /dev/null
@@ -1,266 +0,0 @@
-package imgedit
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "io"
- "time"
-
- "lmika.dev/lmika/weiro/models"
- "lmika.dev/lmika/weiro/services/uploads"
- "lmika.dev/pkg/modash/moslice"
-)
-
-type Service struct {
- scratchDir string
- uploadService *uploads.Service
- sessionStore *sessionStore
-}
-
-func New(
- uploadService *uploads.Service,
- scratchDir string,
-) *Service {
- return &Service{
- scratchDir: scratchDir,
- uploadService: uploadService,
- sessionStore: &sessionStore{baseDir: scratchDir},
- }
-}
-
-func (s *Service) NewSession(ctx context.Context, baseUploadID int64) (*models.ImageEditSession, error) {
- site, user, err := s.fetchSiteAndUser(ctx)
- if err != nil {
- return nil, err
- }
-
- upload, _, err := s.uploadService.OpenUpload(ctx, baseUploadID)
- if err != nil {
- return nil, err
- }
-
- var ext string
- switch upload.MIMEType {
- case "image/jpeg":
- ext = "jpg"
- case "image/png":
- ext = "png"
- default:
- return nil, models.UnsupportedImageFormat
- }
-
- newSession := models.ImageEditSession{
- GUID: models.NewNanoID(),
- SiteID: site.ID,
- UserID: user.ID,
- BaseUploadID: baseUploadID,
- ImageExt: ext,
- CreatedAt: time.Now().UTC(),
- UpdatedAt: time.Now().UTC(),
- Processors: []models.ImageEditProcessor{
- {
- ID: models.NewNanoID(),
- Type: "copy-upload",
- Props: mustToJSON(models.CopyUploadProps{UploadID: baseUploadID}),
- },
- },
- }
-
- newSession.RecalcVersionIDs()
- if err := s.sessionStore.save(&newSession); err != nil {
- return nil, err
- }
-
- if _, err := s.reprocess(ctx, &newSession); err != nil {
- return nil, err
- }
-
- return &newSession, nil
-}
-
-func (s *Service) LoadImageVersion(ctx context.Context, sessionID string, versionID string) (mimeType string, rw func() (io.ReadCloser, error), err error) {
- session, err := s.loadAndVerifySession(ctx, sessionID)
- if err != nil {
- return "", nil, err
- }
-
- return s.sessionStore.getImage(session, versionID+"."+session.ImageExt)
-}
-
-type AddProcessorReq struct {
- Type string `json:"type"`
-}
-
-func (s *Service) AddProcessor(ctx context.Context, sessionID string, req AddProcessorReq) (*models.ImageEditSession, error) {
- session, err := s.loadAndVerifySession(ctx, sessionID)
- if err != nil {
- return nil, err
- }
-
- proc, ok := processors[req.Type]
- if !ok {
- return nil, fmt.Errorf("unknown processor type: %v", req.Type)
- }
-
- paramType := proc.newParams()
- paramBytes, err := json.Marshal(paramType)
- if err != nil {
- return nil, err
- }
-
- session.Processors = append(session.Processors, models.ImageEditProcessor{
- ID: models.NewNanoID(),
- Type: req.Type,
- Props: paramBytes,
- })
-
- session.RecalcVersionIDs()
- if err := s.sessionStore.save(session); err != nil {
- return nil, err
- }
-
- if _, err := s.reprocess(ctx, session); err != nil {
- return nil, err
- }
-
- return session, nil
-}
-
-func (s *Service) DeleteProcessor(ctx context.Context, sessionID, processorID string) (*models.ImageEditSession, error) {
- session, err := s.loadAndVerifySession(ctx, sessionID)
- if err != nil {
- return nil, err
- }
-
- session.Processors = moslice.Filter(session.Processors, func(p models.ImageEditProcessor) bool { return p.ID != processorID })
- session.RecalcVersionIDs()
- if err := s.sessionStore.save(session); err != nil {
- return nil, err
- }
-
- if _, err := s.reprocess(ctx, session); err != nil {
- return nil, err
- }
-
- return session, nil
-}
-
-type UpdateProcessorReq struct {
- ID string `json:"id"`
- Props json.RawMessage `json:"props"`
-}
-
-func (s *Service) UpdateProcessor(ctx context.Context, sessionID string, req UpdateProcessorReq) (*models.ImageEditSession, error) {
- session, err := s.loadAndVerifySession(ctx, sessionID)
- if err != nil {
- return nil, err
- }
-
- for i, p := range session.Processors {
- if p.ID == req.ID {
- session.Processors[i].Props = req.Props
- break
- }
- }
-
- session.RecalcVersionIDs()
- if err := s.sessionStore.save(session); err != nil {
- return nil, err
- }
- if _, err := s.reprocess(ctx, session); err != nil {
- return nil, err
- }
-
- return session, nil
-}
-
-type SaveResult struct {
- UploadID int64 `json:"upload_id"`
-}
-
-func (s *Service) Save(ctx context.Context, sessionID string, mode string) (*SaveResult, error) {
- session, err := s.loadAndVerifySession(ctx, sessionID)
- if err != nil {
- return nil, err
- }
-
- if len(session.Processors) == 0 {
- return nil, fmt.Errorf("no processors in session")
- }
-
- lastProc := session.Processors[len(session.Processors)-1]
- finalImagePath := fmt.Sprintf("%v/%v/%v.%v", s.scratchDir, session.GUID, lastProc.VersionID, session.ImageExt)
-
- var mimeType string
- switch session.ImageExt {
- case "jpg", "jpeg":
- mimeType = "image/jpeg"
- case "png":
- mimeType = "image/png"
- }
-
- var uploadID int64
- switch mode {
- case "replace":
- upload, err := s.uploadService.ReplaceUploadFile(ctx, session.BaseUploadID, finalImagePath)
- if err != nil {
- return nil, err
- }
- uploadID = upload.ID
- case "copy":
- baseUpload, _, err := s.uploadService.OpenUpload(ctx, session.BaseUploadID)
- if err != nil {
- return nil, err
- }
- upload, err := s.uploadService.CreateUploadFromFile(ctx, finalImagePath, baseUpload.Filename, mimeType)
- if err != nil {
- return nil, err
- }
- uploadID = upload.ID
- default:
- return nil, fmt.Errorf("unknown save mode: %v", mode)
- }
-
- s.sessionStore.delete(session.GUID)
-
- return &SaveResult{UploadID: uploadID}, nil
-}
-
-func (s *Service) loadAndVerifySession(ctx context.Context, sessionID string) (*models.ImageEditSession, error) {
- site, user, err := s.fetchSiteAndUser(ctx)
- if err != nil {
- return nil, err
- }
-
- session, err := s.sessionStore.get(sessionID)
- if err != nil {
- return nil, err
- } else if session.SiteID != site.ID || session.UserID != user.ID {
- return nil, models.PermissionError
- }
- return session, nil
-}
-
-func (s *Service) fetchSiteAndUser(ctx context.Context) (models.Site, models.User, error) {
- user, ok := models.GetUser(ctx)
- if !ok {
- return models.Site{}, models.User{}, models.UserRequiredError
- }
-
- site, ok := models.GetSite(ctx)
- if !ok {
- return models.Site{}, models.User{}, models.SiteRequiredError
- }
-
- if site.OwnerID != user.ID {
- return models.Site{}, models.User{}, models.PermissionError
- }
-
- return site, user, nil
-}
-
-func mustToJSON(a any) json.RawMessage {
- b, _ := json.Marshal(a)
- return b
-}
diff --git a/services/imgedit/shadow.go b/services/imgedit/shadow.go
deleted file mode 100644
index 4a308d0..0000000
--- a/services/imgedit/shadow.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package imgedit
-
-import (
- "image"
- "image/color"
-
- "github.com/disintegration/imaging"
-)
-
-func makeBoxShadow(maskImg image.Image, shadowColor color.Color, sigma float64, shadowMargin, offsetY int) image.Image {
- w, h := maskImg.Bounds().Dx(), maskImg.Bounds().Dy()
- cr, cg, cb, _ := shadowColor.RGBA()
- cr8, cg8, cb8 := uint8(cr>>8), uint8(cg>>8), uint8(cb>>8)
-
- // New box image
- backing := image.NewNRGBA(image.Rect(0, 0, w+shadowMargin*2, h+shadowMargin*2+offsetY))
- newImg := image.NewNRGBA(image.Rect(0, 0, w+shadowMargin*2, h+shadowMargin*2+offsetY))
- for x := 0; x < w+shadowMargin*2; x++ {
- for y := 0; y < h+shadowMargin*2; y++ {
- var c = color.NRGBA{R: 255, G: 255, B: 255, A: 0}
- if x >= shadowMargin-4 && y >= shadowMargin-4 && x <= w+shadowMargin+4 && y <= h+shadowMargin+4 {
- _, _, _, a := maskImg.At(x-shadowMargin, y-shadowMargin).RGBA()
- c = color.NRGBA{R: cr8, G: cg8, B: cb8, A: uint8(a >> 8)}
- }
- backing.SetNRGBA(x, y, color.NRGBA{R: 255, G: 255, B: 255, A: 0})
- newImg.SetNRGBA(x, y+offsetY, c)
- }
- }
-
- // Blur
- blurredImage := imaging.Blur(newImg, sigma)
- backing = imaging.OverlayCenter(backing, blurredImage, 0.6)
-
- return backing
-}
diff --git a/services/imgedit/store.go b/services/imgedit/store.go
deleted file mode 100644
index df3403a..0000000
--- a/services/imgedit/store.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package imgedit
-
-import (
- "encoding/json"
- "io"
- "os"
- "path/filepath"
-
- "lmika.dev/lmika/weiro/models"
-)
-
-type sessionStore struct {
- baseDir string
-}
-
-func (ss *sessionStore) save(newSession *models.ImageEditSession) error {
- sessionMeta, err := json.Marshal(newSession)
- if err != nil {
- return err
- }
-
- if err := os.MkdirAll(filepath.Join(ss.baseDir, newSession.GUID), 0755); err != nil {
- return err
- }
- if err := os.WriteFile(filepath.Join(ss.baseDir, newSession.GUID, "session.json"), sessionMeta, 0644); err != nil {
- return err
- }
- return nil
-}
-
-func (ss *sessionStore) get(guid string) (*models.ImageEditSession, error) {
- sessionDataBts, err := os.ReadFile(filepath.Join(ss.baseDir, guid, "session.json"))
- if err != nil {
- return nil, err
- }
-
- sessionData := models.ImageEditSession{}
- if err := json.Unmarshal(sessionDataBts, &sessionData); err != nil {
- return nil, err
- }
-
- return &sessionData, nil
-}
-
-func (ss *sessionStore) delete(guid string) {
- os.RemoveAll(filepath.Join(ss.baseDir, guid))
-}
-
-func (ss *sessionStore) getImage(session *models.ImageEditSession, imageFilename string) (string, func() (io.ReadCloser, error), error) {
- fullPath := filepath.Join(ss.baseDir, session.GUID, imageFilename)
- if s, err := os.Stat(fullPath); err != nil {
- return "", nil, err
- } else if s.IsDir() {
- return "", nil, os.ErrNotExist
- }
-
- var mimeType string
- switch filepath.Ext(imageFilename) {
- case ".jpg", ".jpeg":
- mimeType = "image/jpeg"
- case ".png":
- mimeType = "image/png"
- default:
- return "", nil, models.UnsupportedImageFormat
- }
-
- return mimeType, func() (io.ReadCloser, error) {
- return os.Open(fullPath)
- }, nil
-}
diff --git a/services/obsimport/service.go b/services/obsimport/service.go
deleted file mode 100644
index 0852031..0000000
--- a/services/obsimport/service.go
+++ /dev/null
@@ -1,229 +0,0 @@
-package obsimport
-
-import (
- "archive/zip"
- "bufio"
- "context"
- "fmt"
- "io"
- "log"
- "mime"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- "lmika.dev/lmika/weiro/models"
- "lmika.dev/lmika/weiro/providers/db"
- "lmika.dev/lmika/weiro/providers/uploadfiles"
- "lmika.dev/lmika/weiro/services/publisher"
-)
-
-type Service struct {
- db *db.Provider
- up *uploadfiles.Provider
- publisher *publisher.Queue
- scratchDir string
-}
-
-func New(db *db.Provider, up *uploadfiles.Provider, publisher *publisher.Queue, scratchDir string) *Service {
- return &Service{
- db: db,
- up: up,
- publisher: publisher,
- scratchDir: scratchDir,
- }
-}
-
-type ImportResult struct {
- PostsImported int
- UploadsImported int
-}
-
-func (s *Service) ImportZip(ctx context.Context, zipPath string) (ImportResult, error) {
- site, ok := models.GetSite(ctx)
- if !ok {
- return ImportResult{}, models.SiteRequiredError
- }
-
- zr, err := zip.OpenReader(zipPath)
- if err != nil {
- return ImportResult{}, fmt.Errorf("open zip: %w", err)
- }
- defer zr.Close()
-
- var result ImportResult
-
- for _, f := range zr.File {
- if f.FileInfo().IsDir() {
- continue
- }
-
- ext := strings.ToLower(filepath.Ext(f.Name))
- if ext == ".md" || ext == ".markdown" {
- if err := s.importNote(ctx, site, f); err != nil {
- log.Printf("warn: skipping note %s: %v", f.Name, err)
- continue
- }
- result.PostsImported++
- } else if isAttachment(ext) {
- if err := s.importAttachment(ctx, site, f); err != nil {
- log.Printf("warn: skipping attachment %s: %v", f.Name, err)
- continue
- }
- result.UploadsImported++
- }
- }
-
- s.publisher.Queue(site)
-
- return result, nil
-}
-
-func (s *Service) importNote(ctx context.Context, site models.Site, f *zip.File) error {
- rc, err := f.Open()
- if err != nil {
- return err
- }
- defer rc.Close()
-
- data, err := io.ReadAll(rc)
- if err != nil {
- return err
- }
-
- body := stripFrontMatter(string(data))
- title := strings.TrimSuffix(filepath.Base(f.Name), filepath.Ext(f.Name))
- publishedAt := f.Modified
- if publishedAt.IsZero() {
- publishedAt = time.Now()
- }
-
- renderTZ, err := time.LoadLocation(site.Timezone)
- if err != nil {
- renderTZ = time.UTC
- }
- publishedAt = publishedAt.In(renderTZ)
-
- post := &models.Post{
- SiteID: site.ID,
- GUID: models.NewNanoID(),
- State: models.StatePublished,
- Title: title,
- Body: body,
- CreatedAt: time.Now(),
- UpdatedAt: time.Now(),
- PublishedAt: publishedAt,
- }
- post.Slug = post.BestSlug()
-
- return s.db.SavePost(ctx, post)
-}
-
-func (s *Service) importAttachment(ctx context.Context, site models.Site, f *zip.File) error {
- rc, err := f.Open()
- if err != nil {
- return err
- }
- defer rc.Close()
-
- // Write to a temp file in scratch dir
- if err := os.MkdirAll(s.scratchDir, 0755); err != nil {
- return err
- }
-
- tmpFile, err := os.CreateTemp(s.scratchDir, "obsimport-*"+filepath.Ext(f.Name))
- if err != nil {
- return err
- }
- tmpPath := tmpFile.Name()
-
- if _, err := io.Copy(tmpFile, rc); err != nil {
- tmpFile.Close()
- os.Remove(tmpPath)
- return err
- }
- tmpFile.Close()
-
- filename := filepath.Base(f.Name)
- mimeType := mime.TypeByExtension(filepath.Ext(filename))
- if mimeType == "" {
- mimeType = "application/octet-stream"
- }
-
- stat, err := os.Stat(tmpPath)
- if err != nil {
- os.Remove(tmpPath)
- return err
- }
-
- newUploadGUID := models.NewNanoID()
- newTime := time.Now().UTC()
- newSlug := filepath.Join(
- fmt.Sprintf("%04d", newTime.Year()),
- fmt.Sprintf("%02d", newTime.Month()),
- newUploadGUID+filepath.Ext(filename),
- )
-
- newUpload := models.Upload{
- SiteID: site.ID,
- GUID: models.NewNanoID(),
- FileSize: stat.Size(),
- MIMEType: mimeType,
- Filename: filename,
- CreatedAt: newTime,
- Slug: newSlug,
- }
- if err := s.db.SaveUpload(ctx, &newUpload); err != nil {
- os.Remove(tmpPath)
- return err
- }
-
- if err := s.up.AdoptFile(site, newUpload, tmpPath); err != nil {
- os.Remove(tmpPath)
- return err
- }
-
- return nil
-}
-
-// stripFrontMatter removes YAML front matter (delimited by ---) from markdown content.
-func stripFrontMatter(content string) string {
- scanner := bufio.NewScanner(strings.NewReader(content))
-
- // Check if the first line is a front matter delimiter
- if !scanner.Scan() {
- return content
- }
- firstLine := strings.TrimSpace(scanner.Text())
- if firstLine != "---" {
- return content
- }
-
- // Skip until the closing ---
- for scanner.Scan() {
- if strings.TrimSpace(scanner.Text()) == "---" {
- // Return everything after the closing delimiter
- var rest strings.Builder
- for scanner.Scan() {
- rest.WriteString(scanner.Text())
- rest.WriteString("\n")
- }
- return strings.TrimLeft(rest.String(), "\n")
- }
- }
-
- // No closing delimiter found, return original content
- return content
-}
-
-var attachmentExts = map[string]bool{
- ".png": true, ".jpg": true, ".jpeg": true, ".gif": true, ".svg": true, ".webp": true,
- ".bmp": true, ".ico": true, ".tiff": true, ".tif": true,
- ".mp3": true, ".mp4": true, ".wav": true, ".ogg": true, ".webm": true,
- ".pdf": true, ".doc": true, ".docx": true, ".xls": true, ".xlsx": true,
-}
-
-func isAttachment(ext string) bool {
- return attachmentExts[ext]
-}
diff --git a/services/obsimport/service_test.go b/services/obsimport/service_test.go
deleted file mode 100644
index 51123de..0000000
--- a/services/obsimport/service_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package obsimport
-
-import "testing"
-
-func TestStripFrontMatter(t *testing.T) {
- tests := []struct {
- name string
- input string
- want string
- }{
- {
- name: "no front matter",
- input: "Hello world\nThis is a note",
- want: "Hello world\nThis is a note",
- },
- {
- name: "with front matter",
- input: "---\ntitle: Test\ntags: [a, b]\n---\nHello world\nThis is a note\n",
- want: "Hello world\nThis is a note\n",
- },
- {
- name: "only front matter",
- input: "---\ntitle: Test\n---\n",
- want: "",
- },
- {
- name: "unclosed front matter",
- input: "---\ntitle: Test\nno closing delimiter",
- want: "---\ntitle: Test\nno closing delimiter",
- },
- {
- name: "empty string",
- input: "",
- want: "",
- },
- {
- name: "front matter with leading newlines stripped",
- input: "---\nkey: val\n---\n\n\nBody here\n",
- want: "Body here\n",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := stripFrontMatter(tt.input)
- if got != tt.want {
- t.Errorf("stripFrontMatter() = %q, want %q", got, tt.want)
- }
- })
- }
-}
diff --git a/services/publisher/iter.go b/services/publisher/iter.go
index d07d4fe..ea70616 100644
--- a/services/publisher/iter.go
+++ b/services/publisher/iter.go
@@ -9,10 +9,10 @@ import (
)
// postIter returns a post iterator which returns posts in reverse chronological order.
-func (s *Publisher) publishedPostIter(ctx context.Context, site int64) iter.Seq[models.Maybe[*models.Post]] {
+func (s *Publisher) postIter(ctx context.Context, site int64) iter.Seq[models.Maybe[*models.Post]] {
return func(yield func(models.Maybe[*models.Post]) bool) {
paging := db.PagingParams{Offset: 0, Limit: 50}
- page, err := s.db.SelectPublishedPostsOfSite(ctx, site, paging)
+ page, err := s.db.SelectPostsOfSite(ctx, site, false, paging)
if err != nil {
yield(models.Maybe[*models.Post]{Err: err})
return
@@ -45,7 +45,7 @@ func (s *Publisher) postIterByCategory(ctx context.Context, categoryID int64) it
return func(yield func(models.Maybe[*models.Post]) bool) {
paging := db.PagingParams{Offset: 0, Limit: 50}
for {
- page, err := s.db.SelectPublishedPostsOfCategory(ctx, categoryID, paging)
+ page, err := s.db.SelectPostsOfCategory(ctx, categoryID, paging)
if err != nil {
yield(models.Maybe[*models.Post]{Err: err})
return
diff --git a/services/publisher/service.go b/services/publisher/service.go
index a5072a5..adfcdd7 100644
--- a/services/publisher/service.go
+++ b/services/publisher/service.go
@@ -79,7 +79,7 @@ func (p *Publisher) Publish(ctx context.Context, site models.Site) error {
pubSite := pubmodel.Site{
Site: site,
PostIter: func(ctx context.Context) iter.Seq[models.Maybe[*models.Post]] {
- return p.publishedPostIter(ctx, site.ID)
+ return p.postIter(ctx, site.ID)
},
BaseURL: target.BaseURL,
Uploads: uploads,
diff --git a/services/services.go b/services/services.go
index a79e903..852dea3 100644
--- a/services/services.go
+++ b/services/services.go
@@ -8,8 +8,6 @@ import (
"lmika.dev/lmika/weiro/providers/uploadfiles"
"lmika.dev/lmika/weiro/services/auth"
"lmika.dev/lmika/weiro/services/categories"
- "lmika.dev/lmika/weiro/services/imgedit"
- "lmika.dev/lmika/weiro/services/obsimport"
"lmika.dev/lmika/weiro/services/pages"
"lmika.dev/lmika/weiro/services/posts"
"lmika.dev/lmika/weiro/services/publisher"
@@ -25,10 +23,8 @@ type Services struct {
Posts *posts.Service
Sites *sites.Service
Uploads *uploads.Service
- ImageEdit *imgedit.Service
Categories *categories.Service
Pages *pages.Service
- ObsImport *obsimport.Service
}
func New(cfg config.Config) (*Services, error) {
@@ -45,10 +41,8 @@ func New(cfg config.Config) (*Services, error) {
postService := posts.New(dbp, publisherQueue)
siteService := sites.New(dbp)
uploadService := uploads.New(dbp, ufp, filepath.Join(cfg.ScratchDir, "uploads", "pending"))
- imageEditService := imgedit.New(uploadService, filepath.Join(cfg.ScratchDir, "imageedit"))
categoriesService := categories.New(dbp, publisherQueue)
pagesService := pages.New(dbp, publisherQueue)
- obsImportService := obsimport.New(dbp, ufp, publisherQueue, filepath.Join(cfg.ScratchDir, "obsimport"))
return &Services{
DB: dbp,
@@ -58,10 +52,8 @@ func New(cfg config.Config) (*Services, error) {
Posts: postService,
Sites: siteService,
Uploads: uploadService,
- ImageEdit: imageEditService,
Categories: categoriesService,
Pages: pagesService,
- ObsImport: obsImportService,
}, nil
}
diff --git a/services/uploads/manage.go b/services/uploads/manage.go
index 9cb24ea..32debac 100644
--- a/services/uploads/manage.go
+++ b/services/uploads/manage.go
@@ -6,10 +6,7 @@ import (
"html/template"
"io"
"log"
- "os"
- "path/filepath"
"strings"
- "time"
"lmika.dev/lmika/weiro/models"
)
@@ -70,75 +67,6 @@ func (s *Service) renderCopyTemplate(upload models.Upload) string {
return sb.String()
}
-func (s *Service) ReplaceUploadFile(ctx context.Context, uploadID int64, srcPath string) (models.Upload, error) {
- site, _, err := s.fetchSiteAndUser(ctx)
- if err != nil {
- return models.Upload{}, err
- }
-
- upload, err := s.db.SelectUploadByID(ctx, uploadID)
- if err != nil {
- return models.Upload{}, err
- } else if upload.SiteID != site.ID {
- return models.Upload{}, models.NotFoundError
- }
-
- if err := s.up.ReplaceFile(site, upload, srcPath); err != nil {
- return models.Upload{}, err
- }
-
- stat, err := os.Stat(srcPath)
- if err != nil {
- return models.Upload{}, err
- }
- upload.FileSize = stat.Size()
-
- if err := s.db.UpdateUploadFileSize(ctx, upload.ID, upload.FileSize); err != nil {
- return models.Upload{}, err
- }
-
- return upload, nil
-}
-
-func (s *Service) CreateUploadFromFile(ctx context.Context, srcPath string, filename string, mimeType string) (models.Upload, error) {
- site, _, err := s.fetchSiteAndUser(ctx)
- if err != nil {
- return models.Upload{}, err
- }
-
- stat, err := os.Stat(srcPath)
- if err != nil {
- return models.Upload{}, err
- }
-
- newUploadGUID := models.NewNanoID()
- newTime := time.Now().UTC()
- newSlug := filepath.Join(
- fmt.Sprintf("%04d", newTime.Year()),
- fmt.Sprintf("%02d", newTime.Month()),
- newUploadGUID+filepath.Ext(filename),
- )
-
- newUpload := models.Upload{
- SiteID: site.ID,
- GUID: models.NewNanoID(),
- FileSize: stat.Size(),
- MIMEType: mimeType,
- Filename: filename,
- CreatedAt: newTime,
- Slug: newSlug,
- }
- if err := s.db.SaveUpload(ctx, &newUpload); err != nil {
- return models.Upload{}, err
- }
-
- if err := s.up.AdoptFile(site, newUpload, srcPath); err != nil {
- return models.Upload{}, err
- }
-
- return newUpload, nil
-}
-
func (s *Service) ListUploads(ctx context.Context) (res []UploadWithURL, _ error) {
site, _, err := s.fetchSiteAndUser(ctx)
if err != nil {
diff --git a/sql/queries/categories.sql b/sql/queries/categories.sql
index b8e0e64..4b48506 100644
--- a/sql/queries/categories.sql
+++ b/sql/queries/categories.sql
@@ -17,7 +17,7 @@ INNER JOIN post_categories pc ON pc.category_id = c.id
WHERE pc.post_id = ?
ORDER BY c.name ASC;
--- name: SelectPublishedPostsOfCategory :many
+-- name: SelectPostsOfCategory :many
SELECT p.* FROM posts p
INNER JOIN post_categories pc ON pc.post_id = p.id
WHERE pc.category_id = ? AND p.state = 0 AND p.deleted_at = 0
diff --git a/sql/queries/posts.sql b/sql/queries/posts.sql
index feaae7f..5a4c18e 100644
--- a/sql/queries/posts.sql
+++ b/sql/queries/posts.sql
@@ -17,12 +17,6 @@ WHERE site_id = sqlc.arg(site_id) AND (
END
) ORDER BY created_at DESC LIMIT sqlc.arg(limit) OFFSET sqlc.arg(offset);
--- name: SelectPublishedPostsOfSite :many
-SELECT *
-FROM posts
-WHERE site_id = sqlc.arg(site_id) AND state = 0 AND deleted_at = 0
-ORDER BY published_at DESC LIMIT sqlc.arg(limit) OFFSET sqlc.arg(offset);
-
-- name: SelectPost :one
SELECT * FROM posts WHERE id = ? LIMIT 1;
diff --git a/sql/queries/uploads.sql b/sql/queries/uploads.sql
index f661591..fc8b82d 100644
--- a/sql/queries/uploads.sql
+++ b/sql/queries/uploads.sql
@@ -7,7 +7,7 @@ SELECT * FROM uploads WHERE id = ? LIMIT 1;
-- name: SelectUploadBySiteIDAndSlug :one
SELECT * FROM uploads WHERE site_id = ? AND slug = ? LIMIT 1;
--- name: InsertUpload :one
+-- name: InsertUpload :exec
INSERT INTO uploads (
site_id,
guid,
@@ -23,8 +23,5 @@ RETURNING id;
-- name: UpdateUpload :exec
UPDATE uploads SET alt = ? WHERE id = ?;
--- name: UpdateUploadFileSize :exec
-UPDATE uploads SET file_size = ? WHERE id = ?;
-
-- name: DeleteUpload :exec
DELETE FROM uploads WHERE id = ?;
\ No newline at end of file
diff --git a/views/obsimport/form.html b/views/obsimport/form.html
deleted file mode 100644
index ccb27a5..0000000
--- a/views/obsimport/form.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
Import from Obsidian
-
Select an Obsidian vault exported as a Zip file. All Markdown notes will be imported as posts, and any images or attachments will be imported as uploads.
-
-
-
diff --git a/views/obsimport/result.html b/views/obsimport/result.html
deleted file mode 100644
index 15ebe31..0000000
--- a/views/obsimport/result.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
Import Complete
-
-
Successfully imported {{ .result.PostsImported }} post(s) and {{ .result.UploadsImported }} upload(s).
-
-
Go to Posts
-
Back to Settings
-
-
diff --git a/views/posts/edit.html b/views/posts/edit.html
index fbb94fa..b9f5ea7 100644
--- a/views/posts/edit.html
+++ b/views/posts/edit.html
@@ -1,5 +1,5 @@
{{ $isPublished := ne .post.State 1 }}
-
+
-
-
-
-
Import Obsidian
-
Import posts and attachments from an Obsidian vault zip file.
-
-
\ No newline at end of file
diff --git a/views/uploads/edit.html b/views/uploads/edit.html
deleted file mode 100644
index a7b27ab..0000000
--- a/views/uploads/edit.html
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- Add Processor
-
-
-
-
-
-
-
-
- Save
- Save as Copy
-
-
\ No newline at end of file
diff --git a/views/uploads/show.html b/views/uploads/show.html
index 7b42a38..087c10f 100644
--- a/views/uploads/show.html
+++ b/views/uploads/show.html
@@ -5,10 +5,7 @@
data-show-upload-site-id-value="{{ .upload.Upload.SiteID }}"
data-show-upload-upload-id-value="{{ .upload.Upload.ID }}">
Copy HTML
-
- Edit
- Delete
-
+ Delete