985 lines
30 KiB
Go
985 lines
30 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"brainminder.speedtech.it/internal/request"
|
|
"brainminder.speedtech.it/internal/response"
|
|
"brainminder.speedtech.it/internal/validator"
|
|
"brainminder.speedtech.it/models"
|
|
"github.com/alexedwards/flow"
|
|
)
|
|
|
|
type itemForm struct {
|
|
Id int64 `form:"Id"`
|
|
Type_id int64 `form:"Type_id"`
|
|
Title string `form:"Title"`
|
|
Summary string `form:"Summary"`
|
|
Description string `form:"Description"`
|
|
Notebooks []string `form:"Notebooks"`
|
|
Tags string `form:"Tags"`
|
|
On_dashboard int `form:"On_dashboard"`
|
|
Categories []string `form:"Categories"`
|
|
Type_icon string
|
|
Type_title string
|
|
Type_show_summary int
|
|
Type_show_description int
|
|
FieldsSection map[string][]models.Field
|
|
FieldsValues map[int64]map[int]string
|
|
Relations []models.ItemRelation
|
|
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)
|
|
|
|
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 (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)
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
var fullBuf = new(bytes.Buffer)
|
|
related_item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "related_item_id"), 10, 64)
|
|
|
|
relatedItem, _, _ := itemModel.One(related_item_id)
|
|
data["relatedItem"] = relatedItem
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
|
|
err := response.HXFragment(fullBuf, []string{"items/add_relation.tmpl"}, "item:add_relation", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) itemsSearch(w http.ResponseWriter, r *http.Request) {
|
|
data := app.newTemplateData(r)
|
|
itemModel := models.NewItemModel(app.db)
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
switch r.Method {
|
|
case http.MethodPost:
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
return
|
|
}
|
|
|
|
criteria := make(map[string]any)
|
|
criteria["notebook_id"] = app.getCurrentNotebok_id(r)
|
|
|
|
rows, _, _ := itemModel.Search(r.PostForm.Get("SearchText"), criteria)
|
|
data["items"] = &rows
|
|
err = response.HXFragment(fullBuf, []string{"items/all_list.tmpl", "items/all_list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "itemsAll:list", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
if r.Header.Get("HX-Target") == "page-content" {
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/all_list_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) itemsSearchForRelations(w http.ResponseWriter, r *http.Request) {
|
|
|
|
data := app.newTemplateData(r)
|
|
itemModel := models.NewItemModel(app.db)
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
data["item_id"], _ = strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)
|
|
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
return
|
|
}
|
|
|
|
criteria := make(map[string]any)
|
|
criteria["notebook_id"] = app.getCurrentNotebok_id(r)
|
|
|
|
rows, _, _ := itemModel.Search(r.Form.Get("SearchText"), criteria)
|
|
data["items"] = &rows
|
|
err = response.HXFragment(fullBuf, []string{"items/list_for_relations.tmpl"}, "items:list-for-relations", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) items(w http.ResponseWriter, r *http.Request) {
|
|
data := app.newTemplateData(r)
|
|
itemModel := models.NewItemModel(app.db)
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
|
|
params := r.URL.Query()
|
|
|
|
offset_str := r.URL.Query().Get("offset")
|
|
if len(offset_str) == 0 {
|
|
offset_str = "0"
|
|
}
|
|
offset, _ := strconv.ParseInt(offset_str, 10, 64)
|
|
data["offset"] = offset
|
|
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
|
|
criteria := make(map[string]any)
|
|
|
|
criteriaName := "itemsSearch"
|
|
data["criteriaName"] = criteriaName
|
|
|
|
criteriaParam := r.URL.Query()["criteriaName"]
|
|
if len(criteriaParam) > 0 {
|
|
if criteriaParam[0] == criteriaName {
|
|
criteria_values := app.getSessionValue(w, r, criteriaName)
|
|
if criteria_values != nil {
|
|
criteria = criteria_values.(map[string]any)
|
|
}
|
|
}
|
|
} else {
|
|
app.removeSessionValue(w, r, criteriaName)
|
|
}
|
|
|
|
criteria["notebook_id"] = app.getCurrentNotebok_id(r)
|
|
|
|
rows, _, _ := itemModel.Find(criteria, offset)
|
|
|
|
data["items"] = &rows
|
|
|
|
if r.Header.Get("HX-Request") == "true" {
|
|
|
|
out := params.Get("out")
|
|
|
|
if out == "rows" {
|
|
err := response.HXFragment(fullBuf, []string{"items/all_list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "itemsAll:list_rows", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
} else {
|
|
err := response.HXFragment(fullBuf, []string{"items/all_list.tmpl", "items/all_list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "itemsAll:list", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/all_list_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
} else {
|
|
err := response.Page(w, http.StatusOK, data, []string{"items/index_all.tmpl", "items/all_list.tmpl", "items/all_list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl", "items/all_list_title.tmpl"})
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
case http.MethodPost:
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
return
|
|
}
|
|
|
|
category_id, _ := strconv.ParseInt(r.PostForm.Get("category_id"), 10, 64)
|
|
criteria := map[string]any{
|
|
"Title": r.PostForm.Get("Title"),
|
|
"Tags": r.PostForm.Get("Tags"),
|
|
"category_id": category_id,
|
|
}
|
|
|
|
criteriaName := "itemsSearch"
|
|
data["criteriaName"] = criteriaName
|
|
app.saveSessionValue(w, r, criteriaName, criteria)
|
|
|
|
rows, _, _ := itemModel.Find(criteria, offset)
|
|
data["items"] = &rows
|
|
err = response.HXFragment(fullBuf, []string{"items/all_list.tmpl", "items/all_list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "itemsAll:list", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
if r.Header.Get("HX-Target") == "page-content" {
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/all_list_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) itemsType(w http.ResponseWriter, r *http.Request) {
|
|
data := app.newTemplateData(r)
|
|
|
|
type_id, _ := strconv.ParseInt(flow.Param(r.Context(), "type_id"), 10, 64)
|
|
|
|
itemModel := models.NewItemModel(app.db)
|
|
typeModel := &models.TypeModel{DB: app.db}
|
|
aType, _, _ := typeModel.One(type_id)
|
|
fieldModel := &models.FieldModel{DB: app.db}
|
|
|
|
fields, _, _ := fieldModel.ByTypeOnList(type_id)
|
|
data["type"] = &aType
|
|
data["Fields"] = fields
|
|
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
|
|
params := r.URL.Query()
|
|
|
|
offset_str := params.Get("offset")
|
|
if len(offset_str) == 0 {
|
|
offset_str = "0"
|
|
}
|
|
offset, _ := strconv.ParseInt(offset_str, 10, 64)
|
|
data["offset"] = offset
|
|
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
|
|
criteria := make(map[string]any)
|
|
|
|
criteriaName := fmt.Sprintf("itemsTypeSearch_%d", type_id)
|
|
data["criteriaName"] = criteriaName
|
|
|
|
criteriaParam := r.URL.Query()["criteriaName"]
|
|
if len(criteriaParam) > 0 {
|
|
if criteriaParam[0] == criteriaName {
|
|
criteria_values := app.getSessionValue(w, r, criteriaName)
|
|
if criteria_values != nil {
|
|
criteria = criteria_values.(map[string]any)
|
|
}
|
|
}
|
|
} else {
|
|
app.removeSessionValue(w, r, criteriaName)
|
|
}
|
|
|
|
criteria["type_id"] = type_id
|
|
criteria["notebook_id"] = app.getCurrentNotebok_id(r)
|
|
|
|
rows, _, _ := itemModel.Find(criteria, offset)
|
|
for i, row := range rows {
|
|
rows[i].FieldsValuesMap = fieldModel.GetFieldsValuesAsMap(row.Id)
|
|
}
|
|
|
|
data["items"] = rows
|
|
|
|
if r.Header.Get("HX-Request") == "true" {
|
|
out := params.Get("out")
|
|
|
|
if out == "rows" {
|
|
err := response.HXFragment(fullBuf, []string{"items/list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "items:list_rows", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
} else {
|
|
err := response.HXFragment(fullBuf, []string{"items/list.tmpl", "items/list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "items:list", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
fullBuf.WriteString("<div hx-swap-oob=\"true\" id=\"page-title\">")
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/list_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
fullBuf.WriteTo(w)
|
|
} else {
|
|
err := response.Page(w, http.StatusOK, data, []string{"items/index.tmpl", "items/list.tmpl", "items/list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl", "items/list_title.tmpl"})
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
case http.MethodPost:
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
return
|
|
}
|
|
|
|
category_id, _ := strconv.ParseInt(r.PostForm.Get("category_id"), 10, 64)
|
|
criteria := map[string]any{
|
|
"Title": r.PostForm.Get("Title"),
|
|
"Tags": r.PostForm.Get("Tags"),
|
|
"category_id": category_id,
|
|
"type_id": type_id,
|
|
}
|
|
|
|
criteriaName := fmt.Sprintf("itemsTypeSearch_%d", type_id)
|
|
data["criteriaName"] = criteriaName
|
|
app.saveSessionValue(w, r, criteriaName, criteria)
|
|
|
|
rows, _, _ := itemModel.Find(criteria, offset)
|
|
for i, row := range rows {
|
|
rows[i].FieldsValuesMap = fieldModel.GetFieldsValuesAsMap(row.Id)
|
|
}
|
|
data["items"] = &rows
|
|
err = response.HXFragment(fullBuf, []string{"items/list.tmpl", "items/list_rows.tmpl", "items/add_to_dashboard.tmpl", "items/remove_from_dashboard.tmpl"}, "items:list", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
fullBuf.WriteTo(w)
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) itemCreate(w http.ResponseWriter, r *http.Request) {
|
|
itemModel := models.NewItemModel(app.db)
|
|
fieldModel := &models.FieldModel{DB: app.db}
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
typeModel := &models.TypeModel{DB: app.db}
|
|
|
|
type_id, _ := strconv.ParseInt(flow.Param(r.Context(), "type_id"), 10, 64)
|
|
|
|
aType, _, _ := typeModel.One(type_id)
|
|
|
|
data := app.newTemplateData(r)
|
|
data["type"] = aType
|
|
data["formAction"] = fmt.Sprint("/item/create/", type_id)
|
|
data["formTarget"] = "#page-content"
|
|
data["categories"] = categoryModel.AllAsOptions()
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
|
|
criteria := map[string]any{
|
|
"notebook_id": app.getCurrentNotebok_id(r),
|
|
}
|
|
data["types"] = typeModel.FindAsOptions(criteria)
|
|
|
|
notebookModel := &models.NotebookModel{DB: app.db}
|
|
data["notebooks"] = notebookModel.AllAsOptions(false)
|
|
|
|
var fullBuf = new(bytes.Buffer)
|
|
var categories []string
|
|
|
|
fieldsSection, _, _ := fieldModel.ByTypeSection(int64(type_id))
|
|
fieldsValues := make(map[int64]map[int]string)
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
notebooks := []string{strconv.FormatInt(app.getCurrentNotebok_id(r), 10)}
|
|
|
|
data["item"] = itemForm{
|
|
Title: "",
|
|
Type_id: type_id,
|
|
Type_show_summary: aType.Show_summary,
|
|
Type_show_description: aType.Show_description,
|
|
Summary: "",
|
|
Description: "",
|
|
Tags: "",
|
|
FieldsSection: fieldsSection,
|
|
FieldsValues: fieldsValues,
|
|
Categories: categories,
|
|
Notebooks: notebooks,
|
|
Relations: nil,
|
|
}
|
|
|
|
if r.Header.Get("HX-Request") == "true" {
|
|
|
|
err := response.HXFragment(fullBuf, []string{"items/form.tmpl", "items/fields.tmpl", "items/relations.tmpl"}, "page:content", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/create_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
w.Header().Add("HX-Trigger-After-Settle", `{"activateEasyMDE":"item-description"}`)
|
|
fullBuf.WriteTo(w)
|
|
} else {
|
|
err := response.Page(w, http.StatusOK, data, []string{"items/create_title.tmpl", "items/relations.tmpl", "items/form.tmpl", "items/fields.tmpl", "items/form_jscode.tmpl"})
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
case http.MethodPost:
|
|
var itemFromForm itemForm
|
|
var item_id int64
|
|
|
|
err := request.DecodePostForm(r, &itemFromForm)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
if !itemFromForm.Validate(w, r, app, data) {
|
|
return
|
|
}
|
|
|
|
item := &models.Item{
|
|
Type_id: itemFromForm.Type_id,
|
|
Title: itemFromForm.Title,
|
|
Summary: itemFromForm.Summary,
|
|
Description: itemFromForm.Description,
|
|
Tags: itemFromForm.Tags,
|
|
On_dashboard: itemFromForm.On_dashboard,
|
|
}
|
|
|
|
notebooks_str := strings.Join(itemFromForm.Notebooks, "|")
|
|
if len(notebooks_str) > 0 {
|
|
notebooks_str = "|" + notebooks_str + "|"
|
|
}
|
|
item.Notebooks = notebooks_str
|
|
|
|
categories_str := strings.Join(itemFromForm.Categories, "|")
|
|
if len(categories_str) > 0 {
|
|
categories_str = "|" + categories_str + "|"
|
|
}
|
|
item.Categories = categories_str
|
|
|
|
item_id, err = itemModel.Create(item)
|
|
item.Id = item_id
|
|
if err != nil {
|
|
app.badRequest(w, err)
|
|
return
|
|
}
|
|
|
|
fieldsValues := make(map[int64]map[int]string)
|
|
for name, values := range r.PostForm {
|
|
id_s, found := strings.CutPrefix(name, "FieldsValues-")
|
|
if found {
|
|
parts := strings.Split(id_s, "-")
|
|
type_field_id, _ := strconv.ParseInt(parts[0], 10, 64)
|
|
counter, _ := strconv.Atoi(parts[1])
|
|
|
|
_, found_key := fieldsValues[type_field_id]
|
|
if !found_key {
|
|
fieldsValues[type_field_id] = make(map[int]string)
|
|
}
|
|
fieldsValues[type_field_id][counter] = values[0]
|
|
}
|
|
|
|
related_id_s, found := strings.CutPrefix(name, "ItemRelation-New-")
|
|
if found && len(values) > 0 {
|
|
related_item_id, _ := strconv.ParseInt(related_id_s, 10, 64)
|
|
itemModel.AddRelation(item.Id, related_item_id, values[0])
|
|
}
|
|
}
|
|
|
|
for type_field_id, values := range fieldsValues {
|
|
fieldModel.SaveValues(item.Id, type_field_id, values)
|
|
}
|
|
|
|
item.Type_title = aType.Title
|
|
fields, _, _ := fieldModel.ByType(int64(type_id))
|
|
itemModel.SaveKeywords(item, &fields, fieldsValues)
|
|
|
|
data["formAction"] = fmt.Sprint("/item/update/", item_id)
|
|
data["formTarget"] = "#message"
|
|
|
|
notebooks := strings.Split(strings.Trim(item.Notebooks, "|"), "|")
|
|
categories := strings.Split(strings.Trim(item.Categories, "|"), "|")
|
|
relations, _, _ := itemModel.GetRelations(item.Id)
|
|
|
|
data["item"] = itemForm{
|
|
Id: item_id,
|
|
Type_id: type_id,
|
|
Type_show_summary: aType.Show_summary,
|
|
Type_show_description: aType.Show_description,
|
|
Title: item.Title,
|
|
Summary: item.Summary,
|
|
Description: item.Description,
|
|
Tags: item.Tags,
|
|
Type_icon: item.Type_icon,
|
|
Type_title: item.Type_title,
|
|
FieldsSection: fieldsSection,
|
|
FieldsValues: fieldsValues,
|
|
Notebooks: notebooks,
|
|
Categories: categories,
|
|
Relations: relations,
|
|
}
|
|
|
|
err = response.HXFragment(fullBuf, []string{"items/form.tmpl", "items/fields.tmpl", "items/relations.tmpl"}, "page:content", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/update_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
dataMessage := make(map[string]string)
|
|
dataMessage["messageType"] = "success"
|
|
dataMessage["messageContent"] = "Item created successfully"
|
|
err = response.HXFragmentOOB(fullBuf, []string{"partials/message.tmpl"}, "message", dataMessage, "message")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
w.Header().Add("HX-Trigger-After-Settle", `{"activateEasyMDE":"item-description"}`)
|
|
w.Header().Add("HX-Replace-Url", fmt.Sprint("/item/update/", item_id))
|
|
fullBuf.WriteTo(w)
|
|
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
}
|
|
}
|
|
|
|
func (app *application) itemRead(w http.ResponseWriter, r *http.Request) {
|
|
data := app.newTemplateData(r)
|
|
item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)
|
|
itemModel := models.NewItemModel(app.db)
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
fieldModel := &models.FieldModel{DB: app.db}
|
|
relations, _, _ := itemModel.GetRelations(item_id)
|
|
|
|
item, _, _ := itemModel.One(item_id)
|
|
|
|
data["item"] = &item
|
|
data["relations"] = relations
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
data["fields"] = fieldModel.GetFieldsValues(item_id)
|
|
|
|
if r.Header.Get("HX-Request") == "true" {
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
err := response.HXFragment(fullBuf, []string{"items/read.tmpl", "items/relations_view.tmpl"}, "page:content", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/read_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
} else {
|
|
err := response.Page(w, http.StatusOK, data, []string{"items/read_title.tmpl", "items/relations_view.tmpl", "items/read.tmpl"})
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) itemView(w http.ResponseWriter, r *http.Request) {
|
|
data := app.newTemplateData(r)
|
|
item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)
|
|
itemModel := models.NewItemModel(app.db)
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
fieldModel := &models.FieldModel{DB: app.db}
|
|
|
|
item, _, _ := itemModel.One(item_id)
|
|
relations, _, _ := itemModel.GetRelations(item_id)
|
|
|
|
data["item"] = &item
|
|
data["relations"] = relations
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
data["fields"] = fieldModel.GetFieldsValues(item_id)
|
|
|
|
if r.Header.Get("HX-Request") == "true" {
|
|
var fullBuf = new(bytes.Buffer)
|
|
err := response.HXFragment(fullBuf, []string{"items/view.tmpl", "items/relations_view.tmpl"}, "page:content", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
fullBuf.WriteTo(w)
|
|
} else {
|
|
err := response.Page(w, http.StatusOK, data, []string{"items/read_title.tmpl", "items/relations_view.tmpl", "items/read.tmpl"})
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
|
|
func (app *application) itemUpdate(w http.ResponseWriter, r *http.Request) {
|
|
itemModel := models.NewItemModel(app.db)
|
|
fieldModel := &models.FieldModel{DB: app.db}
|
|
item_id_str := flow.Param(r.Context(), "item_id")
|
|
item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)
|
|
item, _, _ := itemModel.One(item_id)
|
|
fieldsSection, _, _ := fieldModel.ByTypeSection(item.Type_id)
|
|
fieldsValues := fieldModel.GetFieldsValuesAsMap(item.Id)
|
|
|
|
data := app.newTemplateData(r)
|
|
data["formAction"] = "/item/update/" + item_id_str
|
|
data["formTarget"] = "#message"
|
|
|
|
notebookModel := &models.NotebookModel{DB: app.db}
|
|
data["notebooks"] = notebookModel.AllAsOptions(false)
|
|
|
|
categoryModel := &models.CategoryModel{DB: app.db}
|
|
data["categoriesMap"] = categoryModel.AllAsMap()
|
|
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
switch r.Method {
|
|
case http.MethodGet:
|
|
|
|
notebooks := strings.Split(strings.Trim(item.Notebooks, "|"), "|")
|
|
categories := strings.Split(strings.Trim(item.Categories, "|"), "|")
|
|
relations, _, _ := itemModel.GetRelations(item.Id)
|
|
|
|
data["item"] = itemForm{
|
|
Id: item.Id,
|
|
Type_id: item.Type_id,
|
|
Type_show_summary: item.Type_show_summary,
|
|
Type_show_description: item.Type_show_description,
|
|
Title: item.Title,
|
|
Summary: item.Summary,
|
|
Description: item.Description,
|
|
Tags: item.Tags,
|
|
On_dashboard: item.On_dashboard,
|
|
Type_icon: item.Type_icon,
|
|
Type_title: item.Type_title,
|
|
FieldsSection: fieldsSection,
|
|
FieldsValues: fieldsValues,
|
|
Categories: categories,
|
|
Notebooks: notebooks,
|
|
Relations: relations,
|
|
}
|
|
|
|
data["categories"] = categoryModel.AllAsOptions()
|
|
|
|
typeModel := &models.TypeModel{DB: app.db}
|
|
criteria := map[string]any{
|
|
"notebook_id": app.getCurrentNotebok_id(r),
|
|
}
|
|
data["types"] = typeModel.FindAsOptions(criteria)
|
|
|
|
if r.Header.Get("HX-Request") == "true" {
|
|
|
|
err := response.HXFragment(fullBuf, []string{"items/form.tmpl", "items/fields.tmpl", "items/relations.tmpl"}, "page:content", data)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/update_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
w.Header().Add("HX-Trigger-After-Settle", `{"activateEasyMDE":"item-description"}`)
|
|
fullBuf.WriteTo(w)
|
|
} else {
|
|
err := response.Page(w, http.StatusOK, data, []string{"items/update_title.tmpl", "items/form.tmpl", "items/fields.tmpl", "items/relations.tmpl", "items/form_jscode.tmpl"})
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
case http.MethodPost:
|
|
var itemFromForm itemForm
|
|
|
|
err := request.DecodePostForm(r, &itemFromForm)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
if !itemFromForm.Validate(w, r, app, data) {
|
|
return
|
|
}
|
|
|
|
item.Title = itemFromForm.Title
|
|
item.Type_id = itemFromForm.Type_id
|
|
item.Summary = itemFromForm.Summary
|
|
item.Description = itemFromForm.Description
|
|
item.Tags = itemFromForm.Tags
|
|
item.On_dashboard = itemFromForm.On_dashboard
|
|
|
|
notebooks_str := strings.Join(itemFromForm.Notebooks, "|")
|
|
if len(notebooks_str) > 0 {
|
|
notebooks_str = "|" + notebooks_str + "|"
|
|
}
|
|
item.Notebooks = notebooks_str
|
|
|
|
categories_str := strings.Join(itemFromForm.Categories, "|")
|
|
if len(categories_str) > 0 {
|
|
categories_str = "|" + categories_str + "|"
|
|
}
|
|
item.Categories = categories_str
|
|
|
|
err = itemModel.Update(item)
|
|
if err != nil {
|
|
app.badRequest(w, err)
|
|
return
|
|
}
|
|
|
|
fieldsValues := make(map[int64]map[int]string)
|
|
for name, values := range r.PostForm {
|
|
id_s, found := strings.CutPrefix(name, "FieldsValues-")
|
|
if found {
|
|
parts := strings.Split(id_s, "-")
|
|
type_field_id, _ := strconv.ParseInt(parts[0], 10, 64)
|
|
counter, _ := strconv.Atoi(parts[1])
|
|
|
|
valuesRemove, isMapContainsKey := r.PostForm["FieldsValuesToRemove-"+id_s]
|
|
if !isMapContainsKey || valuesRemove[0] == "0" {
|
|
_, found_key := fieldsValues[type_field_id]
|
|
if !found_key {
|
|
fieldsValues[type_field_id] = make(map[int]string)
|
|
}
|
|
fieldsValues[type_field_id][counter] = values[0]
|
|
}
|
|
}
|
|
related_id_s, found := strings.CutPrefix(name, "ItemRelation-New-")
|
|
if found && len(values) > 0 {
|
|
related_item_id, _ := strconv.ParseInt(related_id_s, 10, 64)
|
|
itemModel.AddRelation(item.Id, related_item_id, values[0])
|
|
}
|
|
|
|
id_s, found = strings.CutPrefix(name, "ItemRelation-")
|
|
if found && len(values) > 0 {
|
|
ids := strings.Split(id_s, "-")
|
|
item_id, _ := strconv.ParseInt(ids[0], 10, 64)
|
|
related_item_id, _ := strconv.ParseInt(ids[1], 10, 64)
|
|
valuesRemove, isMapContainsKey := r.PostForm["ItemRelation-ToRemove-"+id_s]
|
|
if isMapContainsKey && valuesRemove[0] == "1" {
|
|
itemModel.DeleteRelation(item_id, related_item_id)
|
|
} else {
|
|
itemModel.UpdateRelation(item_id, related_item_id, values[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
for type_field_id, values := range fieldsValues {
|
|
fieldModel.SaveValues(item.Id, type_field_id, values)
|
|
}
|
|
|
|
fields, _, _ := fieldModel.ByType(item.Type_id)
|
|
itemModel.SaveKeywords(item, &fields, fieldsValues)
|
|
|
|
relations, _, _ := itemModel.GetRelations(item.Id)
|
|
|
|
data["item"] = itemForm{
|
|
Title: item.Title,
|
|
Type_icon: item.Type_icon,
|
|
Type_title: item.Type_title,
|
|
Relations: relations,
|
|
}
|
|
|
|
data["FieldsSection"] = fieldsSection
|
|
data["FieldsValues"] = fieldsValues
|
|
|
|
dataMessage := make(map[string]string)
|
|
dataMessage["messageType"] = "success"
|
|
dataMessage["messageContent"] = "Item saved successfully"
|
|
err = response.HXFragment(fullBuf, []string{"partials/message.tmpl"}, "message", dataMessage)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/update_title.tmpl"}, "page:title", data, "page-title")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/relations.tmpl"}, "item:relations", data, "relations")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
data["uisection"] = "general"
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/fields.tmpl"}, "items:fields", data, "fields-general")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
_, found := fieldsSection["fields"]
|
|
if found {
|
|
data["uisection"] = "fields"
|
|
err = response.HXFragmentOOB(fullBuf, []string{"items/fields.tmpl"}, "items:fields", data, "fields-fields")
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
}
|
|
}
|
|
|
|
func (app *application) itemDelete(w http.ResponseWriter, r *http.Request) {
|
|
itemModel := models.NewItemModel(app.db)
|
|
item_id_str := flow.Param(r.Context(), "item_id")
|
|
item_id, _ := strconv.Atoi(item_id_str)
|
|
|
|
_, err := itemModel.Delete(item_id)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
}
|
|
|
|
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)
|
|
|
|
data := app.newTemplateData(r)
|
|
data["item"] = item
|
|
data["baseUrl"] = app.config.baseURL
|
|
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
func (app *application) itemAddToDashboard(w http.ResponseWriter, r *http.Request) {
|
|
itemModel := models.NewItemModel(app.db)
|
|
item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)
|
|
|
|
err := itemModel.AddToDashboard(item_id)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
err = response.HXFragment(fullBuf, []string{"items/remove_from_dashboard.tmpl"}, "item:remove_from_dashboard", item_id)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
}
|
|
|
|
func (app *application) itemRemoveFromDashboard(w http.ResponseWriter, r *http.Request) {
|
|
itemModel := models.NewItemModel(app.db)
|
|
item_id, _ := strconv.ParseInt(flow.Param(r.Context(), "item_id"), 10, 64)
|
|
|
|
err := itemModel.RemoveFromDashboard(item_id)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
if r.Method == http.MethodPost {
|
|
var fullBuf = new(bytes.Buffer)
|
|
|
|
err := response.HXFragment(fullBuf, []string{"items/add_to_dashboard.tmpl"}, "item:add_to_dashboard", item_id)
|
|
if err != nil {
|
|
app.serverError(w, r, err)
|
|
}
|
|
|
|
fullBuf.WriteTo(w)
|
|
}
|
|
}
|