Этот коммит содержится в:
=Corey Hulen
2015-09-18 09:25:47 -07:00
родитель 1aa4913c44 5a436fd447
Коммит cdf813f07b
22 изменённых файлов: 515 добавлений и 27 удалений

3
.gitignore поставляемый
Просмотреть файл

@@ -6,7 +6,8 @@ dist
npm-debug.log npm-debug.log
bundle*.js bundle*.js
model/version.go
model/version.go.bak
# Compiled Object files, Static and Dynamic libs (Shared Objects) # Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o *.o

Просмотреть файл

@@ -1,6 +1,10 @@
language: go language: go
go: go:
- 1.4.2 - 1.4.2
- 1.5.1
env:
- TRAVIS_DB=mysql
- TRAVIS_DB=postgres
before_install: before_install:
- gem install compass - gem install compass
- sudo apt-get update -qq - sudo apt-get update -qq
@@ -24,6 +28,9 @@ before_script:
- mysql -e "CREATE DATABASE IF NOT EXISTS mattermost_test ;" -uroot - mysql -e "CREATE DATABASE IF NOT EXISTS mattermost_test ;" -uroot
- mysql -e "CREATE USER 'mmuser'@'%' IDENTIFIED BY 'mostest' ;" -uroot - mysql -e "CREATE USER 'mmuser'@'%' IDENTIFIED BY 'mostest' ;" -uroot
- mysql -e "GRANT ALL ON mattermost_test.* TO 'mmuser'@'%' ;" -uroot - mysql -e "GRANT ALL ON mattermost_test.* TO 'mmuser'@'%' ;" -uroot
- psql -c "create database mattermost_test ;" -U postgres
- psql -c "create user mmuser with password 'mostest' ;" -U postgres
- psql -c 'grant all privileges on database "mattermost_test" to mmuser ;' -U postgres
services: services:
- redis-server - redis-server
addons: addons:
@@ -38,6 +45,8 @@ deploy:
on: on:
repo: mattermost/platform repo: mattermost/platform
tags: true tags: true
go: 1.4.2
condition: $TRAVIS_DB = mysql
- provider: s3 - provider: s3
access_key_id: AKIAJCO3KJYEGWJIKDIQ access_key_id: AKIAJCO3KJYEGWJIKDIQ
@@ -52,3 +61,5 @@ deploy:
on: on:
repo: mattermost/platform repo: mattermost/platform
branch: master branch: master
go: 1.4.2
condition: $TRAVIS_DB = mysql

Просмотреть файл

@@ -3,6 +3,8 @@
GOPATH ?= $(GOPATH:) GOPATH ?= $(GOPATH:)
GOFLAGS ?= $(GOFLAGS:) GOFLAGS ?= $(GOFLAGS:)
BUILD_NUMBER ?= $(BUILD_NUMBER:) BUILD_NUMBER ?= $(BUILD_NUMBER:)
BUILD_DATE = $(shell date -u)
BUILD_HASH = $(shell git rev-parse HEAD)
GO=$(GOPATH)/bin/godep go GO=$(GOPATH)/bin/godep go
ESLINT=node_modules/eslint/bin/eslint.js ESLINT=node_modules/eslint/bin/eslint.js
@@ -32,6 +34,11 @@ all: travis
travis: travis:
@echo building for travis @echo building for travis
if [ "$(TRAVIS_DB)" = "postgres" ]; then \
sed -i'.bak' 's|mysql|postgres|g' config/config.json; \
sed -i'.bak' 's|mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8|postgres://mmuser:mostest@dockerhost:5432/mattermost_test?sslmode=disable\&connect_timeout=10|g' config/config.json; \
fi
rm -Rf $(DIST_ROOT) rm -Rf $(DIST_ROOT)
@$(GO) clean $(GOFLAGS) -i ./... @$(GO) clean $(GOFLAGS) -i ./...
@@ -49,6 +56,10 @@ travis:
exit 1; \ exit 1; \
fi fi
@sed -i'.bak' 's|_BUILD_NUMBER_|$(BUILD_NUMBER)|g' ./model/version.go
@sed -i'.bak' 's|_BUILD_DATE_|$(BUILD_DATE)|g' ./model/version.go
@sed -i'.bak' 's|_BUILD_HASH_|$(BUILD_HASH)|g' ./model/version.go
@$(GO) build $(GOFLAGS) ./... @$(GO) build $(GOFLAGS) ./...
@$(GO) install $(GOFLAGS) ./... @$(GO) install $(GOFLAGS) ./...
@@ -222,6 +233,10 @@ cleandb:
fi fi
dist: install dist: install
@sed -i'.bak' 's|_BUILD_NUMBER_|$(BUILD_NUMBER)|g' ./model/version.go
@sed -i'.bak' 's|_BUILD_DATE_|$(BUILD_DATE)|g' ./model/version.go
@sed -i'.bak' 's|_BUILD_HASH_|$(BUILD_HASH)|g' ./model/version.go
@$(GO) build $(GOFLAGS) -i ./... @$(GO) build $(GOFLAGS) -i ./...
@$(GO) install $(GOFLAGS) ./... @$(GO) install $(GOFLAGS) ./...

Просмотреть файл

@@ -125,7 +125,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.setSiteURL(protocol + "://" + r.Host) c.setSiteURL(protocol + "://" + r.Host)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId) w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
w.Header().Set(model.HEADER_VERSION_ID, utils.Cfg.ServiceSettings.Version+fmt.Sprintf(".%v", utils.CfgLastModified)) w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v", model.CurrentVersion, utils.CfgLastModified))
// Instruct the browser not to display us in an iframe for anti-clickjacking // Instruct the browser not to display us in an iframe for anti-clickjacking
if !h.isApi { if !h.isApi {

Просмотреть файл

@@ -23,6 +23,7 @@ import (
var flagCmdCreateTeam bool var flagCmdCreateTeam bool
var flagCmdCreateUser bool var flagCmdCreateUser bool
var flagCmdAssignRole bool var flagCmdAssignRole bool
var flagCmdVersion bool
var flagCmdResetPassword bool var flagCmdResetPassword bool
var flagConfigFile string var flagConfigFile string
var flagEmail string var flagEmail string
@@ -42,6 +43,7 @@ func main() {
} }
pwd, _ := os.Getwd() pwd, _ := os.Getwd()
l4g.Info("Current version is %v (%v/%v/%v)", model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash)
l4g.Info("Current working directory is %v", pwd) l4g.Info("Current working directory is %v", pwd)
l4g.Info("Loaded config file from %v", utils.FindConfigFile(flagConfigFile)) l4g.Info("Loaded config file from %v", utils.FindConfigFile(flagConfigFile))
@@ -83,14 +85,16 @@ func parseCmds() {
flag.BoolVar(&flagCmdCreateTeam, "create_team", false, "") flag.BoolVar(&flagCmdCreateTeam, "create_team", false, "")
flag.BoolVar(&flagCmdCreateUser, "create_user", false, "") flag.BoolVar(&flagCmdCreateUser, "create_user", false, "")
flag.BoolVar(&flagCmdAssignRole, "assign_role", false, "") flag.BoolVar(&flagCmdAssignRole, "assign_role", false, "")
flag.BoolVar(&flagCmdVersion, "version", false, "")
flag.BoolVar(&flagCmdResetPassword, "reset_password", false, "") flag.BoolVar(&flagCmdResetPassword, "reset_password", false, "")
flag.Parse() flag.Parse()
flagRunCmds = flagCmdCreateTeam || flagCmdCreateUser || flagCmdAssignRole || flagCmdResetPassword flagRunCmds = flagCmdCreateTeam || flagCmdCreateUser || flagCmdAssignRole || flagCmdResetPassword || flagCmdVersion
} }
func runCmds() { func runCmds() {
cmdVersion()
cmdCreateTeam() cmdCreateTeam()
cmdCreateUser() cmdCreateUser()
cmdAssignRole() cmdAssignRole()
@@ -184,6 +188,17 @@ func cmdCreateUser() {
} }
} }
func cmdVersion() {
if flagCmdVersion {
fmt.Fprintln(os.Stderr, "Version: "+model.CurrentVersion)
fmt.Fprintln(os.Stderr, "Build Number: "+model.BuildNumber)
fmt.Fprintln(os.Stderr, "Build Date: "+model.BuildDate)
fmt.Fprintln(os.Stderr, "Build Hash: "+model.BuildHash)
os.Exit(0)
}
}
func cmdAssignRole() { func cmdAssignRole() {
if flagCmdAssignRole { if flagCmdAssignRole {
if len(flagTeamName) == 0 { if len(flagTeamName) == 0 {
@@ -298,6 +313,8 @@ Usage:
platform [options] platform [options]
-version Display the current version
-config="config.json" Path to the config file -config="config.json" Path to the config file
-email="user@example.com" Email address used in other commands -email="user@example.com" Email address used in other commands

34
model/system.go Обычный файл
Просмотреть файл

@@ -0,0 +1,34 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
type System struct {
Name string `json:"name"`
Value string `json:"value"`
}
func (o *System) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
return ""
} else {
return string(b)
}
}
func SystemFromJson(data io.Reader) *System {
decoder := json.NewDecoder(data)
var o System
err := decoder.Decode(&o)
if err == nil {
return &o
} else {
return nil
}
}

19
model/system_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strings"
"testing"
)
func TestSystemJson(t *testing.T) {
system := System{Name: "test", Value: NewId()}
json := system.ToJson()
result := SystemFromJson(strings.NewReader(json))
if result.Name != "test" {
t.Fatal("Ids do not match")
}
}

Просмотреть файл

@@ -16,11 +16,6 @@ import (
"time" "time"
) )
const (
// Also change web/react/stores/browser_store.jsx BROWSER_STORE_VERSION
ETAG_ROOT_VERSION = "12"
)
type StringMap map[string]string type StringMap map[string]string
type StringArray []string type StringArray []string
type EncryptStringMap map[string]string type EncryptStringMap map[string]string
@@ -235,7 +230,7 @@ func IsValidAlphaNum(s string, allowUnderscores bool) bool {
func Etag(parts ...interface{}) string { func Etag(parts ...interface{}) string {
etag := ETAG_ROOT_VERSION etag := CurrentVersion
for _, part := range parts { for _, part := range parts {
etag += fmt.Sprintf(".%v", part) etag += fmt.Sprintf(".%v", part)

90
model/version.go Обычный файл
Просмотреть файл

@@ -0,0 +1,90 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strconv"
"strings"
)
// This is a list of all the current viersions including any patches.
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
"0.8.0",
"0.7.1",
"0.7.0",
"0.6.0",
"0.5.0",
}
var CurrentVersion string = versions[0]
var BuildNumber = "_BUILD_NUMBER_"
var BuildDate = "_BUILD_DATE_"
var BuildHash = "_BUILD_HASH_"
func SplitVersion(version string) (int64, int64, int64) {
parts := strings.Split(version, ".")
major := int64(0)
minor := int64(0)
patch := int64(0)
if len(parts) > 0 {
major, _ = strconv.ParseInt(parts[0], 10, 64)
}
if len(parts) > 1 {
minor, _ = strconv.ParseInt(parts[1], 10, 64)
}
if len(parts) > 2 {
patch, _ = strconv.ParseInt(parts[2], 10, 64)
}
return major, minor, patch
}
func GetPreviousVersion(currentVersion string) (int64, int64) {
currentIndex := -1
currentMajor, currentMinor, _ := SplitVersion(currentVersion)
for index, version := range versions {
major, minor, _ := SplitVersion(version)
if currentMajor == major && currentMinor == minor {
currentIndex = index
}
if currentIndex >= 0 {
if currentMajor != major || currentMinor != minor {
return major, minor
}
}
}
return 0, 0
}
func IsCurrentVersion(versionToCheck string) bool {
currentMajor, currentMinor, _ := SplitVersion(CurrentVersion)
toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
if toCheckMajor == currentMajor && toCheckMinor == currentMinor {
return true
} else {
return false
}
}
func IsPreviousVersion(versionToCheck string) bool {
toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck)
prevMajor, prevMinor := GetPreviousVersion(CurrentVersion)
if toCheckMajor == prevMajor && toCheckMinor == prevMinor {
return true
} else {
return false
}
}

74
model/version_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,74 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"fmt"
"testing"
)
func TestSplitVersion(t *testing.T) {
major1, minor1, patch1 := SplitVersion("junk")
if major1 != 0 || minor1 != 0 || patch1 != 0 {
t.Fatal()
}
major2, minor2, patch2 := SplitVersion("1.2.3")
if major2 != 1 || minor2 != 2 || patch2 != 3 {
t.Fatal()
}
major3, minor3, patch3 := SplitVersion("1.2")
if major3 != 1 || minor3 != 2 || patch3 != 0 {
t.Fatal()
}
major4, minor4, patch4 := SplitVersion("1")
if major4 != 1 || minor4 != 0 || patch4 != 0 {
t.Fatal()
}
major5, minor5, patch5 := SplitVersion("1.2.3.junkgoeswhere")
if major5 != 1 || minor5 != 2 || patch5 != 3 {
t.Fatal()
}
}
func TestGetPreviousVersion(t *testing.T) {
if major, minor := GetPreviousVersion("0.8.0"); major != 0 || minor != 7 {
t.Fatal(major, minor)
}
if major, minor := GetPreviousVersion("0.7.0"); major != 0 || minor != 6 {
t.Fatal(major, minor)
}
if major, minor := GetPreviousVersion("0.7.1"); major != 0 || minor != 6 {
t.Fatal(major, minor)
}
if major, minor := GetPreviousVersion("0.7111.1"); major != 0 || minor != 0 {
t.Fatal(major, minor)
}
}
func TestIsCurrentVersion(t *testing.T) {
major, minor, patch := SplitVersion(CurrentVersion)
if !IsCurrentVersion(CurrentVersion) {
t.Fatal()
}
if !IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major, minor, patch+100)) {
t.Fatal()
}
if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major, minor+1, patch)) {
t.Fatal()
}
if IsCurrentVersion(fmt.Sprintf("%v.%v.%v", major+1, minor, patch)) {
t.Fatal()
}
}

Просмотреть файл

@@ -37,7 +37,6 @@ func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore {
} }
func (s SqlChannelStore) UpgradeSchemaIfNeeded() { func (s SqlChannelStore) UpgradeSchemaIfNeeded() {
s.CreateColumnIfNotExists("Channels", "CreatorId", "varchar(26)", "character varying(26)", "")
} }
func (s SqlChannelStore) CreateIndexesIfNotExists() { func (s SqlChannelStore) CreateIndexesIfNotExists() {

Просмотреть файл

@@ -196,9 +196,9 @@ func (s SqlPostStore) GetEtag(channelId string) StoreChannel {
var et etagPosts var et etagPosts
err := s.GetReplica().SelectOne(&et, "SELECT Id, UpdateAt FROM Posts WHERE ChannelId = :ChannelId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"ChannelId": channelId}) err := s.GetReplica().SelectOne(&et, "SELECT Id, UpdateAt FROM Posts WHERE ChannelId = :ChannelId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"ChannelId": channelId})
if err != nil { if err != nil {
result.Data = fmt.Sprintf("%v.0.%v", model.ETAG_ROOT_VERSION, model.GetMillis()) result.Data = fmt.Sprintf("%v.0.%v", model.CurrentVersion, model.GetMillis())
} else { } else {
result.Data = fmt.Sprintf("%v.%v.%v", model.ETAG_ROOT_VERSION, et.Id, et.UpdateAt) result.Data = fmt.Sprintf("%v.%v.%v", model.CurrentVersion, et.Id, et.UpdateAt)
} }
storeChannel <- result storeChannel <- result

Просмотреть файл

@@ -37,14 +37,14 @@ func TestPostStoreGet(t *testing.T) {
o1.Message = "a" + model.NewId() + "b" o1.Message = "a" + model.NewId() + "b"
etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag1, model.ETAG_ROOT_VERSION+".0.") != 0 { if strings.Index(etag1, model.CurrentVersion+".0.") != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
o1 = (<-store.Post().Save(o1)).Data.(*model.Post) o1 = (<-store.Post().Save(o1)).Data.(*model.Post)
etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag2, model.ETAG_ROOT_VERSION+"."+o1.Id) != 0 { if strings.Index(etag2, model.CurrentVersion+"."+o1.Id) != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
@@ -136,7 +136,7 @@ func TestPostStoreDelete(t *testing.T) {
o1.Message = "a" + model.NewId() + "b" o1.Message = "a" + model.NewId() + "b"
etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag1 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag1, model.ETAG_ROOT_VERSION+".0.") != 0 { if strings.Index(etag1, model.CurrentVersion+".0.") != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
@@ -160,7 +160,7 @@ func TestPostStoreDelete(t *testing.T) {
} }
etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string) etag2 := (<-store.Post().GetEtag(o1.ChannelId)).Data.(string)
if strings.Index(etag2, model.ETAG_ROOT_VERSION+"."+o1.Id) != 0 { if strings.Index(etag2, model.CurrentVersion+"."+o1.Id) != 0 {
t.Fatal("Invalid Etag") t.Fatal("Invalid Etag")
} }
} }

Просмотреть файл

@@ -39,6 +39,7 @@ type SqlStore struct {
audit AuditStore audit AuditStore
session SessionStore session SessionStore
oauth OAuthStore oauth OAuthStore
system SystemStore
} }
func NewSqlStore() Store { func NewSqlStore() Store {
@@ -56,9 +57,30 @@ func NewSqlStore() Store {
utils.Cfg.SqlSettings.Trace) utils.Cfg.SqlSettings.Trace)
} }
schemaVersion := sqlStore.GetCurrentSchemaVersion()
// If the version is already set then we are potentially in an 'upgrade needed' state
if schemaVersion != "" {
// Check to see if it's the most current database schema version
if !model.IsCurrentVersion(schemaVersion) {
// If we are upgrading from the previous version then print a warning and continue
if model.IsPreviousVersion(schemaVersion) {
l4g.Warn("The database schema version of " + schemaVersion + " appears to be out of date")
l4g.Warn("Attempting to upgrade the database schema version to " + model.CurrentVersion)
} else {
// If this is an 'upgrade needed' state but the user is attempting to skip a version then halt the world
l4g.Critical("The database schema version of " + schemaVersion + " cannot be upgraded. You must not skip a version.")
time.Sleep(time.Second)
panic("The database schema version of " + schemaVersion + " cannot be upgraded. You must not skip a version.")
}
}
}
// Temporary upgrade code, remove after 0.8.0 release // Temporary upgrade code, remove after 0.8.0 release
if sqlStore.DoesColumnExist("Sessions", "AltId") { if sqlStore.DoesTableExist("Sessions") {
sqlStore.GetMaster().Exec("DROP TABLE IF EXISTS Sessions") if sqlStore.DoesColumnExist("Sessions", "AltId") {
sqlStore.GetMaster().Exec("DROP TABLE IF EXISTS Sessions")
}
} }
sqlStore.team = NewSqlTeamStore(sqlStore) sqlStore.team = NewSqlTeamStore(sqlStore)
@@ -68,6 +90,7 @@ func NewSqlStore() Store {
sqlStore.audit = NewSqlAuditStore(sqlStore) sqlStore.audit = NewSqlAuditStore(sqlStore)
sqlStore.session = NewSqlSessionStore(sqlStore) sqlStore.session = NewSqlSessionStore(sqlStore)
sqlStore.oauth = NewSqlOAuthStore(sqlStore) sqlStore.oauth = NewSqlOAuthStore(sqlStore)
sqlStore.system = NewSqlSystemStore(sqlStore)
sqlStore.master.CreateTablesIfNotExists() sqlStore.master.CreateTablesIfNotExists()
@@ -78,6 +101,7 @@ func NewSqlStore() Store {
sqlStore.audit.(*SqlAuditStore).UpgradeSchemaIfNeeded() sqlStore.audit.(*SqlAuditStore).UpgradeSchemaIfNeeded()
sqlStore.session.(*SqlSessionStore).UpgradeSchemaIfNeeded() sqlStore.session.(*SqlSessionStore).UpgradeSchemaIfNeeded()
sqlStore.oauth.(*SqlOAuthStore).UpgradeSchemaIfNeeded() sqlStore.oauth.(*SqlOAuthStore).UpgradeSchemaIfNeeded()
sqlStore.system.(*SqlSystemStore).UpgradeSchemaIfNeeded()
sqlStore.team.(*SqlTeamStore).CreateIndexesIfNotExists() sqlStore.team.(*SqlTeamStore).CreateIndexesIfNotExists()
sqlStore.channel.(*SqlChannelStore).CreateIndexesIfNotExists() sqlStore.channel.(*SqlChannelStore).CreateIndexesIfNotExists()
@@ -86,6 +110,17 @@ func NewSqlStore() Store {
sqlStore.audit.(*SqlAuditStore).CreateIndexesIfNotExists() sqlStore.audit.(*SqlAuditStore).CreateIndexesIfNotExists()
sqlStore.session.(*SqlSessionStore).CreateIndexesIfNotExists() sqlStore.session.(*SqlSessionStore).CreateIndexesIfNotExists()
sqlStore.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists() sqlStore.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists()
sqlStore.system.(*SqlSystemStore).CreateIndexesIfNotExists()
if model.IsPreviousVersion(schemaVersion) {
sqlStore.system.Update(&model.System{Name: "Version", Value: model.CurrentVersion})
l4g.Warn("The database schema has been upgraded to version " + model.CurrentVersion)
}
if schemaVersion == "" {
sqlStore.system.Save(&model.System{Name: "Version", Value: model.CurrentVersion})
l4g.Info("The database schema has been set to version " + model.CurrentVersion)
}
return sqlStore return sqlStore
} }
@@ -131,6 +166,56 @@ func setupConnection(con_type string, driver string, dataSource string, maxIdle
return dbmap return dbmap
} }
func (ss SqlStore) GetCurrentSchemaVersion() string {
version, _ := ss.GetMaster().SelectStr("SELECT Value FROM Systems WHERE Name='Version'")
return version
}
func (ss SqlStore) DoesTableExist(tableName string) bool {
if utils.Cfg.SqlSettings.DriverName == "postgres" {
count, err := ss.GetMaster().SelectInt(
`SELECT count(relname) FROM pg_class WHERE relname=$1`,
strings.ToLower(tableName),
)
if err != nil {
l4g.Critical("Failed to check if table exists %v", err)
time.Sleep(time.Second)
panic("Failed to check if table exists " + err.Error())
}
return count > 0
} else if utils.Cfg.SqlSettings.DriverName == "mysql" {
count, err := ss.GetMaster().SelectInt(
`SELECT
COUNT(0) AS table_exists
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = ?
`,
tableName,
)
if err != nil {
l4g.Critical("Failed to check if table exists %v", err)
time.Sleep(time.Second)
panic("Failed to check if table exists " + err.Error())
}
return count > 0
} else {
l4g.Critical("Failed to check if column exists because of missing driver")
time.Sleep(time.Second)
panic("Failed to check if column exists because of missing driver")
}
}
func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool { func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool {
if utils.Cfg.SqlSettings.DriverName == "postgres" { if utils.Cfg.SqlSettings.DriverName == "postgres" {
count, err := ss.GetMaster().SelectInt( count, err := ss.GetMaster().SelectInt(
@@ -380,6 +465,10 @@ func (ss SqlStore) OAuth() OAuthStore {
return ss.oauth return ss.oauth
} }
func (ss SqlStore) System() SystemStore {
return ss.system
}
type mattermConverter struct{} type mattermConverter struct{}
func (me mattermConverter) ToDb(val interface{}) (interface{}, error) { func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {

92
store/sql_system_store.go Обычный файл
Просмотреть файл

@@ -0,0 +1,92 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"github.com/mattermost/platform/model"
)
type SqlSystemStore struct {
*SqlStore
}
func NewSqlSystemStore(sqlStore *SqlStore) SystemStore {
s := &SqlSystemStore{sqlStore}
for _, db := range sqlStore.GetAllConns() {
table := db.AddTableWithName(model.System{}, "Systems").SetKeys(false, "Name")
table.ColMap("Name").SetMaxSize(64)
table.ColMap("Value").SetMaxSize(1024)
}
return s
}
func (s SqlSystemStore) UpgradeSchemaIfNeeded() {
}
func (s SqlSystemStore) CreateIndexesIfNotExists() {
}
func (s SqlSystemStore) Save(system *model.System) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
if err := s.GetMaster().Insert(system); err != nil {
result.Err = model.NewAppError("SqlSystemStore.Save", "We encounted an error saving the system property", "")
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlSystemStore) Update(system *model.System) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
if _, err := s.GetMaster().Update(system); err != nil {
result.Err = model.NewAppError("SqlSystemStore.Save", "We encounted an error updating the system property", "")
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlSystemStore) Get() StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
var systems []model.System
props := make(model.StringMap)
if _, err := s.GetReplica().Select(&systems, "SELECT * FROM Systems"); err != nil {
result.Err = model.NewAppError("SqlSystemStore.Get", "We encounted an error finding the system properties", "")
} else {
for _, prop := range systems {
props[prop.Name] = prop.Value
}
result.Data = props
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}

33
store/sql_system_store_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,33 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"github.com/mattermost/platform/model"
"testing"
)
func TestSqlSystemStore(t *testing.T) {
Setup()
system := &model.System{Name: model.NewId(), Value: "value"}
Must(store.System().Save(system))
result := <-store.System().Get()
systems := result.Data.(model.StringMap)
if systems[system.Name] != system.Value {
t.Fatal()
}
system.Value = "value2"
Must(store.System().Update(system))
result2 := <-store.System().Get()
systems2 := result2.Data.(model.StringMap)
if systems2[system.Name] != system.Value {
t.Fatal()
}
}

Просмотреть файл

@@ -325,9 +325,9 @@ func (s SqlUserStore) GetEtagForProfiles(teamId string) StoreChannel {
updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users WHERE TeamId = :TeamId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId}) updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users WHERE TeamId = :TeamId ORDER BY UpdateAt DESC LIMIT 1", map[string]interface{}{"TeamId": teamId})
if err != nil { if err != nil {
result.Data = fmt.Sprintf("%v.%v", model.ETAG_ROOT_VERSION, model.GetMillis()) result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
} else { } else {
result.Data = fmt.Sprintf("%v.%v", model.ETAG_ROOT_VERSION, updateAt) result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
} }
storeChannel <- result storeChannel <- result

Просмотреть файл

@@ -35,6 +35,7 @@ type Store interface {
Audit() AuditStore Audit() AuditStore
Session() SessionStore Session() SessionStore
OAuth() OAuthStore OAuth() OAuthStore
System() SystemStore
Close() Close()
} }
@@ -130,3 +131,9 @@ type OAuthStore interface {
GetAccessDataByAuthCode(authCode string) StoreChannel GetAccessDataByAuthCode(authCode string) StoreChannel
RemoveAccessData(token string) StoreChannel RemoveAccessData(token string) StoreChannel
} }
type SystemStore interface {
Save(system *model.System) StoreChannel
Update(system *model.System) StoreChannel
Get() StoreChannel
}

Просмотреть файл

@@ -170,7 +170,11 @@ func getSanitizeOptions(c *model.Config) map[string]bool {
func getClientProperties(c *model.Config) map[string]string { func getClientProperties(c *model.Config) map[string]string {
props := make(map[string]string) props := make(map[string]string)
props["Version"] = c.ServiceSettings.Version props["Version"] = model.CurrentVersion
props["BuildNumber"] = model.BuildNumber
props["BuildDate"] = model.BuildDate
props["BuildHash"] = model.BuildHash
props["SiteName"] = c.ServiceSettings.SiteName props["SiteName"] = c.ServiceSettings.SiteName
props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail) props["ByPassEmail"] = strconv.FormatBool(c.EmailSettings.ByPassEmail)
props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail props["FeedbackEmail"] = c.EmailSettings.FeedbackEmail

Просмотреть файл

@@ -251,6 +251,17 @@ export default class SecurityTab extends React.Component {
<div className='divider-dark first'/> <div className='divider-dark first'/>
{passwordSection} {passwordSection}
<div className='divider-dark'/> <div className='divider-dark'/>
<ul
className='section-min'
>
<li className='col-sm-10 section-title'>{'Version ' + global.window.config.Version}</li>
<li className='col-sm-7 section-describe'>
<div className='text-nowrap'>{'Build Number: ' + global.window.config.BuildNumber}</div>
<div className='text-nowrap'>{'Build Date: ' + global.window.config.BuildDate}</div>
<div className='text-nowrap'>{'Build Hash: ' + global.window.config.BuildHash}</div>
</li>
</ul>
<div className='divider-dark'/>
<br></br> <br></br>
<a <a
data-toggle='modal' data-toggle='modal'

Просмотреть файл

@@ -9,9 +9,6 @@ function getPrefix() {
return UserStore.getCurrentId() + '_'; return UserStore.getCurrentId() + '_';
} }
// Also change model/utils.go ETAG_ROOT_VERSION
var BROWSER_STORE_VERSION = '.5';
class BrowserStoreClass { class BrowserStoreClass {
constructor() { constructor() {
this.getItem = this.getItem.bind(this); this.getItem = this.getItem.bind(this);
@@ -25,9 +22,9 @@ class BrowserStoreClass {
this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this); this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this);
var currentVersion = localStorage.getItem('local_storage_version'); var currentVersion = localStorage.getItem('local_storage_version');
if (currentVersion !== BROWSER_STORE_VERSION) { if (currentVersion !== global.window.config.Version) {
this.clear(); this.clear();
localStorage.setItem('local_storage_version', BROWSER_STORE_VERSION); localStorage.setItem('local_storage_version', global.window.config.Version);
} }
} }

Просмотреть файл

@@ -56,7 +56,7 @@ function autolinkUrls(text, tokens) {
const linkText = match.getMatchedText(); const linkText = match.getMatchedText();
let url = linkText; let url = linkText;
if (!url.lastIndexOf('http', 0) === 0) { if (url.lastIndexOf('http', 0) !== 0) {
url = `http://${linkText}`; url = `http://${linkText}`;
} }