Item sharing progress

This commit is contained in:
roberto 2025-04-04 17:56:53 +02:00
parent 34054eb1df
commit 007cb94891
9 changed files with 78 additions and 9 deletions

View file

@ -26,7 +26,7 @@
<p style="margin-right: 6px"> <p style="margin-right: 6px">
<label for="share-token">Share Url</label> <label for="share-token">Share Url</label>
<div class="input-container"> <div class="input-container">
<span class="prefix">{{ .baseUrl }}/</span> <span class="prefix">{{ .baseUrl }}/item/share/</span>
<input name="Token" id="share-token" type="url" readonly="readonly" value="{{ .shareToken }}" /> <input name="Token" id="share-token" type="url" readonly="readonly" value="{{ .shareToken }}" />
</div> </div>
</p> </p>

View file

@ -26,7 +26,7 @@
<p style="margin-right: 6px"> <p style="margin-right: 6px">
<label for="share-token">Share Url</label> <label for="share-token">Share Url</label>
<div class="input-container"> <div class="input-container">
<span class="prefix">{{ .baseUrl }}/</span> <span class="prefix">{{ .baseUrl }}/item/share/</span>
<input name="Token" id="share-token" type="url" readonly="readonly" value="{{ .itemShare.Token }}" /> <input name="Token" id="share-token" type="url" readonly="readonly" value="{{ .itemShare.Token }}" />
</div> </div>
</p> </p>

View file

@ -0,0 +1,4 @@
{{define "page:content"}}
Shared item FOUND
{{ .itemShare.ItemTitle}}
{{end}}

View file

@ -0,0 +1,3 @@
{{define "page:content"}}
Shared item not found
{{end}}

View file

@ -134,7 +134,7 @@ func (app *application) signup(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r) data := app.newTemplateData(r)
data["Form"] = form data["Form"] = form
err := response.Page(w, http.StatusUnprocessableEntity, data, []string{"pages/signup.tmpl"}, "full") err := response.GuestPage(w, http.StatusUnprocessableEntity, data, []string{"pages/signup.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }
@ -183,7 +183,7 @@ func (app *application) login(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r) data := app.newTemplateData(r)
data["Form"] = form data["Form"] = form
err := response.Page(w, http.StatusOK, data, []string{"pages/login.tmpl"}, "full") err := response.GuestPage(w, http.StatusOK, data, []string{"pages/login.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }
@ -280,7 +280,7 @@ func (app *application) forgottenPassword(w http.ResponseWriter, r *http.Request
data := app.newTemplateData(r) data := app.newTemplateData(r)
data["Form"] = form data["Form"] = form
err := response.Page(w, http.StatusOK, data, []string{"pages/forgotten-password.tmpl"}, "full") err := response.GuestPage(w, http.StatusOK, data, []string{"pages/forgotten-password.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }
@ -343,7 +343,7 @@ func (app *application) forgottenPassword(w http.ResponseWriter, r *http.Request
func (app *application) forgottenPasswordConfirmation(w http.ResponseWriter, r *http.Request) { func (app *application) forgottenPasswordConfirmation(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r) data := app.newTemplateData(r)
err := response.Page(w, http.StatusOK, data, []string{"pages/forgotten-password-confirmation.tmpl"}, "full") err := response.GuestPage(w, http.StatusOK, data, []string{"pages/forgotten-password-confirmation.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }
@ -364,7 +364,7 @@ func (app *application) passwordReset(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r) data := app.newTemplateData(r)
data["InvalidLink"] = true data["InvalidLink"] = true
err := response.Page(w, http.StatusUnprocessableEntity, data, []string{"pages/password-reset.tmpl"}, "full") err := response.GuestPage(w, http.StatusUnprocessableEntity, data, []string{"pages/password-reset.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }
@ -404,7 +404,7 @@ func (app *application) passwordReset(w http.ResponseWriter, r *http.Request) {
data["Form"] = form data["Form"] = form
data["PlaintextToken"] = plaintextToken data["PlaintextToken"] = plaintextToken
err := response.Page(w, http.StatusUnprocessableEntity, data, []string{"pages/password-reset.tmpl"}, "full") err := response.GuestPage(w, http.StatusUnprocessableEntity, data, []string{"pages/password-reset.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }
@ -436,7 +436,7 @@ func (app *application) passwordReset(w http.ResponseWriter, r *http.Request) {
func (app *application) passwordResetConfirmation(w http.ResponseWriter, r *http.Request) { func (app *application) passwordResetConfirmation(w http.ResponseWriter, r *http.Request) {
data := app.newTemplateData(r) data := app.newTemplateData(r)
err := response.Page(w, http.StatusOK, data, []string{"pages/password-reset-confirmation.tmpl"}, "full") err := response.GuestPage(w, http.StatusOK, data, []string{"pages/password-reset-confirmation.tmpl"}, "full")
if err != nil { if err != nil {
app.serverError(w, r, err) app.serverError(w, r, err)
} }

View file

@ -3,6 +3,7 @@ package main
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/justinas/nosurf"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@ -1125,6 +1126,33 @@ func (app *application) itemShareEdit(w http.ResponseWriter, r *http.Request) {
} }
} }
func (app *application) itemShared(w http.ResponseWriter, r *http.Request) {
token := flow.Param(r.Context(), "token")
itemShareModel := models.NewItemShareModel(app.db)
itemShare, found, _ := itemShareModel.OneByToken(token)
data := map[string]any{"CSRFToken": nosurf.Token(r)}
if !found {
err := response.GuestPage(w, http.StatusOK, data, []string{"items/shared_not_found.tmpl"})
if err != nil {
app.serverError(w, r, err)
}
} else {
//Check dates
//Does it need a password ?
switch r.Method {
case http.MethodGet:
data["itemShare"] = itemShare
err := response.GuestPage(w, http.StatusOK, data, []string{"items/shared.tmpl"})
if err != nil {
app.serverError(w, r, err)
}
case http.MethodPost:
}
}
}
func (app *application) itemAddToDashboard(w http.ResponseWriter, r *http.Request) { func (app *application) itemAddToDashboard(w http.ResponseWriter, r *http.Request) {
itemModel := models.NewItemModel(app.db) itemModel := models.NewItemModel(app.db)
itemId, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64) itemId, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)

View file

@ -27,6 +27,7 @@ func (app *application) routes() http.Handler {
mux.Group(func(mux *flow.Mux) { mux.Group(func(mux *flow.Mux) {
mux.Use(app.requireAnonymousUser) mux.Use(app.requireAnonymousUser)
mux.HandleFunc("/login", app.login, "GET", "POST") mux.HandleFunc("/login", app.login, "GET", "POST")
mux.HandleFunc("/item/shared/:token", app.itemShared, "GET", "POST")
}) })
mux.Group(func(mux *flow.Mux) { mux.Group(func(mux *flow.Mux) {

View file

@ -52,6 +52,22 @@ func Fragment(pagePaths []string, templateName string, data any) (*bytes.Buffer,
return buf, err return buf, err
} }
func GuestPage(w http.ResponseWriter, status int, data any, pagePaths []string, templateNames ...string) error {
templateName := "full"
if len(templateNames) > 0 {
templateName = templateNames[0]
}
return GuestPageWithHeaders(w, status, data, nil, pagePaths, templateName)
}
func GuestPageWithHeaders(w http.ResponseWriter, status int, data any, headers http.Header, pagePaths []string, templateName string) error {
templateFile := templateName + ".tmpl"
pagePaths = append(pagePaths, templateFile)
return NamedTemplateWithHeaders(w, status, data, headers, templateName, pagePaths)
}
func Page(w http.ResponseWriter, status int, data any, pagePaths []string, templateNames ...string) error { func Page(w http.ResponseWriter, status int, data any, pagePaths []string, templateNames ...string) error {
templateName := "base" templateName := "base"

View file

@ -38,6 +38,23 @@ func (model *ItemShareModel) One(id int64) (*ItemShare, bool, error) {
return &row, true, err return &row, true, err
} }
func (model *ItemShareModel) OneByToken(token string) (*ItemShare, bool, error) {
ctx, cancel := database.GetContext()
defer cancel()
var row ItemShare
query := `SELECT bmi.title AS item_title, bmis.* FROM bm_item_shares bmis
INNER JOIN bm_item bmi ON bmis.item_id=bmi.id WHERE bmis.token = $1`
err := model.DB.GetContext(ctx, &row, query, token)
if errors.Is(err, sql.ErrNoRows) {
return nil, false, nil
}
return &row, true, err
}
func (model *ItemShareModel) Create(ItemShare *ItemShare) (int64, error) { func (model *ItemShareModel) Create(ItemShare *ItemShare) (int64, error) {
ctx, cancel := database.GetContext() ctx, cancel := database.GetContext()
defer cancel() defer cancel()