You've already forked focalboard
							
							
				mirror of
				https://github.com/mattermost/focalboard.git
				synced 2025-10-31 00:17:42 +02:00 
			
		
		
		
	Some other code improvements from the golangci
This commit is contained in:
		| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user