diff --git a/assets/migrations/000014_create_bm_item_shares_table.up.sql b/assets/migrations/000014_create_bm_item_shares_table.up.sql index 115238c..5752507 100644 --- a/assets/migrations/000014_create_bm_item_shares_table.up.sql +++ b/assets/migrations/000014_create_bm_item_shares_table.up.sql @@ -1,10 +1,11 @@ CREATE TABLE "bm_item_shares" ( "id" INTEGER, "token" TEXT NOT NULL UNIQUE, - "item_id" INTEGER DEFAULT 0, - "read" INTEGER DEFAULT 0, - "update" INTEGER DEFAULT 0, - "start_datetime" TEXT DEFAULT 0, - "end_datetime" TEXT DEFAULT 0, + "item_id" INTEGER DEFAULT '', + "read" INTEGER DEFAULT '', + "update" INTEGER DEFAULT '', + "start_datetime" TEXT DEFAULT '', + "end_datetime" TEXT DEFAULT '', + "password" TEXT DEFAULT '', PRIMARY KEY("id" AUTOINCREMENT) ); \ No newline at end of file diff --git a/assets/static/css/main.css b/assets/static/css/main.css index 60d19ea..eaacc8f 100644 --- a/assets/static/css/main.css +++ b/assets/static/css/main.css @@ -517,7 +517,8 @@ a { width: 18px; height: 18px; position: relative; - top: 6px + top: 6px; + accent-color: #2b5797; } .w3-sidebar { diff --git a/assets/static/js/serviceWorker.js b/assets/static/js/serviceWorker.js index bf14e82..4b343e3 100644 --- a/assets/static/js/serviceWorker.js +++ b/assets/static/js/serviceWorker.js @@ -1,4 +1,4 @@ -const cacheVersion = "0.266" +const cacheVersion = "0.267" const cacheName = "speedtech-brainminder" const cacheFiles = [ '/static/bootstrap-icons/font/bootstrap-icons.min.css', diff --git a/assets/templates/items/form.tmpl b/assets/templates/items/form.tmpl index a22ff3e..3a4d65e 100644 --- a/assets/templates/items/form.tmpl +++ b/assets/templates/items/form.tmpl @@ -112,6 +112,7 @@

On dashboard +

diff --git a/assets/templates/types/form.tmpl b/assets/templates/types/form.tmpl index 8459dcb..7c80cf7 100644 --- a/assets/templates/types/form.tmpl +++ b/assets/templates/types/form.tmpl @@ -68,6 +68,7 @@

Show summary +

Show description +

diff --git a/cmd/web/items_handlers.go b/cmd/web/items_handlers.go index b38b5ab..e015d26 100644 --- a/cmd/web/items_handlers.go +++ b/cmd/web/items_handlers.go @@ -34,6 +34,18 @@ type itemForm struct { Validator validator.Validator `form:"-"` } +type itemShareForm struct { + Id int64 `form:"Id"` + Item_id int64 `form:"Item_id"` + Token string `form:"Token"` + Start_datetime string `form:"start_datetime"` + End_datetime string `form:"end_datetime"` + Password string `form:"password"` + Permission_read int `form:"read"` + Permission_edit int `form:"edit"` + Validator validator.Validator `form:"-"` +} + func (form *itemForm) Validate(w http.ResponseWriter, r *http.Request, app *application, data map[string]any) bool { var fullBuf = new(bytes.Buffer) @@ -60,6 +72,32 @@ func (form *itemForm) Validate(w http.ResponseWriter, r *http.Request, app *appl return true } +func (form *itemShareForm) Validate(w http.ResponseWriter, r *http.Request, app *application, data map[string]any) bool { + var fullBuf = new(bytes.Buffer) + + //form.Validator.CheckField(form.Title != "", "Title", "Title is required") + //form.Validator.CheckField(form.Description != "", "Description", "Description is required") + + if form.Validator.HasErrors() { + w.Header().Add("HX-Retarget", "#message") + + data["messageType"] = "failure" + data["messageContent"] = "Impossible to save the item" + data["messageFieldErrors"] = form.Validator.FieldErrors + + err := response.HXFragment(fullBuf, []string{"partials/message.tmpl"}, "message", data) + if err != nil { + app.serverError(w, r, err) + } + fullBuf.WriteTo(w) + + w.WriteHeader(http.StatusUnprocessableEntity) + return false + } + + return true +} + func (app *application) itemsRelationAdd(w http.ResponseWriter, r *http.Request) { data := app.newTemplateData(r) itemModel := models.NewItemModel(app.db) @@ -862,19 +900,47 @@ func (app *application) itemShare(w http.ResponseWriter, r *http.Request) { itemModel := models.NewItemModel(app.db) item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64) item, _, _ := itemModel.One(item_id) - var fullBuf = new(bytes.Buffer) data := app.newTemplateData(r) data["item"] = item data["baseUrl"] = app.config.baseURL - data["shareToken"] = app.generateSecureToken(18) - err := response.HXFragment(fullBuf, []string{"items/share.tmpl"}, "page:content", data) - if err != nil { - app.serverError(w, r, err) + switch r.Method { + case http.MethodGet: + var fullBuf = new(bytes.Buffer) + + data["shareToken"] = app.generateSecureToken(18) + + err := response.HXFragment(fullBuf, []string{"items/share.tmpl"}, "page:content", data) + if err != nil { + app.serverError(w, r, err) + } + + fullBuf.WriteTo(w) + case http.MethodPost: + var itemShareFromForm itemShareForm + + err := request.DecodePostForm(r, &itemShareFromForm) + if err != nil { + app.serverError(w, r, err) + } + + if !itemShareFromForm.Validate(w, r, app, data) { + return + } + + itemShare := &models.ItemShare{ + Item_id: item_id, + Token: itemShareFromForm.Token, + } + + itemshareModel := &models.ItemShareModel{DB: app.db} + _, err = itemshareModel.Create(itemShare) + if err != nil { + app.badRequest(w, err) + return + } } - - fullBuf.WriteTo(w) } func (app *application) itemAddToDashboard(w http.ResponseWriter, r *http.Request) { diff --git a/internal/funcs/funcs.go b/internal/funcs/funcs.go index 4f9bba4..8ed85c4 100644 --- a/internal/funcs/funcs.go +++ b/internal/funcs/funcs.go @@ -419,8 +419,8 @@ func widget_checkboxes(name string, label string, value any, options []WidgetOpt } id_str := strings.ReplaceAll(name+"-"+option.Key, " ", "-") o = o + "

" - o = o + fmt.Sprintf(``, id_str, id_str, name, checked, option.Key, attributes) - o = o + fmt.Sprintf(`%v`, id_str, option.Value) + o = o + fmt.Sprintf(``, id_str, name, checked, option.Key, attributes) + o = o + fmt.Sprintf(``, id_str, option.Value) o = o + "

" } o = o + "" diff --git a/models/itemshare.go b/models/itemshare.go new file mode 100644 index 0000000..123925d --- /dev/null +++ b/models/itemshare.go @@ -0,0 +1,38 @@ +package models + +import "brainminder.speedtech.it/internal/database" + +type ItemShareModel struct { + DB *database.DB +} + +type ItemShare struct { + Id int64 `db:"id"` + Token string `db:"token"` + Summary string `db:"summary"` + Item_id int64 `db:"item_id"` + Read int `db:"crypted"` + Update int `db:"hidden"` + Start_datetime string `db:"start_datetime"` + End_datetime string `db:"end_datetime"` + password string `db:"password"` +} + +func (model *ItemShareModel) Create(ItemShare *ItemShare) (int64, error) { + ctx, cancel := database.GetContext() + defer cancel() + + query := `INSERT INTO bm_items_share (title, description, icon, hidden) VALUES (:title, :description, :icon, :hidden)` + + result, err := model.DB.NamedExecContext(ctx, query, ItemShare) + if err != nil { + return 0, err + } + + id, err := result.LastInsertId() + if err != nil { + return 0, err + } + + return id, err +}