mirror of
https://github.com/mattermost/focalboard.git
synced 2024-12-24 13:43:12 +02:00
Some other code improvements from the golangci
This commit is contained in:
parent
607b8aa063
commit
72f4783e34
@ -51,15 +51,18 @@ func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
||||
blocks, err := a.app().GetBlocks(parentID, blockType)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR GetBlocks: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("GetBlocks parentID: %s, type: %s, %d result(s)", parentID, blockType, len(blocks))
|
||||
|
||||
json, err := json.Marshal(blocks)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR json.Marshal: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -69,7 +72,8 @@ func (a *API) handleGetBlocks(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -77,32 +81,41 @@ func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
var blocks []model.Block
|
||||
|
||||
err = json.Unmarshal(requestBody, &blocks)
|
||||
if err != nil {
|
||||
errorResponse(w, http.StatusInternalServerError, ``)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for _, block := range blocks {
|
||||
// Error checking
|
||||
if len(block.Type) < 1 {
|
||||
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf(`{"description": "missing type", "id": "%s"}`, block.ID))
|
||||
errorData := map[string]string{"description": "missing type", "id": block.ID}
|
||||
errorResponse(w, http.StatusBadRequest, errorData)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if block.CreateAt < 1 {
|
||||
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf(`{"description": "invalid createAt", "id": "%s"}`, block.ID))
|
||||
errorData := map[string]string{"description": "invalid createAt", "id": block.ID}
|
||||
errorResponse(w, http.StatusBadRequest, errorData)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if block.UpdateAt < 1 {
|
||||
errorResponse(w, http.StatusInternalServerError, fmt.Sprintf(`{"description": "invalid updateAt", "id": "%s"}`, block.ID))
|
||||
errorData := map[string]string{"description": "invalid UpdateAt", "id": block.ID}
|
||||
errorResponse(w, http.StatusBadRequest, errorData)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -110,7 +123,8 @@ func (a *API) handlePostBlocks(w http.ResponseWriter, r *http.Request) {
|
||||
err = a.app().InsertBlocks(blocks)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -125,7 +139,8 @@ func (a *API) handleDeleteBlock(w http.ResponseWriter, r *http.Request) {
|
||||
err := a.app().DeleteBlock(blockID)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -140,7 +155,8 @@ func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
||||
blocks, err := a.app().GetSubTree(blockID)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -148,7 +164,8 @@ func (a *API) handleGetSubTree(w http.ResponseWriter, r *http.Request) {
|
||||
json, err := json.Marshal(blocks)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR json.Marshal: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -159,15 +176,18 @@ func (a *API) handleExport(w http.ResponseWriter, r *http.Request) {
|
||||
blocks, err := a.app().GetAllBlocks()
|
||||
if err != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("EXPORT Blocks, %d result(s)", len(blocks))
|
||||
|
||||
json, err := json.Marshal(blocks)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR json.Marshal: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -177,7 +197,8 @@ func (a *API) handleExport(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
||||
requestBody, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -185,15 +206,18 @@ func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
var blocks []model.Block
|
||||
|
||||
err = json.Unmarshal(requestBody, &blocks)
|
||||
if err != nil {
|
||||
errorResponse(w, http.StatusInternalServerError, ``)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -201,7 +225,8 @@ func (a *API) handleImport(w http.ResponseWriter, r *http.Request) {
|
||||
err := a.app().InsertBlock(block)
|
||||
if err != nil {
|
||||
log.Printf(`ERROR: %v`, r)
|
||||
errorResponse(w, http.StatusInternalServerError, `{}`)
|
||||
errorResponse(w, http.StatusInternalServerError, nil)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -217,6 +242,7 @@ func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
||||
filename := vars["filename"]
|
||||
|
||||
contentType := "image/jpg"
|
||||
|
||||
fileExtension := strings.ToLower(filepath.Ext(filename))
|
||||
if fileExtension == "png" {
|
||||
contentType = "image/png"
|
||||
@ -234,6 +260,7 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
||||
file, handle, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "%v", err)
|
||||
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
@ -243,6 +270,7 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
||||
url, err := a.app().SaveFile(file, handle.Filename)
|
||||
if err != nil {
|
||||
jsonStringResponse(w, http.StatusInternalServerError, `{}`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -265,10 +293,14 @@ func jsonBytesResponse(w http.ResponseWriter, code int, json []byte) {
|
||||
w.Write(json)
|
||||
}
|
||||
|
||||
func errorResponse(w http.ResponseWriter, code int, message string) {
|
||||
func errorResponse(w http.ResponseWriter, code int, message map[string]string) {
|
||||
log.Printf("%d ERROR", code)
|
||||
data, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
data = []byte("{}")
|
||||
}
|
||||
w.WriteHeader(code)
|
||||
fmt.Fprint(w, message)
|
||||
fmt.Fprint(w, data)
|
||||
}
|
||||
|
||||
func addUserID(rw http.ResponseWriter, req *http.Request, next http.Handler) {
|
||||
|
@ -8,9 +8,11 @@ func (a *App) GetBlocks(parentID string, blockType string) ([]model.Block, error
|
||||
if len(blockType) > 0 && len(parentID) > 0 {
|
||||
return a.store.GetBlocksWithParentAndType(parentID, blockType)
|
||||
}
|
||||
|
||||
if len(blockType) > 0 {
|
||||
return a.store.GetBlocksWithType(blockType)
|
||||
}
|
||||
|
||||
return a.store.GetBlocksWithParent(parentID)
|
||||
}
|
||||
|
||||
@ -23,7 +25,7 @@ func (a *App) InsertBlock(block model.Block) error {
|
||||
}
|
||||
|
||||
func (a *App) InsertBlocks(blocks []model.Block) error {
|
||||
var blockIDsToNotify = []string{}
|
||||
blockIDsToNotify := []string{}
|
||||
|
||||
uniqueBlockIDs := make(map[string]bool)
|
||||
|
||||
@ -43,6 +45,7 @@ func (a *App) InsertBlocks(blocks []model.Block) error {
|
||||
}
|
||||
|
||||
a.wsServer.BroadcastBlockChangeToWebsocketClients(blockIDsToNotify)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -55,7 +58,7 @@ func (a *App) GetAllBlocks() ([]model.Block, error) {
|
||||
}
|
||||
|
||||
func (a *App) DeleteBlock(blockID string) error {
|
||||
var blockIDsToNotify = []string{blockID}
|
||||
blockIDsToNotify := []string{blockID}
|
||||
parentID, err := a.GetParentID(blockID)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -71,5 +74,6 @@ func (a *App) DeleteBlock(blockID string) error {
|
||||
}
|
||||
|
||||
a.wsServer.BroadcastBlockChangeToWebsocketClients(blockIDsToNotify)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -32,5 +32,4 @@ func TestGetParentID(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "block-not-found", err.Error())
|
||||
})
|
||||
|
||||
}
|
||||
|
@ -23,23 +23,24 @@ func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
||||
if appErr != nil {
|
||||
return "", errors.New("unable to store the file in the files storage")
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`%s/files/%s`, a.config.ServerRoot, createdFilename), nil
|
||||
}
|
||||
|
||||
func (a *App) GetFilePath(filename string) string {
|
||||
folderPath := a.config.FilesPath
|
||||
|
||||
return filepath.Join(folderPath, filename)
|
||||
}
|
||||
|
||||
// CreateGUID returns a random GUID
|
||||
// CreateGUID returns a random GUID.
|
||||
func createGUID() string {
|
||||
b := make([]byte, 16)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
uuid := fmt.Sprintf("%x-%x-%x-%x-%x",
|
||||
b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
|
||||
return uuid
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"log"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-octo-tasks/server/server"
|
||||
"github.com/mattermost/mattermost-octo-tasks/server/services/config"
|
||||
@ -26,6 +25,7 @@ func isProcessRunning(pid int) bool {
|
||||
}
|
||||
|
||||
err = process.Signal(syscall.Signal(0))
|
||||
|
||||
return err == nil
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ func main() {
|
||||
config, err := config.ReadConfigFile()
|
||||
if err != nil {
|
||||
log.Fatal("Unable to read the config file: ", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package model
|
||||
|
||||
// Block is the basic data unit
|
||||
// Block is the basic data unit.
|
||||
type Block struct {
|
||||
ID string `json:"id"`
|
||||
ParentID string `json:"parentId"`
|
||||
|
@ -22,12 +22,12 @@ import (
|
||||
"github.com/mattermost/mattermost-server/v5/services/filesstore"
|
||||
)
|
||||
|
||||
const CurrentVersion = "0.0.1"
|
||||
const currentVersion = "0.0.1"
|
||||
|
||||
type Server struct {
|
||||
config *config.Configuration
|
||||
wsServer *ws.Server
|
||||
webServer *web.WebServer
|
||||
webServer *web.Server
|
||||
store store.Store
|
||||
filesBackend filesstore.FileBackend
|
||||
telemetry *telemetry.Service
|
||||
@ -43,6 +43,7 @@ func New(cfg *config.Configuration) (*Server, error) {
|
||||
store, err := sqlstore.New(cfg.DBType, cfg.DBConfigString)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to start the database", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -54,13 +55,14 @@ func New(cfg *config.Configuration) (*Server, error) {
|
||||
filesBackend, appErr := filesstore.NewFileBackend(&filesBackendSettings, false)
|
||||
if appErr != nil {
|
||||
log.Fatal("Unable to initialize the files storage")
|
||||
|
||||
return nil, errors.New("unable to initialize the files storage")
|
||||
}
|
||||
|
||||
appBuilder := func() *app.App { return app.New(cfg, store, wsServer, filesBackend) }
|
||||
|
||||
webServer := web.NewWebServer(cfg.WebPath, cfg.Port, cfg.UseSSL)
|
||||
api := api.NewAPI(appBuilder)
|
||||
|
||||
webServer := web.NewServer(cfg.WebPath, cfg.Port, cfg.UseSSL)
|
||||
webServer.AddRoutes(wsServer)
|
||||
webServer.AddRoutes(api)
|
||||
|
||||
@ -95,7 +97,22 @@ func New(cfg *config.Configuration) (*Server, error) {
|
||||
}
|
||||
|
||||
telemetryService := telemetry.New(telemetryID, zap.NewStdLog(logger))
|
||||
srv := &Server{
|
||||
telemetryService.RegisterTracker("server", func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"version": currentVersion,
|
||||
"operating_system": runtime.GOOS,
|
||||
}
|
||||
})
|
||||
telemetryService.RegisterTracker("config", func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"serverRoot": cfg.ServerRoot == config.DefaultServerRoot,
|
||||
"port": cfg.Port == config.DefaultPort,
|
||||
"useSSL": cfg.UseSSL,
|
||||
"dbType": cfg.DBType,
|
||||
}
|
||||
})
|
||||
|
||||
return &Server{
|
||||
config: cfg,
|
||||
wsServer: wsServer,
|
||||
webServer: webServer,
|
||||
@ -103,29 +120,14 @@ func New(cfg *config.Configuration) (*Server, error) {
|
||||
filesBackend: filesBackend,
|
||||
telemetry: telemetryService,
|
||||
logger: logger,
|
||||
}
|
||||
telemetryService.RegisterTracker("server", func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"version": CurrentVersion,
|
||||
"operating_system": runtime.GOOS,
|
||||
}
|
||||
})
|
||||
telemetryService.RegisterTracker("config", func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"serverRoot": srv.config.ServerRoot == config.DefaultServerRoot,
|
||||
"port": srv.config.Port == config.DefaultPort,
|
||||
"useSSL": srv.config.UseSSL,
|
||||
"dbType": srv.config.DBType,
|
||||
}
|
||||
})
|
||||
|
||||
return srv, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
if err := s.webServer.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ const (
|
||||
DefaultPort = 8000
|
||||
)
|
||||
|
||||
// Configuration is the app configuration stored in a json file
|
||||
// Configuration is the app configuration stored in a json file.
|
||||
type Configuration struct {
|
||||
ServerRoot string `json:"serverRoot" mapstructure:"serverRoot"`
|
||||
Port int `json:"port" mapstructure:"port"`
|
||||
@ -23,6 +23,7 @@ type Configuration struct {
|
||||
Telemetry bool `json:"telemetry" mapstructure:"telemetry"`
|
||||
}
|
||||
|
||||
// ReadConfigFile read the configuration from the filesystem.
|
||||
func ReadConfigFile() (*Configuration, error) {
|
||||
viper.SetConfigName("config") // name of config file (without extension)
|
||||
viper.SetConfigType("json") // REQUIRED if the config file does not have the extension in the name
|
||||
@ -40,6 +41,7 @@ func ReadConfigFile() (*Configuration, error) {
|
||||
}
|
||||
|
||||
configuration := Configuration{}
|
||||
|
||||
err = viper.Unmarshal(&configuration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -22,6 +22,7 @@ func TestCreateTask(t *testing.T) {
|
||||
}
|
||||
|
||||
task := CreateTask(taskName, testFunc, taskTime)
|
||||
|
||||
assert.EqualValues(t, 0, atomic.LoadInt32(executionCount))
|
||||
|
||||
time.Sleep(taskTime + taskWait)
|
||||
@ -43,6 +44,7 @@ func TestCreateRecurringTask(t *testing.T) {
|
||||
}
|
||||
|
||||
task := CreateRecurringTask(taskName, testFunc, taskTime)
|
||||
|
||||
assert.EqualValues(t, 0, atomic.LoadInt32(executionCount))
|
||||
|
||||
time.Sleep(taskTime + taskWait)
|
||||
@ -70,6 +72,7 @@ func TestCancelTask(t *testing.T) {
|
||||
}
|
||||
|
||||
task := CreateTask(taskName, testFunc, taskTime)
|
||||
|
||||
assert.EqualValues(t, 0, atomic.LoadInt32(executionCount))
|
||||
task.Cancel()
|
||||
|
||||
|
@ -13,16 +13,21 @@ import (
|
||||
)
|
||||
|
||||
func (s *SQLStore) latestsBlocksSubquery() sq.SelectBuilder {
|
||||
return sq.Select("*").FromSelect(sq.Select("*", "ROW_NUMBER() OVER (PARTITION BY id ORDER BY insert_at DESC) AS rn").From("blocks"), "a").Where(sq.Eq{"rn": 1})
|
||||
internalQuery := sq.Select("*", "ROW_NUMBER() OVER (PARTITION BY id ORDER BY insert_at DESC) AS rn").From("blocks")
|
||||
|
||||
return sq.Select("*").FromSelect(internalQuery, "a").Where(sq.Eq{"rn": 1})
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetBlocksWithParentAndType(parentID string, blockType string) ([]model.Block, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("id", "parent_id", "schema", "type", "title", "COALESCE(\"fields\", '{}')", "create_at", "update_at", "delete_at").
|
||||
Select("id", "parent_id", "schema", "type", "title",
|
||||
"COALESCE(\"fields\", '{}')", "create_at", "update_at",
|
||||
"delete_at").
|
||||
FromSelect(s.latestsBlocksSubquery(), "latest").
|
||||
Where(sq.Eq{"delete_at": 0}).
|
||||
Where(sq.Eq{"parent_id": parentID}).
|
||||
Where(sq.Eq{"type": blockType})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
log.Printf(`getBlocksWithParentAndType ERROR: %v`, err)
|
||||
@ -35,7 +40,9 @@ func (s *SQLStore) GetBlocksWithParentAndType(parentID string, blockType string)
|
||||
|
||||
func (s *SQLStore) GetBlocksWithParent(parentID string) ([]model.Block, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("id", "parent_id", "schema", "type", "title", "COALESCE(\"fields\", '{}')", "create_at", "update_at", "delete_at").
|
||||
Select("id", "parent_id", "schema", "type", "title",
|
||||
"COALESCE(\"fields\", '{}')", "create_at", "update_at",
|
||||
"delete_at").
|
||||
FromSelect(s.latestsBlocksSubquery(), "latest").
|
||||
Where(sq.Eq{"delete_at": 0}).
|
||||
Where(sq.Eq{"parent_id": parentID})
|
||||
@ -43,6 +50,7 @@ func (s *SQLStore) GetBlocksWithParent(parentID string) ([]model.Block, error) {
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
log.Printf(`getBlocksWithParent ERROR: %v`, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -51,13 +59,17 @@ func (s *SQLStore) GetBlocksWithParent(parentID string) ([]model.Block, error) {
|
||||
|
||||
func (s *SQLStore) GetBlocksWithType(blockType string) ([]model.Block, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("id", "parent_id", "schema", "type", "title", "COALESCE(\"fields\", '{}')", "create_at", "update_at", "delete_at").
|
||||
Select("id", "parent_id", "schema", "type", "title",
|
||||
"COALESCE(\"fields\", '{}')", "create_at", "update_at",
|
||||
"delete_at").
|
||||
FromSelect(s.latestsBlocksSubquery(), "latest").
|
||||
Where(sq.Eq{"delete_at": 0}).
|
||||
Where(sq.Eq{"type": blockType})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
log.Printf(`getBlocksWithParentAndType ERROR: %v`, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -66,7 +78,9 @@ func (s *SQLStore) GetBlocksWithType(blockType string) ([]model.Block, error) {
|
||||
|
||||
func (s *SQLStore) GetSubTree(blockID string) ([]model.Block, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("id", "parent_id", "schema", "type", "title", "COALESCE(\"fields\", '{}')", "create_at", "update_at", "delete_at").
|
||||
Select("id", "parent_id", "schema", "type", "title",
|
||||
"COALESCE(\"fields\", '{}')", "create_at", "update_at",
|
||||
"delete_at").
|
||||
FromSelect(s.latestsBlocksSubquery(), "latest").
|
||||
Where(sq.Eq{"delete_at": 0}).
|
||||
Where(sq.Or{sq.Eq{"id": blockID}, sq.Eq{"parent_id": blockID}})
|
||||
@ -74,6 +88,7 @@ func (s *SQLStore) GetSubTree(blockID string) ([]model.Block, error) {
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
log.Printf(`getSubTree ERROR: %v`, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -82,13 +97,16 @@ func (s *SQLStore) GetSubTree(blockID string) ([]model.Block, error) {
|
||||
|
||||
func (s *SQLStore) GetAllBlocks() ([]model.Block, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("id", "parent_id", "schema", "type", "title", "COALESCE(\"fields\", '{}')", "create_at", "update_at", "delete_at").
|
||||
Select("id", "parent_id", "schema", "type", "title",
|
||||
"COALESCE(\"fields\", '{}')", "create_at", "update_at",
|
||||
"delete_at").
|
||||
FromSelect(s.latestsBlocksSubquery(), "latest").
|
||||
Where(sq.Eq{"delete_at": 0})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
log.Printf(`getAllBlocks ERROR: %v`, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -117,6 +135,7 @@ func blocksFromRows(rows *sql.Rows) ([]model.Block, error) {
|
||||
if err != nil {
|
||||
// handle this error
|
||||
log.Printf(`ERROR blocksFromRows: %v`, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -124,6 +143,7 @@ func blocksFromRows(rows *sql.Rows) ([]model.Block, error) {
|
||||
if err != nil {
|
||||
// handle this error
|
||||
log.Printf(`ERROR blocksFromRows fields: %v`, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -142,6 +162,7 @@ func (s *SQLStore) GetParentID(blockID string) (string, error) {
|
||||
row := query.QueryRow()
|
||||
|
||||
var parentID string
|
||||
|
||||
err := row.Scan(&parentID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -158,20 +179,25 @@ func (s *SQLStore) InsertBlock(block model.Block) error {
|
||||
|
||||
query := s.getQueryBuilder().Insert("blocks").
|
||||
Columns("id", "parent_id", "schema", "type", "title", "fields", "create_at", "update_at", "delete_at").
|
||||
Values(block.ID, block.ParentID, block.Schema, block.Type, block.Title, fieldsJSON, block.CreateAt, block.UpdateAt, block.DeleteAt)
|
||||
Values(block.ID, block.ParentID, block.Schema, block.Type, block.Title,
|
||||
fieldsJSON, block.CreateAt, block.UpdateAt, block.DeleteAt)
|
||||
|
||||
_, err = query.Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) DeleteBlock(blockID string) error {
|
||||
now := time.Now().Unix()
|
||||
query := s.getQueryBuilder().Insert("blocks").Columns("id", "update_at", "delete_at").Values(blockID, now, now)
|
||||
|
||||
_, err := query.Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -7,13 +7,13 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
)
|
||||
|
||||
// SQLStore is a SQL database
|
||||
// SQLStore is a SQL database.
|
||||
type SQLStore struct {
|
||||
db *sql.DB
|
||||
dbType string
|
||||
}
|
||||
|
||||
// New creates a new SQL implementation of the store
|
||||
// New creates a new SQL implementation of the store.
|
||||
func New(dbType, connectionString string) (*SQLStore, error) {
|
||||
log.Println("connectDatabase")
|
||||
var err error
|
||||
@ -21,12 +21,14 @@ func New(dbType, connectionString string) (*SQLStore, error) {
|
||||
db, err := sql.Open(dbType, connectionString)
|
||||
if err != nil {
|
||||
log.Fatal("connectDatabase: ", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
log.Println(`Database Ping failed`)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -38,16 +40,20 @@ func New(dbType, connectionString string) (*SQLStore, error) {
|
||||
err = store.Migrate()
|
||||
if err != nil {
|
||||
log.Println(`Table creation failed`)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return store, nil
|
||||
}
|
||||
|
||||
// Shutdown close the connection with the store.
|
||||
func (s *SQLStore) Shutdown() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
func (s *SQLStore) getQueryBuilder() sq.StatementBuilderType {
|
||||
builder := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
|
||||
|
||||
return builder.RunWith(s.db)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ func SetupTests(t *testing.T) (*SQLStore, func()) {
|
||||
if dbType == "" {
|
||||
dbType = "sqlite3"
|
||||
}
|
||||
|
||||
connectionString := os.Getenv("OT_STORE_TEST_CONN_STRING")
|
||||
if connectionString == "" {
|
||||
connectionString = ":memory:"
|
||||
@ -24,5 +25,6 @@ func SetupTests(t *testing.T) (*SQLStore, func()) {
|
||||
err = store.Shutdown()
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
return store, tearDown
|
||||
}
|
||||
|
@ -14,10 +14,12 @@ func (s *SQLStore) GetSystemSettings() (map[string]string, error) {
|
||||
for rows.Next() {
|
||||
var id string
|
||||
var value string
|
||||
|
||||
err := rows.Scan(&id, &value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results[id] = value
|
||||
}
|
||||
|
||||
@ -31,5 +33,6 @@ func (s *SQLStore) SetSystemSetting(id string, value string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package store
|
||||
|
||||
import "github.com/mattermost/mattermost-octo-tasks/server/model"
|
||||
|
||||
// Store represents the abstraction of the data storage
|
||||
// Store represents the abstraction of the data storage.
|
||||
type Store interface {
|
||||
GetBlocksWithParentAndType(parentID string, blockType string) ([]model.Block, error)
|
||||
GetBlocksWithParent(parentID string) ([]model.Block, error)
|
||||
|
@ -40,6 +40,7 @@ func New(telemetryID string, log *log.Logger) *Service {
|
||||
telemetryID: telemetryID,
|
||||
trackers: map[string]Tracker{},
|
||||
}
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
@ -93,6 +94,7 @@ func (ts *Service) initRudder(endpoint string, rudderKey string) {
|
||||
client, err := rudder.NewWithConfig(rudderKey, endpoint, config)
|
||||
if err != nil {
|
||||
ts.log.Fatal("Failed to create Rudder instance")
|
||||
|
||||
return
|
||||
}
|
||||
client.Enqueue(rudder.Identify{
|
||||
@ -135,5 +137,6 @@ func (ts *Service) Shutdown() error {
|
||||
if ts.rudderClient != nil {
|
||||
return ts.rudderClient.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -11,21 +11,26 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// RoutedService defines the interface that is needed for any service to
|
||||
// register themself in the web server to provide new endpoints. (see
|
||||
// AddRoutes).
|
||||
type RoutedService interface {
|
||||
RegisterRoutes(*mux.Router)
|
||||
}
|
||||
|
||||
type WebServer struct {
|
||||
// Server is the structure responsible for managing our http web server.
|
||||
type Server struct {
|
||||
router *mux.Router
|
||||
rootPath string
|
||||
port int
|
||||
ssl bool
|
||||
}
|
||||
|
||||
func NewWebServer(rootPath string, port int, ssl bool) *WebServer {
|
||||
// NewServer creates a new instance of the webserver.
|
||||
func NewServer(rootPath string, port int, ssl bool) *Server {
|
||||
r := mux.NewRouter()
|
||||
|
||||
ws := &WebServer{
|
||||
ws := &Server{
|
||||
router: r,
|
||||
rootPath: rootPath,
|
||||
port: port,
|
||||
@ -35,11 +40,12 @@ func NewWebServer(rootPath string, port int, ssl bool) *WebServer {
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *WebServer) AddRoutes(rs RoutedService) {
|
||||
// AddRoutes allows services to register themself in the webserver router and provide new endpoints.
|
||||
func (ws *Server) AddRoutes(rs RoutedService) {
|
||||
rs.RegisterRoutes(ws.router)
|
||||
}
|
||||
|
||||
func (ws *WebServer) registerRoutes() {
|
||||
func (ws *Server) registerRoutes() {
|
||||
ws.router.PathPrefix("/static").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(filepath.Join(ws.rootPath, "static")))))
|
||||
ws.router.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
@ -47,12 +53,13 @@ func (ws *WebServer) registerRoutes() {
|
||||
})
|
||||
}
|
||||
|
||||
func (ws *WebServer) Start() error {
|
||||
// Start runs the web server and start listening for charsetnnections.
|
||||
func (ws *Server) Start() error {
|
||||
ws.registerRoutes()
|
||||
http.Handle("/", ws.router)
|
||||
|
||||
urlPort := fmt.Sprintf(`:%d`, ws.port)
|
||||
var isSSL = ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
||||
isSSL := ws.ssl && fileExists("./cert/cert.pem") && fileExists("./cert/key.pem")
|
||||
|
||||
if isSSL {
|
||||
log.Println("https server started on ", urlPort)
|
||||
@ -73,7 +80,7 @@ func (ws *WebServer) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FileExists returns true if a file exists at the path
|
||||
// fileExists returns true if a file exists at the path.
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
|
@ -10,12 +10,12 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// RegisterRoutes registeres routes
|
||||
// RegisterRoutes registers routes.
|
||||
func (ws *Server) RegisterRoutes(r *mux.Router) {
|
||||
r.HandleFunc("/ws/onchange", ws.handleWebSocketOnChange)
|
||||
}
|
||||
|
||||
// AddListener adds a listener for a block's change
|
||||
// AddListener adds a listener for a block's change.
|
||||
func (ws *Server) AddListener(client *websocket.Conn, blockIDs []string) {
|
||||
ws.mu.Lock()
|
||||
for _, blockID := range blockIDs {
|
||||
@ -28,23 +28,24 @@ func (ws *Server) AddListener(client *websocket.Conn, blockIDs []string) {
|
||||
ws.mu.Unlock()
|
||||
}
|
||||
|
||||
// RemoveListener removes a webSocket listener from all blocks
|
||||
// RemoveListener removes a webSocket listener from all blocks.
|
||||
func (ws *Server) RemoveListener(client *websocket.Conn) {
|
||||
ws.mu.Lock()
|
||||
for key, clients := range ws.listeners {
|
||||
var listeners = []*websocket.Conn{}
|
||||
listeners := []*websocket.Conn{}
|
||||
|
||||
for _, existingClient := range clients {
|
||||
if client != existingClient {
|
||||
listeners = append(listeners, existingClient)
|
||||
}
|
||||
}
|
||||
|
||||
ws.listeners[key] = listeners
|
||||
}
|
||||
ws.mu.Unlock()
|
||||
}
|
||||
|
||||
// RemoveListenerFromBlocks removes a webSocket listener from a set of block
|
||||
// RemoveListenerFromBlocks removes a webSocket listener from a set of block.
|
||||
func (ws *Server) RemoveListenerFromBlocks(client *websocket.Conn, blockIDs []string) {
|
||||
ws.mu.Lock()
|
||||
|
||||
@ -69,7 +70,7 @@ func (ws *Server) RemoveListenerFromBlocks(client *websocket.Conn, blockIDs []st
|
||||
ws.mu.Unlock()
|
||||
}
|
||||
|
||||
// GetListeners returns the listeners to a blockID's changes
|
||||
// GetListeners returns the listeners to a blockID's changes.
|
||||
func (ws *Server) GetListeners(blockID string) []*websocket.Conn {
|
||||
ws.mu.Lock()
|
||||
listeners := ws.listeners[blockID]
|
||||
@ -78,14 +79,14 @@ func (ws *Server) GetListeners(blockID string) []*websocket.Conn {
|
||||
return listeners
|
||||
}
|
||||
|
||||
// Server is a WebSocket server
|
||||
// Server is a WebSocket server.
|
||||
type Server struct {
|
||||
upgrader websocket.Upgrader
|
||||
listeners map[string][]*websocket.Conn
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewServer creates a new Server
|
||||
// NewServer creates a new Server.
|
||||
func NewServer() *Server {
|
||||
return &Server{
|
||||
listeners: make(map[string][]*websocket.Conn),
|
||||
@ -97,13 +98,13 @@ func NewServer() *Server {
|
||||
}
|
||||
}
|
||||
|
||||
// WebsocketMsg is sent on block changes
|
||||
// WebsocketMsg is sent on block changes.
|
||||
type WebsocketMsg struct {
|
||||
Action string `json:"action"`
|
||||
BlockID string `json:"blockId"`
|
||||
}
|
||||
|
||||
// WebsocketCommand is an incoming command from the client
|
||||
// WebsocketCommand is an incoming command from the client.
|
||||
type WebsocketCommand struct {
|
||||
Action string `json:"action"`
|
||||
BlockIDs []string `json:"blockIds"`
|
||||
@ -141,6 +142,7 @@ func (ws *Server) handleWebSocketOnChange(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
var command WebsocketCommand
|
||||
|
||||
err = json.Unmarshal(p, &command)
|
||||
if err != nil {
|
||||
// handle this error
|
||||
@ -164,20 +166,21 @@ func (ws *Server) handleWebSocketOnChange(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
// BroadcastBlockChangeToWebsocketClients broadcasts change to clients
|
||||
// BroadcastBlockChangeToWebsocketClients broadcasts change to clients.
|
||||
func (ws *Server) BroadcastBlockChangeToWebsocketClients(blockIDs []string) {
|
||||
for _, blockID := range blockIDs {
|
||||
listeners := ws.GetListeners(blockID)
|
||||
log.Printf("%d listener(s) for blockID: %s", len(listeners), blockID)
|
||||
|
||||
if listeners != nil {
|
||||
var message = WebsocketMsg{
|
||||
message := WebsocketMsg{
|
||||
Action: "UPDATE_BLOCK",
|
||||
BlockID: blockID,
|
||||
}
|
||||
|
||||
for _, listener := range listeners {
|
||||
log.Printf("Broadcast change, blockID: %s, remoteAddr: %s", blockID, listener.RemoteAddr())
|
||||
|
||||
err := listener.WriteJSON(message)
|
||||
if err != nil {
|
||||
log.Printf("broadcast error: %v", err)
|
||||
|
Loading…
Reference in New Issue
Block a user