You've already forked focalboard
mirror of
https://github.com/mattermost/focalboard.git
synced 2025-07-15 23:54:29 +02:00
Refactor database to store Block fields
This commit is contained in:
@ -55,7 +55,7 @@ func handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
parentID := query.Get("parent_id")
|
parentID := query.Get("parent_id")
|
||||||
blockType := query.Get("type")
|
blockType := query.Get("type")
|
||||||
|
|
||||||
var blocks []string
|
var blocks []Block
|
||||||
if len(blockType) > 0 && len(parentID) > 0 {
|
if len(blockType) > 0 && len(parentID) > 0 {
|
||||||
blocks = store.getBlocksWithParentAndType(parentID, blockType)
|
blocks = store.getBlocksWithParentAndType(parentID, blockType)
|
||||||
} else if len(blockType) > 0 {
|
} else if len(blockType) > 0 {
|
||||||
@ -65,8 +65,14 @@ func handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("GetBlocks parentID: %s, type: %s, %d result(s)", parentID, blockType, len(blocks))
|
log.Printf("GetBlocks parentID: %s, type: %s, %d result(s)", parentID, blockType, len(blocks))
|
||||||
response := `[` + strings.Join(blocks[:], ",") + `]`
|
json, err := json.Marshal(blocks)
|
||||||
jsonResponse(w, http.StatusOK, response)
|
if err != nil {
|
||||||
|
log.Printf(`ERROR json.Marshal: %v`, r)
|
||||||
|
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytesResponse(w, http.StatusOK, json)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
func handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -117,19 +123,13 @@ func handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
|||||||
blockIDsToNotify = append(blockIDsToNotify, block.ParentID)
|
blockIDsToNotify = append(blockIDsToNotify, block.ParentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonBytes, err := json.Marshal(block)
|
store.insertBlock(block)
|
||||||
if err != nil {
|
|
||||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
store.insertBlock(block, string(jsonBytes))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wsServer.broadcastBlockChangeToWebsocketClients(blockIDsToNotify)
|
wsServer.broadcastBlockChangeToWebsocketClients(blockIDsToNotify)
|
||||||
|
|
||||||
log.Printf("POST Blocks %d block(s)", len(blocks))
|
log.Printf("POST Blocks %d block(s)", len(blocks))
|
||||||
jsonResponse(w, http.StatusOK, "{}")
|
jsonStringResponse(w, http.StatusOK, "{}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
func handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -149,7 +149,7 @@ func handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
|||||||
wsServer.broadcastBlockChangeToWebsocketClients(blockIDsToNotify)
|
wsServer.broadcastBlockChangeToWebsocketClients(blockIDsToNotify)
|
||||||
|
|
||||||
log.Printf("DELETE Block %s", blockID)
|
log.Printf("DELETE Block %s", blockID)
|
||||||
jsonResponse(w, http.StatusOK, "{}")
|
jsonStringResponse(w, http.StatusOK, "{}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
func handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -159,16 +159,28 @@ func handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
|||||||
blocks := store.getSubTree(blockID)
|
blocks := store.getSubTree(blockID)
|
||||||
|
|
||||||
log.Printf("GetSubTree blockID: %s, %d result(s)", blockID, len(blocks))
|
log.Printf("GetSubTree blockID: %s, %d result(s)", blockID, len(blocks))
|
||||||
response := `[` + strings.Join(blocks[:], ",") + `]`
|
json, err := json.Marshal(blocks)
|
||||||
jsonResponse(w, http.StatusOK, response)
|
if err != nil {
|
||||||
|
log.Printf(`ERROR json.Marshal: %v`, r)
|
||||||
|
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytesResponse(w, http.StatusOK, json)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleExport(w http.ResponseWriter, r *http.Request) {
|
func handleExport(w http.ResponseWriter, r *http.Request) {
|
||||||
blocks := store.getAllBlocks()
|
blocks := store.getAllBlocks()
|
||||||
|
|
||||||
log.Printf("EXPORT Blocks, %d result(s)", len(blocks))
|
log.Printf("EXPORT Blocks, %d result(s)", len(blocks))
|
||||||
response := `[` + strings.Join(blocks[:], ",") + `]`
|
json, err := json.Marshal(blocks)
|
||||||
jsonResponse(w, http.StatusOK, response)
|
if err != nil {
|
||||||
|
log.Printf(`ERROR json.Marshal: %v`, r)
|
||||||
|
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytesResponse(w, http.StatusOK, json)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleImport(w http.ResponseWriter, r *http.Request) {
|
func handleImport(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -195,17 +207,11 @@ func handleImport(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, block := range blocks {
|
for _, block := range blocks {
|
||||||
jsonBytes, err := json.Marshal(block)
|
store.insertBlock(block)
|
||||||
if err != nil {
|
|
||||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
store.insertBlock(block, string(jsonBytes))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("IMPORT Blocks %d block(s)", len(blocks))
|
log.Printf("IMPORT Blocks %d block(s)", len(blocks))
|
||||||
jsonResponse(w, http.StatusOK, "{}")
|
jsonStringResponse(w, http.StatusOK, "{}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// File upload
|
// File upload
|
||||||
@ -261,23 +267,29 @@ func saveFile(w http.ResponseWriter, file multipart.File, handle *multipart.File
|
|||||||
os.MkdirAll(folderPath, os.ModePerm)
|
os.MkdirAll(folderPath, os.ModePerm)
|
||||||
err = ioutil.WriteFile(filePath, data, 0666)
|
err = ioutil.WriteFile(filePath, data, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonResponse(w, http.StatusInternalServerError, `{}`)
|
jsonStringResponse(w, http.StatusInternalServerError, `{}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf(`%s/files/%s`, config.ServerRoot, filename)
|
url := fmt.Sprintf(`%s/files/%s`, config.ServerRoot, filename)
|
||||||
log.Printf(`saveFile, url: %s`, url)
|
log.Printf(`saveFile, url: %s`, url)
|
||||||
json := fmt.Sprintf(`{ "url": "%s" }`, url)
|
json := fmt.Sprintf(`{ "url": "%s" }`, url)
|
||||||
jsonResponse(w, http.StatusOK, json)
|
jsonStringResponse(w, http.StatusOK, json)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response helpers
|
// Response helpers
|
||||||
|
|
||||||
func jsonResponse(w http.ResponseWriter, code int, message string) {
|
func jsonStringResponse(w http.ResponseWriter, code int, message string) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
fmt.Fprint(w, message)
|
fmt.Fprint(w, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func jsonBytesResponse(w http.ResponseWriter, code int, json []byte) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(code)
|
||||||
|
w.Write(json)
|
||||||
|
}
|
||||||
|
|
||||||
func errorResponse(w http.ResponseWriter, code int, message string) {
|
func errorResponse(w http.ResponseWriter, code int, message string) {
|
||||||
log.Printf("%d ERROR", code)
|
log.Printf("%d ERROR", code)
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
@ -53,7 +54,6 @@ type Block struct {
|
|||||||
Schema int64 `json:"schema"`
|
Schema int64 `json:"schema"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Order int64 `json:"order"`
|
|
||||||
Fields map[string]interface{} `json:"fields"`
|
Fields map[string]interface{} `json:"fields"`
|
||||||
CreateAt int64 `json:"createAt"`
|
CreateAt int64 `json:"createAt"`
|
||||||
UpdateAt int64 `json:"updateAt"`
|
UpdateAt int64 `json:"updateAt"`
|
||||||
@ -69,8 +69,10 @@ func (s *SQLStore) createTablesIfNotExists() error {
|
|||||||
id VARCHAR(36),
|
id VARCHAR(36),
|
||||||
insert_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
|
insert_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
|
||||||
parent_id VARCHAR(36),
|
parent_id VARCHAR(36),
|
||||||
|
schema BIGINT,
|
||||||
type TEXT,
|
type TEXT,
|
||||||
json TEXT,
|
title TEXT,
|
||||||
|
fields TEXT,
|
||||||
create_at BIGINT,
|
create_at BIGINT,
|
||||||
update_at BIGINT,
|
update_at BIGINT,
|
||||||
delete_at BIGINT,
|
delete_at BIGINT,
|
||||||
@ -81,8 +83,10 @@ func (s *SQLStore) createTablesIfNotExists() error {
|
|||||||
id VARCHAR(36),
|
id VARCHAR(36),
|
||||||
insert_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
insert_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
parent_id VARCHAR(36),
|
parent_id VARCHAR(36),
|
||||||
|
schema BIGINT,
|
||||||
type TEXT,
|
type TEXT,
|
||||||
json TEXT,
|
title TEXT,
|
||||||
|
fields TEXT,
|
||||||
create_at BIGINT,
|
create_at BIGINT,
|
||||||
update_at BIGINT,
|
update_at BIGINT,
|
||||||
delete_at BIGINT,
|
delete_at BIGINT,
|
||||||
@ -99,7 +103,7 @@ func (s *SQLStore) createTablesIfNotExists() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) getBlocksWithParentAndType(parentID string, blockType string) []string {
|
func (s *SQLStore) getBlocksWithParentAndType(parentID string, blockType string) []Block {
|
||||||
query := `WITH latest AS
|
query := `WITH latest AS
|
||||||
(
|
(
|
||||||
SELECT * FROM
|
SELECT * FROM
|
||||||
@ -112,7 +116,7 @@ func (s *SQLStore) getBlocksWithParentAndType(parentID string, blockType string)
|
|||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
SELECT COALESCE("json", '{}')
|
SELECT id, parent_id, schema, type, title, COALESCE("fields", '{}'), create_at, update_at, delete_at
|
||||||
FROM latest
|
FROM latest
|
||||||
WHERE delete_at = 0 and parent_id = $1 and type = $2`
|
WHERE delete_at = 0 and parent_id = $1 and type = $2`
|
||||||
|
|
||||||
@ -125,7 +129,7 @@ func (s *SQLStore) getBlocksWithParentAndType(parentID string, blockType string)
|
|||||||
return blocksFromRows(rows)
|
return blocksFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) getBlocksWithParent(parentID string) []string {
|
func (s *SQLStore) getBlocksWithParent(parentID string) []Block {
|
||||||
query := `WITH latest AS
|
query := `WITH latest AS
|
||||||
(
|
(
|
||||||
SELECT * FROM
|
SELECT * FROM
|
||||||
@ -138,7 +142,7 @@ func (s *SQLStore) getBlocksWithParent(parentID string) []string {
|
|||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
SELECT COALESCE("json", '{}')
|
SELECT id, parent_id, schema, type, title, COALESCE("fields", '{}'), create_at, update_at, delete_at
|
||||||
FROM latest
|
FROM latest
|
||||||
WHERE delete_at = 0 and parent_id = $1`
|
WHERE delete_at = 0 and parent_id = $1`
|
||||||
|
|
||||||
@ -151,7 +155,7 @@ func (s *SQLStore) getBlocksWithParent(parentID string) []string {
|
|||||||
return blocksFromRows(rows)
|
return blocksFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) getBlocksWithType(blockType string) []string {
|
func (s *SQLStore) getBlocksWithType(blockType string) []Block {
|
||||||
query := `WITH latest AS
|
query := `WITH latest AS
|
||||||
(
|
(
|
||||||
SELECT * FROM
|
SELECT * FROM
|
||||||
@ -164,7 +168,7 @@ func (s *SQLStore) getBlocksWithType(blockType string) []string {
|
|||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
SELECT COALESCE("json", '{}')
|
SELECT id, parent_id, schema, type, title, COALESCE("fields", '{}'), create_at, update_at, delete_at
|
||||||
FROM latest
|
FROM latest
|
||||||
WHERE delete_at = 0 and type = $1`
|
WHERE delete_at = 0 and type = $1`
|
||||||
|
|
||||||
@ -177,7 +181,7 @@ func (s *SQLStore) getBlocksWithType(blockType string) []string {
|
|||||||
return blocksFromRows(rows)
|
return blocksFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) getSubTree(blockID string) []string {
|
func (s *SQLStore) getSubTree(blockID string) []Block {
|
||||||
query := `WITH latest AS
|
query := `WITH latest AS
|
||||||
(
|
(
|
||||||
SELECT * FROM
|
SELECT * FROM
|
||||||
@ -190,7 +194,7 @@ func (s *SQLStore) getSubTree(blockID string) []string {
|
|||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
SELECT COALESCE("json", '{}')
|
SELECT id, parent_id, schema, type, title, COALESCE("fields", '{}'), create_at, update_at, delete_at
|
||||||
FROM latest
|
FROM latest
|
||||||
WHERE delete_at = 0
|
WHERE delete_at = 0
|
||||||
AND (id = $1
|
AND (id = $1
|
||||||
@ -205,7 +209,7 @@ func (s *SQLStore) getSubTree(blockID string) []string {
|
|||||||
return blocksFromRows(rows)
|
return blocksFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) getAllBlocks() []string {
|
func (s *SQLStore) getAllBlocks() []Block {
|
||||||
query := `WITH latest AS
|
query := `WITH latest AS
|
||||||
(
|
(
|
||||||
SELECT * FROM
|
SELECT * FROM
|
||||||
@ -218,7 +222,7 @@ func (s *SQLStore) getAllBlocks() []string {
|
|||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
SELECT COALESCE("json", '{}')
|
SELECT id, parent_id, schema, type, title, COALESCE("fields", '{}'), create_at, update_at, delete_at
|
||||||
FROM latest
|
FROM latest
|
||||||
WHERE delete_at = 0`
|
WHERE delete_at = 0`
|
||||||
|
|
||||||
@ -231,21 +235,38 @@ func (s *SQLStore) getAllBlocks() []string {
|
|||||||
return blocksFromRows(rows)
|
return blocksFromRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
func blocksFromRows(rows *sql.Rows) []string {
|
func blocksFromRows(rows *sql.Rows) []Block {
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
var results []string
|
var results []Block
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var json string
|
var block Block
|
||||||
err := rows.Scan(&json)
|
var fieldsJSON string
|
||||||
|
err := rows.Scan(
|
||||||
|
&block.ID,
|
||||||
|
&block.ParentID,
|
||||||
|
&block.Schema,
|
||||||
|
&block.Type,
|
||||||
|
&block.Title,
|
||||||
|
&fieldsJSON,
|
||||||
|
&block.CreateAt,
|
||||||
|
&block.UpdateAt,
|
||||||
|
&block.DeleteAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle this error
|
// handle this error
|
||||||
log.Printf(`blocksFromRows ERROR: %v`, err)
|
log.Printf(`ERROR blocksFromRows: %v`, err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, json)
|
err = json.Unmarshal([]byte(fieldsJSON), &block.Fields)
|
||||||
|
if err != nil {
|
||||||
|
// handle this error
|
||||||
|
log.Printf(`ERROR blocksFromRows fields: %v`, err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@ -281,9 +302,35 @@ func (s *SQLStore) getParentID(blockID string) string {
|
|||||||
return parentID
|
return parentID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLStore) insertBlock(block Block, json string) {
|
func (s *SQLStore) insertBlock(block Block) {
|
||||||
statement := `INSERT INTO blocks(id, parent_id, type, json, create_at, update_at, delete_at) VALUES($1, $2, $3, $4, $5, $6, $7)`
|
fieldsJSON, err := json.Marshal(block.Fields)
|
||||||
_, err := s.db.Exec(statement, block.ID, block.ParentID, block.Type, json, block.CreateAt, block.UpdateAt, block.DeleteAt)
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
statement := `INSERT INTO blocks(
|
||||||
|
id,
|
||||||
|
parent_id,
|
||||||
|
schema,
|
||||||
|
type,
|
||||||
|
title,
|
||||||
|
fields,
|
||||||
|
create_at,
|
||||||
|
update_at,
|
||||||
|
delete_at
|
||||||
|
)
|
||||||
|
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9)`
|
||||||
|
_, err = s.db.Exec(
|
||||||
|
statement,
|
||||||
|
block.ID,
|
||||||
|
block.ParentID,
|
||||||
|
block.Schema,
|
||||||
|
block.Type,
|
||||||
|
block.Title,
|
||||||
|
fieldsJSON,
|
||||||
|
block.CreateAt,
|
||||||
|
block.UpdateAt,
|
||||||
|
block.DeleteAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user