You've already forked focalboard
mirror of
https://github.com/mattermost/focalboard.git
synced 2025-07-15 23:54:29 +02:00
Channels style UUID (#1369)
* server channels style uuids * webapp channels style uuids
This commit is contained in:
@ -1170,7 +1170,7 @@ func (a *API) handlePostWorkspaceRegenerateSignupToken(w http.ResponseWriter, r
|
|||||||
auditRec := a.makeAuditRecord(r, "regenerateSignupToken", audit.Fail)
|
auditRec := a.makeAuditRecord(r, "regenerateSignupToken", audit.Fail)
|
||||||
defer a.audit.LogRecord(audit.LevelModify, auditRec)
|
defer a.audit.LogRecord(audit.LevelModify, auditRec)
|
||||||
|
|
||||||
workspace.SignupToken = utils.CreateGUID()
|
workspace.SignupToken = utils.NewID(utils.IDTypeToken)
|
||||||
|
|
||||||
err = a.app.UpsertWorkspaceSignupToken(*workspace)
|
err = a.app.UpsertWorkspaceSignupToken(*workspace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/mattermost/focalboard/server/model"
|
"github.com/mattermost/focalboard/server/model"
|
||||||
"github.com/mattermost/focalboard/server/services/auth"
|
"github.com/mattermost/focalboard/server/services/auth"
|
||||||
"github.com/mattermost/focalboard/server/services/store"
|
"github.com/mattermost/focalboard/server/services/store"
|
||||||
|
"github.com/mattermost/focalboard/server/utils"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
|
|
||||||
@ -102,8 +102,8 @@ func (a *App) Login(username, email, password, mfaToken string) (string, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
session := model.Session{
|
session := model.Session{
|
||||||
ID: uuid.New().String(),
|
ID: utils.NewID(utils.IDTypeSession),
|
||||||
Token: uuid.New().String(),
|
Token: utils.NewID(utils.IDTypeToken),
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
AuthService: authService,
|
AuthService: authService,
|
||||||
Props: map[string]interface{}{},
|
Props: map[string]interface{}{},
|
||||||
@ -149,7 +149,7 @@ func (a *App) RegisterUser(username, email, password string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = a.store.CreateUser(&model.User{
|
err = a.store.CreateUser(&model.User{
|
||||||
ID: uuid.New().String(),
|
ID: utils.NewID(utils.IDTypeUser),
|
||||||
Username: username,
|
Username: username,
|
||||||
Email: email,
|
Email: email,
|
||||||
Password: auth.HashPassword(password),
|
Password: auth.HashPassword(password),
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var mockUser = &model.User{
|
var mockUser = &model.User{
|
||||||
ID: utils.CreateGUID(),
|
ID: utils.NewID(utils.IDTypeUser),
|
||||||
Username: "testUsername",
|
Username: "testUsername",
|
||||||
Email: "testEmail",
|
Email: "testEmail",
|
||||||
Password: auth.HashPassword("testPassword"),
|
Password: auth.HashPassword("testPassword"),
|
||||||
|
@ -20,7 +20,7 @@ func (a *App) SaveFile(reader io.Reader, workspaceID, rootID, filename string) (
|
|||||||
fileExtension = ".jpg"
|
fileExtension = ".jpg"
|
||||||
}
|
}
|
||||||
|
|
||||||
createdFilename := fmt.Sprintf(`%s%s`, utils.CreateGUID(), fileExtension)
|
createdFilename := fmt.Sprintf(`%s%s`, utils.NewID(utils.IDTypeNone), fileExtension)
|
||||||
filePath := filepath.Join(workspaceID, rootID, createdFilename)
|
filePath := filepath.Join(workspaceID, rootID, createdFilename)
|
||||||
|
|
||||||
_, appErr := a.filesBackend.WriteFile(reader, filePath)
|
_, appErr := a.filesBackend.WriteFile(reader, filePath)
|
||||||
|
@ -18,12 +18,12 @@ func TestGetSharing(t *testing.T) {
|
|||||||
defer tearDown()
|
defer tearDown()
|
||||||
|
|
||||||
container := st.Container{
|
container := st.Container{
|
||||||
WorkspaceID: utils.CreateGUID(),
|
WorkspaceID: utils.NewID(utils.IDTypeWorkspace),
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("should get a sharing successfully", func(t *testing.T) {
|
t.Run("should get a sharing successfully", func(t *testing.T) {
|
||||||
want := &model.Sharing{
|
want := &model.Sharing{
|
||||||
ID: utils.CreateGUID(),
|
ID: utils.NewID(utils.IDTypeBlock),
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Token: "token",
|
Token: "token",
|
||||||
ModifiedBy: "otherid",
|
ModifiedBy: "otherid",
|
||||||
@ -67,10 +67,10 @@ func TestUpsertSharing(t *testing.T) {
|
|||||||
defer tearDown()
|
defer tearDown()
|
||||||
|
|
||||||
container := st.Container{
|
container := st.Container{
|
||||||
WorkspaceID: utils.CreateGUID(),
|
WorkspaceID: utils.NewID(utils.IDTypeWorkspace),
|
||||||
}
|
}
|
||||||
sharing := model.Sharing{
|
sharing := model.Sharing{
|
||||||
ID: utils.CreateGUID(),
|
ID: utils.NewID(utils.IDTypeBlock),
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Token: "token",
|
Token: "token",
|
||||||
ModifiedBy: "otherid",
|
ModifiedBy: "otherid",
|
||||||
|
@ -16,7 +16,7 @@ func (a *App) GetRootWorkspace() (*model.Workspace, error) {
|
|||||||
if workspace == nil {
|
if workspace == nil {
|
||||||
workspace = &model.Workspace{
|
workspace = &model.Workspace{
|
||||||
ID: workspaceID,
|
ID: workspaceID,
|
||||||
SignupToken: utils.CreateGUID(),
|
SignupToken: utils.NewID(utils.IDTypeToken),
|
||||||
}
|
}
|
||||||
err := a.store.UpsertWorkspaceSignupToken(*workspace)
|
err := a.store.UpsertWorkspaceSignupToken(*workspace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -22,7 +22,7 @@ type TestHelper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mockSession = &model.Session{
|
var mockSession = &model.Session{
|
||||||
ID: utils.CreateGUID(),
|
ID: utils.NewID(utils.IDTypeSession),
|
||||||
Token: "goodToken",
|
Token: "goodToken",
|
||||||
UserID: "12345",
|
UserID: "12345",
|
||||||
CreateAt: time.Now().Unix() - 2000,
|
CreateAt: time.Now().Unix() - 2000,
|
||||||
|
@ -7,7 +7,6 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/golang-migrate/migrate/v4 v4.14.1
|
github.com/golang-migrate/migrate/v4 v4.14.1
|
||||||
github.com/golang/mock v1.5.0
|
github.com/golang/mock v1.5.0
|
||||||
github.com/google/uuid v1.2.0
|
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/lib/pq v1.10.2
|
github.com/lib/pq v1.10.2
|
||||||
|
@ -17,8 +17,8 @@ func TestGetBlocks(t *testing.T) {
|
|||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
initialCount := len(blocks)
|
initialCount := len(blocks)
|
||||||
|
|
||||||
blockID1 := utils.CreateGUID()
|
blockID1 := utils.NewID(utils.IDTypeBlock)
|
||||||
blockID2 := utils.CreateGUID()
|
blockID2 := utils.NewID(utils.IDTypeBlock)
|
||||||
newBlocks := []model.Block{
|
newBlocks := []model.Block{
|
||||||
{
|
{
|
||||||
ID: blockID1,
|
ID: blockID1,
|
||||||
@ -58,9 +58,9 @@ func TestPostBlock(t *testing.T) {
|
|||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
initialCount := len(blocks)
|
initialCount := len(blocks)
|
||||||
|
|
||||||
blockID1 := utils.CreateGUID()
|
blockID1 := utils.NewID(utils.IDTypeBlock)
|
||||||
blockID2 := utils.CreateGUID()
|
blockID2 := utils.NewID(utils.IDTypeBlock)
|
||||||
blockID3 := utils.CreateGUID()
|
blockID3 := utils.NewID(utils.IDTypeBlock)
|
||||||
|
|
||||||
t.Run("Create a single block", func(t *testing.T) {
|
t.Run("Create a single block", func(t *testing.T) {
|
||||||
block := model.Block{
|
block := model.Block{
|
||||||
@ -152,7 +152,7 @@ func TestPatchBlock(t *testing.T) {
|
|||||||
th := SetupTestHelper().InitBasic()
|
th := SetupTestHelper().InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
blockID := utils.CreateGUID()
|
blockID := utils.NewID(utils.IDTypeBlock)
|
||||||
|
|
||||||
block := model.Block{
|
block := model.Block{
|
||||||
ID: blockID,
|
ID: blockID,
|
||||||
@ -253,7 +253,7 @@ func TestDeleteBlock(t *testing.T) {
|
|||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
initialCount := len(blocks)
|
initialCount := len(blocks)
|
||||||
|
|
||||||
blockID := utils.CreateGUID()
|
blockID := utils.NewID(utils.IDTypeBlock)
|
||||||
t.Run("Create a block", func(t *testing.T) {
|
t.Run("Create a block", func(t *testing.T) {
|
||||||
block := model.Block{
|
block := model.Block{
|
||||||
ID: blockID,
|
ID: blockID,
|
||||||
@ -298,9 +298,10 @@ func TestGetSubtree(t *testing.T) {
|
|||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
initialCount := len(blocks)
|
initialCount := len(blocks)
|
||||||
|
|
||||||
parentBlockID := utils.CreateGUID()
|
parentBlockID := utils.NewID(utils.IDTypeBlock)
|
||||||
childBlockID1 := utils.CreateGUID()
|
childBlockID1 := utils.NewID(utils.IDTypeBlock)
|
||||||
childBlockID2 := utils.CreateGUID()
|
childBlockID2 := utils.NewID(utils.IDTypeBlock)
|
||||||
|
|
||||||
t.Run("Create the block structure", func(t *testing.T) {
|
t.Run("Create the block structure", func(t *testing.T) {
|
||||||
newBlocks := []model.Block{
|
newBlocks := []model.Block{
|
||||||
{
|
{
|
||||||
|
@ -12,8 +12,8 @@ func TestSharing(t *testing.T) {
|
|||||||
th := SetupTestHelper().InitBasic()
|
th := SetupTestHelper().InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
rootID := utils.CreateGUID()
|
rootID := utils.NewID(utils.IDTypeBlock)
|
||||||
token := utils.CreateGUID()
|
token := utils.NewID(utils.IDTypeToken)
|
||||||
|
|
||||||
t.Run("Check no initial sharing", func(t *testing.T) {
|
t.Run("Check no initial sharing", func(t *testing.T) {
|
||||||
sharing, resp := th.Client.GetSharing(rootID)
|
sharing, resp := th.Client.GetSharing(rootID)
|
||||||
|
@ -23,7 +23,7 @@ func TestUserRegister(t *testing.T) {
|
|||||||
registerRequest := &api.RegisterRequest{
|
registerRequest := &api.RegisterRequest{
|
||||||
Username: fakeUsername,
|
Username: fakeUsername,
|
||||||
Email: fakeEmail,
|
Email: fakeEmail,
|
||||||
Password: utils.CreateGUID(),
|
Password: utils.NewID(utils.IDTypeNone),
|
||||||
}
|
}
|
||||||
success, resp := th.Client.Register(registerRequest)
|
success, resp := th.Client.Register(registerRequest)
|
||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
@ -44,7 +44,7 @@ func TestUserLogin(t *testing.T) {
|
|||||||
Type: "normal",
|
Type: "normal",
|
||||||
Username: "nonexistuser",
|
Username: "nonexistuser",
|
||||||
Email: "",
|
Email: "",
|
||||||
Password: utils.CreateGUID(),
|
Password: utils.NewID(utils.IDTypeNone),
|
||||||
}
|
}
|
||||||
data, resp := th.Client.Login(loginRequest)
|
data, resp := th.Client.Login(loginRequest)
|
||||||
require.Error(t, resp.Error)
|
require.Error(t, resp.Error)
|
||||||
@ -52,7 +52,7 @@ func TestUserLogin(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with registered user", func(t *testing.T) {
|
t.Run("with registered user", func(t *testing.T) {
|
||||||
password := utils.CreateGUID()
|
password := utils.NewID(utils.IDTypeNone)
|
||||||
// register
|
// register
|
||||||
registerRequest := &api.RegisterRequest{
|
registerRequest := &api.RegisterRequest{
|
||||||
Username: fakeUsername,
|
Username: fakeUsername,
|
||||||
@ -89,7 +89,7 @@ func TestGetMe(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("logged in", func(t *testing.T) {
|
t.Run("logged in", func(t *testing.T) {
|
||||||
// register
|
// register
|
||||||
password := utils.CreateGUID()
|
password := utils.NewID(utils.IDTypeNone)
|
||||||
registerRequest := &api.RegisterRequest{
|
registerRequest := &api.RegisterRequest{
|
||||||
Username: fakeUsername,
|
Username: fakeUsername,
|
||||||
Email: fakeEmail,
|
Email: fakeEmail,
|
||||||
@ -124,7 +124,7 @@ func TestGetUser(t *testing.T) {
|
|||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
// register
|
// register
|
||||||
password := utils.CreateGUID()
|
password := utils.NewID(utils.IDTypeNone)
|
||||||
registerRequest := &api.RegisterRequest{
|
registerRequest := &api.RegisterRequest{
|
||||||
Username: fakeUsername,
|
Username: fakeUsername,
|
||||||
Email: fakeEmail,
|
Email: fakeEmail,
|
||||||
@ -169,7 +169,7 @@ func TestUserChangePassword(t *testing.T) {
|
|||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
// register
|
// register
|
||||||
password := utils.CreateGUID()
|
password := utils.NewID(utils.IDTypeNone)
|
||||||
registerRequest := &api.RegisterRequest{
|
registerRequest := &api.RegisterRequest{
|
||||||
Username: fakeUsername,
|
Username: fakeUsername,
|
||||||
Email: fakeEmail,
|
Email: fakeEmail,
|
||||||
@ -197,7 +197,7 @@ func TestUserChangePassword(t *testing.T) {
|
|||||||
// change password
|
// change password
|
||||||
success, resp = th.Client.UserChangePassword(originalMe.ID, &api.ChangePasswordRequest{
|
success, resp = th.Client.UserChangePassword(originalMe.ID, &api.ChangePasswordRequest{
|
||||||
OldPassword: password,
|
OldPassword: password,
|
||||||
NewPassword: utils.CreateGUID(),
|
NewPassword: utils.NewID(utils.IDTypeNone),
|
||||||
})
|
})
|
||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
@ -216,7 +216,7 @@ func TestWorkspaceUploadFile(t *testing.T) {
|
|||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
workspaceID := "0"
|
workspaceID := "0"
|
||||||
rootID := utils.CreateGUID()
|
rootID := utils.NewID(utils.IDTypeBlock)
|
||||||
data := randomBytes(t, 1024)
|
data := randomBytes(t, 1024)
|
||||||
result, resp := th.Client.WorkspaceUploadFile(workspaceID, rootID, bytes.NewReader(data))
|
result, resp := th.Client.WorkspaceUploadFile(workspaceID, rootID, bytes.NewReader(data))
|
||||||
require.Error(t, resp.Error)
|
require.Error(t, resp.Error)
|
||||||
@ -228,7 +228,7 @@ func TestWorkspaceUploadFile(t *testing.T) {
|
|||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
workspaceID := "0"
|
workspaceID := "0"
|
||||||
rootID := utils.CreateGUID()
|
rootID := utils.NewID(utils.IDTypeBlock)
|
||||||
data := randomBytes(t, 1024)
|
data := randomBytes(t, 1024)
|
||||||
result, resp := th.Client.WorkspaceUploadFile(workspaceID, rootID, bytes.NewReader(data))
|
result, resp := th.Client.WorkspaceUploadFile(workspaceID, rootID, bytes.NewReader(data))
|
||||||
require.NoError(t, resp.Error)
|
require.NoError(t, resp.Error)
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@ -30,6 +29,7 @@ import (
|
|||||||
"github.com/mattermost/focalboard/server/services/store/sqlstore"
|
"github.com/mattermost/focalboard/server/services/store/sqlstore"
|
||||||
"github.com/mattermost/focalboard/server/services/telemetry"
|
"github.com/mattermost/focalboard/server/services/telemetry"
|
||||||
"github.com/mattermost/focalboard/server/services/webhook"
|
"github.com/mattermost/focalboard/server/services/webhook"
|
||||||
|
"github.com/mattermost/focalboard/server/utils"
|
||||||
"github.com/mattermost/focalboard/server/web"
|
"github.com/mattermost/focalboard/server/web"
|
||||||
"github.com/mattermost/focalboard/server/ws"
|
"github.com/mattermost/focalboard/server/ws"
|
||||||
"github.com/oklog/run"
|
"github.com/oklog/run"
|
||||||
@ -37,7 +37,6 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/filestore"
|
"github.com/mattermost/mattermost-server/v6/shared/filestore"
|
||||||
"github.com/mattermost/mattermost-server/v6/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -170,8 +169,8 @@ func New(params Params) (*Server, error) {
|
|||||||
// Init telemetry
|
// Init telemetry
|
||||||
telemetryID := settings["TelemetryID"]
|
telemetryID := settings["TelemetryID"]
|
||||||
if len(telemetryID) == 0 {
|
if len(telemetryID) == 0 {
|
||||||
telemetryID = uuid.New().String()
|
telemetryID = utils.NewID(utils.IDTypeNone)
|
||||||
if err = params.DBStore.SetSystemSetting("TelemetryID", uuid.New().String()); err != nil {
|
if err = params.DBStore.SetSystemSetting("TelemetryID", telemetryID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -284,7 +283,7 @@ func (s *Server) Start() error {
|
|||||||
s.metricsUpdaterTask = scheduler.CreateRecurringTask("updateMetrics", metricsUpdater, updateMetricsTaskFrequency)
|
s.metricsUpdaterTask = scheduler.CreateRecurringTask("updateMetrics", metricsUpdater, updateMetricsTaskFrequency)
|
||||||
|
|
||||||
if s.config.Telemetry {
|
if s.config.Telemetry {
|
||||||
firstRun := utils.MillisFromTime(time.Now())
|
firstRun := utils.GetMillis()
|
||||||
s.telemetry.RunTelemetryJob(firstRun)
|
s.telemetry.RunTelemetryJob(firstRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func (s *SQLStore) UpsertWorkspaceSignupToken(workspace model.Workspace) error {
|
|||||||
|
|
||||||
func (s *SQLStore) UpsertWorkspaceSettings(workspace model.Workspace) error {
|
func (s *SQLStore) UpsertWorkspaceSettings(workspace model.Workspace) error {
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
signupToken := utils.CreateGUID()
|
signupToken := utils.NewID(utils.IDTypeToken)
|
||||||
|
|
||||||
settingsJSON, err := json.Marshal(workspace.Settings)
|
settingsJSON, err := json.Marshal(workspace.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -8,11 +8,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/mattermost/focalboard/server/model"
|
"github.com/mattermost/focalboard/server/model"
|
||||||
"github.com/mattermost/focalboard/server/services/store"
|
"github.com/mattermost/focalboard/server/services/store"
|
||||||
|
"github.com/mattermost/focalboard/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StoreTestUserStore(t *testing.T, setup func(t *testing.T) (store.Store, func())) {
|
func StoreTestUserStore(t *testing.T, setup func(t *testing.T) (store.Store, func())) {
|
||||||
@ -47,7 +47,7 @@ func testGetWorkspaceUsers(t *testing.T, store store.Store) {
|
|||||||
require.Equal(t, 0, len(users))
|
require.Equal(t, 0, len(users))
|
||||||
require.Equal(t, sql.ErrNoRows, err)
|
require.Equal(t, sql.ErrNoRows, err)
|
||||||
|
|
||||||
userID := uuid.New().String()
|
userID := utils.NewID(utils.IDTypeUser)
|
||||||
|
|
||||||
err = store.CreateUser(&model.User{
|
err = store.CreateUser(&model.User{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
@ -71,7 +71,7 @@ func testGetWorkspaceUsers(t *testing.T, store store.Store) {
|
|||||||
|
|
||||||
func testCreateAndGetUser(t *testing.T, store store.Store) {
|
func testCreateAndGetUser(t *testing.T, store store.Store) {
|
||||||
user := &model.User{
|
user := &model.User{
|
||||||
ID: uuid.New().String(),
|
ID: utils.NewID(utils.IDTypeUser),
|
||||||
Username: "damao",
|
Username: "damao",
|
||||||
Email: "mock@email.com",
|
Email: "mock@email.com",
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ func testCreateAndGetUser(t *testing.T, store store.Store) {
|
|||||||
|
|
||||||
func testCreateAndUpdateUser(t *testing.T, store store.Store) {
|
func testCreateAndUpdateUser(t *testing.T, store store.Store) {
|
||||||
user := &model.User{
|
user := &model.User{
|
||||||
ID: uuid.New().String(),
|
ID: utils.NewID(utils.IDTypeUser),
|
||||||
}
|
}
|
||||||
err := store.CreateUser(user)
|
err := store.CreateUser(user)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -129,7 +129,7 @@ func testCreateAndUpdateUser(t *testing.T, store store.Store) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("UpdateUserPassword", func(t *testing.T) {
|
t.Run("UpdateUserPassword", func(t *testing.T) {
|
||||||
newPassword := uuid.New().String()
|
newPassword := utils.NewID(utils.IDTypeNone)
|
||||||
err := store.UpdateUserPassword(user.Username, newPassword)
|
err := store.UpdateUserPassword(user.Username, newPassword)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ func testCreateAndUpdateUser(t *testing.T, store store.Store) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("UpdateUserPasswordByID", func(t *testing.T) {
|
t.Run("UpdateUserPasswordByID", func(t *testing.T) {
|
||||||
newPassword := uuid.New().String()
|
newPassword := utils.NewID(utils.IDTypeNone)
|
||||||
err := store.UpdateUserPasswordByID(user.ID, newPassword)
|
err := store.UpdateUserPasswordByID(user.ID, newPassword)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ func testCreateAndGetRegisteredUserCount(t *testing.T, store store.Store) {
|
|||||||
randomN := int(time.Now().Unix() % 10)
|
randomN := int(time.Now().Unix() % 10)
|
||||||
for i := 0; i < randomN; i++ {
|
for i := 0; i < randomN; i++ {
|
||||||
err := store.CreateUser(&model.User{
|
err := store.CreateUser(&model.User{
|
||||||
ID: uuid.New().String(),
|
ID: utils.NewID(utils.IDTypeUser),
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ func testUpsertWorkspaceSignupToken(t *testing.T, store store.Store) {
|
|||||||
workspaceID := "0"
|
workspaceID := "0"
|
||||||
workspace := &model.Workspace{
|
workspace := &model.Workspace{
|
||||||
ID: workspaceID,
|
ID: workspaceID,
|
||||||
SignupToken: utils.CreateGUID(),
|
SignupToken: utils.NewID(utils.IDTypeToken),
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert
|
// insert
|
||||||
@ -55,7 +55,7 @@ func testUpsertWorkspaceSignupToken(t *testing.T, store store.Store) {
|
|||||||
require.Equal(t, workspace.SignupToken, got.SignupToken)
|
require.Equal(t, workspace.SignupToken, got.SignupToken)
|
||||||
|
|
||||||
// update signup token
|
// update signup token
|
||||||
workspace.SignupToken = utils.CreateGUID()
|
workspace.SignupToken = utils.NewID(utils.IDTypeToken)
|
||||||
err = store.UpsertWorkspaceSignupToken(*workspace)
|
err = store.UpsertWorkspaceSignupToken(*workspace)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ func testGetWorkspaceCount(t *testing.T, store store.Store) {
|
|||||||
workspaceID := fmt.Sprintf("%d", i)
|
workspaceID := fmt.Sprintf("%d", i)
|
||||||
workspace := &model.Workspace{
|
workspace := &model.Workspace{
|
||||||
ID: workspaceID,
|
ID: workspaceID,
|
||||||
SignupToken: utils.CreateGUID(),
|
SignupToken: utils.NewID(utils.IDTypeToken),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := store.UpsertWorkspaceSignupToken(*workspace)
|
err := store.UpsertWorkspaceSignupToken(*workspace)
|
||||||
|
@ -1,28 +1,52 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
mm_model "github.com/mattermost/mattermost-server/v6/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateGUID returns a random GUID.
|
type IDType byte
|
||||||
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:])
|
|
||||||
|
|
||||||
return uuid
|
const (
|
||||||
|
IDTypeNone IDType = '7'
|
||||||
|
IDTypeWorkspace IDType = 'w'
|
||||||
|
IDTypeBoard IDType = 'b'
|
||||||
|
IDTypeCard IDType = 'c'
|
||||||
|
IDTypeView IDType = 'v'
|
||||||
|
IDTypeSession IDType = 's'
|
||||||
|
IDTypeUser IDType = 'u'
|
||||||
|
IDTypeToken IDType = 'k'
|
||||||
|
IDTypeBlock IDType = 'a'
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewId is a globally unique identifier. It is a [A-Z0-9] string 27
|
||||||
|
// characters long. It is a UUID version 4 Guid that is zbased32 encoded
|
||||||
|
// with the padding stripped off, and a one character alpha prefix indicating the
|
||||||
|
// type of entity or a `7` if unknown type.
|
||||||
|
func NewID(idType IDType) string {
|
||||||
|
return string(idType) + mm_model.NewId()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMillis is a convenience method to get milliseconds since epoch.
|
// GetMillis is a convenience method to get milliseconds since epoch.
|
||||||
func GetMillis() int64 {
|
func GetMillis() int64 {
|
||||||
return time.Now().UnixNano() / int64(time.Millisecond)
|
return mm_model.GetMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMillisForTime is a convenience method to get milliseconds since epoch for provided Time.
|
||||||
|
func GetMillisForTime(thisTime time.Time) int64 {
|
||||||
|
return mm_model.GetMillisForTime(thisTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTimeForMillis is a convenience method to get time.Time for milliseconds since epoch.
|
||||||
|
func GetTimeForMillis(millis int64) time.Time {
|
||||||
|
return mm_model.GetTimeForMillis(millis)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecondsToMillis is a convenience method to convert seconds to milliseconds.
|
||||||
|
func SecondsToMillis(seconds int64) int64 {
|
||||||
|
return seconds * 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
func StructToMap(v interface{}) (m map[string]interface{}) {
|
func StructToMap(v interface{}) (m map[string]interface{}) {
|
||||||
|
@ -41,7 +41,7 @@ interface Block {
|
|||||||
function createBlock(block?: Block): Block {
|
function createBlock(block?: Block): Block {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
return {
|
return {
|
||||||
id: block?.id || Utils.createGuid(),
|
id: block?.id || Utils.createGuid(Utils.blockTypeToIDType(block?.type)),
|
||||||
schema: 1,
|
schema: 1,
|
||||||
workspaceId: block?.workspaceId || '',
|
workspaceId: block?.workspaceId || '',
|
||||||
parentId: block?.parentId || '',
|
parentId: block?.parentId || '',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
import {Utils} from '../utils'
|
import {Utils, IDType} from '../utils'
|
||||||
|
|
||||||
import TelemetryClient, {TelemetryCategory, TelemetryActions} from '../telemetry/telemetryClient'
|
import TelemetryClient, {TelemetryCategory, TelemetryActions} from '../telemetry/telemetryClient'
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ function createBoard(block?: Block): Board {
|
|||||||
const selectProperties = cardProperties.find((o) => o.type === 'select')
|
const selectProperties = cardProperties.find((o) => o.type === 'select')
|
||||||
if (!selectProperties) {
|
if (!selectProperties) {
|
||||||
const property: IPropertyTemplate = {
|
const property: IPropertyTemplate = {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.BlockID),
|
||||||
name: 'Status',
|
name: 'Status',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: [],
|
options: [],
|
||||||
|
@ -8,7 +8,7 @@ import {Board, IPropertyOption, IPropertyTemplate, BoardGroup} from '../../block
|
|||||||
import {Card} from '../../blocks/card'
|
import {Card} from '../../blocks/card'
|
||||||
import {BoardView} from '../../blocks/boardView'
|
import {BoardView} from '../../blocks/boardView'
|
||||||
import mutator from '../../mutator'
|
import mutator from '../../mutator'
|
||||||
import {Utils} from '../../utils'
|
import {Utils, IDType} from '../../utils'
|
||||||
import Button from '../../widgets/buttons/button'
|
import Button from '../../widgets/buttons/button'
|
||||||
|
|
||||||
import KanbanCard from './kanbanCard'
|
import KanbanCard from './kanbanCard'
|
||||||
@ -55,7 +55,7 @@ const Kanban = (props: Props) => {
|
|||||||
Utils.log('onAddGroupClicked')
|
Utils.log('onAddGroupClicked')
|
||||||
|
|
||||||
const option: IPropertyOption = {
|
const option: IPropertyOption = {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.BlockID),
|
||||||
value: 'New group',
|
value: 'New group',
|
||||||
color: 'propColorDefault',
|
color: 'propColorDefault',
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import {Editor} from 'codemirror'
|
|||||||
import SimpleMDE from 'easymde'
|
import SimpleMDE from 'easymde'
|
||||||
import 'easymde/dist/easymde.min.css'
|
import 'easymde/dist/easymde.min.css'
|
||||||
|
|
||||||
import {Utils} from '../utils'
|
import {Utils, IDType} from '../utils'
|
||||||
import './markdownEditor.scss'
|
import './markdownEditor.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -25,7 +25,7 @@ type Props = {
|
|||||||
const MarkdownEditor = (props: Props): JSX. Element => {
|
const MarkdownEditor = (props: Props): JSX. Element => {
|
||||||
const {placeholderText, onFocus, onBlur, onChange, text, id} = props
|
const {placeholderText, onFocus, onBlur, onChange, text, id} = props
|
||||||
const [isEditing, setIsEditing] = useState(false)
|
const [isEditing, setIsEditing] = useState(false)
|
||||||
const [uniqueId] = useState(id || Utils.createGuid())
|
const [uniqueId] = useState(id || Utils.createGuid(IDType.None))
|
||||||
|
|
||||||
const [active, setActive] = useState(false)
|
const [active, setActive] = useState(false)
|
||||||
const [editorInstance, setEditorInstance] = useState<SimpleMDE>()
|
const [editorInstance, setEditorInstance] = useState<SimpleMDE>()
|
||||||
|
@ -10,7 +10,7 @@ import {ContentBlock} from '../blocks/contentBlock'
|
|||||||
import {CommentBlock} from '../blocks/commentBlock'
|
import {CommentBlock} from '../blocks/commentBlock'
|
||||||
import mutator from '../mutator'
|
import mutator from '../mutator'
|
||||||
import {OctoUtils} from '../octoUtils'
|
import {OctoUtils} from '../octoUtils'
|
||||||
import {Utils} from '../utils'
|
import {Utils, IDType} from '../utils'
|
||||||
import Editable from '../widgets/editable'
|
import Editable from '../widgets/editable'
|
||||||
import Switch from '../widgets/switch'
|
import Switch from '../widgets/switch'
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ const PropertyValueElement = (props:Props): JSX.Element => {
|
|||||||
onCreate={
|
onCreate={
|
||||||
async (newValue, currentValues) => {
|
async (newValue, currentValues) => {
|
||||||
const option: IPropertyOption = {
|
const option: IPropertyOption = {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.BlockID),
|
||||||
value: newValue,
|
value: newValue,
|
||||||
color: 'propColorDefault',
|
color: 'propColorDefault',
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ const PropertyValueElement = (props:Props): JSX.Element => {
|
|||||||
onCreate={
|
onCreate={
|
||||||
async (newValue) => {
|
async (newValue) => {
|
||||||
const option: IPropertyOption = {
|
const option: IPropertyOption = {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.BlockID),
|
||||||
value: newValue,
|
value: newValue,
|
||||||
color: 'propColorDefault',
|
color: 'propColorDefault',
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import {ISharing} from '../blocks/sharing'
|
|||||||
|
|
||||||
import client from '../octoClient'
|
import client from '../octoClient'
|
||||||
|
|
||||||
import {Utils} from '../utils'
|
import {Utils, IDType} from '../utils'
|
||||||
import {sendFlashMessage} from '../components/flashMessages'
|
import {sendFlashMessage} from '../components/flashMessages'
|
||||||
|
|
||||||
import Button from '../widgets/buttons/button'
|
import Button from '../widgets/buttons/button'
|
||||||
@ -38,7 +38,7 @@ const ShareBoardComponent = React.memo((props: Props): JSX.Element => {
|
|||||||
const newSharing: ISharing = {
|
const newSharing: ISharing = {
|
||||||
id: props.boardId,
|
id: props.boardId,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
token: Utils.createGuid(),
|
token: Utils.createGuid(IDType.Token),
|
||||||
}
|
}
|
||||||
return newSharing
|
return newSharing
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ const ShareBoardComponent = React.memo((props: Props): JSX.Element => {
|
|||||||
const accept = window.confirm(intl.formatMessage({id: 'ShareBoard.confirmRegenerateToken', defaultMessage: 'This will invalidate previously shared links. Continue?'}))
|
const accept = window.confirm(intl.formatMessage({id: 'ShareBoard.confirmRegenerateToken', defaultMessage: 'This will invalidate previously shared links. Continue?'}))
|
||||||
if (accept) {
|
if (accept) {
|
||||||
const newSharing: ISharing = sharing || createSharingInfo()
|
const newSharing: ISharing = sharing || createSharingInfo()
|
||||||
newSharing.token = Utils.createGuid()
|
newSharing.token = Utils.createGuid(IDType.Token)
|
||||||
await client.setSharing(newSharing)
|
await client.setSharing(newSharing)
|
||||||
await loadData()
|
await loadData()
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import {BoardView} from '../../blocks/boardView'
|
|||||||
|
|
||||||
import {IUser} from '../../user'
|
import {IUser} from '../../user'
|
||||||
|
|
||||||
import {Utils} from '../../utils'
|
import {Utils, IDType} from '../../utils'
|
||||||
|
|
||||||
import {wrapDNDIntl} from '../../testUtils'
|
import {wrapDNDIntl} from '../../testUtils'
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ describe('components/table/Table extended', () => {
|
|||||||
test('should match snapshot with CreatedBy', async () => {
|
test('should match snapshot with CreatedBy', async () => {
|
||||||
const board = TestBlockFactory.createBoard()
|
const board = TestBlockFactory.createBoard()
|
||||||
|
|
||||||
const dateCreatedId = Utils.createGuid()
|
const dateCreatedId = Utils.createGuid(IDType.User)
|
||||||
board.fields.cardProperties.push({
|
board.fields.cardProperties.push({
|
||||||
id: dateCreatedId,
|
id: dateCreatedId,
|
||||||
name: 'Date Created',
|
name: 'Date Created',
|
||||||
@ -236,7 +236,7 @@ describe('components/table/Table extended', () => {
|
|||||||
test('should match snapshot with UpdatedAt', async () => {
|
test('should match snapshot with UpdatedAt', async () => {
|
||||||
const board = TestBlockFactory.createBoard()
|
const board = TestBlockFactory.createBoard()
|
||||||
|
|
||||||
const dateUpdatedId = Utils.createGuid()
|
const dateUpdatedId = Utils.createGuid(IDType.User)
|
||||||
board.fields.cardProperties.push({
|
board.fields.cardProperties.push({
|
||||||
id: dateUpdatedId,
|
id: dateUpdatedId,
|
||||||
name: 'Date Updated',
|
name: 'Date Updated',
|
||||||
@ -315,7 +315,7 @@ describe('components/table/Table extended', () => {
|
|||||||
test('should match snapshot with CreatedBy', async () => {
|
test('should match snapshot with CreatedBy', async () => {
|
||||||
const board = TestBlockFactory.createBoard()
|
const board = TestBlockFactory.createBoard()
|
||||||
|
|
||||||
const createdById = Utils.createGuid()
|
const createdById = Utils.createGuid(IDType.User)
|
||||||
board.fields.cardProperties.push({
|
board.fields.cardProperties.push({
|
||||||
id: createdById,
|
id: createdById,
|
||||||
name: 'Created By',
|
name: 'Created By',
|
||||||
@ -373,7 +373,7 @@ describe('components/table/Table extended', () => {
|
|||||||
test('should match snapshot with UpdatedBy', async () => {
|
test('should match snapshot with UpdatedBy', async () => {
|
||||||
const board = TestBlockFactory.createBoard()
|
const board = TestBlockFactory.createBoard()
|
||||||
|
|
||||||
const modifiedById = Utils.createGuid()
|
const modifiedById = Utils.createGuid(IDType.User)
|
||||||
board.fields.cardProperties.push({
|
board.fields.cardProperties.push({
|
||||||
id: modifiedById,
|
id: modifiedById,
|
||||||
name: 'Last Modified By',
|
name: 'Last Modified By',
|
||||||
|
@ -8,7 +8,7 @@ import {Board, IPropertyTemplate} from '../blocks/board'
|
|||||||
import {IViewType, BoardView, createBoardView} from '../blocks/boardView'
|
import {IViewType, BoardView, createBoardView} from '../blocks/boardView'
|
||||||
import {Constants} from '../constants'
|
import {Constants} from '../constants'
|
||||||
import mutator from '../mutator'
|
import mutator from '../mutator'
|
||||||
import {Utils} from '../utils'
|
import {Utils, IDType} from '../utils'
|
||||||
import AddIcon from '../widgets/icons/add'
|
import AddIcon from '../widgets/icons/add'
|
||||||
import BoardIcon from '../widgets/icons/board'
|
import BoardIcon from '../widgets/icons/board'
|
||||||
import DeleteIcon from '../widgets/icons/delete'
|
import DeleteIcon from '../widgets/icons/delete'
|
||||||
@ -43,7 +43,7 @@ const ViewMenu = React.memo((props: Props) => {
|
|||||||
const currentViewId = activeView.id
|
const currentViewId = activeView.id
|
||||||
const newView = createBoardView(activeView)
|
const newView = createBoardView(activeView)
|
||||||
newView.title = `${activeView.title} copy`
|
newView.title = `${activeView.title} copy`
|
||||||
newView.id = Utils.createGuid()
|
newView.id = Utils.createGuid(IDType.View)
|
||||||
mutator.insertBlock(
|
mutator.insertBlock(
|
||||||
newView,
|
newView,
|
||||||
'duplicate view',
|
'duplicate view',
|
||||||
|
@ -9,7 +9,7 @@ import {FilterGroup} from './blocks/filterGroup'
|
|||||||
import octoClient, {OctoClient} from './octoClient'
|
import octoClient, {OctoClient} from './octoClient'
|
||||||
import {OctoUtils} from './octoUtils'
|
import {OctoUtils} from './octoUtils'
|
||||||
import undoManager from './undomanager'
|
import undoManager from './undomanager'
|
||||||
import {Utils} from './utils'
|
import {Utils, IDType} from './utils'
|
||||||
import {UserSettings} from './userSettings'
|
import {UserSettings} from './userSettings'
|
||||||
import TelemetryClient, {TelemetryCategory, TelemetryActions} from './telemetry/telemetryClient'
|
import TelemetryClient, {TelemetryCategory, TelemetryActions} from './telemetry/telemetryClient'
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ class Mutator {
|
|||||||
Utils.assertFailure('UndoManager does not support nested groups')
|
Utils.assertFailure('UndoManager does not support nested groups')
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
this.undoGroupId = Utils.createGuid()
|
this.undoGroupId = Utils.createGuid(IDType.None)
|
||||||
return this.undoGroupId
|
return this.undoGroupId
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ class Mutator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const newTemplate = template || {
|
const newTemplate = template || {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.BlockID),
|
||||||
name: 'New Property',
|
name: 'New Property',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
options: [],
|
options: [],
|
||||||
@ -276,7 +276,7 @@ class Mutator {
|
|||||||
}
|
}
|
||||||
const srcTemplate = newBoard.fields.cardProperties[index]
|
const srcTemplate = newBoard.fields.cardProperties[index]
|
||||||
const newTemplate: IPropertyTemplate = {
|
const newTemplate: IPropertyTemplate = {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.BlockID),
|
||||||
name: `${srcTemplate.name} copy`,
|
name: `${srcTemplate.name} copy`,
|
||||||
type: srcTemplate.type,
|
type: srcTemplate.type,
|
||||||
options: srcTemplate.options.slice(),
|
options: srcTemplate.options.slice(),
|
||||||
@ -462,7 +462,7 @@ class Mutator {
|
|||||||
let option = newTemplate.options.find((o: IPropertyOption) => o.value === oldValue)
|
let option = newTemplate.options.find((o: IPropertyOption) => o.value === oldValue)
|
||||||
if (!option) {
|
if (!option) {
|
||||||
option = {
|
option = {
|
||||||
id: Utils.createGuid(),
|
id: Utils.createGuid(IDType.None),
|
||||||
value: oldValue,
|
value: oldValue,
|
||||||
color: 'propColorDefault',
|
color: 'propColorDefault',
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ class OctoUtils {
|
|||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const newBlocks = blocks.map((block) => {
|
const newBlocks = blocks.map((block) => {
|
||||||
const newBlock = this.hydrateBlock(block)
|
const newBlock = this.hydrateBlock(block)
|
||||||
newBlock.id = Utils.createGuid()
|
newBlock.id = Utils.createGuid(Utils.blockTypeToIDType(newBlock.type))
|
||||||
newBlock.createAt = now
|
newBlock.createAt = now
|
||||||
newBlock.updateAt = now
|
newBlock.updateAt = now
|
||||||
idMap[block.id] = newBlock.id
|
idMap[block.id] = newBlock.id
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import {createIntl} from 'react-intl'
|
import {createIntl} from 'react-intl'
|
||||||
|
|
||||||
import {Utils} from './utils'
|
import {Utils, IDType} from './utils'
|
||||||
|
|
||||||
describe('utils', () => {
|
describe('utils', () => {
|
||||||
describe('assureProtocol', () => {
|
describe('assureProtocol', () => {
|
||||||
@ -23,6 +23,21 @@ describe('utils', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('createGuid', () => {
|
||||||
|
test('should create 27 char random id for workspace', () => {
|
||||||
|
expect(Utils.createGuid(IDType.Workspace)).toMatch(/^w[ybndrfg8ejkmcpqxot1uwisza345h769]{26}$/)
|
||||||
|
})
|
||||||
|
test('should create 27 char random id for board', () => {
|
||||||
|
expect(Utils.createGuid(IDType.Board)).toMatch(/^b[ybndrfg8ejkmcpqxot1uwisza345h769]{26}$/)
|
||||||
|
})
|
||||||
|
test('should create 27 char random id for card', () => {
|
||||||
|
expect(Utils.createGuid(IDType.Card)).toMatch(/^c[ybndrfg8ejkmcpqxot1uwisza345h769]{26}$/)
|
||||||
|
})
|
||||||
|
test('should create 27 char random id', () => {
|
||||||
|
expect(Utils.createGuid(IDType.None)).toMatch(/^7[ybndrfg8ejkmcpqxot1uwisza345h769]{26}$/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('htmlFromMarkdown', () => {
|
describe('htmlFromMarkdown', () => {
|
||||||
test('should not allow XSS on links href on the webapp', () => {
|
test('should not allow XSS on links href on the webapp', () => {
|
||||||
expect(Utils.htmlFromMarkdown('[]("xss-attack="true"other="whatever)')).toBe('<p><a target="_blank" rel="noreferrer" href="%22xss-attack=%22true%22other=%22whatever" title="" onclick="event.stopPropagation();"></a></p>')
|
expect(Utils.htmlFromMarkdown('[]("xss-attack="true"other="whatever)')).toBe('<p><a target="_blank" rel="noreferrer" href="%22xss-attack=%22true%22other=%22whatever" title="" onclick="event.stopPropagation();"></a></p>')
|
||||||
|
@ -19,20 +19,84 @@ const IconClass = 'octo-icon'
|
|||||||
const OpenButtonClass = 'open-button'
|
const OpenButtonClass = 'open-button'
|
||||||
const SpacerClass = 'octo-spacer'
|
const SpacerClass = 'octo-spacer'
|
||||||
const HorizontalGripClass = 'HorizontalGrip'
|
const HorizontalGripClass = 'HorizontalGrip'
|
||||||
|
const base32Alphabet = 'ybndrfg8ejkmcpqxot1uwisza345h769'
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-shadow
|
||||||
|
enum IDType {
|
||||||
|
None = '7',
|
||||||
|
Workspace = 'w',
|
||||||
|
Board = 'b',
|
||||||
|
Card = 'c',
|
||||||
|
View = 'v',
|
||||||
|
Session = 's',
|
||||||
|
User = 'u',
|
||||||
|
Token = 'k',
|
||||||
|
BlockID = 'a',
|
||||||
|
}
|
||||||
|
|
||||||
class Utils {
|
class Utils {
|
||||||
static createGuid(): string {
|
static createGuid(idType: IDType): string {
|
||||||
const crypto = window.crypto || window.msCrypto
|
const data = Utils.randomArray(16)
|
||||||
function randomDigit() {
|
return idType + this.base32encode(data, false)
|
||||||
if (crypto && crypto.getRandomValues) {
|
}
|
||||||
const rands = new Uint8Array(1)
|
|
||||||
crypto.getRandomValues(rands)
|
|
||||||
return (rands[0] % 16).toString(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Math.floor((Math.random() * 16))).toString(16)
|
static blockTypeToIDType(blockType: string | undefined): IDType {
|
||||||
|
let ret: IDType = IDType.None
|
||||||
|
switch (blockType) {
|
||||||
|
case 'workspace':
|
||||||
|
ret = IDType.Workspace
|
||||||
|
break
|
||||||
|
case 'board':
|
||||||
|
ret = IDType.Board
|
||||||
|
break
|
||||||
|
case 'card':
|
||||||
|
ret = IDType.Card
|
||||||
|
break
|
||||||
|
case 'view':
|
||||||
|
ret = IDType.View
|
||||||
|
break
|
||||||
}
|
}
|
||||||
return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit)
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
static randomArray(size: number): Uint8Array {
|
||||||
|
const crypto = window.crypto || window.msCrypto
|
||||||
|
const rands = new Uint8Array(size)
|
||||||
|
if (crypto && crypto.getRandomValues) {
|
||||||
|
crypto.getRandomValues(rands)
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < size; i++) {
|
||||||
|
rands[i] = Math.floor((Math.random() * 255))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rands
|
||||||
|
}
|
||||||
|
|
||||||
|
static base32encode(data: Int8Array | Uint8Array | Uint8ClampedArray, pad: boolean): string {
|
||||||
|
const dview = new DataView(data.buffer, data.byteOffset, data.byteLength)
|
||||||
|
let bits = 0
|
||||||
|
let value = 0
|
||||||
|
let output = ''
|
||||||
|
|
||||||
|
// adapted from https://github.com/LinusU/base32-encode
|
||||||
|
for (let i = 0; i < dview.byteLength; i++) {
|
||||||
|
value = (value << 8) | dview.getUint8(i)
|
||||||
|
bits += 8
|
||||||
|
|
||||||
|
while (bits >= 5) {
|
||||||
|
output += base32Alphabet[(value >>> (bits - 5)) & 31]
|
||||||
|
bits -= 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bits > 0) {
|
||||||
|
output += base32Alphabet[(value << (5 - bits)) & 31]
|
||||||
|
}
|
||||||
|
if (pad) {
|
||||||
|
while ((output.length % 8) !== 0) {
|
||||||
|
output += '='
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
static htmlToElement(html: string): HTMLElement {
|
static htmlToElement(html: string): HTMLElement {
|
||||||
@ -512,4 +576,4 @@ class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {Utils}
|
export {Utils, IDType}
|
||||||
|
Reference in New Issue
Block a user