fixing merge conflicts
Этот коммит содержится в:
10
Makefile
10
Makefile
@@ -41,17 +41,23 @@ build:
|
||||
install:
|
||||
@go get $(GOFLAGS) github.com/tools/godep
|
||||
|
||||
@if [ $(shell docker ps | grep -ci mattermost-mysql) -eq 0 ]; then \
|
||||
@if [ $(shell docker ps -a | grep -ci mattermost-mysql) -eq 0 ]; then \
|
||||
echo restoring go libs using godep; \
|
||||
$(GOPATH)/bin/godep restore; \
|
||||
echo starting mattermost-mysql; \
|
||||
docker run --name mattermost-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mostest \
|
||||
-e MYSQL_USER=mmuser -e MYSQL_PASSWORD=mostest -e MYSQL_DATABASE=mattermost_test -d mysql > /dev/null; \
|
||||
elif [ $(shell docker ps | grep -ci mattermost-mysql) -eq 0 ]; then \
|
||||
echo restarting mattermost-mysql; \
|
||||
docker start mattermost-mysql > /dev/null; \
|
||||
fi
|
||||
|
||||
@if [ $(shell docker ps | grep -ci mattermost-redis) -eq 0 ]; then \
|
||||
@if [ $(shell docker ps -a | grep -ci mattermost-redis) -eq 0 ]; then \
|
||||
echo starting mattermost-redis; \
|
||||
docker run --name mattermost-redis -p 6379:6379 -d redis > /dev/null; \
|
||||
elif [ $(shell docker ps | grep -ci mattermost-redis) -eq 0 ]; then \
|
||||
echo restarting mattermost-redis; \
|
||||
docker start mattermost-redis > /dev/null; \
|
||||
fi
|
||||
|
||||
@cd web/react/ && npm install
|
||||
|
||||
25
README.md
25
README.md
@@ -108,26 +108,10 @@ AWS Elastic Beanstalk Setup (Docker)
|
||||
11. You can set the configuration details as you please but they may be left at their defaults. When you are done press next.
|
||||
12. Environment tags my be left blank. Press next.
|
||||
13. You will be asked to review your information. Press Launch.
|
||||
14. Up near the top of the dashboard you will see a domain of the form \*.elasticbeanstalk.com copy this as you will need it later.
|
||||
|
||||
2. Map a wildcard domain to the new elastic beanstalk application
|
||||
15. From the AWS console select route 53
|
||||
16. From the sidebar select Hosted Zones
|
||||
17. Select the domain you want to use or create a new one.
|
||||
18. Modify an existing CNAME record set or create a new one with the name * and the value of the domain you copied in step 1.13.
|
||||
19. Save the record set
|
||||
|
||||
3. Set the environment variable "MATTERMOST\_DOMAIN" to the domain you mapped above (example.com not www.example.com)
|
||||
20. Return the Elastic Beanstalk from the AWS console.
|
||||
21. Select the environment you created.
|
||||
22. Select configuration from the sidebar.
|
||||
23. Click the gear beside software configuration.
|
||||
24. Add an environment property with the name “MATTERMOST\_DOMAIN” and a value of the domain you mapped in route 53. For example if your domain is \*.example.com you would enter example.com not www.example.com.
|
||||
25. Select apply.
|
||||
|
||||
4. Try it out!
|
||||
26. Return to the dashboard on the sidebar and wait for beanstalk update the environment.
|
||||
27. Try it out by entering the domain you mapped into your browser.
|
||||
14. Wait for beanstalk to update the environment.
|
||||
15. Try it out by entering the domain of the form \*.elasticbeanstalk.com found at the top of the dashboard into your browser. You can also map your own domain if you wish.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
@@ -137,8 +121,5 @@ To contribute to this open source project please review the Mattermost Contribut
|
||||
License
|
||||
-------
|
||||
|
||||
Most Mattermost source files are made available under the terms of the GNU Affero General Public License (AGPL). See individual files for details.
|
||||
|
||||
As an exception, Admin Tools and Configuration Files are are made available under the terms of the Apache License, version 2.0. See LICENSE.txt for more information.
|
||||
|
||||
Mattermost is licensed under an "Apache-wrapped AGPL" model, which means you can run and link to the system using Configuration Files and Admin Tools licensed under Apache, version 2.0, as described in the LICENSE file, as an explicit exception to the terms of the GNU Affero General Public License (AGPL) that applies to most of the remaining source files. See individual files for details.
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ var ServerTemplates *template.Template
|
||||
|
||||
type ServerTemplatePage Page
|
||||
|
||||
func NewServerTemplatePage(templateName, teamUrl string) *ServerTemplatePage {
|
||||
func NewServerTemplatePage(templateName, teamURL string) *ServerTemplatePage {
|
||||
props := make(map[string]string)
|
||||
props["AnalyticsUrl"] = utils.Cfg.ServiceSettings.AnalyticsUrl
|
||||
return &ServerTemplatePage{TemplateName: templateName, SiteName: utils.Cfg.ServiceSettings.SiteName, FeedbackEmail: utils.Cfg.EmailSettings.FeedbackEmail, TeamUrl: teamUrl, Props: props}
|
||||
return &ServerTemplatePage{TemplateName: templateName, SiteName: utils.Cfg.ServiceSettings.SiteName, FeedbackEmail: utils.Cfg.EmailSettings.FeedbackEmail, TeamURL: teamURL, Props: props}
|
||||
}
|
||||
|
||||
func (me *ServerTemplatePage) Render() string {
|
||||
|
||||
@@ -24,12 +24,12 @@ func Setup() {
|
||||
func SetupBenchmark() (*model.Team, *model.User, *model.Channel) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Benchmark Team", Domain: "z-z-" + model.NewId() + "a", Email: "benchmark@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Benchmark Team", Name: "z-z-" + model.NewId() + "a", Email: "benchmark@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "benchmark@test.com", FullName: "Mr. Benchmarker", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "benchmark@test.com", Nickname: "Mr. Benchmarker", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
channel := &model.Channel{DisplayName: "Benchmark Channel", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ const (
|
||||
USER_PASSWORD = "passwd"
|
||||
CHANNEL_TYPE = model.CHANNEL_OPEN
|
||||
FUZZ_USER_EMAIL_PREFIX_LEN = 10
|
||||
BTEST_TEAM_NAME = "TestTeam"
|
||||
BTEST_TEAM_DOMAIN_NAME = "z-z-testdomaina"
|
||||
BTEST_TEAM_DISPLAY_NAME = "TestTeam"
|
||||
BTEST_TEAM_NAME = "z-z-testdomaina"
|
||||
BTEST_TEAM_EMAIL = "test@nowhere.com"
|
||||
BTEST_TEAM_TYPE = model.TEAM_OPEN
|
||||
BTEST_USER_NAME = "Mr. Testing Tester"
|
||||
|
||||
@@ -39,22 +39,22 @@ func NewAutoTeamCreator(client *model.Client) *AutoTeamCreator {
|
||||
|
||||
func (cfg *AutoTeamCreator) createRandomTeam() (*model.Team, bool) {
|
||||
var teamEmail string
|
||||
var teamDisplayName string
|
||||
var teamName string
|
||||
var teamDomain string
|
||||
if cfg.Fuzzy {
|
||||
teamEmail = utils.FuzzEmail()
|
||||
teamDisplayName = utils.FuzzName()
|
||||
teamName = utils.FuzzName()
|
||||
teamDomain = utils.FuzzName()
|
||||
} else {
|
||||
teamEmail = utils.RandomEmail(cfg.EmailLength, cfg.EmailCharset)
|
||||
teamName = utils.RandomName(cfg.NameLength, cfg.NameCharset)
|
||||
teamDomain = utils.RandomName(cfg.NameLength, cfg.NameCharset) + model.NewId()
|
||||
teamDisplayName = utils.RandomName(cfg.NameLength, cfg.NameCharset)
|
||||
teamName = utils.RandomName(cfg.NameLength, cfg.NameCharset) + model.NewId()
|
||||
}
|
||||
team := &model.Team{
|
||||
Name: teamName,
|
||||
Domain: teamDomain,
|
||||
Email: teamEmail,
|
||||
Type: model.TEAM_OPEN,
|
||||
DisplayName: teamDisplayName,
|
||||
Name: teamName,
|
||||
Email: teamEmail,
|
||||
Type: model.TEAM_OPEN,
|
||||
}
|
||||
|
||||
result, err := cfg.client.CreateTeam(team)
|
||||
|
||||
@@ -33,15 +33,15 @@ func NewAutoUserCreator(client *model.Client, teamID string) *AutoUserCreator {
|
||||
|
||||
// Basic test team and user so you always know one
|
||||
func CreateBasicUser(client *model.Client) *model.AppError {
|
||||
result, _ := client.FindTeamByDomain(BTEST_TEAM_DOMAIN_NAME, true)
|
||||
result, _ := client.FindTeamByName(BTEST_TEAM_NAME, true)
|
||||
if result.Data.(bool) == false {
|
||||
newteam := &model.Team{Name: BTEST_TEAM_NAME, Domain: BTEST_TEAM_DOMAIN_NAME, Email: BTEST_TEAM_EMAIL, Type: BTEST_TEAM_TYPE}
|
||||
newteam := &model.Team{DisplayName: BTEST_TEAM_DISPLAY_NAME, Name: BTEST_TEAM_NAME, Email: BTEST_TEAM_EMAIL, Type: BTEST_TEAM_TYPE}
|
||||
result, err := client.CreateTeam(newteam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
basicteam := result.Data.(*model.Team)
|
||||
newuser := &model.User{TeamId: basicteam.Id, Email: BTEST_USER_EMAIL, FullName: BTEST_USER_NAME, Password: BTEST_USER_PASSWORD}
|
||||
newuser := &model.User{TeamId: basicteam.Id, Email: BTEST_USER_EMAIL, Nickname: BTEST_USER_NAME, Password: BTEST_USER_PASSWORD}
|
||||
result, err = client.CreateUser(newuser, "")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -65,7 +65,7 @@ func (cfg *AutoUserCreator) createRandomUser() (*model.User, bool) {
|
||||
user := &model.User{
|
||||
TeamId: cfg.teamID,
|
||||
Email: userEmail,
|
||||
FullName: userName,
|
||||
Nickname: userName,
|
||||
Password: USER_PASSWORD}
|
||||
|
||||
result, err := cfg.client.CreateUser(user, "")
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
@@ -542,7 +541,7 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
message := model.NewMessage(c.Session.TeamId, id, c.Session.UserId, model.ACTION_VIEWED)
|
||||
message.Add("channel_id", id)
|
||||
|
||||
store.PublishAndForget(message)
|
||||
PublishAndForget(message)
|
||||
|
||||
result := make(map[string]string)
|
||||
result["id"] = id
|
||||
@@ -657,7 +656,7 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
message := model.NewMessage(c.Session.TeamId, "", userId, model.ACTION_USER_ADDED)
|
||||
|
||||
store.PublishAndForget(message)
|
||||
PublishAndForget(message)
|
||||
|
||||
<-Srv.Store.Channel().UpdateLastViewedAt(id, oUser.Id)
|
||||
w.Write([]byte(cm.ToJson()))
|
||||
|
||||
@@ -138,10 +138,10 @@ func BenchmarkJoinChannel(b *testing.B) {
|
||||
}
|
||||
|
||||
// Secondary test user to join channels created by primary test user
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "random@test.com", FullName: "That Guy", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "random@test.com", Nickname: "That Guy", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
// Benchmark Start
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -14,17 +14,17 @@ import (
|
||||
func TestCreateChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
team2 := &model.Team{Name: "Name Team 2", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
channel := model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
rchannel, err := Client.CreateChannel(&channel)
|
||||
@@ -94,18 +94,18 @@ func TestCreateChannel(t *testing.T) {
|
||||
func TestCreateDirectChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
data := make(map[string]string)
|
||||
data["user_id"] = user2.Id
|
||||
@@ -149,23 +149,23 @@ func TestCreateDirectChannel(t *testing.T) {
|
||||
func TestUpdateChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, FullName: "Corey Hulen", Password: "pwd"}
|
||||
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
|
||||
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
|
||||
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
|
||||
userStd.Roles = ""
|
||||
|
||||
Client.LoginByEmail(team.Domain, userChannelAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userChannelAdmin.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -184,7 +184,7 @@ func TestUpdateChannel(t *testing.T) {
|
||||
t.Fatal("Channel admin failed to skip displayName")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, userTeamAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
|
||||
|
||||
desc = "b" + model.NewId() + "b"
|
||||
upChannel1 = &model.Channel{Id: channel1.Id, Description: desc}
|
||||
@@ -210,7 +210,7 @@ func TestUpdateChannel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, userStd.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userStd.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateChannel(upChannel1); err == nil {
|
||||
t.Fatal("Standard User should have failed to update")
|
||||
@@ -220,14 +220,14 @@ func TestUpdateChannel(t *testing.T) {
|
||||
func TestUpdateChannelDesc(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -266,11 +266,11 @@ func TestUpdateChannelDesc(t *testing.T) {
|
||||
t.Fatal("should have errored on bad channel desc")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
data["channel_id"] = channel1.Id
|
||||
data["channel_description"] = "new desc"
|
||||
@@ -282,14 +282,14 @@ func TestUpdateChannelDesc(t *testing.T) {
|
||||
func TestGetChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -324,14 +324,14 @@ func TestGetChannel(t *testing.T) {
|
||||
func TestGetMoreChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -339,11 +339,11 @@ func TestGetMoreChannel(t *testing.T) {
|
||||
channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
rget := Client.Must(Client.GetMoreChannels(""))
|
||||
data := rget.Data.(*model.ChannelList)
|
||||
@@ -368,14 +368,14 @@ func TestGetMoreChannel(t *testing.T) {
|
||||
func TestJoinChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -383,11 +383,11 @@ func TestJoinChannel(t *testing.T) {
|
||||
channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
|
||||
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
Client.Must(Client.JoinChannel(channel1.Id))
|
||||
|
||||
@@ -399,10 +399,10 @@ func TestJoinChannel(t *testing.T) {
|
||||
data["user_id"] = user1.Id
|
||||
rchannel := Client.Must(Client.CreateDirectChannel(data)).Data.(*model.Channel)
|
||||
|
||||
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
|
||||
Client.LoginByEmail(team.Domain, user3.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user3.Email, "pwd")
|
||||
|
||||
if _, err := Client.JoinChannel(rchannel.Id); err == nil {
|
||||
t.Fatal("shoudn't be able to join direct channel")
|
||||
@@ -412,14 +412,14 @@ func TestJoinChannel(t *testing.T) {
|
||||
func TestLeaveChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -427,11 +427,11 @@ func TestLeaveChannel(t *testing.T) {
|
||||
channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
|
||||
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
Client.Must(Client.JoinChannel(channel1.Id))
|
||||
|
||||
@@ -461,25 +461,25 @@ func TestLeaveChannel(t *testing.T) {
|
||||
func TestDeleteChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, FullName: "Corey Hulen", Password: "pwd"}
|
||||
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
|
||||
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, userChannelAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userChannelAdmin.Email, "pwd")
|
||||
|
||||
channelMadeByCA := &model.Channel{DisplayName: "C Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channelMadeByCA = Client.Must(Client.CreateChannel(channelMadeByCA)).Data.(*model.Channel)
|
||||
|
||||
Client.AddChannelMember(channelMadeByCA.Id, userTeamAdmin.Id)
|
||||
|
||||
Client.LoginByEmail(team.Domain, userTeamAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -500,11 +500,11 @@ func TestDeleteChannel(t *testing.T) {
|
||||
t.Fatal("should have failed to post to deleted channel")
|
||||
}
|
||||
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, userStd.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userStd.Email, "pwd")
|
||||
|
||||
if _, err := Client.JoinChannel(channel1.Id); err == nil {
|
||||
t.Fatal("should have failed to join deleted channel")
|
||||
@@ -531,14 +531,14 @@ func TestDeleteChannel(t *testing.T) {
|
||||
func TestGetChannelExtraInfo(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -552,19 +552,19 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
func TestAddChannelMember(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -591,13 +591,13 @@ func TestAddChannelMember(t *testing.T) {
|
||||
channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
if _, err := Client.AddChannelMember(channel2.Id, user2.Id); err == nil {
|
||||
t.Fatal("Should have errored, user not in channel")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
Client.Must(Client.DeleteChannel(channel2.Id))
|
||||
|
||||
@@ -610,30 +610,30 @@ func TestAddChannelMember(t *testing.T) {
|
||||
func TestRemoveChannelMember(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, FullName: "Corey Hulen", Password: "pwd"}
|
||||
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
|
||||
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, userChannelAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userChannelAdmin.Email, "pwd")
|
||||
|
||||
channelMadeByCA := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channelMadeByCA = Client.Must(Client.CreateChannel(channelMadeByCA)).Data.(*model.Channel)
|
||||
|
||||
Client.Must(Client.AddChannelMember(channelMadeByCA.Id, userTeamAdmin.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, userTeamAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
|
||||
|
||||
@@ -660,13 +660,13 @@ func TestRemoveChannelMember(t *testing.T) {
|
||||
channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
|
||||
Client.LoginByEmail(team.Domain, userStd.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userStd.Email, "pwd")
|
||||
|
||||
if _, err := Client.RemoveChannelMember(channel2.Id, userStd.Id); err == nil {
|
||||
t.Fatal("Should have errored, user not channel admin")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, userTeamAdmin.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
|
||||
Client.Must(Client.AddChannelMember(channel2.Id, userStd.Id))
|
||||
|
||||
Client.Must(Client.DeleteChannel(channel2.Id))
|
||||
@@ -680,14 +680,14 @@ func TestRemoveChannelMember(t *testing.T) {
|
||||
func TestUpdateNotifyLevel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -746,10 +746,10 @@ func TestUpdateNotifyLevel(t *testing.T) {
|
||||
t.Fatal("Should have errored - bad notify level")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
data["channel_id"] = channel1.Id
|
||||
data["user_id"] = user2.Id
|
||||
@@ -762,14 +762,14 @@ func TestUpdateNotifyLevel(t *testing.T) {
|
||||
func TestFuzzyChannel(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
// Strings that should pass as acceptable channel names
|
||||
var fuzzyStringsPass = []string{
|
||||
|
||||
@@ -27,8 +27,6 @@ var commands = []commandHandler{
|
||||
func InitCommand(r *mux.Router) {
|
||||
l4g.Debug("Initializing command api routes")
|
||||
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
|
||||
|
||||
hub.Start()
|
||||
}
|
||||
|
||||
func command(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -323,14 +321,14 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool {
|
||||
numPosts, _ = strconv.Atoi(tokens[numArgs+2])
|
||||
}
|
||||
}
|
||||
client := model.NewClient(c.TeamUrl + "/api/v1")
|
||||
client := model.NewClient(c.GetSiteURL() + "/api/v1")
|
||||
|
||||
if doTeams {
|
||||
if err := CreateBasicUser(client); err != nil {
|
||||
l4g.Error("Failed to create testing enviroment")
|
||||
return true
|
||||
}
|
||||
client.LoginByEmail(BTEST_TEAM_DOMAIN_NAME, BTEST_USER_EMAIL, BTEST_USER_PASSWORD)
|
||||
client.LoginByEmail(BTEST_TEAM_NAME, BTEST_USER_EMAIL, BTEST_USER_PASSWORD)
|
||||
enviroment, err := CreateTestEnviromentWithTeams(
|
||||
client,
|
||||
utils.Range{numTeams, numTeams},
|
||||
@@ -344,7 +342,7 @@ func loadTestSetupCommand(c *Context, command *model.Command) bool {
|
||||
} else {
|
||||
l4g.Info("Testing enviroment created")
|
||||
for i := 0; i < len(enviroment.Teams); i++ {
|
||||
l4g.Info("Team Created: " + enviroment.Teams[i].Domain)
|
||||
l4g.Info("Team Created: " + enviroment.Teams[i].Name)
|
||||
l4g.Info("\t User to login: " + enviroment.Enviroments[i].Users[0].Email + ", " + USER_PASSWORD)
|
||||
}
|
||||
}
|
||||
@@ -383,7 +381,7 @@ func loadTestUsersCommand(c *Context, command *model.Command) bool {
|
||||
if err == false {
|
||||
usersr = utils.Range{10, 15}
|
||||
}
|
||||
client := model.NewClient(c.TeamUrl + "/api/v1")
|
||||
client := model.NewClient(c.GetSiteURL() + "/api/v1")
|
||||
userCreator := NewAutoUserCreator(client, c.Session.TeamId)
|
||||
userCreator.Fuzzy = doFuzz
|
||||
userCreator.CreateTestUsers(usersr)
|
||||
@@ -413,7 +411,7 @@ func loadTestChannelsCommand(c *Context, command *model.Command) bool {
|
||||
if err == false {
|
||||
channelsr = utils.Range{20, 30}
|
||||
}
|
||||
client := model.NewClient(c.TeamUrl + "/api/v1")
|
||||
client := model.NewClient(c.GetSiteURL() + "/api/v1")
|
||||
client.MockSession(c.Session.Id)
|
||||
channelCreator := NewAutoChannelCreator(client, c.Session.TeamId)
|
||||
channelCreator.Fuzzy = doFuzz
|
||||
@@ -465,7 +463,7 @@ func loadTestPostsCommand(c *Context, command *model.Command) bool {
|
||||
}
|
||||
}
|
||||
|
||||
client := model.NewClient(c.TeamUrl + "/api/v1")
|
||||
client := model.NewClient(c.GetSiteURL() + "/api/v1")
|
||||
client.MockSession(c.Session.Id)
|
||||
testPoster := NewAutoPostCreator(client, command.ChannelId)
|
||||
testPoster.Fuzzy = doFuzz
|
||||
|
||||
@@ -12,14 +12,14 @@ import (
|
||||
func TestSuggestRootCommands(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
if _, err := Client.Command("", "", true); err == nil {
|
||||
t.Fatal("Should fail")
|
||||
@@ -55,14 +55,14 @@ func TestSuggestRootCommands(t *testing.T) {
|
||||
func TestLogoutCommands(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
rs1 := Client.Must(Client.Command("", "/logout", false)).Data.(*model.Command)
|
||||
if rs1.GotoLocation != "/logout" {
|
||||
@@ -73,14 +73,14 @@ func TestLogoutCommands(t *testing.T) {
|
||||
func TestJoinCommands(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -90,7 +90,7 @@ func TestJoinCommands(t *testing.T) {
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
Client.Must(Client.LeaveChannel(channel2.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@ import (
|
||||
var sessionCache *utils.Cache = utils.NewLru(model.SESSION_CACHE_SIZE)
|
||||
|
||||
type Context struct {
|
||||
Session model.Session
|
||||
RequestId string
|
||||
IpAddress string
|
||||
TeamUrl string
|
||||
Path string
|
||||
Err *model.AppError
|
||||
Session model.Session
|
||||
RequestId string
|
||||
IpAddress string
|
||||
Path string
|
||||
Err *model.AppError
|
||||
teamURLValid bool
|
||||
teamURL string
|
||||
siteURL string
|
||||
}
|
||||
|
||||
type Page struct {
|
||||
@@ -30,32 +32,36 @@ type Page struct {
|
||||
Title string
|
||||
SiteName string
|
||||
FeedbackEmail string
|
||||
TeamUrl string
|
||||
TeamURL string
|
||||
Props map[string]string
|
||||
}
|
||||
|
||||
func ApiAppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
return &handler{h, false, false, true, false}
|
||||
return &handler{h, false, false, true, false, false}
|
||||
}
|
||||
|
||||
func AppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
return &handler{h, false, false, false, false}
|
||||
return &handler{h, false, false, false, false, false}
|
||||
}
|
||||
|
||||
func AppHandlerIndependent(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
return &handler{h, false, false, false, false, true}
|
||||
}
|
||||
|
||||
func ApiUserRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
return &handler{h, true, false, true, true}
|
||||
return &handler{h, true, false, true, true, false}
|
||||
}
|
||||
|
||||
func ApiUserRequiredActivity(h func(*Context, http.ResponseWriter, *http.Request), isUserActivity bool) http.Handler {
|
||||
return &handler{h, true, false, true, isUserActivity}
|
||||
return &handler{h, true, false, true, isUserActivity, false}
|
||||
}
|
||||
|
||||
func UserRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
return &handler{h, true, false, false, false}
|
||||
return &handler{h, true, false, false, false, false}
|
||||
}
|
||||
|
||||
func ApiAdminSystemRequired(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
|
||||
return &handler{h, true, true, true, false}
|
||||
return &handler{h, true, true, true, false, false}
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
@@ -64,6 +70,7 @@ type handler struct {
|
||||
requireSystemAdmin bool
|
||||
isApi bool
|
||||
isUserActivity bool
|
||||
isTeamIndependent bool
|
||||
}
|
||||
|
||||
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -73,7 +80,6 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
c := &Context{}
|
||||
c.RequestId = model.NewId()
|
||||
c.IpAddress = GetIpAddress(r)
|
||||
c.Path = r.URL.Path
|
||||
|
||||
protocol := "http"
|
||||
|
||||
@@ -90,7 +96,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
c.TeamUrl = protocol + "://" + r.Host
|
||||
c.setSiteURL(protocol + "://" + r.Host)
|
||||
|
||||
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
|
||||
w.Header().Set(model.HEADER_VERSION_ID, utils.Cfg.ServiceSettings.Version)
|
||||
@@ -135,6 +141,15 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if h.isApi || h.isTeamIndependent {
|
||||
c.setTeamURL(c.GetSiteURL(), false)
|
||||
c.Path = r.URL.Path
|
||||
} else {
|
||||
splitURL := strings.Split(r.URL.Path, "/")
|
||||
c.setTeamURL(protocol+"://"+r.Host+"/"+splitURL[1], true)
|
||||
c.Path = "/" + strings.Join(splitURL[2:], "/")
|
||||
}
|
||||
|
||||
if c.Err == nil && h.requireUser {
|
||||
c.UserRequired()
|
||||
}
|
||||
@@ -165,7 +180,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(c.Err.ToJson()))
|
||||
} else {
|
||||
if c.Err.StatusCode == http.StatusUnauthorized {
|
||||
http.Redirect(w, r, "/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, c.GetTeamURL()+"/?redirect="+url.QueryEscape(r.URL.Path), http.StatusTemporaryRedirect)
|
||||
} else {
|
||||
RenderWebError(c.Err, w, r)
|
||||
}
|
||||
@@ -265,6 +280,16 @@ func (c *Context) IsSystemAdmin() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Context) IsTeamAdmin(userId string) bool {
|
||||
if uresult := <-Srv.Store.User().Get(userId); uresult.Err != nil {
|
||||
c.Err = uresult.Err
|
||||
return false
|
||||
} else {
|
||||
user := uresult.Data.(*model.User)
|
||||
return strings.Contains(c.Session.Roles, model.ROLE_ADMIN) && user.TeamId == c.Session.TeamId
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) RemoveSessionCookie(w http.ResponseWriter) {
|
||||
|
||||
sessionCache.Remove(c.Session.Id)
|
||||
@@ -289,6 +314,39 @@ func (c *Context) SetUnknownError(where string, details string) {
|
||||
c.Err = model.NewAppError(where, "An unknown error has occured. Please contact support.", details)
|
||||
}
|
||||
|
||||
func (c *Context) setTeamURL(url string, valid bool) {
|
||||
c.teamURL = url
|
||||
c.teamURLValid = valid
|
||||
}
|
||||
|
||||
func (c *Context) setTeamURLFromSession() {
|
||||
if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err == nil {
|
||||
c.setTeamURL(c.GetSiteURL()+"/"+result.Data.(*model.Team).Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) setSiteURL(url string) {
|
||||
c.siteURL = url
|
||||
}
|
||||
|
||||
func (c *Context) GetTeamURLFromTeam(team *model.Team) string {
|
||||
return c.GetSiteURL() + "/" + team.Name
|
||||
}
|
||||
|
||||
func (c *Context) GetTeamURL() string {
|
||||
if !c.teamURLValid {
|
||||
c.setTeamURLFromSession()
|
||||
if !c.teamURLValid {
|
||||
l4g.Debug("TeamURL accessed when not valid. Team URL should not be used in api functions or those that are team independent")
|
||||
}
|
||||
}
|
||||
return c.teamURL
|
||||
}
|
||||
|
||||
func (c *Context) GetSiteURL() string {
|
||||
return c.siteURL
|
||||
}
|
||||
|
||||
func GetIpAddress(r *http.Request) string {
|
||||
address := r.Header.Get(model.HEADER_FORWARDED)
|
||||
if len(address) == 0 {
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"github.com/nfnt/resize"
|
||||
_ "golang.org/x/image/bmp"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "golang.org/x/image/bmp"
|
||||
"image/jpeg"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -115,7 +115,7 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
fileUrl := c.TeamUrl + "/api/v1/files/get/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + url.QueryEscape(files[i].Filename)
|
||||
fileUrl := c.GetSiteURL() + "/api/v1/files/get/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + url.QueryEscape(files[i].Filename)
|
||||
resStruct.Filenames = append(resStruct.Filenames, fileUrl)
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
data := model.MapToJson(newProps)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.PublicLinkSalt))
|
||||
|
||||
url := fmt.Sprintf("%s/api/v1/files/%s/%s/%s/%s?d=%s&h=%s&t=%s", c.TeamUrl, getType, channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.Session.TeamId)
|
||||
url := fmt.Sprintf("%s/api/v1/files/%s/%s/%s/%s?d=%s&h=%s&t=%s", c.GetSiteURL(), getType, channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.Session.TeamId)
|
||||
|
||||
if !c.HasPermissionsToChannel(cchan, "getPublicLink") {
|
||||
return
|
||||
|
||||
@@ -24,14 +24,14 @@ import (
|
||||
func TestUploadFile(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -111,14 +111,14 @@ func TestUploadFile(t *testing.T) {
|
||||
func TestGetFile(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -173,10 +173,10 @@ func TestGetFile(t *testing.T) {
|
||||
t.Fatal("file get failed")
|
||||
}
|
||||
|
||||
team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user2 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -187,7 +187,7 @@ func TestGetFile(t *testing.T) {
|
||||
data := model.MapToJson(newProps)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.PublicLinkSalt))
|
||||
|
||||
Client.LoginByEmail(team2.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team2.Name, user2.Email, "pwd")
|
||||
|
||||
if _, downErr := Client.GetFile(filenames[0]+"?d="+url.QueryEscape(data)+"&h="+url.QueryEscape(hash)+"&t="+team.Id, true); downErr != nil {
|
||||
t.Fatal(downErr)
|
||||
@@ -258,18 +258,18 @@ func TestGetFile(t *testing.T) {
|
||||
func TestGetPublicLink(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -344,7 +344,7 @@ func TestGetPublicLink(t *testing.T) {
|
||||
t.Fatal("Should have errored - bad file path")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
data["filename"] = filenames[0]
|
||||
if _, err := Client.GetPublicLink(data); err == nil {
|
||||
t.Fatal("should have errored, user not member of channel")
|
||||
|
||||
68
api/post.go
68
api/post.go
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/mattermost/platform/store"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -121,7 +122,7 @@ func CreateValetPost(c *Context, post *model.Post) (*model.Post, *model.AppError
|
||||
rpost = result.Data.(*model.Post)
|
||||
}
|
||||
|
||||
fireAndForgetNotifications(rpost, c.Session.TeamId, c.TeamUrl)
|
||||
fireAndForgetNotifications(rpost, c.Session.TeamId, c.GetSiteURL())
|
||||
|
||||
return rpost, nil
|
||||
}
|
||||
@@ -200,14 +201,14 @@ func CreatePost(c *Context, post *model.Post, doUpdateLastViewed bool) (*model.P
|
||||
} else {
|
||||
rpost = result.Data.(*model.Post)
|
||||
|
||||
fireAndForgetNotifications(rpost, c.Session.TeamId, c.TeamUrl)
|
||||
fireAndForgetNotifications(rpost, c.Session.TeamId, c.GetSiteURL())
|
||||
|
||||
}
|
||||
|
||||
return rpost, nil
|
||||
}
|
||||
|
||||
func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
|
||||
func fireAndForgetNotifications(post *model.Post, teamId, siteURL string) {
|
||||
|
||||
go func() {
|
||||
// Get a list of user names (to be used as keywords) and ids for the given team
|
||||
@@ -297,14 +298,11 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
|
||||
for _, k := range splitKeys {
|
||||
keywordMap[k] = append(keywordMap[strings.ToLower(k)], profile.Id)
|
||||
}
|
||||
}
|
||||
|
||||
// If turned on, add the user's case sensitive first name
|
||||
if profile.NotifyProps["first_name"] == "true" {
|
||||
splitName := strings.Split(profile.FullName, " ")
|
||||
if len(splitName) > 0 && splitName[0] != "" {
|
||||
keywordMap[splitName[0]] = append(keywordMap[splitName[0]], profile.Id)
|
||||
}
|
||||
}
|
||||
// If turned on, add the user's case sensitive first name
|
||||
if profile.NotifyProps["first_name"] == "true" {
|
||||
keywordMap[profile.FirstName] = append(keywordMap[profile.FirstName], profile.Id)
|
||||
}
|
||||
|
||||
// Add @all to keywords if user has them turned on
|
||||
@@ -364,20 +362,22 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
|
||||
mentionedUsers = append(mentionedUsers, k)
|
||||
}
|
||||
|
||||
var teamName string
|
||||
var teamDisplayName string
|
||||
var teamURL string
|
||||
if result := <-tchan; result.Err != nil {
|
||||
l4g.Error("Failed to retrieve team team_id=%v, err=%v", teamId, result.Err)
|
||||
return
|
||||
} else {
|
||||
teamName = result.Data.(*model.Team).Name
|
||||
teamDisplayName = result.Data.(*model.Team).DisplayName
|
||||
teamURL = siteURL + "/" + result.Data.(*model.Team).Name
|
||||
}
|
||||
|
||||
// Build and send the emails
|
||||
location, _ := time.LoadLocation("UTC")
|
||||
tm := time.Unix(post.CreateAt/1000, 0).In(location)
|
||||
|
||||
subjectPage := NewServerTemplatePage("post_subject", teamUrl)
|
||||
subjectPage.Props["TeamName"] = teamName
|
||||
subjectPage := NewServerTemplatePage("post_subject", teamURL)
|
||||
subjectPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
subjectPage.Props["SubjectText"] = subjectText
|
||||
subjectPage.Props["Month"] = tm.Month().String()[:3]
|
||||
subjectPage.Props["Day"] = fmt.Sprintf("%d", tm.Day())
|
||||
@@ -394,11 +394,9 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
|
||||
continue
|
||||
}
|
||||
|
||||
firstName := strings.Split(profileMap[id].FullName, " ")[0]
|
||||
|
||||
bodyPage := NewServerTemplatePage("post_body", teamUrl)
|
||||
bodyPage.Props["FullName"] = firstName
|
||||
bodyPage.Props["TeamName"] = teamName
|
||||
bodyPage := NewServerTemplatePage("post_body", teamURL)
|
||||
bodyPage.Props["Nickname"] = profileMap[id].FirstName
|
||||
bodyPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage.Props["ChannelName"] = channelName
|
||||
bodyPage.Props["BodyText"] = bodyText
|
||||
bodyPage.Props["SenderName"] = senderName
|
||||
@@ -407,7 +405,7 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
|
||||
bodyPage.Props["Month"] = tm.Month().String()[:3]
|
||||
bodyPage.Props["Day"] = fmt.Sprintf("%d", tm.Day())
|
||||
bodyPage.Props["PostMessage"] = model.ClearMentionTags(post.Message)
|
||||
bodyPage.Props["TeamLink"] = teamUrl + "/channels/" + channel.Name
|
||||
bodyPage.Props["TeamLink"] = teamURL + "/channels/" + channel.Name
|
||||
|
||||
if err := utils.SendMail(profileMap[id].Email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
l4g.Error("Failed to send mention email successfully email=%v err=%v", profileMap[id].Email, err)
|
||||
@@ -437,11 +435,24 @@ func fireAndForgetNotifications(post *model.Post, teamId, teamUrl string) {
|
||||
|
||||
message := model.NewMessage(teamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
|
||||
message.Add("post", post.ToJson())
|
||||
|
||||
if len(post.Filenames) != 0 {
|
||||
message.Add("otherFile", "true")
|
||||
|
||||
for _, filename := range post.Filenames {
|
||||
ext := filepath.Ext(filename)
|
||||
if model.IsFileExtImage(ext) {
|
||||
message.Add("image", "true")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(mentionedUsers) != 0 {
|
||||
message.Add("mentions", model.ArrayToJson(mentionedUsers))
|
||||
}
|
||||
|
||||
store.PublishAndForget(message)
|
||||
PublishAndForget(message)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -507,7 +518,7 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
message.Add("channel_id", rpost.ChannelId)
|
||||
message.Add("message", rpost.Message)
|
||||
|
||||
store.PublishAndForget(message)
|
||||
PublishAndForget(message)
|
||||
|
||||
w.Write([]byte(rpost.ToJson()))
|
||||
}
|
||||
@@ -620,16 +631,17 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
|
||||
pchan := Srv.Store.Post().Get(postId)
|
||||
|
||||
if !c.HasPermissionsToChannel(cchan, "deletePost") {
|
||||
return
|
||||
}
|
||||
|
||||
if result := <-pchan; result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
|
||||
post := result.Data.(*model.PostList).Posts[postId]
|
||||
|
||||
if !c.HasPermissionsToChannel(cchan, "deletePost") && !c.IsTeamAdmin(post.UserId) {
|
||||
return
|
||||
}
|
||||
|
||||
if post == nil {
|
||||
c.SetInvalidParam("deletePost", "postId")
|
||||
return
|
||||
@@ -641,7 +653,7 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if post.UserId != c.Session.UserId {
|
||||
if post.UserId != c.Session.UserId && !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) {
|
||||
c.Err = model.NewAppError("deletePost", "You do not have the appropriate permissions", "")
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
@@ -656,7 +668,7 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
message.Add("post_id", post.Id)
|
||||
message.Add("channel_id", post.ChannelId)
|
||||
|
||||
store.PublishAndForget(message)
|
||||
PublishAndForget(message)
|
||||
|
||||
result := make(map[string]string)
|
||||
result["id"] = postId
|
||||
|
||||
@@ -15,21 +15,21 @@ import (
|
||||
func TestCreatePost(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
team2 := &model.Team{Name: "Name Team 2", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -96,18 +96,18 @@ func TestCreatePost(t *testing.T) {
|
||||
t.Fatal("Should have been forbidden")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
post7 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
|
||||
_, err = Client.CreatePost(post7)
|
||||
if err.StatusCode != http.StatusForbidden {
|
||||
t.Fatal("Should have been forbidden")
|
||||
}
|
||||
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
|
||||
channel3 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
|
||||
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
|
||||
@@ -126,21 +126,21 @@ func TestCreatePost(t *testing.T) {
|
||||
func TestCreateValetPost(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
team2 := &model.Team{Name: "Name Team 2", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -181,18 +181,18 @@ func TestCreateValetPost(t *testing.T) {
|
||||
t.Fatal("Should have been forbidden")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
post5 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
|
||||
_, err = Client.CreateValetPost(post5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
|
||||
channel3 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
|
||||
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
|
||||
@@ -218,21 +218,21 @@ func TestCreateValetPost(t *testing.T) {
|
||||
func TestUpdatePost(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
team2 := &model.Team{Name: "Name Team 2", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -289,14 +289,14 @@ func TestUpdatePost(t *testing.T) {
|
||||
func TestGetPosts(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -354,14 +354,14 @@ func TestGetPosts(t *testing.T) {
|
||||
func TestSearchPosts(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -400,14 +400,14 @@ func TestSearchPosts(t *testing.T) {
|
||||
func TestSearchHashtagPosts(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -431,14 +431,14 @@ func TestSearchHashtagPosts(t *testing.T) {
|
||||
func TestGetPostsCache(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -480,14 +480,18 @@ func TestGetPostsCache(t *testing.T) {
|
||||
func TestDeletePosts(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
userAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
|
||||
userAdmin = Client.Must(Client.CreateUser(userAdmin, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(userAdmin.Id))
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -522,21 +526,29 @@ func TestDeletePosts(t *testing.T) {
|
||||
r2 := Client.Must(Client.GetPosts(channel1.Id, 0, 10, "")).Data.(*model.PostList)
|
||||
|
||||
if len(r2.Posts) != 4 {
|
||||
t.Fatal("should have returned 5 items")
|
||||
t.Fatal("should have returned 4 items")
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
post4 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
|
||||
post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
|
||||
|
||||
Client.LoginByEmail(team.Name, userAdmin.Email, "pwd")
|
||||
|
||||
Client.Must(Client.DeletePost(channel1.Id, post4.Id))
|
||||
}
|
||||
|
||||
func TestEmailMention(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: "corey@test.com", FullName: "Bob Bobby", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: "corey@test.com", Nickname: "Bob Bobby", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -551,14 +563,14 @@ func TestEmailMention(t *testing.T) {
|
||||
func TestFuzzyPosts(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
|
||||
@@ -28,7 +28,6 @@ func NewServer() {
|
||||
Srv = &Server{}
|
||||
Srv.Server = manners.NewServer()
|
||||
Srv.Store = store.NewSqlStore()
|
||||
store.RedisClient()
|
||||
|
||||
Srv.Router = mux.NewRouter()
|
||||
Srv.Router.NotFoundHandler = http.HandlerFunc(Handle404)
|
||||
@@ -54,7 +53,7 @@ func StopServer() {
|
||||
|
||||
Srv.Server.Shutdown <- true
|
||||
Srv.Store.Close()
|
||||
store.RedisClose()
|
||||
hub.Stop()
|
||||
|
||||
l4g.Info("Server stopped")
|
||||
}
|
||||
|
||||
79
api/sharding.go
Обычный файл
79
api/sharding.go
Обычный файл
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package api
|
||||
|
||||
/*
|
||||
func createSubDomain(subDomain string, target string) {
|
||||
|
||||
if utils.Cfg.AWSSettings.Route53AccessKeyId == "" {
|
||||
return
|
||||
}
|
||||
|
||||
creds := aws.Creds(utils.Cfg.AWSSettings.Route53AccessKeyId, utils.Cfg.AWSSettings.Route53SecretAccessKey, "")
|
||||
r53 := route53.New(aws.DefaultConfig.Merge(&aws.Config{Credentials: creds, Region: utils.Cfg.AWSSettings.Route53Region}))
|
||||
|
||||
rr := route53.ResourceRecord{
|
||||
Value: aws.String(target),
|
||||
}
|
||||
|
||||
rrs := make([]*route53.ResourceRecord, 1)
|
||||
rrs[0] = &rr
|
||||
|
||||
change := route53.Change{
|
||||
Action: aws.String("CREATE"),
|
||||
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||
Name: aws.String(fmt.Sprintf("%v.%v", subDomain, utils.Cfg.ServiceSettings.Domain)),
|
||||
TTL: aws.Long(300),
|
||||
Type: aws.String("CNAME"),
|
||||
ResourceRecords: rrs,
|
||||
},
|
||||
}
|
||||
|
||||
changes := make([]*route53.Change, 1)
|
||||
changes[0] = &change
|
||||
|
||||
r53req := &route53.ChangeResourceRecordSetsInput{
|
||||
HostedZoneID: aws.String(utils.Cfg.AWSSettings.Route53ZoneId),
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
Changes: changes,
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := r53.ChangeResourceRecordSets(r53req); err != nil {
|
||||
l4g.Error("erro in createSubDomain domain=%v err=%v", subDomain, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func doesSubDomainExist(subDomain string) bool {
|
||||
|
||||
// if it's configured for testing then skip this step
|
||||
if utils.Cfg.AWSSettings.Route53AccessKeyId == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
creds := aws.Creds(utils.Cfg.AWSSettings.Route53AccessKeyId, utils.Cfg.AWSSettings.Route53SecretAccessKey, "")
|
||||
r53 := route53.New(aws.DefaultConfig.Merge(&aws.Config{Credentials: creds, Region: utils.Cfg.AWSSettings.Route53Region}))
|
||||
|
||||
r53req := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneID: aws.String(utils.Cfg.AWSSettings.Route53ZoneId),
|
||||
MaxItems: aws.String("1"),
|
||||
StartRecordName: aws.String(fmt.Sprintf("%v.%v.", subDomain, utils.Cfg.ServiceSettings.Domain)),
|
||||
}
|
||||
|
||||
if result, err := r53.ListResourceRecordSets(r53req); err != nil {
|
||||
l4g.Error("error in doesSubDomainExist domain=%v err=%v", subDomain, err)
|
||||
return true
|
||||
} else {
|
||||
|
||||
for _, v := range result.ResourceRecordSets {
|
||||
if v.Name != nil && *v.Name == fmt.Sprintf("%v.%v.", subDomain, utils.Cfg.ServiceSettings.Domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
*/
|
||||
243
api/team.go
243
api/team.go
@@ -6,8 +6,6 @@ package api
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"fmt"
|
||||
"github.com/awslabs/aws-sdk-go/aws"
|
||||
"github.com/awslabs/aws-sdk-go/service/route53"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
@@ -24,11 +22,11 @@ func InitTeam(r *mux.Router) {
|
||||
sr.Handle("/create", ApiAppHandler(createTeam)).Methods("POST")
|
||||
sr.Handle("/create_from_signup", ApiAppHandler(createTeamFromSignup)).Methods("POST")
|
||||
sr.Handle("/signup", ApiAppHandler(signupTeam)).Methods("POST")
|
||||
sr.Handle("/find_team_by_domain", ApiAppHandler(findTeamByDomain)).Methods("POST")
|
||||
sr.Handle("/find_team_by_name", ApiAppHandler(findTeamByName)).Methods("POST")
|
||||
sr.Handle("/find_teams", ApiAppHandler(findTeams)).Methods("POST")
|
||||
sr.Handle("/email_teams", ApiAppHandler(emailTeams)).Methods("POST")
|
||||
sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST")
|
||||
sr.Handle("/update_name", ApiUserRequired(updateTeamName)).Methods("POST")
|
||||
sr.Handle("/update_name", ApiUserRequired(updateTeamDisplayName)).Methods("POST")
|
||||
sr.Handle("/update_valet_feature", ApiUserRequired(updateValetFeature)).Methods("POST")
|
||||
sr.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET")
|
||||
}
|
||||
@@ -37,38 +35,38 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
m := model.MapFromJson(r.Body)
|
||||
email := strings.ToLower(strings.TrimSpace(m["email"]))
|
||||
name := strings.TrimSpace(m["name"])
|
||||
displayName := strings.TrimSpace(m["display_name"])
|
||||
|
||||
if len(email) == 0 {
|
||||
c.SetInvalidParam("signupTeam", "email")
|
||||
return
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
c.SetInvalidParam("signupTeam", "name")
|
||||
if len(displayName) == 0 {
|
||||
c.SetInvalidParam("signupTeam", "display_name")
|
||||
return
|
||||
}
|
||||
|
||||
subjectPage := NewServerTemplatePage("signup_team_subject", c.TeamUrl)
|
||||
bodyPage := NewServerTemplatePage("signup_team_body", c.TeamUrl)
|
||||
subjectPage := NewServerTemplatePage("signup_team_subject", c.GetSiteURL())
|
||||
bodyPage := NewServerTemplatePage("signup_team_body", c.GetSiteURL())
|
||||
bodyPage.Props["TourUrl"] = utils.Cfg.TeamSettings.TourLink
|
||||
|
||||
props := make(map[string]string)
|
||||
props["email"] = email
|
||||
props["name"] = name
|
||||
props["display_name"] = displayName
|
||||
props["time"] = fmt.Sprintf("%v", model.GetMillis())
|
||||
|
||||
data := model.MapToJson(props)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
|
||||
|
||||
bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_team_complete/?d=%s&h=%s", c.TeamUrl, url.QueryEscape(data), url.QueryEscape(hash))
|
||||
bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_team_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
|
||||
if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV || utils.Cfg.EmailSettings.ByPassEmail {
|
||||
m["follow_link"] = bodyPage.Props["Link"]
|
||||
}
|
||||
|
||||
@@ -119,25 +117,16 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
found := FindTeamByDomain(c, teamSignup.Team.Domain, "true")
|
||||
found := FindTeamByName(c, teamSignup.Team.Name, "true")
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if found {
|
||||
c.Err = model.NewAppError("createTeamFromSignup", "This URL is unavailable. Please try another.", "d="+teamSignup.Team.Domain)
|
||||
c.Err = model.NewAppError("createTeamFromSignup", "This URL is unavailable. Please try another.", "d="+teamSignup.Team.Name)
|
||||
return
|
||||
}
|
||||
|
||||
if IsBetaDomain(r) {
|
||||
for key, value := range utils.Cfg.ServiceSettings.Shards {
|
||||
if strings.Index(r.Host, key) == 0 {
|
||||
createSubDomain(teamSignup.Team.Domain, value)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
teamSignup.Team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
|
||||
|
||||
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
|
||||
@@ -166,7 +155,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
InviteMembers(rteam, ruser, teamSignup.Invites)
|
||||
InviteMembers(c, rteam, ruser, teamSignup.Invites)
|
||||
|
||||
teamSignup.Team = *rteam
|
||||
teamSignup.User = *ruser
|
||||
@@ -211,87 +200,14 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func doesSubDomainExist(subDomain string) bool {
|
||||
|
||||
// if it's configured for testing then skip this step
|
||||
if utils.Cfg.AWSSettings.Route53AccessKeyId == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
creds := aws.Creds(utils.Cfg.AWSSettings.Route53AccessKeyId, utils.Cfg.AWSSettings.Route53SecretAccessKey, "")
|
||||
r53 := route53.New(aws.DefaultConfig.Merge(&aws.Config{Credentials: creds, Region: utils.Cfg.AWSSettings.Route53Region}))
|
||||
|
||||
r53req := &route53.ListResourceRecordSetsInput{
|
||||
HostedZoneID: aws.String(utils.Cfg.AWSSettings.Route53ZoneId),
|
||||
MaxItems: aws.String("1"),
|
||||
StartRecordName: aws.String(fmt.Sprintf("%v.%v.", subDomain, utils.Cfg.ServiceSettings.Domain)),
|
||||
}
|
||||
|
||||
if result, err := r53.ListResourceRecordSets(r53req); err != nil {
|
||||
l4g.Error("error in doesSubDomainExist domain=%v err=%v", subDomain, err)
|
||||
return true
|
||||
} else {
|
||||
|
||||
for _, v := range result.ResourceRecordSets {
|
||||
if v.Name != nil && *v.Name == fmt.Sprintf("%v.%v.", subDomain, utils.Cfg.ServiceSettings.Domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func createSubDomain(subDomain string, target string) {
|
||||
|
||||
if utils.Cfg.AWSSettings.Route53AccessKeyId == "" {
|
||||
return
|
||||
}
|
||||
|
||||
creds := aws.Creds(utils.Cfg.AWSSettings.Route53AccessKeyId, utils.Cfg.AWSSettings.Route53SecretAccessKey, "")
|
||||
r53 := route53.New(aws.DefaultConfig.Merge(&aws.Config{Credentials: creds, Region: utils.Cfg.AWSSettings.Route53Region}))
|
||||
|
||||
rr := route53.ResourceRecord{
|
||||
Value: aws.String(target),
|
||||
}
|
||||
|
||||
rrs := make([]*route53.ResourceRecord, 1)
|
||||
rrs[0] = &rr
|
||||
|
||||
change := route53.Change{
|
||||
Action: aws.String("CREATE"),
|
||||
ResourceRecordSet: &route53.ResourceRecordSet{
|
||||
Name: aws.String(fmt.Sprintf("%v.%v", subDomain, utils.Cfg.ServiceSettings.Domain)),
|
||||
TTL: aws.Long(300),
|
||||
Type: aws.String("CNAME"),
|
||||
ResourceRecords: rrs,
|
||||
},
|
||||
}
|
||||
|
||||
changes := make([]*route53.Change, 1)
|
||||
changes[0] = &change
|
||||
|
||||
r53req := &route53.ChangeResourceRecordSetsInput{
|
||||
HostedZoneID: aws.String(utils.Cfg.AWSSettings.Route53ZoneId),
|
||||
ChangeBatch: &route53.ChangeBatch{
|
||||
Changes: changes,
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := r53.ChangeResourceRecordSets(r53req); err != nil {
|
||||
l4g.Error("erro in createSubDomain domain=%v err=%v", subDomain, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func findTeamByDomain(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
m := model.MapFromJson(r.Body)
|
||||
|
||||
domain := strings.ToLower(strings.TrimSpace(m["domain"]))
|
||||
name := strings.ToLower(strings.TrimSpace(m["name"]))
|
||||
all := strings.ToLower(strings.TrimSpace(m["all"]))
|
||||
|
||||
found := FindTeamByDomain(c, domain, all)
|
||||
found := FindTeamByName(c, name, all)
|
||||
|
||||
if c.Err != nil {
|
||||
return
|
||||
@@ -304,56 +220,25 @@ func findTeamByDomain(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func FindTeamByDomain(c *Context, domain string, all string) bool {
|
||||
func FindTeamByName(c *Context, name string, all string) bool {
|
||||
|
||||
if domain == "" || len(domain) > 64 {
|
||||
c.SetInvalidParam("findTeamByDomain", "domain")
|
||||
if name == "" || len(name) > 64 {
|
||||
c.SetInvalidParam("findTeamByName", "domain")
|
||||
return false
|
||||
}
|
||||
|
||||
if model.IsReservedDomain(domain) {
|
||||
c.Err = model.NewAppError("findTeamByDomain", "This URL is unavailable. Please try another.", "d="+domain)
|
||||
if model.IsReservedTeamName(name) {
|
||||
c.Err = model.NewAppError("findTeamByName", "This URL is unavailable. Please try another.", "name="+name)
|
||||
return false
|
||||
}
|
||||
|
||||
if all == "false" {
|
||||
if result := <-Srv.Store.Team().GetByDomain(domain); result.Err != nil {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
if result := <-Srv.Store.Team().GetByName(name); result.Err != nil {
|
||||
return false
|
||||
} else {
|
||||
if doesSubDomainExist(domain) {
|
||||
return true
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
|
||||
if utils.Cfg.ServiceSettings.UseSSL {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
for key, _ := range utils.Cfg.ServiceSettings.Shards {
|
||||
url := fmt.Sprintf("%v://%v.%v/api/v1", protocol, key, utils.Cfg.ServiceSettings.Domain)
|
||||
|
||||
if strings.Index(utils.Cfg.ServiceSettings.Domain, "localhost") == 0 {
|
||||
url = fmt.Sprintf("%v://%v/api/v1", protocol, utils.Cfg.ServiceSettings.Domain)
|
||||
}
|
||||
|
||||
client := model.NewClient(url)
|
||||
|
||||
if result, err := client.FindTeamByDomain(domain, false); err != nil {
|
||||
c.Err = err
|
||||
return false
|
||||
} else {
|
||||
if result.Data.(bool) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func findTeams(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -376,7 +261,7 @@ func findTeams(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
s := make([]string, 0, len(teams))
|
||||
|
||||
for _, v := range teams {
|
||||
s = append(s, v.Domain)
|
||||
s = append(s, v.Name)
|
||||
}
|
||||
|
||||
w.Write([]byte(model.ArrayToJson(s)))
|
||||
@@ -394,33 +279,8 @@ func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
protocol := "http"
|
||||
|
||||
if utils.Cfg.ServiceSettings.UseSSL {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
subjectPage := NewServerTemplatePage("find_teams_subject", c.TeamUrl)
|
||||
bodyPage := NewServerTemplatePage("find_teams_body", c.TeamUrl)
|
||||
|
||||
for key, _ := range utils.Cfg.ServiceSettings.Shards {
|
||||
url := fmt.Sprintf("%v://%v.%v/api/v1", protocol, key, utils.Cfg.ServiceSettings.Domain)
|
||||
|
||||
if strings.Index(utils.Cfg.ServiceSettings.Domain, "localhost") == 0 {
|
||||
url = fmt.Sprintf("%v://%v/api/v1", protocol, utils.Cfg.ServiceSettings.Domain)
|
||||
}
|
||||
|
||||
client := model.NewClient(url)
|
||||
|
||||
if result, err := client.FindTeams(email); err != nil {
|
||||
l4g.Error("An error occured while finding teams at %v err=%v", key, err)
|
||||
} else {
|
||||
data := result.Data.([]string)
|
||||
for _, domain := range data {
|
||||
bodyPage.Props[fmt.Sprintf("%v://%v.%v", protocol, domain, utils.Cfg.ServiceSettings.Domain)] = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
subjectPage := NewServerTemplatePage("find_teams_subject", c.GetSiteURL())
|
||||
bodyPage := NewServerTemplatePage("find_teams_body", c.GetSiteURL())
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
l4g.Error("An error occured while sending an email in emailTeams err=%v", err)
|
||||
@@ -470,29 +330,18 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
ia = append(ia, invite["email"])
|
||||
}
|
||||
|
||||
InviteMembers(team, user, ia)
|
||||
InviteMembers(c, team, user, ia)
|
||||
|
||||
w.Write([]byte(invites.ToJson()))
|
||||
}
|
||||
|
||||
func InviteMembers(team *model.Team, user *model.User, invites []string) {
|
||||
func InviteMembers(c *Context, team *model.Team, user *model.User, invites []string) {
|
||||
for _, invite := range invites {
|
||||
if len(invite) > 0 {
|
||||
teamUrl := ""
|
||||
if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
|
||||
teamUrl = "http://localhost:8065"
|
||||
} else if utils.Cfg.ServiceSettings.UseSSL {
|
||||
teamUrl = fmt.Sprintf("https://%v.%v", team.Domain, utils.Cfg.ServiceSettings.Domain)
|
||||
} else {
|
||||
teamUrl = fmt.Sprintf("http://%v.%v", team.Domain, utils.Cfg.ServiceSettings.Domain)
|
||||
}
|
||||
teamURL := ""
|
||||
teamURL = c.GetTeamURLFromTeam(team)
|
||||
|
||||
sender := ""
|
||||
if len(strings.TrimSpace(user.FullName)) == 0 {
|
||||
sender = user.Username
|
||||
} else {
|
||||
sender = user.FullName
|
||||
}
|
||||
sender := user.GetDisplayName()
|
||||
|
||||
senderRole := ""
|
||||
if strings.Contains(user.Roles, model.ROLE_ADMIN) || strings.Contains(user.Roles, model.ROLE_SYSTEM_ADMIN) {
|
||||
@@ -501,11 +350,11 @@ func InviteMembers(team *model.Team, user *model.User, invites []string) {
|
||||
senderRole = "member"
|
||||
}
|
||||
|
||||
subjectPage := NewServerTemplatePage("invite_subject", teamUrl)
|
||||
subjectPage := NewServerTemplatePage("invite_subject", teamURL)
|
||||
subjectPage.Props["SenderName"] = sender
|
||||
subjectPage.Props["TeamName"] = team.Name
|
||||
bodyPage := NewServerTemplatePage("invite_body", teamUrl)
|
||||
bodyPage.Props["TeamName"] = team.Name
|
||||
subjectPage.Props["TeamDisplayName"] = team.DisplayName
|
||||
bodyPage := NewServerTemplatePage("invite_body", teamURL)
|
||||
bodyPage.Props["TeamDisplayName"] = team.DisplayName
|
||||
bodyPage.Props["SenderName"] = sender
|
||||
bodyPage.Props["SenderStatus"] = senderRole
|
||||
|
||||
@@ -514,12 +363,12 @@ func InviteMembers(team *model.Team, user *model.User, invites []string) {
|
||||
props := make(map[string]string)
|
||||
props["email"] = invite
|
||||
props["id"] = team.Id
|
||||
props["display_name"] = team.DisplayName
|
||||
props["name"] = team.Name
|
||||
props["domain"] = team.Domain
|
||||
props["time"] = fmt.Sprintf("%v", model.GetMillis())
|
||||
data := model.MapToJson(props)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
|
||||
bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", teamUrl, url.QueryEscape(data), url.QueryEscape(hash))
|
||||
bodyPage.Props["Link"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&h=%s", c.GetSiteURL(), url.QueryEscape(data), url.QueryEscape(hash))
|
||||
|
||||
if utils.Cfg.ServiceSettings.Mode == utils.MODE_DEV {
|
||||
l4g.Info("sending invitation to %v %v", invite, bodyPage.Props["Link"])
|
||||
@@ -532,35 +381,35 @@ func InviteMembers(team *model.Team, user *model.User, invites []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func updateTeamName(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
func updateTeamDisplayName(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
props := model.MapFromJson(r.Body)
|
||||
|
||||
new_name := props["new_name"]
|
||||
if len(new_name) == 0 {
|
||||
c.SetInvalidParam("updateTeamName", "new_name")
|
||||
c.SetInvalidParam("updateTeamDisplayName", "new_name")
|
||||
return
|
||||
}
|
||||
|
||||
teamId := props["team_id"]
|
||||
if len(teamId) > 0 && len(teamId) != 26 {
|
||||
c.SetInvalidParam("updateTeamName", "team_id")
|
||||
c.SetInvalidParam("updateTeamDisplayName", "team_id")
|
||||
return
|
||||
} else if len(teamId) == 0 {
|
||||
teamId = c.Session.TeamId
|
||||
}
|
||||
|
||||
if !c.HasPermissionsToTeam(teamId, "updateTeamName") {
|
||||
if !c.HasPermissionsToTeam(teamId, "updateTeamDisplayName") {
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) {
|
||||
c.Err = model.NewAppError("updateTeamName", "You do not have the appropriate permissions", "userId="+c.Session.UserId)
|
||||
c.Err = model.NewAppError("updateTeamDisplayName", "You do not have the appropriate permissions", "userId="+c.Session.UserId)
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.Team().UpdateName(new_name, c.Session.TeamId); result.Err != nil {
|
||||
if result := <-Srv.Store.Team().UpdateDisplayName(new_name, c.Session.TeamId); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ func TestCreateFromSignupTeam(t *testing.T) {
|
||||
data := model.MapToJson(props)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
user := model.User{Email: props["email"], FullName: "Corey Hulen", Password: "hello"}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
|
||||
|
||||
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"corey@test.com"}, Data: data, Hash: hash}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestCreateFromSignupTeam(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if rts.Data.(*model.TeamSignup).Team.Name != team.Name {
|
||||
if rts.Data.(*model.TeamSignup).Team.DisplayName != team.DisplayName {
|
||||
t.Fatal("full name didn't match")
|
||||
}
|
||||
|
||||
@@ -71,24 +71,24 @@ func TestCreateFromSignupTeam(t *testing.T) {
|
||||
func TestCreateTeam(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, err := Client.CreateTeam(&team)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user := &model.User{TeamId: rteam.Data.(*model.Team).Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: rteam.Data.(*model.Team).Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
|
||||
if len(c1.Channels) != 2 {
|
||||
t.Fatal("default channels not created")
|
||||
}
|
||||
|
||||
if rteam.Data.(*model.Team).Name != team.Name {
|
||||
if rteam.Data.(*model.Team).DisplayName != team.DisplayName {
|
||||
t.Fatal("full name didn't match")
|
||||
}
|
||||
|
||||
@@ -111,10 +111,10 @@ func TestCreateTeam(t *testing.T) {
|
||||
func TestFindTeamByEmail(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -122,7 +122,7 @@ func TestFindTeamByEmail(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
domains := r1.Data.([]string)
|
||||
if domains[0] != team.Domain {
|
||||
if domains[0] != team.Name {
|
||||
t.Fatal(domains)
|
||||
}
|
||||
}
|
||||
@@ -139,14 +139,14 @@ XXXXXX investigate and fix failing test
|
||||
func TestFindTeamByDomain(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
if r1, err := Client.FindTeamByDomain(team.Domain, false); err != nil {
|
||||
if r1, err := Client.FindTeamByDomain(team.Name, false); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
val := r1.Data.(bool)
|
||||
@@ -155,7 +155,7 @@ func TestFindTeamByDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if r1, err := Client.FindTeamByDomain(team.Domain, true); err != nil {
|
||||
if r1, err := Client.FindTeamByDomain(team.Name, true); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
val := r1.Data.(bool)
|
||||
@@ -179,10 +179,10 @@ func TestFindTeamByDomain(t *testing.T) {
|
||||
func TestFindTeamByEmailSend(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -203,14 +203,14 @@ func TestFindTeamByEmailSend(t *testing.T) {
|
||||
func TestInviteMembers(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
invite := make(map[string]string)
|
||||
invite["email"] = model.NewId() + "corey@test.com"
|
||||
@@ -229,54 +229,54 @@ func TestInviteMembers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTeamName(t *testing.T) {
|
||||
func TestUpdateTeamDisplayName(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
data := make(map[string]string)
|
||||
data["new_name"] = "NewName"
|
||||
if _, err := Client.UpdateTeamName(data); err == nil {
|
||||
if _, err := Client.UpdateTeamDisplayName(data); err == nil {
|
||||
t.Fatal("Should have errored, not admin")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
data["new_name"] = ""
|
||||
if _, err := Client.UpdateTeamName(data); err == nil {
|
||||
if _, err := Client.UpdateTeamDisplayName(data); err == nil {
|
||||
t.Fatal("Should have errored, empty name")
|
||||
}
|
||||
|
||||
data["new_name"] = "NewName"
|
||||
if _, err := Client.UpdateTeamName(data); err != nil {
|
||||
if _, err := Client.UpdateTeamDisplayName(data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// No GET team web service, so hard to confirm here that team name updated
|
||||
|
||||
data["team_id"] = "junk"
|
||||
if _, err := Client.UpdateTeamName(data); err == nil {
|
||||
if _, err := Client.UpdateTeamDisplayName(data); err == nil {
|
||||
t.Fatal("Should have errored, junk team id")
|
||||
}
|
||||
|
||||
data["team_id"] = "12345678901234567890123456"
|
||||
if _, err := Client.UpdateTeamName(data); err == nil {
|
||||
if _, err := Client.UpdateTeamDisplayName(data); err == nil {
|
||||
t.Fatal("Should have errored, bad team id")
|
||||
}
|
||||
|
||||
data["team_id"] = team.Id
|
||||
data["new_name"] = "NewNameAgain"
|
||||
if _, err := Client.UpdateTeamName(data); err != nil {
|
||||
if _, err := Client.UpdateTeamDisplayName(data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// No GET team web service, so hard to confirm here that team name updated
|
||||
@@ -285,17 +285,17 @@ func TestUpdateTeamName(t *testing.T) {
|
||||
func TestFuzzyTeamCreate(t *testing.T) {
|
||||
|
||||
for i := 0; i < len(utils.FUZZY_STRINGS_NAMES) || i < len(utils.FUZZY_STRINGS_EMAILS); i++ {
|
||||
testName := "Name"
|
||||
testDisplayName := "Name"
|
||||
testEmail := "test@nowhere.com"
|
||||
|
||||
if i < len(utils.FUZZY_STRINGS_NAMES) {
|
||||
testName = utils.FUZZY_STRINGS_NAMES[i]
|
||||
testDisplayName = utils.FUZZY_STRINGS_NAMES[i]
|
||||
}
|
||||
if i < len(utils.FUZZY_STRINGS_EMAILS) {
|
||||
testEmail = utils.FUZZY_STRINGS_EMAILS[i]
|
||||
}
|
||||
|
||||
team := model.Team{Name: testName, Domain: "z-z-" + model.NewId() + "a", Email: testEmail, Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: testDisplayName, Name: "z-z-" + model.NewId() + "a", Email: testEmail, Type: model.TEAM_OPEN}
|
||||
|
||||
_, err := Client.CreateTeam(&team)
|
||||
if err != nil {
|
||||
@@ -307,22 +307,22 @@ func TestFuzzyTeamCreate(t *testing.T) {
|
||||
func TestGetMyTeam(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, user.Password)
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
if result, err := Client.GetMyTeam(""); err != nil {
|
||||
t.Fatal("Failed to get user")
|
||||
} else {
|
||||
if result.Data.(*model.Team).Name != team.Name {
|
||||
if result.Data.(*model.Team).DisplayName != team.DisplayName {
|
||||
t.Fatal("team names did not match")
|
||||
}
|
||||
if result.Data.(*model.Team).Domain != team.Domain {
|
||||
if result.Data.(*model.Team).Name != team.Name {
|
||||
t.Fatal("team domains did not match")
|
||||
}
|
||||
if result.Data.(*model.Team).Type != team.Type {
|
||||
@@ -334,25 +334,25 @@ func TestGetMyTeam(t *testing.T) {
|
||||
func TestUpdateValetFeature(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
data := make(map[string]string)
|
||||
data["allow_valet"] = "true"
|
||||
@@ -360,7 +360,7 @@ func TestUpdateValetFeature(t *testing.T) {
|
||||
t.Fatal("Should have errored, not admin")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
data["allow_valet"] = ""
|
||||
if _, err := Client.UpdateValetFeature(data); err == nil {
|
||||
@@ -398,7 +398,7 @@ func TestUpdateValetFeature(t *testing.T) {
|
||||
t.Fatal("Should have errored - allow valet property not updated")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
|
||||
data["team_id"] = team.Id
|
||||
data["allow_valet"] = "true"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You updated your email</h2>
|
||||
<p>You updated your email for {{.Props.TeamName}} on {{ .TeamUrl }}<br> If this change wasn't initiated by you, please reply to this email and let us know.</p>
|
||||
<p>You updated your email for {{.Props.TeamDisplayName}} on {{ .TeamURL }}<br> If this change wasn't initiated by you, please reply to this email and let us know.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -34,7 +34,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "email_change_subject"}}You updated your email for {{.Props.TeamName}} on {{ .Props.Domain }}{{end}}
|
||||
{{define "email_change_subject"}}You updated your email for {{.Props.TeamDisplayName}} on {{ .Props.Domain }}{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -42,7 +42,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You've been invited</h2>
|
||||
<p>{{.Props.TeamName}} started using {{.SiteName}}.<br> The team {{.Props.SenderStatus}} <strong>{{.Props.SenderName}}</strong>, has invited you to join <strong>{{.Props.TeamName}}</strong>.</p>
|
||||
<p>{{.Props.TeamDisplayName}} started using {{.SiteName}}.<br> The team {{.Props.SenderStatus}} <strong>{{.Props.SenderName}}</strong>, has invited you to join <strong>{{.Props.TeamDisplayName}}</strong>.</p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.Link}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Join Team</a>
|
||||
</p>
|
||||
@@ -37,7 +37,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "invite_subject"}}{{ .Props.SenderName }} invited you to join {{ .Props.TeamName }} Team on {{.SiteName}}{{end}}
|
||||
{{define "invite_subject"}}{{ .Props.SenderName }} invited you to join {{ .Props.TeamDisplayName }} Team on {{.SiteName}}{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You updated your password</h2>
|
||||
<p>You updated your password for {{.Props.TeamName}} on {{ .TeamUrl }} by {{.Props.Method}}.<br> If this change wasn't initiated by you, please reply to this email and let us know.</p>
|
||||
<p>You updated your password for {{.Props.TeamDisplayName}} on {{ .TeamURL }} by {{.Props.Method}}.<br> If this change wasn't initiated by you, please reply to this email and let us know.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -34,7 +34,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "password_change_subject"}}You updated your password for {{.Props.TeamName}} on {{ .SiteName }}{{end}}
|
||||
{{define "password_change_subject"}}You updated your password for {{.Props.TeamDisplayName}} on {{ .SiteName }}{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -37,7 +37,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "post_subject"}}[{{.Props.TeamName}} {{.SiteName}}] {{.Props.SubjectText}} for {{.Props.Month}} {{.Props.Day}}, {{.Props.Year}}{{end}}
|
||||
{{define "post_subject"}}[{{.Props.TeamDisplayName}} {{.SiteName}}] {{.Props.SubjectText}} for {{.Props.Month}} {{.Props.Day}}, {{.Props.Year}}{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -18,7 +18,7 @@
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You requested a password reset</h2>
|
||||
<p>To change your password, click below.<br>If you did not mean to reset your password, please ignore this email and your password will remain the same.</p>
|
||||
<p>To change your password, click "Reset Password" below.<br>If you did not mean to reset your password, please ignore this email and your password will remain the same.</p>
|
||||
<p style="margin: 20px 0 15px">
|
||||
<a href="{{.Props.ResetUrl}}" style="background: #2389D7; border-radius: 3px; color: #fff; border: none; outline: none; min-width: 200px; padding: 15px 25px; font-size: 14px; font-family: inherit; cursor: pointer; -webkit-appearance: none;text-decoration: none;">Reset Password</a>
|
||||
</p>
|
||||
@@ -37,7 +37,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -40,7 +40,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -37,7 +37,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
@@ -1 +1 @@
|
||||
{{define "verify_subject"}}[{{ .Props.TeamName }} {{ .SiteName }}] Email Verification{{end}}
|
||||
{{define "verify_subject"}}[{{ .Props.TeamDisplayName }} {{ .SiteName }}] Email Verification{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;">
|
||||
<tr>
|
||||
<td style="padding: 20px 30px 10px; text-align:left;">
|
||||
<img src="{{.TeamUrl}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
<img src="{{.TeamURL}}/static/images/{{.SiteName}}-logodark.png" width="130px" style="opacity: 0.5" alt="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -17,8 +17,8 @@
|
||||
<table border="0" cellpadding="0" cellspacing="0" style="padding: 20px 50px 0; text-align: center; margin: 0 auto">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px solid #ddd; padding: 0 0 20px;">
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You joined the {{.Props.TeamName}} team at {{.SiteName}}!</h2>
|
||||
<p>Please let me know if you have any questions.<br>Enjoy your stay at <a href="{{.TeamUrl}}">{{.SiteName}}</a>.</p>
|
||||
<h2 style="font-weight: normal; margin-top: 10px;">You joined the {{.Props.TeamDisplayName}} team at {{.SiteName}}!</h2>
|
||||
<p>Please let me know if you have any questions.<br>Enjoy your stay at <a href="{{.TeamURL}}">{{.SiteName}}</a>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -34,7 +34,7 @@
|
||||
<tr>
|
||||
<td style="text-align: center;color: #AAA; font-size: 13px; padding-bottom: 10px;">
|
||||
<p style="margin: 25px 0;">
|
||||
<img width="65" src="{{.TeamUrl}}/static/images/circles.png" alt="">
|
||||
<img width="65" src="{{.TeamURL}}/static/images/circles.png" alt="">
|
||||
</p>
|
||||
<p style="padding: 0 50px;">
|
||||
(c) 2015 SpinPunch, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.<br>
|
||||
|
||||
88
api/user.go
88
api/user.go
@@ -181,14 +181,13 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
||||
l4g.Error("Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v", ruser.Id, ruser.TeamId, err)
|
||||
}
|
||||
|
||||
//fireAndForgetWelcomeEmail(strings.Split(ruser.FullName, " ")[0], ruser.Email, team.Name, c.TeamUrl+"/channels/town-square")
|
||||
|
||||
//fireAndForgetWelcomeEmail(ruser.FirstName, ruser.Email, team.Name, c.TeamURL+"/channels/town-square")
|
||||
if user.EmailVerified {
|
||||
if cresult := <-Srv.Store.User().VerifyEmail(ruser.Id); cresult.Err != nil {
|
||||
l4g.Error("Failed to set email verified err=%v", cresult.Err)
|
||||
}
|
||||
} else {
|
||||
FireAndForgetVerifyEmail(result.Data.(*model.User).Id, strings.Split(ruser.FullName, " ")[0], ruser.Email, team.Name, c.TeamUrl)
|
||||
FireAndForgetVerifyEmail(result.Data.(*model.User).Id, ruser.FirstName, ruser.Email, team.DisplayName, c.GetTeamURLFromTeam(team))
|
||||
}
|
||||
|
||||
ruser.Sanitize(map[string]bool{})
|
||||
@@ -196,19 +195,19 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
||||
// This message goes to every channel, so the channelId is irrelevant
|
||||
message := model.NewMessage(team.Id, "", ruser.Id, model.ACTION_NEW_USER)
|
||||
|
||||
store.PublishAndForget(message)
|
||||
PublishAndForget(message)
|
||||
|
||||
return ruser
|
||||
}
|
||||
}
|
||||
|
||||
func fireAndForgetWelcomeEmail(name, email, teamName, link string) {
|
||||
func fireAndForgetWelcomeEmail(name, email, teamDisplayName, link string) {
|
||||
go func() {
|
||||
|
||||
subjectPage := NewServerTemplatePage("welcome_subject", link)
|
||||
bodyPage := NewServerTemplatePage("welcome_body", link)
|
||||
bodyPage.Props["FullName"] = name
|
||||
bodyPage.Props["TeamName"] = teamName
|
||||
bodyPage.Props["Nickname"] = name
|
||||
bodyPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage.Props["FeedbackName"] = utils.Cfg.EmailSettings.FeedbackName
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
@@ -218,16 +217,16 @@ func fireAndForgetWelcomeEmail(name, email, teamName, link string) {
|
||||
}()
|
||||
}
|
||||
|
||||
func FireAndForgetVerifyEmail(userId, name, email, teamName, teamUrl string) {
|
||||
func FireAndForgetVerifyEmail(userId, name, email, teamDisplayName, teamURL string) {
|
||||
go func() {
|
||||
|
||||
link := fmt.Sprintf("%s/verify?uid=%s&hid=%s", teamUrl, userId, model.HashPassword(userId))
|
||||
link := fmt.Sprintf("%s/verify_email?uid=%s&hid=%s", teamURL, userId, model.HashPassword(userId))
|
||||
|
||||
subjectPage := NewServerTemplatePage("verify_subject", teamUrl)
|
||||
subjectPage.Props["TeamName"] = teamName
|
||||
bodyPage := NewServerTemplatePage("verify_body", teamUrl)
|
||||
bodyPage.Props["FullName"] = name
|
||||
bodyPage.Props["TeamName"] = teamName
|
||||
subjectPage := NewServerTemplatePage("verify_subject", teamURL)
|
||||
subjectPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage := NewServerTemplatePage("verify_body", teamURL)
|
||||
bodyPage.Props["Nickname"] = name
|
||||
bodyPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage.Props["VerifyUrl"] = link
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
@@ -251,10 +250,10 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var team *model.Team
|
||||
if result.Data == nil && len(props["email"]) != 0 && len(props["domain"]) != 0 {
|
||||
extraInfo = props["email"] + " in " + props["domain"]
|
||||
if result.Data == nil && len(props["email"]) != 0 && len(props["name"]) != 0 {
|
||||
extraInfo = props["email"] + " in " + props["name"]
|
||||
|
||||
if nr := <-Srv.Store.Team().GetByDomain(props["domain"]); nr.Err != nil {
|
||||
if nr := <-Srv.Store.Team().GetByName(props["name"]); nr.Err != nil {
|
||||
c.Err = nr.Err
|
||||
return
|
||||
} else {
|
||||
@@ -293,7 +292,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !user.EmailVerified {
|
||||
if !user.EmailVerified && !utils.Cfg.EmailSettings.ByPassEmail {
|
||||
c.Err = model.NewAppError("login", "Login failed because email address has not been verified", extraInfo)
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
@@ -517,7 +516,6 @@ func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
||||
w.Header().Set("Cache-Control", "max-age=120, public") // 2 mins
|
||||
w.Write([]byte(model.UserMapToJson(profiles)))
|
||||
return
|
||||
}
|
||||
@@ -729,6 +727,8 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
Srv.Store.User().UpdateLastPictureUpdate(c.Session.UserId)
|
||||
|
||||
c.LogAudit("")
|
||||
}
|
||||
|
||||
@@ -756,7 +756,8 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if tresult := <-Srv.Store.Team().Get(rusers[1].TeamId); tresult.Err != nil {
|
||||
l4g.Error(tresult.Err.Message)
|
||||
} else {
|
||||
fireAndForgetEmailChangeEmail(rusers[1].Email, tresult.Data.(*model.Team).Name, c.TeamUrl)
|
||||
team := tresult.Data.(*model.Team)
|
||||
fireAndForgetEmailChangeEmail(rusers[1].Email, team.DisplayName, c.GetTeamURLFromTeam(team))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,7 +828,8 @@ func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if tresult := <-tchan; tresult.Err != nil {
|
||||
l4g.Error(tresult.Err.Message)
|
||||
} else {
|
||||
fireAndForgetPasswordChangeEmail(user.Email, tresult.Data.(*model.Team).Name, c.TeamUrl, "using the settings menu")
|
||||
team := tresult.Data.(*model.Team)
|
||||
fireAndForgetPasswordChangeEmail(user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), "using the settings menu")
|
||||
}
|
||||
|
||||
data := make(map[string]string)
|
||||
@@ -986,14 +988,14 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
domain := props["domain"]
|
||||
if len(domain) == 0 {
|
||||
c.SetInvalidParam("sendPasswordReset", "domain")
|
||||
name := props["name"]
|
||||
if len(name) == 0 {
|
||||
c.SetInvalidParam("sendPasswordReset", "name")
|
||||
return
|
||||
}
|
||||
|
||||
var team *model.Team
|
||||
if result := <-Srv.Store.Team().GetByDomain(domain); result.Err != nil {
|
||||
if result := <-Srv.Store.Team().GetByName(name); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
@@ -1015,10 +1017,10 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
data := model.MapToJson(newProps)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.ResetSalt))
|
||||
|
||||
link := fmt.Sprintf("%s/reset_password?d=%s&h=%s", c.TeamUrl, url.QueryEscape(data), url.QueryEscape(hash))
|
||||
link := fmt.Sprintf("%s/reset_password?d=%s&h=%s", c.GetTeamURLFromTeam(team), url.QueryEscape(data), url.QueryEscape(hash))
|
||||
|
||||
subjectPage := NewServerTemplatePage("reset_subject", c.TeamUrl)
|
||||
bodyPage := NewServerTemplatePage("reset_body", c.TeamUrl)
|
||||
subjectPage := NewServerTemplatePage("reset_subject", c.GetTeamURLFromTeam(team))
|
||||
bodyPage := NewServerTemplatePage("reset_body", c.GetTeamURLFromTeam(team))
|
||||
bodyPage.Props["ResetUrl"] = link
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
@@ -1060,16 +1062,16 @@ func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
domain := props["domain"]
|
||||
if len(domain) == 0 {
|
||||
c.SetInvalidParam("resetPassword", "domain")
|
||||
name := props["name"]
|
||||
if len(name) == 0 {
|
||||
c.SetInvalidParam("resetPassword", "name")
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAuditWithUserId(userId, "attempt")
|
||||
|
||||
var team *model.Team
|
||||
if result := <-Srv.Store.Team().GetByDomain(domain); result.Err != nil {
|
||||
if result := <-Srv.Store.Team().GetByName(name); result.Err != nil {
|
||||
c.Err = result.Err
|
||||
return
|
||||
} else {
|
||||
@@ -1108,19 +1110,19 @@ func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.LogAuditWithUserId(userId, "success")
|
||||
}
|
||||
|
||||
fireAndForgetPasswordChangeEmail(user.Email, team.Name, c.TeamUrl, "using a reset password link")
|
||||
fireAndForgetPasswordChangeEmail(user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), "using a reset password link")
|
||||
|
||||
props["new_password"] = ""
|
||||
w.Write([]byte(model.MapToJson(props)))
|
||||
}
|
||||
|
||||
func fireAndForgetPasswordChangeEmail(email, teamName, teamUrl, method string) {
|
||||
func fireAndForgetPasswordChangeEmail(email, teamDisplayName, teamURL, method string) {
|
||||
go func() {
|
||||
|
||||
subjectPage := NewServerTemplatePage("password_change_subject", teamUrl)
|
||||
subjectPage.Props["TeamName"] = teamName
|
||||
bodyPage := NewServerTemplatePage("password_change_body", teamUrl)
|
||||
bodyPage.Props["TeamName"] = teamName
|
||||
subjectPage := NewServerTemplatePage("password_change_subject", teamURL)
|
||||
subjectPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage := NewServerTemplatePage("password_change_body", teamURL)
|
||||
bodyPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage.Props["Method"] = method
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
@@ -1130,13 +1132,13 @@ func fireAndForgetPasswordChangeEmail(email, teamName, teamUrl, method string) {
|
||||
}()
|
||||
}
|
||||
|
||||
func fireAndForgetEmailChangeEmail(email, teamName, teamUrl string) {
|
||||
func fireAndForgetEmailChangeEmail(email, teamDisplayName, teamURL string) {
|
||||
go func() {
|
||||
|
||||
subjectPage := NewServerTemplatePage("email_change_subject", teamUrl)
|
||||
subjectPage.Props["TeamName"] = teamName
|
||||
bodyPage := NewServerTemplatePage("email_change_body", teamUrl)
|
||||
bodyPage.Props["TeamName"] = teamName
|
||||
subjectPage := NewServerTemplatePage("email_change_subject", teamURL)
|
||||
subjectPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
bodyPage := NewServerTemplatePage("email_change_body", teamURL)
|
||||
bodyPage.Props["TeamDisplayName"] = teamDisplayName
|
||||
|
||||
if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil {
|
||||
l4g.Error("Failed to send update password email successfully err=%v", err)
|
||||
|
||||
168
api/user_test.go
168
api/user_test.go
@@ -25,18 +25,18 @@ import (
|
||||
func TestCreateUser(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "hello"}
|
||||
|
||||
ruser, err := Client.CreateUser(&user, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ruser.Data.(*model.User).FullName != user.FullName {
|
||||
t.Fatal("full name didn't match")
|
||||
if ruser.Data.(*model.User).Nickname != user.Nickname {
|
||||
t.Fatal("nickname didn't match")
|
||||
}
|
||||
|
||||
if ruser.Data.(*model.User).Password != "" {
|
||||
@@ -68,7 +68,7 @@ func TestCreateUser(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "hello", Username: model.BOT_USERNAME}
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "hello", Username: model.BOT_USERNAME}
|
||||
|
||||
if _, err := Client.CreateUser(&user2, ""); err == nil {
|
||||
t.Fatal("Should have failed using reserved bot name")
|
||||
@@ -82,10 +82,10 @@ func TestCreateUser(t *testing.T) {
|
||||
func TestCreateUserAllowedDomains(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE, AllowedDomains: "spinpunch.com, @nowh.com,@hello.com"}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE, AllowedDomains: "spinpunch.com, @nowh.com,@hello.com"}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "hello"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "hello"}
|
||||
|
||||
_, err := Client.CreateUser(&user, "")
|
||||
if err == nil {
|
||||
@@ -102,10 +102,10 @@ func TestCreateUserAllowedDomains(t *testing.T) {
|
||||
func TestLogin(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
@@ -117,7 +117,7 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if result, err := Client.LoginByEmail(team.Domain, user.Email, user.Password); err != nil {
|
||||
if result, err := Client.LoginByEmail(team.Name, user.Email, user.Password); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if result.Data.(*model.User).Email != user.Email {
|
||||
@@ -125,11 +125,11 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByEmail(team.Domain, user.Email, user.Password+"invalid"); err == nil {
|
||||
if _, err := Client.LoginByEmail(team.Name, user.Email, user.Password+"invalid"); err == nil {
|
||||
t.Fatal("Invalid Password")
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByEmail(team.Domain, "", user.Password); err == nil {
|
||||
if _, err := Client.LoginByEmail(team.Name, "", user.Password); err == nil {
|
||||
t.Fatal("should have failed")
|
||||
}
|
||||
|
||||
@@ -142,10 +142,10 @@ func TestLogin(t *testing.T) {
|
||||
|
||||
Client.AuthToken = ""
|
||||
|
||||
team2 := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE}
|
||||
team2 := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_INVITE}
|
||||
rteam2 := Client.Must(Client.CreateTeam(&team2))
|
||||
|
||||
user2 := model.User{TeamId: rteam2.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{TeamId: rteam2.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
|
||||
if _, err := Client.CreateUserFromSignup(&user2, "junk", "1231312"); err == nil {
|
||||
t.Fatal("Should have errored, signed up without hashed email")
|
||||
@@ -154,14 +154,14 @@ func TestLogin(t *testing.T) {
|
||||
props := make(map[string]string)
|
||||
props["email"] = user2.Email
|
||||
props["id"] = rteam2.Data.(*model.Team).Id
|
||||
props["name"] = rteam2.Data.(*model.Team).Name
|
||||
props["display_name"] = rteam2.Data.(*model.Team).DisplayName
|
||||
props["time"] = fmt.Sprintf("%v", model.GetMillis())
|
||||
data := model.MapToJson(props)
|
||||
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ServiceSettings.InviteSalt))
|
||||
|
||||
ruser2, _ := Client.CreateUserFromSignup(&user2, data, hash)
|
||||
|
||||
if _, err := Client.LoginByEmail(team2.Domain, ruser2.Data.(*model.User).Email, user2.Password); err != nil {
|
||||
if _, err := Client.LoginByEmail(team2.Name, ruser2.Data.(*model.User).Email, user2.Password); err != nil {
|
||||
t.Fatal("From verfied hash")
|
||||
}
|
||||
|
||||
@@ -171,16 +171,16 @@ func TestLogin(t *testing.T) {
|
||||
func TestSessions(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
deviceId := model.NewId()
|
||||
Client.LoginByEmailWithDevice(team.Domain, user.Email, user.Password, deviceId)
|
||||
Client.LoginByEmail(team.Domain, user.Email, user.Password)
|
||||
Client.LoginByEmailWithDevice(team.Name, user.Email, user.Password, deviceId)
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
r1, err := Client.GetSessions(ruser.Id)
|
||||
if err != nil {
|
||||
@@ -228,18 +228,18 @@ func TestSessions(t *testing.T) {
|
||||
func TestGetUser(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser2, _ := Client.CreateUser(&user2, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser2.Data.(*model.User).Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, user.Password)
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
rId := ruser.Data.(*model.User).Id
|
||||
if result, err := Client.GetUser(rId, ""); err != nil {
|
||||
@@ -299,16 +299,16 @@ func TestGetUser(t *testing.T) {
|
||||
func TestGetAudits(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser, _ := Client.CreateUser(&user, "")
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, user.Password)
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
@@ -352,14 +352,14 @@ func TestUserCreateImage(t *testing.T) {
|
||||
t.Fatal("Failed to create correct color")
|
||||
}
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
Client.DoGet("/users/"+user.Id+"/image", "", "")
|
||||
|
||||
@@ -368,10 +368,10 @@ func TestUserCreateImage(t *testing.T) {
|
||||
func TestUserUploadProfileImage(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -384,7 +384,7 @@ func TestUserUploadProfileImage(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
if _, upErr := Client.UploadFile("/users/newimage", body.Bytes(), writer.FormDataContentType()); upErr == nil {
|
||||
t.Fatal("Should have errored")
|
||||
@@ -465,12 +465,12 @@ func TestUserUploadProfileImage(t *testing.T) {
|
||||
func TestUserUpdate(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
time1 := model.GetMillis()
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd", LastActivityAt: time1, LastPingAt: time1, Roles: ""}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd", LastActivityAt: time1, LastPingAt: time1, Roles: ""}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -478,7 +478,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
@@ -486,7 +486,7 @@ func TestUserUpdate(t *testing.T) {
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
user.FullName = "Jim Jimmy"
|
||||
user.Nickname = "Jim Jimmy"
|
||||
user.TeamId = "12345678901234567890123456"
|
||||
user.LastActivityAt = time2
|
||||
user.LastPingAt = time2
|
||||
@@ -496,8 +496,8 @@ func TestUserUpdate(t *testing.T) {
|
||||
if result, err := Client.UpdateUser(user); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
if result.Data.(*model.User).FullName != "Jim Jimmy" {
|
||||
t.Fatal("FullName did not update properly")
|
||||
if result.Data.(*model.User).Nickname != "Jim Jimmy" {
|
||||
t.Fatal("Nickname did not update properly")
|
||||
}
|
||||
if result.Data.(*model.User).TeamId != team.Id {
|
||||
t.Fatal("TeamId should not have updated")
|
||||
@@ -526,13 +526,13 @@ func TestUserUpdate(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
user.FullName = "Tim Timmy"
|
||||
user.Nickname = "Tim Timmy"
|
||||
|
||||
if _, err := Client.UpdateUser(user); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
@@ -542,10 +542,10 @@ func TestUserUpdate(t *testing.T) {
|
||||
func TestUserUpdatePassword(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -553,7 +553,7 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("Should have errored")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateUserPassword("123", "pwd", "newpwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
@@ -584,14 +584,14 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
t.Fatal("LastPasswordUpdate should have changed")
|
||||
}
|
||||
|
||||
if _, err := Client.LoginByEmail(team.Domain, user.Email, "newpwd"); err != nil {
|
||||
if _, err := Client.LoginByEmail(team.Name, user.Email, "newpwd"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateUserPassword(user.Id, "pwd", "newpwd"); err == nil {
|
||||
t.Fatal("Should have errored")
|
||||
@@ -601,14 +601,14 @@ func TestUserUpdatePassword(t *testing.T) {
|
||||
func TestUserUpdateRoles(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -620,20 +620,20 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
t.Fatal("Should have errored, not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateUserRoles(data); err == nil {
|
||||
t.Fatal("Should have errored, not admin")
|
||||
}
|
||||
|
||||
team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user3 := &model.User{TeamId: team2.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team2.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
|
||||
data["user_id"] = user2.Id
|
||||
|
||||
@@ -641,7 +641,7 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
t.Fatal("Should have errored, wrong team")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
data["user_id"] = "junk"
|
||||
data["new_roles"] = "admin"
|
||||
@@ -670,14 +670,14 @@ func TestUserUpdateRoles(t *testing.T) {
|
||||
func TestUserUpdateActive(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
|
||||
@@ -685,26 +685,26 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
t.Fatal("Should have errored, not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateActive(user.Id, false); err == nil {
|
||||
t.Fatal("Should have errored, not admin")
|
||||
}
|
||||
|
||||
team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
user3 := &model.User{TeamId: team2.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user3 := &model.User{TeamId: team2.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
|
||||
|
||||
Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
|
||||
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateActive(user.Id, false); err == nil {
|
||||
t.Fatal("Should have errored, wrong team")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
if _, err := Client.UpdateActive("junk", false); err == nil {
|
||||
t.Fatal("Should have errored, bad id")
|
||||
@@ -734,16 +734,16 @@ func TestUserUpdateActive(t *testing.T) {
|
||||
func TestSendPasswordReset(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
data := make(map[string]string)
|
||||
data["email"] = user.Email
|
||||
data["domain"] = team.Domain
|
||||
data["name"] = team.Name
|
||||
|
||||
if _, err := Client.SendPasswordReset(data); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -760,24 +760,24 @@ func TestSendPasswordReset(t *testing.T) {
|
||||
}
|
||||
|
||||
data["email"] = user.Email
|
||||
data["domain"] = ""
|
||||
data["name"] = ""
|
||||
if _, err := Client.SendPasswordReset(data); err == nil {
|
||||
t.Fatal("Should have errored - no domain")
|
||||
t.Fatal("Should have errored - no name")
|
||||
}
|
||||
|
||||
data["domain"] = "junk"
|
||||
data["name"] = "junk"
|
||||
if _, err := Client.SendPasswordReset(data); err == nil {
|
||||
t.Fatal("Should have errored - bad domain")
|
||||
t.Fatal("Should have errored - bad name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetPassword(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -788,7 +788,7 @@ func TestResetPassword(t *testing.T) {
|
||||
props["time"] = fmt.Sprintf("%v", model.GetMillis())
|
||||
data["data"] = model.MapToJson(props)
|
||||
data["hash"] = model.HashPassword(fmt.Sprintf("%v:%v", data["data"], utils.Cfg.ServiceSettings.ResetSalt))
|
||||
data["domain"] = team.Domain
|
||||
data["name"] = team.Name
|
||||
|
||||
if _, err := Client.ResetPassword(data); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -846,10 +846,10 @@ func TestResetPassword(t *testing.T) {
|
||||
t.Fatal("Should have errored - bad domain")
|
||||
}
|
||||
|
||||
team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test2@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test2@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||
|
||||
data["domain"] = team2.Domain
|
||||
data["domain"] = team2.Name
|
||||
if _, err := Client.ResetPassword(data); err == nil {
|
||||
t.Fatal("Should have errored - domain team doesn't match user team")
|
||||
}
|
||||
@@ -858,10 +858,10 @@ func TestResetPassword(t *testing.T) {
|
||||
func TestUserUpdateNotify(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd", Roles: ""}
|
||||
user := &model.User{TeamId: team.Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd", Roles: ""}
|
||||
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user.Id))
|
||||
|
||||
@@ -875,7 +875,7 @@ func TestUserUpdateNotify(t *testing.T) {
|
||||
t.Fatal("Should have errored - not logged in")
|
||||
}
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user.Email, "pwd")
|
||||
|
||||
if result, err := Client.UpdateUserNotify(data); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -926,7 +926,7 @@ func TestUserUpdateNotify(t *testing.T) {
|
||||
|
||||
func TestFuzzyUserCreate(t *testing.T) {
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
for i := 0; i < len(utils.FUZZY_STRINGS_NAMES) || i < len(utils.FUZZY_STRINGS_EMAILS); i++ {
|
||||
@@ -940,7 +940,7 @@ func TestFuzzyUserCreate(t *testing.T) {
|
||||
testEmail = utils.FUZZY_STRINGS_EMAILS[i]
|
||||
}
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + testEmail, FullName: testName, Password: "hello"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + testEmail, Nickname: testName, Password: "hello"}
|
||||
|
||||
_, err := Client.CreateUser(&user, "")
|
||||
if err != nil {
|
||||
@@ -952,14 +952,14 @@ func TestFuzzyUserCreate(t *testing.T) {
|
||||
func TestStatuses(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
rteam, _ := Client.CreateTeam(&team)
|
||||
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
|
||||
|
||||
Client.LoginByEmail(team.Domain, user.Email, user.Password)
|
||||
Client.LoginByEmail(team.Name, user.Email, user.Password)
|
||||
|
||||
r1, err := Client.GetStatuses()
|
||||
if err != nil {
|
||||
|
||||
@@ -70,7 +70,7 @@ func (c *WebConn) readPump() {
|
||||
} else {
|
||||
msg.TeamId = c.TeamId
|
||||
msg.UserId = c.UserId
|
||||
store.PublishAndForget(&msg)
|
||||
PublishAndForget(&msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@ package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
type Hub struct {
|
||||
teamHubs map[string]*TeamHub
|
||||
register chan *WebConn
|
||||
unregister chan *WebConn
|
||||
broadcast chan *model.Message
|
||||
stop chan string
|
||||
}
|
||||
|
||||
@@ -18,9 +20,16 @@ var hub = &Hub{
|
||||
register: make(chan *WebConn),
|
||||
unregister: make(chan *WebConn),
|
||||
teamHubs: make(map[string]*TeamHub),
|
||||
broadcast: make(chan *model.Message),
|
||||
stop: make(chan string),
|
||||
}
|
||||
|
||||
func PublishAndForget(message *model.Message) {
|
||||
go func() {
|
||||
hub.Broadcast(message)
|
||||
}()
|
||||
}
|
||||
|
||||
func (h *Hub) Register(webConn *WebConn) {
|
||||
h.register <- webConn
|
||||
}
|
||||
@@ -29,8 +38,14 @@ func (h *Hub) Unregister(webConn *WebConn) {
|
||||
h.unregister <- webConn
|
||||
}
|
||||
|
||||
func (h *Hub) Stop(teamId string) {
|
||||
h.stop <- teamId
|
||||
func (h *Hub) Broadcast(message *model.Message) {
|
||||
if message != nil {
|
||||
h.broadcast <- message
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Hub) Stop() {
|
||||
h.stop <- "all"
|
||||
}
|
||||
|
||||
func (h *Hub) Start() {
|
||||
@@ -53,18 +68,17 @@ func (h *Hub) Start() {
|
||||
if nh, ok := h.teamHubs[c.TeamId]; ok {
|
||||
nh.Unregister(c)
|
||||
}
|
||||
|
||||
case s := <-h.stop:
|
||||
if len(s) == 0 {
|
||||
l4g.Debug("stopping all connections")
|
||||
for _, v := range h.teamHubs {
|
||||
v.Stop()
|
||||
}
|
||||
return
|
||||
} else if nh, ok := h.teamHubs[s]; ok {
|
||||
delete(h.teamHubs, s)
|
||||
nh.Stop()
|
||||
case msg := <-h.broadcast:
|
||||
nh := h.teamHubs[msg.TeamId]
|
||||
if nh != nil {
|
||||
nh.broadcast <- msg
|
||||
}
|
||||
case s := <-h.stop:
|
||||
l4g.Debug("stopping %v connections", s)
|
||||
for _, v := range h.teamHubs {
|
||||
v.Stop()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -17,13 +17,13 @@ func TestSocket(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
url := "ws://localhost:" + utils.Cfg.ServiceSettings.Port + "/api/v1/websocket"
|
||||
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||
Client.LoginByEmail(team.Domain, user1.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "Test Web Scoket 1", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
@@ -39,10 +39,10 @@ func TestSocket(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
|
||||
header2 := http.Header{}
|
||||
header2.Set(model.HEADER_AUTH, "BEARER "+Client.AuthToken)
|
||||
@@ -115,9 +115,6 @@ func TestSocket(t *testing.T) {
|
||||
}()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
hub.Stop(team.Id)
|
||||
|
||||
}
|
||||
|
||||
func TestZZWebSocketTearDown(t *testing.T) {
|
||||
|
||||
@@ -6,8 +6,6 @@ package api
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TeamHub struct {
|
||||
@@ -43,43 +41,6 @@ func (h *TeamHub) Stop() {
|
||||
}
|
||||
|
||||
func (h *TeamHub) Start() {
|
||||
|
||||
pubsub := store.RedisClient().PubSub()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
l4g.Debug("redis reader finished for teamId=%v", h.teamId)
|
||||
hub.Stop(h.teamId)
|
||||
}()
|
||||
|
||||
l4g.Debug("redis reader starting for teamId=%v", h.teamId)
|
||||
|
||||
err := pubsub.Subscribe(h.teamId)
|
||||
if err != nil {
|
||||
l4g.Error("Error while subscribing to redis %v %v", h.teamId, err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
if payload, err := pubsub.ReceiveTimeout(REDIS_WAIT); err != nil {
|
||||
if strings.Contains(err.Error(), "i/o timeout") {
|
||||
if len(h.connections) == 0 {
|
||||
l4g.Debug("No active connections so sending stop %v", h.teamId)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
msg := store.GetMessageFromPayload(payload)
|
||||
if msg != nil {
|
||||
h.broadcast <- msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
@@ -110,7 +71,6 @@ func (h *TeamHub) Start() {
|
||||
webCon.WebSocket.Close()
|
||||
}
|
||||
|
||||
pubsub.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
},
|
||||
"ServiceSettings": {
|
||||
"SiteName": "Mattermost",
|
||||
"Domain": "xxxxxxmustbefilledin.com",
|
||||
"Mode" : "dev",
|
||||
"AllowTesting" : false,
|
||||
"UseSSL": false,
|
||||
@@ -31,19 +30,11 @@
|
||||
"Trace": false,
|
||||
"AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
|
||||
},
|
||||
"RedisSettings": {
|
||||
"DataSource": "dockerhost:6379",
|
||||
"MaxOpenConns": 1000
|
||||
},
|
||||
"AWSSettings": {
|
||||
"S3AccessKeyId": "",
|
||||
"S3SecretAccessKey": "",
|
||||
"S3Bucket": "",
|
||||
"S3Region": "",
|
||||
"Route53AccessKeyId": "",
|
||||
"Route53SecretAccessKey": "",
|
||||
"Route53ZoneId": "",
|
||||
"Route53Region": ""
|
||||
"S3Region": ""
|
||||
},
|
||||
"ImageSettings": {
|
||||
"ThumbnailWidth": 200,
|
||||
@@ -54,11 +45,12 @@
|
||||
"ProfileHeight": 128
|
||||
},
|
||||
"EmailSettings": {
|
||||
"ByPassEmail" : true,
|
||||
"SMTPUsername": "",
|
||||
"SMTPPassword": "",
|
||||
"SMTPServer": "",
|
||||
"UseTLS": false,
|
||||
"FeedbackEmail": "feedback@xxxxxxmustbefilledin.com",
|
||||
"FeedbackEmail": "",
|
||||
"FeedbackName": "",
|
||||
"ApplePushServer": "",
|
||||
"ApplePushCertPublic": "",
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
},
|
||||
"ServiceSettings": {
|
||||
"SiteName": "Mattermost",
|
||||
"Domain": "",
|
||||
"Mode" : "dev",
|
||||
"AllowTesting" : false,
|
||||
"UseSSL": false,
|
||||
@@ -31,19 +30,11 @@
|
||||
"Trace": false,
|
||||
"AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
|
||||
},
|
||||
"RedisSettings": {
|
||||
"DataSource": "localhost:6379",
|
||||
"MaxOpenConns": 1000
|
||||
},
|
||||
"AWSSettings": {
|
||||
"S3AccessKeyId": "",
|
||||
"S3SecretAccessKey": "",
|
||||
"S3Bucket": "",
|
||||
"S3Region": "",
|
||||
"Route53AccessKeyId": "",
|
||||
"Route53SecretAccessKey": "",
|
||||
"Route53ZoneId": "",
|
||||
"Route53Region": ""
|
||||
"S3Region": ""
|
||||
},
|
||||
"ImageSettings": {
|
||||
"ThumbnailWidth": 200,
|
||||
@@ -54,9 +45,10 @@
|
||||
"ProfileHeight": 128
|
||||
},
|
||||
"EmailSettings": {
|
||||
"ByPassEmail" : true,
|
||||
"SMTPUsername": "",
|
||||
"SMTPPassword": "",
|
||||
"SMTPServer": "localhost:25",
|
||||
"SMTPServer": "",
|
||||
"UseTLS": false,
|
||||
"FeedbackEmail": "",
|
||||
"FeedbackName": "",
|
||||
|
||||
@@ -57,17 +57,17 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Check for username parameter and create a user if present
|
||||
username, ok1 := params["username"]
|
||||
teamname, ok2 := params["teamname"]
|
||||
teamDisplayName, ok2 := params["teamname"]
|
||||
var teamID string
|
||||
var userID string
|
||||
if ok1 && ok2 {
|
||||
l4g.Info("Creating user and team")
|
||||
// Create team for testing
|
||||
team := &model.Team{
|
||||
Name: teamname[0],
|
||||
Domain: utils.RandomName(utils.Range{20, 20}, utils.LOWERCASE),
|
||||
Email: utils.RandomEmail(utils.Range{20, 20}, utils.LOWERCASE),
|
||||
Type: model.TEAM_OPEN,
|
||||
DisplayName: teamDisplayName[0],
|
||||
Name: utils.RandomName(utils.Range{20, 20}, utils.LOWERCASE),
|
||||
Email: utils.RandomEmail(utils.Range{20, 20}, utils.LOWERCASE),
|
||||
Type: model.TEAM_OPEN,
|
||||
}
|
||||
|
||||
if result := <-api.Srv.Store.Team().Save(team); result.Err != nil {
|
||||
@@ -90,7 +90,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
||||
user := &model.User{
|
||||
TeamId: teamID,
|
||||
Email: utils.RandomEmail(utils.Range{20, 20}, utils.LOWERCASE),
|
||||
FullName: username[0],
|
||||
Nickname: username[0],
|
||||
Password: api.USER_PASSWORD}
|
||||
|
||||
result, err := client.CreateUser(user, "")
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
type ExtraMember struct {
|
||||
Id string `json:"id"`
|
||||
FullName string `json:"full_name"`
|
||||
Nickname string `json:"nickname"`
|
||||
Email string `json:"email"`
|
||||
Roles string `json:"roles"`
|
||||
Username string `json:"username"`
|
||||
@@ -20,9 +20,6 @@ func (o *ExtraMember) Sanitize(options map[string]bool) {
|
||||
if len(options) == 0 || !options["email"] {
|
||||
o.Email = ""
|
||||
}
|
||||
if len(options) == 0 || !options["fullname"] {
|
||||
o.FullName = ""
|
||||
}
|
||||
}
|
||||
|
||||
type ChannelExtra struct {
|
||||
|
||||
@@ -100,10 +100,10 @@ func (c *Client) Must(result *Result, err *AppError) *Result {
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Client) SignupTeam(email string, name string) (*Result, *AppError) {
|
||||
func (c *Client) SignupTeam(email string, displayName string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["email"] = email
|
||||
m["name"] = name
|
||||
m["display_name"] = displayName
|
||||
if r, err := c.DoPost("/teams/signup", MapToJson(m)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
@@ -130,11 +130,11 @@ func (c *Client) CreateTeam(team *Team) (*Result, *AppError) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) FindTeamByDomain(domain string, allServers bool) (*Result, *AppError) {
|
||||
func (c *Client) FindTeamByName(name string, allServers bool) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["domain"] = domain
|
||||
m["name"] = name
|
||||
m["all"] = fmt.Sprintf("%v", allServers)
|
||||
if r, err := c.DoPost("/teams/find_team_by_domain", MapToJson(m)); err != nil {
|
||||
if r, err := c.DoPost("/teams/find_team_by_name", MapToJson(m)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
val := false
|
||||
@@ -179,7 +179,7 @@ func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) UpdateTeamName(data map[string]string) (*Result, *AppError) {
|
||||
func (c *Client) UpdateTeamDisplayName(data map[string]string) (*Result, *AppError) {
|
||||
if r, err := c.DoPost("/teams/update_name", MapToJson(data)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
@@ -249,17 +249,17 @@ func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
|
||||
return c.login(m)
|
||||
}
|
||||
|
||||
func (c *Client) LoginByEmail(domain string, email string, password string) (*Result, *AppError) {
|
||||
func (c *Client) LoginByEmail(name string, email string, password string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["domain"] = domain
|
||||
m["name"] = name
|
||||
m["email"] = email
|
||||
m["password"] = password
|
||||
return c.login(m)
|
||||
}
|
||||
|
||||
func (c *Client) LoginByEmailWithDevice(domain string, email string, password string, deviceId string) (*Result, *AppError) {
|
||||
func (c *Client) LoginByEmailWithDevice(name string, email string, password string, deviceId string) (*Result, *AppError) {
|
||||
m := make(map[string]string)
|
||||
m["domain"] = domain
|
||||
m["name"] = name
|
||||
m["email"] = email
|
||||
m["password"] = password
|
||||
m["device_id"] = deviceId
|
||||
|
||||
@@ -18,8 +18,8 @@ type Team struct {
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Name string `json:"name"`
|
||||
Domain string `json:"domain"`
|
||||
Email string `json:"email"`
|
||||
Type string `json:"type"`
|
||||
CompanyName string `json:"company_name"`
|
||||
@@ -97,20 +97,20 @@ func (o *Team) IsValid() *AppError {
|
||||
return NewAppError("Team.IsValid", "Invalid email", "id="+o.Id)
|
||||
}
|
||||
|
||||
if len(o.Name) > 64 {
|
||||
if len(o.DisplayName) > 64 {
|
||||
return NewAppError("Team.IsValid", "Invalid name", "id="+o.Id)
|
||||
}
|
||||
|
||||
if len(o.Domain) > 64 {
|
||||
return NewAppError("Team.IsValid", "Invalid domain", "id="+o.Id)
|
||||
if len(o.Name) > 64 {
|
||||
return NewAppError("Team.IsValid", "Invalid URL Identifier", "id="+o.Id)
|
||||
}
|
||||
|
||||
if IsReservedDomain(o.Domain) {
|
||||
if IsReservedTeamName(o.Name) {
|
||||
return NewAppError("Team.IsValid", "This URL is unavailable. Please try another.", "id="+o.Id)
|
||||
}
|
||||
|
||||
if !IsValidDomain(o.Domain) {
|
||||
return NewAppError("Team.IsValid", "Domain must be 4 or more lowercase alphanumeric characters", "id="+o.Id)
|
||||
if !IsValidTeamName(o.Name) {
|
||||
return NewAppError("Team.IsValid", "Name must be 4 or more lowercase alphanumeric characters", "id="+o.Id)
|
||||
}
|
||||
|
||||
if !(o.Type == TEAM_OPEN || o.Type == TEAM_INVITE) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTeamSignupJson(t *testing.T) {
|
||||
team := Team{Id: NewId(), Name: NewId()}
|
||||
team := Team{Id: NewId(), DisplayName: NewId()}
|
||||
o := TeamSignup{Team: team, Data: "data"}
|
||||
json := o.ToJson()
|
||||
ro := TeamSignupFromJson(strings.NewReader(json))
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTeamJson(t *testing.T) {
|
||||
o := Team{Id: NewId(), Name: NewId()}
|
||||
o := Team{Id: NewId(), DisplayName: NewId()}
|
||||
json := o.ToJson()
|
||||
ro := TeamFromJson(strings.NewReader(json))
|
||||
|
||||
@@ -46,18 +46,18 @@ func TestTeamIsValid(t *testing.T) {
|
||||
}
|
||||
|
||||
o.Email = "corey@hulen.com"
|
||||
o.Name = strings.Repeat("01234567890", 20)
|
||||
o.DisplayName = strings.Repeat("01234567890", 20)
|
||||
if err := o.IsValid(); err == nil {
|
||||
t.Fatal("should be invalid")
|
||||
}
|
||||
|
||||
o.Name = "1234"
|
||||
o.Domain = "ZZZZZZZ"
|
||||
o.DisplayName = "1234"
|
||||
o.Name = "ZZZZZZZ"
|
||||
if err := o.IsValid(); err == nil {
|
||||
t.Fatal("should be invalid")
|
||||
}
|
||||
|
||||
o.Domain = "zzzzz"
|
||||
o.Name = "zzzzz"
|
||||
o.Type = TEAM_OPEN
|
||||
if err := o.IsValid(); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -65,12 +65,12 @@ func TestTeamIsValid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTeamPreSave(t *testing.T) {
|
||||
o := Team{Name: "test"}
|
||||
o := Team{DisplayName: "test"}
|
||||
o.PreSave()
|
||||
o.Etag()
|
||||
}
|
||||
|
||||
func TestTeamPreUpdate(t *testing.T) {
|
||||
o := Team{Name: "test"}
|
||||
o := Team{DisplayName: "test"}
|
||||
o.PreUpdate()
|
||||
}
|
||||
|
||||
@@ -37,7 +37,9 @@ type User struct {
|
||||
AuthData string `json:"auth_data"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
FullName string `json:"full_name"`
|
||||
Nickname string `json:"nickname"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Roles string `json:"roles"`
|
||||
LastActivityAt int64 `json:"last_activity_at"`
|
||||
LastPingAt int64 `json:"last_ping_at"`
|
||||
@@ -45,6 +47,7 @@ type User struct {
|
||||
Props StringMap `json:"props"`
|
||||
NotifyProps StringMap `json:"notify_props"`
|
||||
LastPasswordUpdate int64 `json:"last_password_update"`
|
||||
LastPictureUpdate int64 `json:"last_picture_update"`
|
||||
}
|
||||
|
||||
// IsValid validates the user and returns an error if it isn't configured
|
||||
@@ -81,8 +84,16 @@ func (u *User) IsValid() *AppError {
|
||||
return NewAppError("User.IsValid", "Invalid email", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.FullName) > 64 {
|
||||
return NewAppError("User.IsValid", "Invalid full name", "user_id="+u.Id)
|
||||
if len(u.Nickname) > 64 {
|
||||
return NewAppError("User.IsValid", "Invalid nickname", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.FirstName) > 64 {
|
||||
return NewAppError("User.IsValid", "Invalid first name", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.LastName) > 64 {
|
||||
return NewAppError("User.IsValid", "Invalid last name", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -151,7 +162,7 @@ func (u *User) SetDefaultNotifications() {
|
||||
u.NotifyProps["first_name"] = "false"
|
||||
u.NotifyProps["all"] = "true"
|
||||
u.NotifyProps["channel"] = "true"
|
||||
splitName := strings.Split(u.FullName, " ")
|
||||
splitName := strings.Split(u.Nickname, " ")
|
||||
if len(splitName) > 0 && splitName[0] != "" {
|
||||
u.NotifyProps["first_name"] = "true"
|
||||
u.NotifyProps["mention_keys"] += "," + splitName[0]
|
||||
@@ -190,7 +201,8 @@ func (u *User) Sanitize(options map[string]bool) {
|
||||
u.Email = ""
|
||||
}
|
||||
if len(options) != 0 && !options["fullname"] {
|
||||
u.FullName = ""
|
||||
u.FirstName = ""
|
||||
u.LastName = ""
|
||||
}
|
||||
if len(options) != 0 && !options["skypeid"] {
|
||||
// TODO - fill in when SkypeId is added to user model
|
||||
@@ -225,6 +237,28 @@ func (u *User) AddNotifyProp(key string, value string) {
|
||||
u.NotifyProps[key] = value
|
||||
}
|
||||
|
||||
func (u *User) GetFullName() string {
|
||||
if u.FirstName != "" && u.LastName != "" {
|
||||
return u.FirstName + " " + u.LastName
|
||||
} else if u.FirstName != "" {
|
||||
return u.FirstName
|
||||
} else if u.LastName != "" {
|
||||
return u.LastName
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) GetDisplayName() string {
|
||||
if u.Nickname != "" {
|
||||
return u.Nickname
|
||||
} else if fullName := u.GetFullName(); fullName != "" {
|
||||
return fullName
|
||||
} else {
|
||||
return u.Username
|
||||
}
|
||||
}
|
||||
|
||||
// UserFromJson will decode the input and return a User
|
||||
func UserFromJson(data io.Reader) *User {
|
||||
decoder := json.NewDecoder(data)
|
||||
|
||||
@@ -80,13 +80,73 @@ func TestUserIsValid(t *testing.T) {
|
||||
}
|
||||
|
||||
user.Email = "test@nowhere.com"
|
||||
user.FullName = strings.Repeat("01234567890", 20)
|
||||
user.Nickname = strings.Repeat("01234567890", 20)
|
||||
if err := user.IsValid(); err == nil {
|
||||
t.Fatal()
|
||||
}
|
||||
|
||||
user.FullName = ""
|
||||
user.Nickname = ""
|
||||
if err := user.IsValid(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user.FirstName = ""
|
||||
user.LastName = ""
|
||||
if err := user.IsValid(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user.FirstName = strings.Repeat("01234567890", 20)
|
||||
if err := user.IsValid(); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
user.FirstName = ""
|
||||
user.LastName = strings.Repeat("01234567890", 20)
|
||||
if err := user.IsValid(); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserGetFullName(t *testing.T) {
|
||||
user := User{}
|
||||
|
||||
if fullName := user.GetFullName(); fullName != "" {
|
||||
t.Fatal("Full name should be blank")
|
||||
}
|
||||
|
||||
user.FirstName = "first"
|
||||
if fullName := user.GetFullName(); fullName != "first" {
|
||||
t.Fatal("Full name should be first name")
|
||||
}
|
||||
|
||||
user.FirstName = ""
|
||||
user.LastName = "last"
|
||||
if fullName := user.GetFullName(); fullName != "last" {
|
||||
t.Fatal("Full name should be last name")
|
||||
}
|
||||
|
||||
user.FirstName = "first"
|
||||
if fullName := user.GetFullName(); fullName != "first last" {
|
||||
t.Fatal("Full name should be first name and last name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserGetDisplayName(t *testing.T) {
|
||||
user := User{Username: "user"}
|
||||
|
||||
if displayName := user.GetDisplayName(); displayName != "user" {
|
||||
t.Fatal("Display name should be username")
|
||||
}
|
||||
|
||||
user.FirstName = "first"
|
||||
user.LastName = "last"
|
||||
if displayName := user.GetDisplayName(); displayName != "first last" {
|
||||
t.Fatal("Display name should be full name")
|
||||
}
|
||||
|
||||
user.Nickname = "nickname"
|
||||
if displayName := user.GetDisplayName(); displayName != "nickname" {
|
||||
t.Fatal("Display name should be nickname")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func IsValidEmail(email string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var reservedDomains = []string{
|
||||
var reservedName = []string{
|
||||
"www",
|
||||
"web",
|
||||
"admin",
|
||||
@@ -168,10 +168,10 @@ var reservedDomains = []string{
|
||||
"api",
|
||||
}
|
||||
|
||||
func IsReservedDomain(s string) bool {
|
||||
func IsReservedTeamName(s string) bool {
|
||||
s = strings.ToLower(s)
|
||||
|
||||
for _, value := range reservedDomains {
|
||||
for _, value := range reservedName {
|
||||
if strings.Index(s, value) == 0 {
|
||||
return true
|
||||
}
|
||||
@@ -180,7 +180,7 @@ func IsReservedDomain(s string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func IsValidDomain(s string) bool {
|
||||
func IsValidTeamName(s string) bool {
|
||||
|
||||
if !IsValidAlphaNum(s) {
|
||||
return false
|
||||
|
||||
@@ -83,9 +83,9 @@ var domains = []struct {
|
||||
{"test", true},
|
||||
}
|
||||
|
||||
func TestValidDomain(t *testing.T) {
|
||||
func TestValidTeamName(t *testing.T) {
|
||||
for _, v := range domains {
|
||||
if IsValidDomain(v.value) != v.expected {
|
||||
if IsValidTeamName(v.value) != v.expected {
|
||||
t.Errorf("expect %v as %v", v.value, v.expected)
|
||||
}
|
||||
}
|
||||
@@ -102,9 +102,9 @@ var tReservedDomains = []struct {
|
||||
{"spin-punch-admin", false},
|
||||
}
|
||||
|
||||
func TestReservedDomain(t *testing.T) {
|
||||
func TestReservedTeamName(t *testing.T) {
|
||||
for _, v := range tReservedDomains {
|
||||
if IsReservedDomain(v.value) != v.expected {
|
||||
if IsReservedTeamName(v.value) != v.expected {
|
||||
t.Errorf("expect %v as %v", v.value, v.expected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ DOCKER SETUP
|
||||
3. Add a line to your /etc/hosts that goes `<Docker IP> dockerhost`
|
||||
4. Run `boot2docker shellinit` and copy the export statements to your ~/.bash_profile
|
||||
|
||||
Any issues? Please let us know on our forums at: http://bit.ly/1MY1kul
|
||||
Any issues? Please let us know on our forums at: http://forum.mattermost.org
|
||||
|
||||
GO SETUP
|
||||
|
||||
@@ -39,4 +39,4 @@ MATTERMOST SETUP
|
||||
6. Then do `cd platform` and `make test`. Provided the test runs fine, you now have a complete build environment.
|
||||
7. Use `make run` to run your code
|
||||
|
||||
Any issues? Please let us know on our forums at: http://bit.ly/1MY1kul
|
||||
Any issues? Please let us know on our forums at: http://forum.mattermost.org
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"gopkg.in/redis.v2"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var client *redis.Client
|
||||
|
||||
func RedisClient() *redis.Client {
|
||||
|
||||
if client == nil {
|
||||
|
||||
addr := utils.Cfg.RedisSettings.DataSource
|
||||
|
||||
client = redis.NewTCPClient(&redis.Options{
|
||||
Addr: addr,
|
||||
Password: "",
|
||||
DB: 0,
|
||||
PoolSize: utils.Cfg.RedisSettings.MaxOpenConns,
|
||||
})
|
||||
|
||||
l4g.Info("Pinging redis at '%v'", addr)
|
||||
pong, err := client.Ping().Result()
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to open redis connection to '%v' err:%v", addr, err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to open redis connection " + err.Error())
|
||||
}
|
||||
|
||||
if pong != "PONG" {
|
||||
l4g.Critical("Failed to ping redis connection to '%v' err:%v", addr, err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to open ping connection " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
func RedisClose() {
|
||||
l4g.Info("Closing redis")
|
||||
|
||||
if client != nil {
|
||||
client.Close()
|
||||
client = nil
|
||||
}
|
||||
}
|
||||
|
||||
func PublishAndForget(message *model.Message) {
|
||||
|
||||
go func() {
|
||||
c := RedisClient()
|
||||
result := c.Publish(message.TeamId, message.ToJson())
|
||||
if result.Err() != nil {
|
||||
l4g.Error("Failed to publish message err=%v, payload=%v", result.Err(), message.ToJson())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func GetMessageFromPayload(m interface{}) *model.Message {
|
||||
if msg, found := m.(*redis.Message); found {
|
||||
return model.MessageFromJson(strings.NewReader(msg.Payload))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRedis(t *testing.T) {
|
||||
utils.LoadConfig("config.json")
|
||||
|
||||
c := RedisClient()
|
||||
|
||||
if c == nil {
|
||||
t.Fatal("should have a valid redis connection")
|
||||
}
|
||||
|
||||
pubsub := c.PubSub()
|
||||
defer pubsub.Close()
|
||||
|
||||
m := model.NewMessage(model.NewId(), model.NewId(), model.NewId(), model.ACTION_TYPING)
|
||||
m.Add("RootId", model.NewId())
|
||||
|
||||
err := pubsub.Subscribe(m.TeamId)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// should be the subscribe success message
|
||||
// lets gobble that up
|
||||
if _, err := pubsub.Receive(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
PublishAndForget(m)
|
||||
|
||||
fmt.Println("here1")
|
||||
|
||||
if msg, err := pubsub.Receive(); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
|
||||
rmsg := GetMessageFromPayload(msg)
|
||||
|
||||
if m.TeamId != rmsg.TeamId {
|
||||
t.Fatal("Ids do not match")
|
||||
}
|
||||
|
||||
if m.Props["RootId"] != rmsg.Props["RootId"] {
|
||||
t.Fatal("Ids do not match")
|
||||
}
|
||||
}
|
||||
|
||||
RedisClose()
|
||||
}
|
||||
@@ -360,7 +360,7 @@ func (s SqlChannelStore) GetExtraMembers(channelId string, limit int) StoreChann
|
||||
result := StoreResult{}
|
||||
|
||||
var members []model.ExtraMember
|
||||
_, err := s.GetReplica().Select(&members, "SELECT Id, FullName, Email, ChannelMembers.Roles, Username FROM ChannelMembers, Users WHERE ChannelMembers.UserId = Users.Id AND ChannelId = :ChannelId LIMIT :Limit", map[string]interface{}{"ChannelId": channelId, "Limit": limit})
|
||||
_, err := s.GetReplica().Select(&members, "SELECT Id, Nickname, Email, ChannelMembers.Roles, Username FROM ChannelMembers, Users WHERE ChannelMembers.UserId = Users.Id AND ChannelId = :ChannelId LIMIT :Limit", map[string]interface{}{"ChannelId": channelId, "Limit": limit})
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlChannelStore.GetExtraMembers", "We couldn't get the extra info for channel members", "channel_id="+channelId+", "+err.Error())
|
||||
} else {
|
||||
|
||||
@@ -200,13 +200,13 @@ func TestChannelMemberStore(t *testing.T) {
|
||||
u1 := model.User{}
|
||||
u1.TeamId = model.NewId()
|
||||
u1.Email = model.NewId()
|
||||
u1.FullName = model.NewId()
|
||||
u1.Nickname = model.NewId()
|
||||
Must(store.User().Save(&u1))
|
||||
|
||||
u2 := model.User{}
|
||||
u2.TeamId = model.NewId()
|
||||
u2.Email = model.NewId()
|
||||
u2.FullName = model.NewId()
|
||||
u2.Nickname = model.NewId()
|
||||
Must(store.User().Save(&u2))
|
||||
|
||||
o1 := model.ChannelMember{}
|
||||
|
||||
@@ -36,6 +36,11 @@ func NewSqlPostStore(sqlStore *SqlStore) PostStore {
|
||||
}
|
||||
|
||||
func (s SqlPostStore) UpgradeSchemaIfNeeded() {
|
||||
|
||||
// These execs are for upgrading currently created databases to full utf8mb4 compliance
|
||||
// Will be removed as seen fit for upgrading
|
||||
s.GetMaster().Exec("ALTER TABLE Posts charset=utf8mb4")
|
||||
s.GetMaster().Exec("ALTER TABLE Posts MODIFY COLUMN Message varchar(4000) CHARACTER SET utf8mb4")
|
||||
}
|
||||
|
||||
func (s SqlPostStore) CreateIndexesIfNotExists() {
|
||||
|
||||
@@ -83,7 +83,14 @@ func NewSqlStore() Store {
|
||||
|
||||
func setupConnection(con_type string, driver string, dataSource string, maxIdle int, maxOpen int, trace bool) *gorp.DbMap {
|
||||
|
||||
db, err := dbsql.Open(driver, dataSource)
|
||||
charset := ""
|
||||
if strings.Index(dataSource, "?") > -1 {
|
||||
charset = "&charset=utf8mb4,utf8"
|
||||
} else {
|
||||
charset = "?charset=utf8mb4,utf8"
|
||||
}
|
||||
|
||||
db, err := dbsql.Open(driver, dataSource+charset)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to open sql connection to '%v' err:%v", dataSource, err)
|
||||
time.Sleep(time.Second)
|
||||
@@ -106,7 +113,7 @@ func setupConnection(con_type string, driver string, dataSource string, maxIdle
|
||||
if driver == "sqlite3" {
|
||||
dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.SqliteDialect{}}
|
||||
} else if driver == "mysql" {
|
||||
dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8"}}
|
||||
dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8MB4"}}
|
||||
} else if driver == "postgres" {
|
||||
dbmap = &gorp.DbMap{Db: db, TypeConverter: mattermConverter{}, Dialect: gorp.PostgresDialect{}}
|
||||
} else {
|
||||
@@ -122,62 +129,9 @@ func setupConnection(con_type string, driver string, dataSource string, maxIdle
|
||||
return dbmap
|
||||
}
|
||||
|
||||
func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string, colType string, defaultValue string) bool {
|
||||
|
||||
var count int64
|
||||
var err error
|
||||
|
||||
if utils.Cfg.SqlSettings.DriverName == "postgres" {
|
||||
|
||||
count, err = ss.GetMaster().SelectInt(
|
||||
`SELECT
|
||||
COUNT(0) AS column_exists
|
||||
FROM
|
||||
information_schema.COLUMNS
|
||||
WHERE
|
||||
TABLE_NAME = $1
|
||||
AND COLUMN_NAME = $2`,
|
||||
tableName,
|
||||
columnName,
|
||||
)
|
||||
} else if utils.Cfg.SqlSettings.DriverName == "mysql" {
|
||||
count, err = ss.GetMaster().SelectInt(
|
||||
`SELECT
|
||||
COUNT(0) AS column_exists
|
||||
FROM
|
||||
information_schema.COLUMNS
|
||||
WHERE
|
||||
TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = ?
|
||||
AND COLUMN_NAME = ?`,
|
||||
tableName,
|
||||
columnName,
|
||||
)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check if column exists %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check if column exists " + err.Error())
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err = ss.GetMaster().Exec("ALTER TABLE " + tableName + " ADD " + columnName + " " + colType + " DEFAULT '" + defaultValue + "'")
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create column %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create column " + err.Error())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) bool {
|
||||
func (ss SqlStore) DoesColumnExist(tableName string, columnName string) bool {
|
||||
count, err := ss.GetMaster().SelectInt(
|
||||
`SELECT
|
||||
`SELECT
|
||||
COUNT(0) AS column_exists
|
||||
FROM
|
||||
information_schema.COLUMNS
|
||||
@@ -194,11 +148,30 @@ func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) boo
|
||||
panic("Failed to check if column exists " + err.Error())
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string, afterName string, colType string, defaultValue string) bool {
|
||||
if ss.DoesColumnExist(tableName, columnName) {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err = ss.GetMaster().Exec("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " ADD " + columnName + " " + colType + " DEFAULT '" + defaultValue + "'" + " AFTER " + afterName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create column %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create column " + err.Error())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) bool {
|
||||
if !ss.DoesColumnExist(tableName, columnName) {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to drop column %v", err)
|
||||
time.Sleep(time.Second)
|
||||
@@ -208,6 +181,25 @@ func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) boo
|
||||
return true
|
||||
}
|
||||
|
||||
func (ss SqlStore) RenameColumnIfExists(tableName string, oldColumnName string, newColumnName string, colType string) bool {
|
||||
if !ss.DoesColumnExist(tableName, oldColumnName) {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " CHANGE " + oldColumnName + " " + newColumnName + " " + colType)
|
||||
|
||||
// when we eventually support PostgreSQL, we can use the following instead
|
||||
//_, err := ss.GetMaster().Exec("ALTER TABLE " + tableName + " RENAME COLUMN " + oldColumnName + " TO " + newColumnName)
|
||||
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to rename column %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to drop column " + err.Error())
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ss SqlStore) CreateIndexIfNotExists(indexName string, tableName string, columnName string) {
|
||||
ss.createIndexIfNotExists(indexName, tableName, columnName, false)
|
||||
}
|
||||
@@ -217,55 +209,27 @@ func (ss SqlStore) CreateFullTextIndexIfNotExists(indexName string, tableName st
|
||||
}
|
||||
|
||||
func (ss SqlStore) createIndexIfNotExists(indexName string, tableName string, columnName string, fullText bool) {
|
||||
|
||||
if utils.Cfg.SqlSettings.DriverName == "postgres" {
|
||||
_, err := ss.GetMaster().SelectStr("SELECT to_regclass($1)", indexName)
|
||||
// It should fail if the index does not exist
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
query := ""
|
||||
if fullText {
|
||||
query = "CREATE INDEX " + indexName + " ON " + tableName + " USING gin(to_tsvector('english', " + columnName + "))"
|
||||
} else {
|
||||
query = "CREATE INDEX " + indexName + " ON " + tableName + " (" + columnName + ")"
|
||||
}
|
||||
|
||||
_, err = ss.GetMaster().Exec(query)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create index %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index " + err.Error())
|
||||
}
|
||||
} else if utils.Cfg.SqlSettings.DriverName == "mysql" {
|
||||
|
||||
count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check index %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to check index " + err.Error())
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
fullTextIndex := ""
|
||||
if fullText {
|
||||
fullTextIndex = " FULLTEXT "
|
||||
}
|
||||
|
||||
_, err = ss.GetMaster().Exec("CREATE " + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + columnName + ")")
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create index %v", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index " + err.Error())
|
||||
}
|
||||
} else {
|
||||
l4g.Critical("Failed to create index because of missing driver")
|
||||
count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to check index", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index because of missing driver")
|
||||
panic("Failed to check index" + err.Error())
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
fullTextIndex := ""
|
||||
if fullText {
|
||||
fullTextIndex = " FULLTEXT "
|
||||
}
|
||||
|
||||
_, err = ss.GetMaster().Exec("CREATE " + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + columnName + ")")
|
||||
if err != nil {
|
||||
l4g.Critical("Failed to create index", err)
|
||||
time.Sleep(time.Second)
|
||||
panic("Failed to create index " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore {
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(model.Team{}, "Teams").SetKeys(false, "Id")
|
||||
table.ColMap("Id").SetMaxSize(26)
|
||||
table.ColMap("Name").SetMaxSize(64)
|
||||
table.ColMap("Domain").SetMaxSize(64).SetUnique(true)
|
||||
table.ColMap("DisplayName").SetMaxSize(64)
|
||||
table.ColMap("Name").SetMaxSize(64).SetUnique(true)
|
||||
table.ColMap("Email").SetMaxSize(128)
|
||||
table.ColMap("CompanyName").SetMaxSize(64)
|
||||
table.ColMap("AllowedDomains").SetMaxSize(500)
|
||||
@@ -28,6 +28,15 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore {
|
||||
}
|
||||
|
||||
func (s SqlTeamStore) UpgradeSchemaIfNeeded() {
|
||||
defaultValue := "0"
|
||||
if utils.Cfg.TeamSettings.AllowValetDefault {
|
||||
defaultValue = "1"
|
||||
}
|
||||
s.CreateColumnIfNotExists("Teams", "AllowValet", "AllowedDomains", "tinyint(1)", defaultValue)
|
||||
if !s.DoesColumnExist("Teams", "DisplayName") {
|
||||
s.RenameColumnIfExists("Teams", "Name", "DisplayName", "varchar(64)")
|
||||
s.RenameColumnIfExists("Teams", "Domain", "Name", "varchar(64)")
|
||||
}
|
||||
}
|
||||
|
||||
func (s SqlTeamStore) CreateIndexesIfNotExists() {
|
||||
@@ -56,7 +65,7 @@ func (s SqlTeamStore) Save(team *model.Team) StoreChannel {
|
||||
}
|
||||
|
||||
if err := s.GetMaster().Insert(team); err != nil {
|
||||
if IsUniqueConstraintError(err.Error(), "Domain", "teams_domain_key") {
|
||||
if IsUniqueConstraintError(err.Error(), "Name", "teams_domain_key") {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Save", "A team with that domain already exists", "id="+team.Id+", "+err.Error())
|
||||
} else {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Save", "We couldn't save the team", "id="+team.Id+", "+err.Error())
|
||||
@@ -94,7 +103,7 @@ func (s SqlTeamStore) Update(team *model.Team) StoreChannel {
|
||||
} else {
|
||||
oldTeam := oldResult.(*model.Team)
|
||||
team.CreateAt = oldTeam.CreateAt
|
||||
team.Domain = oldTeam.Domain
|
||||
team.Name = oldTeam.Name
|
||||
|
||||
if count, err := s.GetMaster().Update(team); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.Update", "We encounted an error updating the team", "id="+team.Id+", "+err.Error())
|
||||
@@ -112,14 +121,14 @@ func (s SqlTeamStore) Update(team *model.Team) StoreChannel {
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlTeamStore) UpdateName(name string, teamId string) StoreChannel {
|
||||
func (s SqlTeamStore) UpdateDisplayName(name string, teamId string) StoreChannel {
|
||||
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
if _, err := s.GetMaster().Exec("UPDATE Teams SET Name = :Name WHERE Id = :Id", map[string]interface{}{"Name": name, "Id": teamId}); err != nil {
|
||||
if _, err := s.GetMaster().Exec("UPDATE Teams SET DisplayName = :Name WHERE Id = :Id", map[string]interface{}{"Name": name, "Id": teamId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.UpdateName", "We couldn't update the team name", "team_id="+teamId)
|
||||
} else {
|
||||
result.Data = teamId
|
||||
@@ -153,7 +162,7 @@ func (s SqlTeamStore) Get(id string) StoreChannel {
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (s SqlTeamStore) GetByDomain(domain string) StoreChannel {
|
||||
func (s SqlTeamStore) GetByName(name string) StoreChannel {
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
go func() {
|
||||
@@ -161,8 +170,8 @@ func (s SqlTeamStore) GetByDomain(domain string) StoreChannel {
|
||||
|
||||
team := model.Team{}
|
||||
|
||||
if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Domain = :Domain", map[string]interface{}{"Domain": domain}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetByDomain", "We couldn't find the existing team", "domain="+domain+", "+err.Error())
|
||||
if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
|
||||
result.Err = model.NewAppError("SqlTeamStore.GetByName", "We couldn't find the existing team", "name="+name+", "+err.Error())
|
||||
}
|
||||
|
||||
result.Data = &team
|
||||
|
||||
@@ -13,8 +13,8 @@ func TestTeamStoreSave(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
o1 := model.Team{}
|
||||
o1.Name = "Name"
|
||||
o1.Domain = "a" + model.NewId() + "b"
|
||||
o1.DisplayName = "DisplayName"
|
||||
o1.Name = "a" + model.NewId() + "b"
|
||||
o1.Email = model.NewId() + "@nowhere.com"
|
||||
o1.Type = model.TEAM_OPEN
|
||||
|
||||
@@ -36,8 +36,8 @@ func TestTeamStoreUpdate(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
o1 := model.Team{}
|
||||
o1.Name = "Name"
|
||||
o1.Domain = "a" + model.NewId() + "b"
|
||||
o1.DisplayName = "DisplayName"
|
||||
o1.Name = "a" + model.NewId() + "b"
|
||||
o1.Email = model.NewId() + "@nowhere.com"
|
||||
o1.Type = model.TEAM_OPEN
|
||||
if err := (<-store.Team().Save(&o1)).Err; err != nil {
|
||||
@@ -61,25 +61,25 @@ func TestTeamStoreUpdate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeamStoreUpdateName(t *testing.T) {
|
||||
func TestTeamStoreUpdateDisplayName(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
o1 := &model.Team{}
|
||||
o1.Name = "Name"
|
||||
o1.Domain = "a" + model.NewId() + "b"
|
||||
o1.DisplayName = "Display Name"
|
||||
o1.Name = "a" + model.NewId() + "b"
|
||||
o1.Email = model.NewId() + "@nowhere.com"
|
||||
o1.Type = model.TEAM_OPEN
|
||||
o1 = (<-store.Team().Save(o1)).Data.(*model.Team)
|
||||
|
||||
newName := "NewName"
|
||||
newDisplayName := "NewDisplayName"
|
||||
|
||||
if err := (<-store.Team().UpdateName(newName, o1.Id)).Err; err != nil {
|
||||
if err := (<-store.Team().UpdateDisplayName(newDisplayName, o1.Id)).Err; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ro1 := (<-store.Team().Get(o1.Id)).Data.(*model.Team)
|
||||
if ro1.Name != newName {
|
||||
t.Fatal("Name not updated")
|
||||
if ro1.DisplayName != newDisplayName {
|
||||
t.Fatal("DisplayName not updated")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ func TestTeamStoreGet(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
o1 := model.Team{}
|
||||
o1.Name = "Name"
|
||||
o1.Domain = "a" + model.NewId() + "b"
|
||||
o1.DisplayName = "DisplayName"
|
||||
o1.Name = "a" + model.NewId() + "b"
|
||||
o1.Email = model.NewId() + "@nowhere.com"
|
||||
o1.Type = model.TEAM_OPEN
|
||||
Must(store.Team().Save(&o1))
|
||||
@@ -106,12 +106,12 @@ func TestTeamStoreGet(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeamStoreGetByDomain(t *testing.T) {
|
||||
func TestTeamStoreGetByName(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
o1 := model.Team{}
|
||||
o1.Name = "Name"
|
||||
o1.Domain = "a" + model.NewId() + "b"
|
||||
o1.DisplayName = "DisplayName"
|
||||
o1.Name = "a" + model.NewId() + "b"
|
||||
o1.Email = model.NewId() + "@nowhere.com"
|
||||
o1.Type = model.TEAM_OPEN
|
||||
|
||||
@@ -119,7 +119,7 @@ func TestTeamStoreGetByDomain(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if r1 := <-store.Team().GetByDomain(o1.Domain); r1.Err != nil {
|
||||
if r1 := <-store.Team().GetByName(o1.Name); r1.Err != nil {
|
||||
t.Fatal(r1.Err)
|
||||
} else {
|
||||
if r1.Data.(*model.Team).ToJson() != o1.ToJson() {
|
||||
@@ -127,7 +127,7 @@ func TestTeamStoreGetByDomain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := (<-store.Team().GetByDomain("")).Err; err == nil {
|
||||
if err := (<-store.Team().GetByName("")).Err; err == nil {
|
||||
t.Fatal("Missing id should have failed")
|
||||
}
|
||||
}
|
||||
@@ -136,8 +136,8 @@ func TestTeamStoreGetForEmail(t *testing.T) {
|
||||
Setup()
|
||||
|
||||
o1 := model.Team{}
|
||||
o1.Name = "Name"
|
||||
o1.Domain = "a" + model.NewId() + "b"
|
||||
o1.DisplayName = "DisplayName"
|
||||
o1.Name = "a" + model.NewId() + "b"
|
||||
o1.Email = model.NewId() + "@nowhere.com"
|
||||
o1.Type = model.TEAM_OPEN
|
||||
Must(store.Team().Save(&o1))
|
||||
|
||||
@@ -24,7 +24,9 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore {
|
||||
table.ColMap("Password").SetMaxSize(128)
|
||||
table.ColMap("AuthData").SetMaxSize(128)
|
||||
table.ColMap("Email").SetMaxSize(128)
|
||||
table.ColMap("FullName").SetMaxSize(64)
|
||||
table.ColMap("Nickname").SetMaxSize(64)
|
||||
table.ColMap("FirstName").SetMaxSize(64)
|
||||
table.ColMap("LastName").SetMaxSize(64)
|
||||
table.ColMap("Roles").SetMaxSize(64)
|
||||
table.ColMap("Props").SetMaxSize(4000)
|
||||
table.ColMap("NotifyProps").SetMaxSize(2000)
|
||||
@@ -35,9 +37,29 @@ func NewSqlUserStore(sqlStore *SqlStore) UserStore {
|
||||
return us
|
||||
}
|
||||
|
||||
func (s SqlUserStore) UpgradeSchemaIfNeeded() {
|
||||
func (us SqlUserStore) UpgradeSchemaIfNeeded() {
|
||||
us.CreateColumnIfNotExists("Users", "LastPictureUpdate", "LastPasswordUpdate", "bigint(20)", "0")
|
||||
|
||||
// migrating the FullName column to Nickname and adding the FirstName and LastName columns for MM-825
|
||||
if us.RenameColumnIfExists("Users", "FullName", "Nickname", "varchar(64)") {
|
||||
us.CreateColumnIfNotExists("Users", "FirstName", "Nickname", "varchar(64)", "")
|
||||
us.CreateColumnIfNotExists("Users", "LastName", "FirstName", "varchar(64)", "")
|
||||
|
||||
// infer values of first and last name by splitting the previous full name
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET FirstName = SUBSTRING_INDEX(SUBSTRING_INDEX(Nickname, ' ', 1), ' ', -1)"); err != nil {
|
||||
panic("Failed to set first name from nickname " + err.Error())
|
||||
}
|
||||
|
||||
// only set the last name from full names that are comprised of multiple words (ie that have at least one space in them)
|
||||
if _, err := us.GetMaster().Exec("Update Users SET LastName = SUBSTRING(Nickname, INSTR(Nickname, ' ') + 1) " +
|
||||
"WHERE CHAR_LENGTH(REPLACE(Nickname, ' ', '')) < CHAR_LENGTH(Nickname)"); err != nil {
|
||||
panic("Failed to set last name from nickname " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string, afterName string, colType string, defaultValue string) bool {
|
||||
|
||||
func (us SqlUserStore) CreateIndexesIfNotExists() {
|
||||
us.CreateIndexIfNotExists("idx_users_team_id", "Users", "TeamId")
|
||||
us.CreateIndexIfNotExists("idx_users_email", "Users", "Email")
|
||||
@@ -120,6 +142,7 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha
|
||||
user.AuthData = oldUser.AuthData
|
||||
user.Password = oldUser.Password
|
||||
user.LastPasswordUpdate = oldUser.LastPasswordUpdate
|
||||
user.LastPictureUpdate = oldUser.LastPictureUpdate
|
||||
user.TeamId = oldUser.TeamId
|
||||
user.LastActivityAt = oldUser.LastActivityAt
|
||||
user.LastPingAt = oldUser.LastPingAt
|
||||
@@ -150,6 +173,27 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (us SqlUserStore) UpdateLastPictureUpdate(userId string) StoreChannel {
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
curTime := model.GetMillis()
|
||||
|
||||
if _, err := us.GetMaster().Exec("UPDATE Users SET LastPictureUpdate = ?, UpdateAt = ? WHERE Id = ?", curTime, curTime, userId); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.UpdateUpdateAt", "We couldn't update the update_at", "user_id="+userId)
|
||||
} else {
|
||||
result.Data = userId
|
||||
}
|
||||
|
||||
storeChannel <- result
|
||||
close(storeChannel)
|
||||
}()
|
||||
|
||||
return storeChannel
|
||||
}
|
||||
|
||||
func (us SqlUserStore) UpdateLastPingAt(userId string, time int64) StoreChannel {
|
||||
storeChannel := make(StoreChannel)
|
||||
|
||||
|
||||
@@ -36,9 +36,9 @@ type Store interface {
|
||||
type TeamStore interface {
|
||||
Save(team *model.Team) StoreChannel
|
||||
Update(team *model.Team) StoreChannel
|
||||
UpdateName(name string, teamId string) StoreChannel
|
||||
UpdateDisplayName(name string, teamId string) StoreChannel
|
||||
Get(id string) StoreChannel
|
||||
GetByDomain(domain string) StoreChannel
|
||||
GetByName(name string) StoreChannel
|
||||
GetTeamsForEmail(domain string) StoreChannel
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ type PostStore interface {
|
||||
type UserStore interface {
|
||||
Save(user *model.User) StoreChannel
|
||||
Update(user *model.User, allowRoleUpdate bool) StoreChannel
|
||||
UpdateLastPictureUpdate(userId string) StoreChannel
|
||||
UpdateLastPingAt(userId string, time int64) StoreChannel
|
||||
UpdateLastActivityAt(userId string, time int64) StoreChannel
|
||||
UpdateUserAndSessionActivity(userId string, sessionId string, time int64) StoreChannel
|
||||
|
||||
@@ -19,13 +19,11 @@ const (
|
||||
|
||||
type ServiceSettings struct {
|
||||
SiteName string
|
||||
Domain string
|
||||
Mode string
|
||||
AllowTesting bool
|
||||
UseSSL bool
|
||||
Port string
|
||||
Version string
|
||||
Shards map[string]string
|
||||
InviteSalt string
|
||||
PublicLinkSalt string
|
||||
ResetSalt string
|
||||
@@ -42,11 +40,6 @@ type SqlSettings struct {
|
||||
AtRestEncryptKey string
|
||||
}
|
||||
|
||||
type RedisSettings struct {
|
||||
DataSource string
|
||||
MaxOpenConns int
|
||||
}
|
||||
|
||||
type LogSettings struct {
|
||||
ConsoleEnable bool
|
||||
ConsoleLevel string
|
||||
@@ -57,14 +50,10 @@ type LogSettings struct {
|
||||
}
|
||||
|
||||
type AWSSettings struct {
|
||||
S3AccessKeyId string
|
||||
S3SecretAccessKey string
|
||||
S3Bucket string
|
||||
S3Region string
|
||||
Route53AccessKeyId string
|
||||
Route53SecretAccessKey string
|
||||
Route53ZoneId string
|
||||
Route53Region string
|
||||
S3AccessKeyId string
|
||||
S3SecretAccessKey string
|
||||
S3Bucket string
|
||||
S3Region string
|
||||
}
|
||||
|
||||
type ImageSettings struct {
|
||||
@@ -77,6 +66,7 @@ type ImageSettings struct {
|
||||
}
|
||||
|
||||
type EmailSettings struct {
|
||||
ByPassEmail bool
|
||||
SMTPUsername string
|
||||
SMTPPassword string
|
||||
SMTPServer string
|
||||
@@ -112,7 +102,6 @@ type Config struct {
|
||||
LogSettings LogSettings
|
||||
ServiceSettings ServiceSettings
|
||||
SqlSettings SqlSettings
|
||||
RedisSettings RedisSettings
|
||||
AWSSettings AWSSettings
|
||||
ImageSettings ImageSettings
|
||||
EmailSettings EmailSettings
|
||||
@@ -218,18 +207,10 @@ func LoadConfig(fileName string) {
|
||||
panic("Error decoding configuration " + err.Error())
|
||||
}
|
||||
|
||||
// Grabs the domain from enviroment variable if not in configuration
|
||||
if config.ServiceSettings.Domain == "" {
|
||||
config.ServiceSettings.Domain = os.Getenv("MATTERMOST_DOMAIN")
|
||||
// If the enviroment variable is not set, use a default
|
||||
if config.ServiceSettings.Domain == "" {
|
||||
config.ServiceSettings.Domain = "localhost"
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a valid email for feedback, if not then do feedback@domain
|
||||
if _, err := mail.ParseAddress(config.EmailSettings.FeedbackEmail); err != nil {
|
||||
config.EmailSettings.FeedbackEmail = "feedback@" + config.ServiceSettings.Domain
|
||||
config.EmailSettings.FeedbackEmail = "feedback@localhost"
|
||||
l4g.Error("Misconfigured feedback email setting: %s", config.EmailSettings.FeedbackEmail)
|
||||
}
|
||||
|
||||
configureLog(config.LogSettings)
|
||||
|
||||
@@ -4,24 +4,9 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
LoadConfig("config.json")
|
||||
}
|
||||
|
||||
func TestEnvOverride(t *testing.T) {
|
||||
os.Setenv("MATTERMOST_DOMAIN", "testdomain.com")
|
||||
|
||||
LoadConfig("config_docker.json")
|
||||
if Cfg.ServiceSettings.Domain != "testdomain.com" {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
LoadConfig("config.json")
|
||||
if Cfg.ServiceSettings.Domain == "testdomain.com" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/mattermost/platform/model"
|
||||
"html"
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"html"
|
||||
)
|
||||
|
||||
func CheckMailSettings() *model.AppError {
|
||||
if len(Cfg.EmailSettings.SMTPServer) == 0 {
|
||||
if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
|
||||
return model.NewAppError("CheckMailSettings", "No email settings present, mail will not be sent", "")
|
||||
}
|
||||
conn, err := connectToSMTPServer()
|
||||
@@ -79,6 +79,10 @@ func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
|
||||
|
||||
func SendMail(to, subject, body string) *model.AppError {
|
||||
|
||||
if len(Cfg.EmailSettings.SMTPServer) == 0 || Cfg.EmailSettings.ByPassEmail {
|
||||
return nil
|
||||
}
|
||||
|
||||
fromMail := mail.Address{"", Cfg.EmailSettings.FeedbackEmail}
|
||||
toMail := mail.Address{"", to}
|
||||
|
||||
@@ -95,11 +99,6 @@ func SendMail(to, subject, body string) *model.AppError {
|
||||
}
|
||||
message += "\r\n<html><body>" + body + "</body></html>"
|
||||
|
||||
if len(Cfg.EmailSettings.SMTPServer) == 0 {
|
||||
l4g.Warn("Skipping sending of email because EmailSettings are not configured")
|
||||
return nil
|
||||
}
|
||||
|
||||
conn, err1 := connectToSMTPServer()
|
||||
if err1 != nil {
|
||||
return err1
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var PostStore = require('../stores/post_store.jsx');
|
||||
@@ -16,7 +17,7 @@ var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
var ExtraMembers = React.createClass({
|
||||
var PopoverListMembers = React.createClass({
|
||||
componentDidMount: function() {
|
||||
var originalLeave = $.fn.popover.Constructor.prototype.leave;
|
||||
$.fn.popover.Constructor.prototype.leave = function(obj) {
|
||||
@@ -35,30 +36,29 @@ var ExtraMembers = React.createClass({
|
||||
|
||||
$("#member_popover").popover({placement : 'bottom', trigger: 'click', html: true});
|
||||
$('body').on('click', function (e) {
|
||||
if ($(e.target.parentNode.parentNode)[0] !== $("#member_popover")[0] && $(e.target).parents('.popover.in').length === 0) {
|
||||
if ($(e.target.parentNode.parentNode)[0] !== $("#member_popover")[0] && $(e.target).parents('.popover.in').length === 0) {
|
||||
$("#member_popover").popover('hide');
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var count = this.props.members.length == 0 ? "-" : this.props.members.length;
|
||||
count = this.props.members.length > 19 ? "20+" : count;
|
||||
var data_content = "";
|
||||
var sortedMembers = this.props.members;
|
||||
var popoverHtml = '';
|
||||
var members = this.props.members;
|
||||
var count = (members.length > 20) ? "20+" : (members.length || '-');
|
||||
|
||||
if(sortedMembers) {
|
||||
sortedMembers.sort(function(a,b) {
|
||||
if (members) {
|
||||
members.sort(function(a,b) {
|
||||
return a.username.localeCompare(b.username);
|
||||
})
|
||||
});
|
||||
|
||||
sortedMembers.forEach(function(m) {
|
||||
data_content += "<div style='white-space: nowrap'>" + m.username + "</div>";
|
||||
members.forEach(function(m) {
|
||||
popoverHtml += "<div class='text--nowrap'>" + m.username + "</div>";
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{"cursor" : "pointer"}} id="member_popover" data-toggle="popover" data-content={data_content} data-original-title="Members" >
|
||||
<div id="member_popover" data-toggle="popover" data-content={popoverHtml} data-original-title="Members" >
|
||||
<div id="member_tooltip" data-toggle="tooltip" title="View Channel Members">
|
||||
{count} <span className="glyphicon glyphicon-user" aria-hidden="true"></span>
|
||||
</div>
|
||||
@@ -78,6 +78,7 @@ function getStateFromStores() {
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'ChannelHeader',
|
||||
componentDidMount: function() {
|
||||
ChannelStore.addChangeListener(this._onChange);
|
||||
ChannelStore.addExtraInfoChangeListener(this._onChange);
|
||||
@@ -99,7 +100,7 @@ module.exports = React.createClass({
|
||||
$(".channel-header__info .description").popover({placement : 'bottom', trigger: 'hover', html: true, delay: {show: 500, hide: 500}});
|
||||
},
|
||||
_onSocketChange: function(msg) {
|
||||
if(msg.action === "new_user") {
|
||||
if (msg.action === "new_user") {
|
||||
AsyncClient.getChannelExtraInfo(true);
|
||||
}
|
||||
},
|
||||
@@ -107,15 +108,14 @@ module.exports = React.createClass({
|
||||
return getStateFromStores();
|
||||
},
|
||||
handleLeave: function(e) {
|
||||
var self = this;
|
||||
Client.leaveChannel(this.state.channel.id,
|
||||
function(data) {
|
||||
var townsquare = ChannelStore.getByName('town-square');
|
||||
utils.switchChannel(townsquare);
|
||||
}.bind(this),
|
||||
},
|
||||
function(err) {
|
||||
AsyncClient.dispatchError(err, "handleLeave");
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
},
|
||||
searchMentions: function(e) {
|
||||
@@ -131,52 +131,29 @@ module.exports = React.createClass({
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH_TERM,
|
||||
term: terms,
|
||||
do_search: false
|
||||
do_search: true,
|
||||
is_mention_search: true
|
||||
});
|
||||
|
||||
Client.search(
|
||||
terms,
|
||||
function(data) {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECIEVED_SEARCH,
|
||||
results: data,
|
||||
is_mention_search: true
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
dispatchError(err, "search");
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
if (this.state.channel == null) {
|
||||
return (
|
||||
<div></div>
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
var description = utils.textToJsx(this.state.channel.description, {"singleline": true, "noMentionHighlight": true});
|
||||
var popoverContent = React.renderToString(<MessageWrapper message={this.state.channel.description}/>);
|
||||
var channelTitle = "";
|
||||
var channelName = this.state.channel.name;
|
||||
var channel = this.state.channel;
|
||||
var description = utils.textToJsx(channel.description, {"singleline": true, "noMentionHighlight": true});
|
||||
var popoverContent = React.renderToString(<MessageWrapper message={channel.description}/>);
|
||||
var channelTitle = channel.display_name;
|
||||
var currentId = UserStore.getCurrentId();
|
||||
var isAdmin = this.state.memberChannel.roles.indexOf("admin") > -1 || this.state.memberTeam.roles.indexOf("admin") > -1;
|
||||
var searchForm = <th className="search-bar__container"><NavbarSearchBox /></th>;
|
||||
var isDirect = false;
|
||||
var isDirect = (this.state.channel.type === 'D');
|
||||
|
||||
if (this.state.channel.type === 'O') {
|
||||
channelTitle = this.state.channel.display_name;
|
||||
} else if (this.state.channel.type === 'P') {
|
||||
channelTitle = this.state.channel.display_name;
|
||||
} else if (this.state.channel.type === 'D') {
|
||||
isDirect = true;
|
||||
if (isDirect) {
|
||||
if (this.state.users.length > 1) {
|
||||
if (this.state.users[0].id === UserStore.getCurrentId()) {
|
||||
channelTitle = <UserProfile userId={this.state.users[1].id} overwriteName={this.state.users[1].full_name ? this.state.users[1].full_name : this.state.users[1].username} />;
|
||||
} else {
|
||||
channelTitle = <UserProfile userId={this.state.users[0].id} overwriteName={this.state.users[0].full_name ? this.state.users[0].full_name : this.state.users[0].username} />;
|
||||
}
|
||||
var contact = this.state.users[((this.state.users[0].id === currentId) ? 1 : 0)];
|
||||
channelTitle = <UserProfile userId={contact.id} overwriteName={contact.nickname || contact.username} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,25 +169,28 @@ module.exports = React.createClass({
|
||||
<span className="glyphicon glyphicon-chevron-down header-dropdown__icon"></span>
|
||||
</a>
|
||||
<ul className="dropdown-menu" role="menu" aria-labelledby="channel_header_dropdown">
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_info" data-channelid={this.state.channel.id} href="#">View Info</a></li>
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_invite" href="#">Add Members</a></li>
|
||||
{ isAdmin ?
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_info" data-channelid={channel.id} href="#">View Info</a></li>
|
||||
{ !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_invite" href="#">Add Members</a></li>
|
||||
: null
|
||||
}
|
||||
{ isAdmin && !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_members" href="#">Manage Members</a></li>
|
||||
: ""
|
||||
: null
|
||||
}
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#edit_channel" data-desc={this.state.channel.description} data-title={this.state.channel.display_name} data-channelid={this.state.channel.id}>Set Channel Description...</a></li>
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#channel_notifications" data-title={this.state.channel.display_name} data-channelid={this.state.channel.id}>Notification Preferences</a></li>
|
||||
{ isAdmin && channelName != Constants.DEFAULT_CHANNEL ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#rename_channel" data-display={this.state.channel.display_name} data-name={this.state.channel.name} data-channelid={this.state.channel.id}>Rename Channel...</a></li>
|
||||
: ""
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#edit_channel" data-desc={channel.description} data-title={channel.display_name} data-channelid={channel.id}>Set Channel Description...</a></li>
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#channel_notifications" data-title={channel.display_name} data-channelid={channel.id}>Notification Preferences</a></li>
|
||||
{ isAdmin && !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#rename_channel" data-display={channel.display_name} data-name={channel.name} data-channelid={channel.id}>Rename Channel...</a></li>
|
||||
: null
|
||||
}
|
||||
{ isAdmin && channelName != Constants.DEFAULT_CHANNEL ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#delete_channel" data-title={this.state.channel.display_name} data-channelid={this.state.channel.id}>Delete Channel...</a></li>
|
||||
: ""
|
||||
{ isAdmin && !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#delete_channel" data-title={channel.display_name} data-channelid={channel.id}>Delete Channel...</a></li>
|
||||
: null
|
||||
}
|
||||
{ channelName != Constants.DEFAULT_CHANNEL ?
|
||||
{ !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" href="#" onClick={this.handleLeave}>Leave Channel</a></li>
|
||||
: ""
|
||||
: null
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -220,14 +200,13 @@ module.exports = React.createClass({
|
||||
<a href="#"><strong className="heading">{channelTitle}</strong></a>
|
||||
}
|
||||
</th>
|
||||
<th><ExtraMembers members={this.state.users} channelId={this.state.channel.id} /></th>
|
||||
{ searchForm }
|
||||
<th><PopoverListMembers members={this.state.users} channelId={channel.id} /></th>
|
||||
<th className="search-bar__container"><NavbarSearchBox /></th>
|
||||
<th>
|
||||
<div className="dropdown" style={{"marginLeft":"5px", "marginRight":"10px"}}>
|
||||
<div className="dropdown channel-header__links">
|
||||
<a href="#" className="dropdown-toggle theme" type="button" id="channel_header_right_dropdown" data-toggle="dropdown" aria-expanded="true">
|
||||
<i className="fa fa-caret-down"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu" role="menu" aria-labelledby="channel_header_right_dropdown" style={{"left": "-150px"}}>
|
||||
<span dangerouslySetInnerHTML={{__html: " <svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'width='4px' height='16px' viewBox='0 0 8 32' enable-background='new 0 0 8 32' xml:space='preserve'> <g> <circle cx='4' cy='4.062' r='4'/> <circle cx='4' cy='16' r='4'/> <circle cx='4' cy='28' r='4'/> </g> </svg>"}} /> </a>
|
||||
<ul className="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="channel_header_right_dropdown">
|
||||
<li role="presentation"><a role="menuitem" href="#" onClick={this.searchMentions}>Recent Mentions</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -237,5 +216,3 @@ module.exports = React.createClass({
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ module.exports = React.createClass({
|
||||
|
||||
client.createPost(post, ChannelStore.getCurrent(),
|
||||
function(data) {
|
||||
this.setState({ messageText: '', submitting: false, post_error: null });
|
||||
this.setState({ messageText: '', submitting: false, post_error: null, server_error: null });
|
||||
this.clearPreviews();
|
||||
AsyncClient.getPosts(true, this.props.channelId);
|
||||
|
||||
@@ -57,6 +57,7 @@ module.exports = React.createClass({
|
||||
function(err) {
|
||||
var state = {};
|
||||
state.server_error = err.message;
|
||||
state.submitting = false;
|
||||
|
||||
if (err.message === "Invalid RootId parameter") {
|
||||
if ($('#post_deleted').length > 0) $('#post_deleted').modal('show');
|
||||
|
||||
@@ -234,7 +234,7 @@ module.exports = React.createClass({
|
||||
},
|
||||
render: function() {
|
||||
|
||||
var server_error = this.state.server_error ? <div className='form-group has-error'><label className='control-label'>{ this.state.server_error }</label></div> : null;
|
||||
var server_error = this.state.server_error ? <div className='has-error'><label className='control-label'>{ this.state.server_error }</label></div> : null;
|
||||
var post_error = this.state.post_error ? <label className='control-label'>{this.state.post_error}</label> : null;
|
||||
var limit_error = this.state.limit_error ? <div className='has-error'><label className='control-label'>{this.state.limit_error}</label></div> : null;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ module.exports = React.createClass({
|
||||
Client.deleteChannel(this.state.channel_id,
|
||||
function(data) {
|
||||
AsyncClient.getChannels(true);
|
||||
window.location.href = '/channels/town-square';
|
||||
window.location.href = '/';
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
AsyncClient.dispatchError(err, "handleDelete");
|
||||
|
||||
@@ -56,13 +56,13 @@ module.exports = React.createClass({
|
||||
$(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) {
|
||||
var newState = {};
|
||||
if(BrowserStore.getItem('edit_state_transfer')) {
|
||||
newState = JSON.parse(BrowserStore.getItem('edit_state_transfer'));
|
||||
newState = BrowserStore.getItem('edit_state_transfer');
|
||||
BrowserStore.removeItem('edit_state_transfer');
|
||||
} else {
|
||||
var button = e.relatedTarget;
|
||||
newState = { title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), post_id: $(button).attr('data-postid'), comments: $(button).attr('data-comments') };
|
||||
}
|
||||
self.setState(newState)
|
||||
self.setState(newState);
|
||||
});
|
||||
PostStore.addSelectedPostChangeListener(this._onChange);
|
||||
},
|
||||
|
||||
@@ -43,7 +43,7 @@ module.exports = React.createClass({
|
||||
<h4 className="modal-title" ref="title">Edit {this.state.title} Description</h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<textarea className="form-control" style={{resize: "none"}} rows="6" ref="channelDesc" maxLength="1024" value={this.state.description} onChange={this.handleUserInput}></textarea>
|
||||
<textarea className="form-control no-resize" rows="6" ref="channelDesc" maxLength="1024" value={this.state.description} onChange={this.handleUserInput}></textarea>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
var Client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var Textbox = require('./textbox.jsx');
|
||||
var BrowserStore = require('../stores/browser_store.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleEdit: function(e) {
|
||||
@@ -13,14 +14,14 @@ module.exports = React.createClass({
|
||||
if (updatedPost.message.length === 0) {
|
||||
var tempState = this.state;
|
||||
delete tempState.editText;
|
||||
BrowserStore.setItem('edit_state_transfer', JSON.stringify(tempState));
|
||||
BrowserStore.setItem('edit_state_transfer', tempState);
|
||||
$("#edit_post").modal('hide');
|
||||
$("#delete_post").modal('show');
|
||||
return;
|
||||
}
|
||||
|
||||
updatedPost.id = this.state.post_id
|
||||
updatedPost.channel_id = this.state.channel_id
|
||||
updatedPost.id = this.state.post_id;
|
||||
updatedPost.channel_id = this.state.channel_id;
|
||||
|
||||
Client.updatePost(updatedPost,
|
||||
function(data) {
|
||||
|
||||
@@ -38,7 +38,7 @@ module.exports = React.createClass({
|
||||
<div className="modal-body">
|
||||
<p>{"The link below is used for open " + strings.TeamPlural + " or if you allowed your " + strings.Team + " members to sign up using their " + strings.Company + " email addresses."}
|
||||
</p>
|
||||
<textarea className="form-control" style={{resize: "none"}} readOnly="true" value={this.state.value}></textarea>
|
||||
<textarea className="form-control no-resize" readOnly="true" value={this.state.value}></textarea>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
|
||||
|
||||
24
web/react/components/loading_screen.jsx
Обычный файл
24
web/react/components/loading_screen.jsx
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "LoadingScreen",
|
||||
propTypes: {
|
||||
position: React.PropTypes.oneOf(['absolute', 'fixed', 'relative', 'static', 'inherit'])
|
||||
},
|
||||
getDefaultProps: function() {
|
||||
return { position: 'relative' };
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<div className="loading-screen" style={{position: this.props.position}}>
|
||||
<div className="loading__content">
|
||||
<h3>Loading</h3>
|
||||
<div className="round round-1"></div>
|
||||
<div className="round round-2"></div>
|
||||
<div className="round round-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1,102 +1,21 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
|
||||
|
||||
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var TeamStore = require('../stores/team_store.jsx');
|
||||
var BrowserStore = require('../stores/browser_store.jsx');
|
||||
|
||||
|
||||
var FindTeamDomain = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
var state = { }
|
||||
|
||||
var domain = this.refs.domain.getDOMNode().value.trim();
|
||||
if (!domain) {
|
||||
state.server_error = "A domain is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BrowserStore.isLocalStorageSupported()) {
|
||||
state.server_error = "This service requires local storage to be enabled. Please enable it or exit private browsing.";
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.server_error = "";
|
||||
this.setState(state);
|
||||
|
||||
client.findTeamByDomain(domain,
|
||||
function(data) {
|
||||
console.log(data);
|
||||
if (data) {
|
||||
window.location.href = window.location.protocol + "//" + domain + "." + utils.getDomainWithOutSub();
|
||||
}
|
||||
else {
|
||||
this.state.server_error = "We couldn't find your " + strings.Team + ".";
|
||||
this.setState(this.state);
|
||||
}
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
this.state.server_error = err.message;
|
||||
this.setState(this.state);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
render: function() {
|
||||
var server_error = this.state.server_error ? <label className="control-label">{this.state.server_error}</label> : null;
|
||||
|
||||
return (
|
||||
<div className="signup-team__container">
|
||||
<div>
|
||||
<span className="signup-team__name">{ config.SiteName }</span>
|
||||
<br/>
|
||||
<span className="signup-team__subdomain">Enter your {strings.Team}'s domain.</span>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
{ server_error }
|
||||
<input type="text" className="form-control" name="domain" ref="domain" placeholder="team domain" />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<button type="submit" className="btn btn-primary">Continue</button>
|
||||
</div>
|
||||
<div>
|
||||
<span>Don't remember your {strings.Team}'s domain? <a href="/find_team">Find it here</a></span>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<div>
|
||||
<span>{"Want to create your own " + strings.Team + "?"} <a href={utils.getHomeLink()} className="signup-team-login">Sign up now</a></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
var state = { }
|
||||
|
||||
var domain = this.refs.domain.getDOMNode().value.trim();
|
||||
if (!domain) {
|
||||
state.server_error = "A domain is required"
|
||||
var name = this.props.teamName
|
||||
if (!name) {
|
||||
state.server_error = "Bad team name"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
@@ -124,23 +43,22 @@ module.exports = React.createClass({
|
||||
state.server_error = "";
|
||||
this.setState(state);
|
||||
|
||||
client.loginByEmail(domain, email, password,
|
||||
client.loginByEmail(name, email, password,
|
||||
function(data) {
|
||||
UserStore.setLastDomain(domain);
|
||||
UserStore.setLastEmail(email);
|
||||
UserStore.setCurrentUser(data);
|
||||
UserStore.setLastEmail(email);
|
||||
|
||||
var redirect = utils.getUrlParameter("redirect");
|
||||
if (redirect) {
|
||||
window.location.href = decodeURI(redirect);
|
||||
window.location.pathname = decodeURI(redirect);
|
||||
} else {
|
||||
window.location.href = '/channels/town-square';
|
||||
window.location.pathname = '/' + name + '/channels/town-square';
|
||||
}
|
||||
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
if (err.message == "Login failed because email address has not been verified") {
|
||||
window.location.href = '/verify?domain=' + encodeURIComponent(domain) + '&email=' + encodeURIComponent(email);
|
||||
window.location.href = '/verify_email?name=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
|
||||
return;
|
||||
}
|
||||
state.server_error = err.message;
|
||||
@@ -161,35 +79,35 @@ module.exports = React.createClass({
|
||||
priorEmail = decodeURIComponent(emailParam);
|
||||
}
|
||||
|
||||
var subDomainClass = "form-control hidden";
|
||||
var subDomain = utils.getSubDomain();
|
||||
var teamDisplayName = this.props.teamDisplayName;
|
||||
var teamName = this.props.teamName;
|
||||
|
||||
if (utils.isTestDomain()) {
|
||||
subDomainClass = "form-control";
|
||||
subDomain = UserStore.getLastDomain();
|
||||
} else if (subDomain == "") {
|
||||
return (<FindTeamDomain />);
|
||||
var focusEmail = false;
|
||||
var focusPassword = false;
|
||||
if (priorEmail != "") {
|
||||
focusPassword = true;
|
||||
} else {
|
||||
focusEmail = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="signup-team__container">
|
||||
<div>
|
||||
<span className="signup-team__name">{ subDomain }</span>
|
||||
<span className="signup-team__name">{ teamDisplayName }</span>
|
||||
<br/>
|
||||
<span className="signup-team__subdomain">{ utils.getDomainWithOutSub() }</span>
|
||||
<span className="signup-team__subdomain">/{ teamName }/</span>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
{ server_error }
|
||||
<input type="text" className={subDomainClass} name="domain" defaultValue={subDomain} ref="domain" placeholder="Domain" />
|
||||
</div>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="email" className="form-control" name="email" defaultValue={priorEmail} ref="email" placeholder="Email" />
|
||||
<input autoFocus={focusEmail} type="email" className="form-control" name="email" defaultValue={priorEmail} ref="email" placeholder="Email" />
|
||||
</div>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="password" className="form-control" name="password" ref="password" placeholder="Password" />
|
||||
<input autoFocus={focusPassword} type="password" className="form-control" name="password" ref="password" placeholder="Password" />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<button type="submit" className="btn btn-primary">Sign in</button>
|
||||
@@ -198,10 +116,10 @@ module.exports = React.createClass({
|
||||
<span><a href="/find_team">{"Find other " + strings.TeamPlural}</a></span>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<a href="/reset_password">I forgot my password</a>
|
||||
<a href={"/" + teamName + "/reset_password"}>I forgot my password</a>
|
||||
</div>
|
||||
<div className="external-link">
|
||||
<span>{"Want to create your own " + strings.Team + "?"} <a href={utils.getHomeLink()} className="signup-team-login">Sign up now</a></span>
|
||||
<span>{"Want to create your own " + strings.Team + "?"} <a href="/" className="signup-team-login">Sign up now</a></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -23,6 +23,7 @@ module.exports = React.createClass({
|
||||
var member = this.props.member;
|
||||
var isAdmin = this.props.isAdmin;
|
||||
var isMemberAdmin = member.roles.indexOf("admin") > -1;
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
var invite;
|
||||
if (member.invited && this.props.handleInvite) {
|
||||
@@ -48,12 +49,12 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
invite = <div className="member-role text-capitalize" style={{marginRight: 15}}>{member.roles || 'Member'}</div>;
|
||||
invite = <div className="member-role text-capitalize">{member.roles || 'Member'}<span className="caret hidden"></span></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row member-div">
|
||||
<img className="post-profile-img pull-left" src={"/api/v1/users/" + member.id + "/image"} height="36" width="36" />
|
||||
<img className="post-profile-img pull-left" src={"/api/v1/users/" + member.id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
<span className="member-name">{member.username}</span>
|
||||
<span className="member-email">{member.email}</span>
|
||||
{ invite }
|
||||
|
||||
@@ -5,6 +5,7 @@ var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var Client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
|
||||
var MemberListTeamItem = React.createClass({
|
||||
handleMakeMember: function() {
|
||||
@@ -59,9 +60,10 @@ var MemberListTeamItem = React.createClass({
|
||||
return {};
|
||||
},
|
||||
render: function() {
|
||||
var server_error = this.state.server_error ? <div style={{ clear: "both" }} className="has-error"><label className='has-error control-label'>{this.state.server_error}</label></div> : null;
|
||||
var server_error = this.state.server_error ? <div className="has-error"><label className='has-error control-label'>{this.state.server_error}</label></div> : null;
|
||||
var user = this.props.user;
|
||||
var currentRoles = "Member"
|
||||
var currentRoles = "Member";
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
if (user.roles.length > 0) {
|
||||
currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1);
|
||||
@@ -83,9 +85,9 @@ var MemberListTeamItem = React.createClass({
|
||||
|
||||
return (
|
||||
<div className="row member-div">
|
||||
<img className="post-profile-img pull-left" src={"/api/v1/users/" + user.id + "/image"} height="36" width="36" />
|
||||
<span className="member-name">{user.full_name.trim() ? user.full_name : user.username}</span>
|
||||
<span className="member-email">{user.full_name.trim() ? user.username : email}</span>
|
||||
<img className="post-profile-img pull-left" src={"/api/v1/users/" + user.id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
<span className="member-name">{utils.getDisplayName(user)}</span>
|
||||
<span className="member-email">{email}</span>
|
||||
<div className="dropdown member-drop">
|
||||
<a href="#" className="dropdown-toggle theme" type="button" id="channel_header_dropdown" data-toggle="dropdown" aria-expanded="true">
|
||||
<span>{currentRoles} </span>
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
var UserStore = require("../stores/user_store.jsx");
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleClick: function() {
|
||||
this.props.handleClick(this.props.username);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return null;
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
var icon;
|
||||
if (this.props.id != null) {
|
||||
icon = <span><img className="mention-img" src={"/api/v1/users/" + this.props.id + "/image"}/></span>;
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
if (this.props.id === "allmention" || this.props.id === "channelmention") {
|
||||
icon = <span><i className="mention-img fa fa-users fa-2x"></i></span>;
|
||||
} else if (this.props.id != null) {
|
||||
icon = <span><img className="mention-img" src={"/api/v1/users/" + this.props.id + "/image?time=" + timestamp}/></span>;
|
||||
} else {
|
||||
icon = <span><i className="mention-img fa fa-users fa-2x"></i></span>;
|
||||
}
|
||||
return (
|
||||
<div className="mentions-name" onClick={this.handleClick}>
|
||||
<div className={"mentions-name " + this.props.isFocused} id={this.props.id + "_mentions"} onClick={this.handleClick} onMouseEnter={this.props.handleMouseEnter}>
|
||||
<div className="pull-left">{icon}</div>
|
||||
<div className="pull-left mention-align"><span>@{this.props.username}</span><span className="mention-fullname">{this.props.secondary_text}</span></div>
|
||||
</div>
|
||||
|
||||
@@ -7,19 +7,48 @@ var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var Mention = require('./mention.jsx');
|
||||
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var Utils = require('../utils/utils.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
var MAX_HEIGHT_LIST = 292;
|
||||
var MAX_ITEMS_IN_LIST = 25;
|
||||
var ITEM_HEIGHT = 36;
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "MentionList",
|
||||
componentDidMount: function() {
|
||||
PostStore.addMentionDataChangeListener(this._onChange);
|
||||
|
||||
var self = this;
|
||||
$('body').on('keypress.mentionlist', '#'+this.props.id,
|
||||
|
||||
$('body').on('keydown.mentionlist', '#'+this.props.id,
|
||||
function(e) {
|
||||
if (!self.isEmpty() && self.state.mentionText != '-1' && e.which === 13) {
|
||||
if (!self.isEmpty() && self.state.mentionText != '-1' && (e.which === 13 || e.which === 9)) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
self.addFirstMention();
|
||||
self.addCurrentMention();
|
||||
}
|
||||
else if (!self.isEmpty() && self.state.mentionText != '-1' && (e.which === 38 || e.which === 40)) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
var tempSelectedMention = -1;
|
||||
if (e.which === 38) {
|
||||
if (self.getSelection(self.state.selectedMention - 1))
|
||||
self.setState({ selectedMention: self.state.selectedMention - 1, selectedUsername: self.refs['mention' + (self.state.selectedMention - 1)].props.username });
|
||||
else {
|
||||
while (self.getSelection(++tempSelectedMention))
|
||||
; //Need to find the top of the list
|
||||
self.setState({ selectedMention: tempSelectedMention - 1, selectedUsername: self.refs['mention' + (tempSelectedMention - 1)].props.username });
|
||||
}
|
||||
}
|
||||
else if (e.which === 40) {
|
||||
if (self.getSelection(self.state.selectedMention + 1))
|
||||
self.setState({ selectedMention: self.state.selectedMention + 1, selectedUsername: self.refs['mention' + (self.state.selectedMention + 1)].props.username });
|
||||
else
|
||||
self.setState({ selectedMention: 0, selectedUsername: self.refs.mention0.props.username });
|
||||
}
|
||||
|
||||
self.scrollToMention(e.which, tempSelectedMention);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -32,7 +61,28 @@ module.exports = React.createClass({
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
PostStore.removeMentionDataChangeListener(this._onChange);
|
||||
$('body').off('keypress.mentionlist', '#'+this.props.id);
|
||||
$('body').off('keydown.mentionlist', '#'+this.props.id);
|
||||
},
|
||||
componentDidUpdate: function() {
|
||||
if (this.state.mentionText != "-1") {
|
||||
if (this.state.selectedUsername !== "" && (!this.getSelection(this.state.selectedMention) || this.state.selectedUsername !== this.refs['mention' + this.state.selectedMention].props.username)) {
|
||||
var tempSelectedMention = -1;
|
||||
var foundMatch = false;
|
||||
while (tempSelectedMention < this.state.selectedMention && this.getSelection(++tempSelectedMention)) {
|
||||
if (this.state.selectedUsername === this.refs['mention' + tempSelectedMention].props.username) {
|
||||
this.setState({ selectedMention: tempSelectedMention });
|
||||
foundMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.getSelection(0) && !foundMatch) {
|
||||
this.setState({ selectedMention: 0, selectedUsername: this.refs.mention0.props.username });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.state.selectedMention !== 0) {
|
||||
this.setState({ selectedMention: 0, selectedUsername: "" });
|
||||
}
|
||||
},
|
||||
_onChange: function(id, mentionText, excludeList) {
|
||||
if (id !== this.props.id) return;
|
||||
@@ -40,6 +90,7 @@ module.exports = React.createClass({
|
||||
var newState = this.state;
|
||||
if (mentionText != null) newState.mentionText = mentionText;
|
||||
if (excludeList != null) newState.excludeUsers = excludeList;
|
||||
|
||||
this.setState(newState);
|
||||
},
|
||||
handleClick: function(name) {
|
||||
@@ -51,6 +102,21 @@ module.exports = React.createClass({
|
||||
|
||||
this.setState({ mentionText: '-1' });
|
||||
},
|
||||
handleMouseEnter: function(listId) {
|
||||
this.setState({ selectedMention: listId, selectedUsername: this.refs['mention' + listId].props.username });
|
||||
},
|
||||
getSelection: function(listId) {
|
||||
if (!this.refs['mention' + listId])
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
addCurrentMention: function() {
|
||||
if (!this.getSelection(this.state.selectedMention))
|
||||
this.addFirstMention();
|
||||
else
|
||||
this.refs['mention' + this.state.selectedMention].handleClick();
|
||||
},
|
||||
addFirstMention: function() {
|
||||
if (!this.refs.mention0) return;
|
||||
this.refs.mention0.handleClick();
|
||||
@@ -58,6 +124,23 @@ module.exports = React.createClass({
|
||||
isEmpty: function() {
|
||||
return (!this.refs.mention0);
|
||||
},
|
||||
scrollToMention: function(keyPressed, ifLoopUp) {
|
||||
var direction = keyPressed === 38 ? "up" : "down";
|
||||
var scrollAmount = 0;
|
||||
|
||||
if (direction === "up" && ifLoopUp !== -1)
|
||||
scrollAmount = $("#mentionsbox").height() * 100; //Makes sure that it scrolls all the way to the bottom
|
||||
else if (direction === "down" && this.state.selectedMention === 0)
|
||||
scrollAmount = 0;
|
||||
else if (direction === "up")
|
||||
scrollAmount = "-=" + ($('#'+this.refs['mention' + this.state.selectedMention].props.id +"_mentions").innerHeight() - 5);
|
||||
else if (direction === "down")
|
||||
scrollAmount = "+=" + ($('#'+this.refs['mention' + this.state.selectedMention].props.id +"_mentions").innerHeight() - 5);
|
||||
|
||||
$("#mentionsbox").animate({
|
||||
scrollTop: scrollAmount
|
||||
}, 75);
|
||||
},
|
||||
alreadyMentioned: function(username) {
|
||||
var excludeUsers = this.state.excludeUsers;
|
||||
for (var i = 0; i < excludeUsers.length; i++) {
|
||||
@@ -68,11 +151,12 @@ module.exports = React.createClass({
|
||||
return false;
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { excludeUsers: [], mentionText: "-1" };
|
||||
return { excludeUsers: [], mentionText: "-1", selectedMention: 0, selectedUsername: "" };
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
var mentionText = this.state.mentionText;
|
||||
if (mentionText === '-1') return (<div/>);
|
||||
if (mentionText === '-1') return null;
|
||||
|
||||
var profiles = UserStore.getActiveOnlyProfiles();
|
||||
var users = [];
|
||||
@@ -82,14 +166,16 @@ module.exports = React.createClass({
|
||||
|
||||
var all = {};
|
||||
all.username = "all";
|
||||
all.full_name = "";
|
||||
all.nickname = "";
|
||||
all.secondary_text = "Notifies everyone in the team";
|
||||
all.id = "allmention";
|
||||
users.push(all);
|
||||
|
||||
var channel = {};
|
||||
channel.username = "channel";
|
||||
channel.full_name = "";
|
||||
channel.nickname = "";
|
||||
channel.secondary_text = "Notifies everyone in the channel";
|
||||
channel.id = "channelmention";
|
||||
users.push(channel);
|
||||
|
||||
users.sort(function(a,b) {
|
||||
@@ -100,44 +186,42 @@ module.exports = React.createClass({
|
||||
var mentions = {};
|
||||
var index = 0;
|
||||
|
||||
for (var i = 0; i < users.length; i++) {
|
||||
if (Object.keys(mentions).length >= 25) break;
|
||||
for (var i = 0; i < users.length && index < MAX_ITEMS_IN_LIST; i++) {
|
||||
if (this.alreadyMentioned(users[i].username)) continue;
|
||||
|
||||
var firstName = "", lastName = "";
|
||||
if (users[i].full_name.length > 0) {
|
||||
var splitName = users[i].full_name.split(' ');
|
||||
firstName = splitName[0].toLowerCase();
|
||||
lastName = splitName.length > 1 ? splitName[splitName.length-1].toLowerCase() : "";
|
||||
users[i].secondary_text = users[i].full_name;
|
||||
}
|
||||
|
||||
if (firstName.lastIndexOf(mentionText,0) === 0
|
||||
|| lastName.lastIndexOf(mentionText,0) === 0 || users[i].username.lastIndexOf(mentionText,0) === 0) {
|
||||
mentions[i+1] = (
|
||||
if ((users[i].first_name && users[i].first_name.lastIndexOf(mentionText,0) === 0)
|
||||
|| (users[i].last_name && users[i].last_name.lastIndexOf(mentionText,0) === 0) || users[i].username.lastIndexOf(mentionText,0) === 0) {
|
||||
mentions[index] = (
|
||||
<Mention
|
||||
ref={'mention' + index}
|
||||
username={users[i].username}
|
||||
secondary_text={users[i].secondary_text}
|
||||
secondary_text={Utils.getFullName(users[i])}
|
||||
id={users[i].id}
|
||||
listId={index}
|
||||
isFocused={this.state.selectedMention === index ? "mentions-focus" : ""}
|
||||
handleMouseEnter={function(value) { return function() { self.handleMouseEnter(value); } }(index)}
|
||||
handleClick={this.handleClick} />
|
||||
);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
var numMentions = Object.keys(mentions).length;
|
||||
|
||||
if (numMentions < 1) return (<div/>);
|
||||
if (numMentions < 1) return null;
|
||||
|
||||
var height = (numMentions*36) + 4;
|
||||
var width = $('#'+this.props.id).parent().width();
|
||||
var bottom = $(window).height() - $('#'+this.props.id).offset().top;
|
||||
var left = $('#'+this.props.id).offset().left;
|
||||
var max_height = $('#'+this.props.id).offset().top - 10;
|
||||
var $mention_tab = $('#'+this.props.id);
|
||||
var maxHeight = Math.min(MAX_HEIGHT_LIST, $mention_tab.offset().top - 10);
|
||||
var style = {
|
||||
height: Math.min(maxHeight, (numMentions*ITEM_HEIGHT) + 4),
|
||||
width: $mention_tab.parent().width(),
|
||||
bottom: $(window).height() - $mention_tab.offset().top,
|
||||
left: $mention_tab.offset().left
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mentions--top" style={{height: height, width: width, bottom: bottom, left: left}}>
|
||||
<div ref="mentionlist" className="mentions-box" style={{height: height, width: width}}>
|
||||
<div className="mentions--top" style={style}>
|
||||
<div ref="mentionlist" className="mentions-box" id="mentionsbox">
|
||||
{ mentions }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@ var client = require('../utils/client.jsx');
|
||||
var asyncClient = require('../utils/async_client.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var LoadingScreen = require('./loading_screen.jsx');
|
||||
|
||||
function getStateFromStores() {
|
||||
return {
|
||||
@@ -16,6 +17,8 @@ function getStateFromStores() {
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "MoreChannelsModal",
|
||||
|
||||
componentDidMount: function() {
|
||||
ChannelStore.addMoreChangeListener(this._onChange);
|
||||
$(this.refs.modal.getDOMNode()).on('shown.bs.modal', function (e) {
|
||||
@@ -90,7 +93,7 @@ module.exports = React.createClass({
|
||||
<p className="more-channel-name">{channel.display_name}</p>
|
||||
<p className="more-channel-description">{channel.description}</p>
|
||||
</td>
|
||||
<td className="td--action"><button onClick={outter.handleJoin.bind(outter, channel.id)} className="pull-right btn btn-primary">Join</button></td>
|
||||
<td className="td--action"><button onClick={outter.handleJoin.bind(outter, channel.id)} className="btn btn-primary">Join</button></td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
@@ -100,15 +103,7 @@ module.exports = React.createClass({
|
||||
<p className="primary-message">No more channels to join</p>
|
||||
<p className="secondary-message">Click 'Create New Channel' to make a new one</p>
|
||||
</div>)
|
||||
: <div ref="loadingscreen" className="loading-screen loading-screen--channel">
|
||||
<div className="loading__content">
|
||||
<h3>Loading</h3>
|
||||
<div id="round_1" className="round"></div>
|
||||
<div id="round_2" className="round"></div>
|
||||
<div id="round_3" className="round"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
: <LoadingScreen /> }
|
||||
{ server_error }
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
|
||||
@@ -51,7 +51,7 @@ module.exports = React.createClass({
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<span className="msg-typing">{ this.state.text }</span>
|
||||
<span className="msg-typing">{ this.state.text }</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var Sidebar = require('./sidebar.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var SocketStore = require('../stores/socket_store.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var TeamStore = require('../stores/team_store.jsx');
|
||||
|
||||
var UserProfile = require('./user_profile.jsx');
|
||||
var MessageWrapper = require('./message_wrapper.jsx');
|
||||
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
|
||||
function getCountsStateFromStores() {
|
||||
|
||||
var count = 0;
|
||||
var channels = ChannelStore.getAll();
|
||||
var members = ChannelStore.getAllMembers();
|
||||
@@ -34,7 +34,7 @@ function getCountsStateFromStores() {
|
||||
}
|
||||
});
|
||||
|
||||
return { count: count }
|
||||
return { count: count };
|
||||
}
|
||||
|
||||
var NotifyCounts = React.createClass({
|
||||
@@ -54,99 +54,11 @@ var NotifyCounts = React.createClass({
|
||||
return getCountsStateFromStores();
|
||||
},
|
||||
render: function() {
|
||||
if (this.state.count == 0) {
|
||||
return (<span></span>);
|
||||
if (this.state.count) {
|
||||
return <span className="badge badge-notify">{ this.state.count }</span>;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return (<span className="badge badge-notify">{ this.state.count }</span>);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var NavbarLoginForm = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
var state = { }
|
||||
|
||||
var domain = this.refs.domain.getDOMNode().value.trim();
|
||||
if (!domain) {
|
||||
state.server_error = "A domain is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
var email = this.refs.email.getDOMNode().value.trim();
|
||||
if (!email) {
|
||||
state.server_error = "An email is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
var password = this.refs.password.getDOMNode().value.trim();
|
||||
if (!password) {
|
||||
state.server_error = "A password is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.server_error = "";
|
||||
this.setState(state);
|
||||
|
||||
client.loginByEmail(domain, email, password,
|
||||
function(data) {
|
||||
UserStore.setLastDomain(domain);
|
||||
UserStore.setLastEmail(email);
|
||||
UserStore.setCurrentUser(data);
|
||||
|
||||
var redirect = utils.getUrlParameter("redirect");
|
||||
if (redirect) {
|
||||
window.location.href = decodeURI(redirect);
|
||||
} else {
|
||||
window.location.href = '/channels/town-square';
|
||||
}
|
||||
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
if (err.message == "Login failed because email address has not been verified") {
|
||||
window.location.href = '/verify?domain=' + encodeURIComponent(domain) + '&email=' + encodeURIComponent(email);
|
||||
return;
|
||||
}
|
||||
state.server_error = err.message;
|
||||
this.valid = false;
|
||||
this.setState(state);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
render: function() {
|
||||
var server_error = this.state.server_error ? <label className="control-label">{this.state.server_error}</label> : null;
|
||||
|
||||
var subDomain = utils.getSubDomain();
|
||||
var subDomainClass = "form-control hidden";
|
||||
|
||||
if (subDomain == "") {
|
||||
subDomain = UserStore.getLastDomain();
|
||||
subDomainClass = "form-control";
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="navbar-form navbar-right" onSubmit={this.handleSubmit}>
|
||||
<a href="/find_team">Find your team</a>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
{ server_error }
|
||||
<input type="text" className={subDomainClass} name="domain" defaultValue={subDomain} ref="domain" placeholder="Domain" />
|
||||
</div>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="text" className="form-control" name="email" defaultValue={UserStore.getLastEmail()} ref="email" placeholder="Email" />
|
||||
</div>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="password" className="form-control" name="password" ref="password" placeholder="Password" />
|
||||
</div>
|
||||
<button type="submit" className="btn btn-default">Login</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -159,13 +71,14 @@ function getStateFromStores() {
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Navbar',
|
||||
|
||||
componentDidMount: function() {
|
||||
ChannelStore.addChangeListener(this._onChange);
|
||||
ChannelStore.addExtraInfoChangeListener(this._onChange);
|
||||
var self = this;
|
||||
$('.inner__wrap').click(self.hideSidebars);
|
||||
$('.inner__wrap').click(this.hideSidebars);
|
||||
|
||||
$('body').on('click.infopopover', function(e){
|
||||
$('body').on('click.infopopover', function(e) {
|
||||
if ($(e.target).attr('data-toggle') !== 'popover'
|
||||
&& $(e.target).parents('.popover.in').length === 0) {
|
||||
$('.info-popover').popover('hide');
|
||||
@@ -181,13 +94,13 @@ module.exports = React.createClass({
|
||||
},
|
||||
handleLeave: function(e) {
|
||||
client.leaveChannel(this.state.channel.id,
|
||||
function(data) {
|
||||
function(data, text, req) {
|
||||
AsyncClient.getChannels(true);
|
||||
window.location.href = '/channels/town-square';
|
||||
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/town-square';
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
AsyncClient.dispatchError(err, "handleLeave");
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
},
|
||||
hideSidebars: function(e) {
|
||||
@@ -204,7 +117,7 @@ module.exports = React.createClass({
|
||||
});
|
||||
|
||||
if (e.target.className != 'navbar-toggle' && e.target.className != 'icon-bar') {
|
||||
$('.inner__wrap').removeClass('move--right').removeClass('move--left').removeClass('move--left-small');
|
||||
$('.inner__wrap').removeClass('move--right move--left move--left-small');
|
||||
$('.sidebar--left').removeClass('move--right');
|
||||
$('.sidebar--right').removeClass('move--left');
|
||||
$('.sidebar--menu').removeClass('move--left');
|
||||
@@ -229,24 +142,22 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
|
||||
var currentId = UserStore.getCurrentId();
|
||||
var channelName = "";
|
||||
var popoverContent = "";
|
||||
var channelTitle = this.props.teamName;
|
||||
var channelTitle = this.props.teamDisplayName;
|
||||
var isAdmin = false;
|
||||
var isDirect = false;
|
||||
var description = ""
|
||||
var channel = this.state.channel;
|
||||
|
||||
if (this.state.channel) {
|
||||
var channel = this.state.channel;
|
||||
description = utils.textToJsx(this.state.channel.description, {"singleline": true, "noMentionHighlight": true});
|
||||
popoverContent = React.renderToString(<MessageWrapper message={this.state.channel.description}/>);
|
||||
channelName = this.state.channel.name;
|
||||
if (channel) {
|
||||
description = utils.textToJsx(channel.description, {"singleline": true, "noMentionHighlight": true});
|
||||
popoverContent = React.renderToString(<MessageWrapper message={channel.description}/>);
|
||||
isAdmin = this.state.member.roles.indexOf("admin") > -1;
|
||||
|
||||
if (channel.type === 'O') {
|
||||
channelTitle = this.state.channel.display_name;
|
||||
channelTitle = channel.display_name;
|
||||
} else if (channel.type === 'P') {
|
||||
channelTitle = this.state.channel.display_name;
|
||||
channelTitle = channel.display_name;
|
||||
} else if (channel.type === 'D') {
|
||||
isDirect = true;
|
||||
if (this.state.users.length > 1) {
|
||||
@@ -258,12 +169,11 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
|
||||
if(this.state.channel.description.length == 0){
|
||||
popoverContent = React.renderToString(<div>No channel description yet. <br /><a href='#' data-toggle='modal' data-desc={this.state.channel.description} data-title={this.state.channel.display_name} data-channelid={this.state.channel.id} data-target='#edit_channel'>Click here</a> to add one.</div>);
|
||||
if (channel.description.length == 0) {
|
||||
popoverContent = React.renderToString(<div>No channel description yet. <br /><a href='#' data-toggle='modal' data-desc={channel.description} data-title={channel.display_name} data-channelid={channel.id} data-target='#edit_channel'>Click here</a> to add one.</div>);
|
||||
}
|
||||
}
|
||||
|
||||
var loginForm = currentId == null ? <NavbarLoginForm /> : null;
|
||||
var navbar_collapse_button = currentId != null ? null :
|
||||
<button type="button" className="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">
|
||||
<span className="sr-only">Toggle sidebar</span>
|
||||
@@ -292,60 +202,55 @@ module.exports = React.createClass({
|
||||
{ navbar_collapse_button }
|
||||
{ sidebar_collapse_button }
|
||||
{ right_sidebar_collapse_button }
|
||||
{ !isDirect && this.state.channel ?
|
||||
<div className="navbar-brand">
|
||||
<div className="dropdown">
|
||||
<div data-toggle="popover" data-content={popoverContent} className="description info-popover"></div>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" id="channel_header_dropdown" data-toggle="dropdown" aria-expanded="true">
|
||||
<strong className="heading">{channelTitle} </strong>
|
||||
<span className="glyphicon glyphicon-chevron-down header-dropdown__icon"></span>
|
||||
</a>
|
||||
<ul className="dropdown-menu" role="menu" aria-labelledby="channel_header_dropdown">
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_invite" href="#">Add Members</a></li>
|
||||
{ isAdmin ?
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_members" href="#">Manage Members</a></li>
|
||||
: ""
|
||||
}
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#edit_channel" data-desc={this.state.channel.description} data-title={this.state.channel.display_name} data-channelid={this.state.channel.id}>Set Channel Description...</a></li>
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#channel_notifications" data-title={this.state.channel.display_name} data-channelid={this.state.channel.id}>Notification Preferences</a></li>
|
||||
{ isAdmin && channelName != Constants.DEFAULT_CHANNEL ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#rename_channel" data-display={this.state.channel.display_name} data-name={this.state.channel.name} data-channelid={this.state.channel.id}>Rename Channel...</a></li>
|
||||
: ""
|
||||
}
|
||||
{ isAdmin && channelName != Constants.DEFAULT_CHANNEL ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#delete_channel" data-title={this.state.channel.display_name} data-channelid={this.state.channel.id}>Delete Channel...</a></li>
|
||||
: ""
|
||||
}
|
||||
{ channelName != Constants.DEFAULT_CHANNEL ?
|
||||
<li role="presentation"><a role="menuitem" href="#" onClick={this.handleLeave}>Leave Channel</a></li>
|
||||
: ""
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
: "" }
|
||||
{ isDirect && this.state.channel ?
|
||||
{ !isDirect && channel ?
|
||||
<div className="navbar-brand">
|
||||
<strong>
|
||||
<a href="#"><strong className="heading">{channelTitle}</strong></a>
|
||||
</strong>
|
||||
<div className="dropdown">
|
||||
<div data-toggle="popover" data-content={popoverContent} className="description info-popover"></div>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" id="channel_header_dropdown" data-toggle="dropdown" aria-expanded="true">
|
||||
<span className="heading">{channelTitle} </span>
|
||||
<span className="glyphicon glyphicon-chevron-down header-dropdown__icon"></span>
|
||||
</a>
|
||||
<ul className="dropdown-menu" role="menu" aria-labelledby="channel_header_dropdown">
|
||||
{ !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_invite" href="#">Add Members</a></li>
|
||||
: null
|
||||
}
|
||||
{ isAdmin && !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" data-toggle="modal" data-target="#channel_members" href="#">Manage Members</a></li>
|
||||
: null
|
||||
}
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#edit_channel" data-desc={channel.description} data-title={channel.display_name} data-channelid={channel.id}>Set Channel Description...</a></li>
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#channel_notifications" data-title={channel.display_name} data-channelid={channel.id}>Notification Preferences</a></li>
|
||||
{ isAdmin && !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#rename_channel" data-display={channel.display_name} data-name={channel.name} data-channelid={channel.id}>Rename Channel...</a></li>
|
||||
: null
|
||||
}
|
||||
{ isAdmin && !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" href="#" data-toggle="modal" data-target="#delete_channel" data-title={channel.display_name} data-channelid={channel.id}>Delete Channel...</a></li>
|
||||
: null
|
||||
}
|
||||
{ !ChannelStore.isDefault(channel) ?
|
||||
<li role="presentation"><a role="menuitem" href="#" onClick={this.handleLeave}>Leave Channel</a></li>
|
||||
: null
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
: "" }
|
||||
{ !this.state.channel ?
|
||||
: null
|
||||
}
|
||||
{ isDirect && channel ?
|
||||
<div className="navbar-brand">
|
||||
<strong>
|
||||
<a href="/"><strong className="heading">{ channelTitle }</strong></a>
|
||||
</strong>
|
||||
<a href="#" className="heading">{ channelTitle }</a>
|
||||
</div>
|
||||
: null }
|
||||
{ !channel ?
|
||||
<div className="navbar-brand">
|
||||
<a href="/" className="heading">{ channelTitle }</a>
|
||||
</div>
|
||||
: "" }
|
||||
</div>
|
||||
<div className="collapse navbar-collapse" id="navbar-collapse-1">
|
||||
{ loginForm }
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ var utils = require('../utils/utils.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var asyncClient = require('../utils/async_client.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var TeamStore = require('../stores/team_store.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
@@ -60,13 +62,13 @@ module.exports = React.createClass({
|
||||
|
||||
var self = this;
|
||||
client.createChannel(channel,
|
||||
function(data) {
|
||||
function() {
|
||||
this.refs.display_name.getDOMNode().value = "";
|
||||
this.refs.channel_name.getDOMNode().value = "";
|
||||
this.refs.channel_desc.getDOMNode().value = "";
|
||||
|
||||
$(self.refs.modal.getDOMNode()).modal('hide');
|
||||
window.location.href = "/channels/" + channel.name;
|
||||
window.location = TeamStore.getCurrentTeamUrl() + "/channels/" + channel.name;
|
||||
asyncClient.getChannels(true);
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
@@ -122,7 +124,7 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label className='control-label'>Description</label>
|
||||
<textarea className="form-control" style={{resize: "none"}} ref="channel_desc" rows="3" placeholder="Description" maxLength="1024"></textarea>
|
||||
<textarea className="form-control no-resize" ref="channel_desc" rows="3" placeholder="Description" maxLength="1024"></textarea>
|
||||
</div>
|
||||
{ server_error }
|
||||
</form>
|
||||
|
||||
@@ -10,13 +10,6 @@ SendResetPasswordLink = React.createClass({
|
||||
e.preventDefault();
|
||||
var state = {};
|
||||
|
||||
var domain = this.refs.domain.getDOMNode().value.trim();
|
||||
if (!domain) {
|
||||
state.error = "A domain is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
var email = this.refs.email.getDOMNode().value.trim();
|
||||
if (!email) {
|
||||
state.error = "Please enter a valid email address."
|
||||
@@ -29,17 +22,17 @@ SendResetPasswordLink = React.createClass({
|
||||
|
||||
data = {};
|
||||
data['email'] = email;
|
||||
data['domain'] = domain;
|
||||
data['name'] = this.props.teamName;
|
||||
|
||||
client.sendPasswordReset(data,
|
||||
function(data) {
|
||||
this.setState({ error: null, update_text: <p>A password reset link has been sent to <b>{email}</b> for your <b>{this.props.teamName}</b> team on {config.SiteName}.com.</p>, more_update_text: "Please check your inbox." });
|
||||
$(this.refs.reset_form.getDOMNode()).hide();
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
this.setState({ error: err.message, update_text: null, more_update_text: null });
|
||||
}.bind(this)
|
||||
);
|
||||
function(data) {
|
||||
this.setState({ error: null, update_text: <p>A password reset link has been sent to <b>{email}</b> for your <b>{this.props.teamDisplayName}</b> team on {window.location.hostname}.</p>, more_update_text: "Please check your inbox." });
|
||||
$(this.refs.reset_form.getDOMNode()).hide();
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
this.setState({ error: err.message, update_text: null, more_update_text: null });
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {};
|
||||
@@ -48,24 +41,13 @@ SendResetPasswordLink = React.createClass({
|
||||
var update_text = this.state.update_text ? <div className="reset-form alert alert-success">{this.state.update_text}{this.state.more_update_text}</div> : null;
|
||||
var error = this.state.error ? <div className="form-group has-error"><label className="control-label">{this.state.error}</label></div> : null;
|
||||
|
||||
var subDomain = utils.getSubDomain();
|
||||
var subDomainClass = "form-control hidden";
|
||||
|
||||
if (subDomain == "") {
|
||||
subDomain = UserStore.getLastDomain();
|
||||
subDomainClass = "form-control";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="col-sm-12">
|
||||
<div className="signup-team__container">
|
||||
<h3>Password Reset</h3>
|
||||
{ update_text }
|
||||
<form onSubmit={this.handleSendLink} ref="reset_form">
|
||||
<p>{"To reset your password, enter the email address you used to sign up for " + this.props.teamName + "."}</p>
|
||||
<div className="form-group">
|
||||
<input type="text" className={subDomainClass} name="domain" defaultValue={subDomain} ref="domain" placeholder="Domain" />
|
||||
</div>
|
||||
<p>{"To reset your password, enter the email address you used to sign up for " + this.props.teamDisplayName + "."}</p>
|
||||
<div className={error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="text" className="form-control" name="email" ref="email" placeholder="Email" />
|
||||
</div>
|
||||
@@ -83,13 +65,6 @@ ResetPassword = React.createClass({
|
||||
e.preventDefault();
|
||||
var state = {};
|
||||
|
||||
var domain = this.refs.domain.getDOMNode().value.trim();
|
||||
if (!domain) {
|
||||
state.error = "A domain is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
var password = this.refs.password.getDOMNode().value.trim();
|
||||
if (!password || password.length < 5) {
|
||||
state.error = "Please enter at least 5 characters."
|
||||
@@ -104,41 +79,30 @@ ResetPassword = React.createClass({
|
||||
data['new_password'] = password;
|
||||
data['hash'] = this.props.hash;
|
||||
data['data'] = this.props.data;
|
||||
data['domain'] = domain;
|
||||
data['name'] = this.props.teamName;
|
||||
|
||||
client.resetPassword(data,
|
||||
function(data) {
|
||||
this.setState({ error: null, update_text: "Your password has been updated successfully." });
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
this.setState({ error: err.message, update_text: null });
|
||||
}.bind(this)
|
||||
);
|
||||
function(data) {
|
||||
this.setState({ error: null, update_text: "Your password has been updated successfully." });
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
this.setState({ error: err.message, update_text: null });
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {};
|
||||
},
|
||||
render: function() {
|
||||
var update_text = this.state.update_text ? <div className="form-group"><br/><label className="control-label reset-form">{this.state.update_text} Click <a href="/login">here</a> to log in.</label></div> : null;
|
||||
var update_text = this.state.update_text ? <div className="form-group"><br/><label className="control-label reset-form">{this.state.update_text} Click <a href={"/" + this.props.teamName + "/login"}>here</a> to log in.</label></div> : null;
|
||||
var error = this.state.error ? <div className="form-group has-error"><label className="control-label">{this.state.error}</label></div> : null;
|
||||
|
||||
var subDomain = this.props.domain != "" ? this.props.domain : utils.getSubDomain();
|
||||
var subDomainClass = "form-control hidden";
|
||||
|
||||
if (subDomain == "") {
|
||||
subDomain = UserStore.getLastDomain();
|
||||
subDomainClass = "form-control";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="col-sm-12">
|
||||
<div className="signup-team__container">
|
||||
<h3>Password Reset</h3>
|
||||
<form onSubmit={this.handlePasswordReset}>
|
||||
<p>{"Enter a new password for your " + this.props.teamName + " " + config.SiteName + " account."}</p>
|
||||
<div className="form-group">
|
||||
<input type="text" className={subDomainClass} name="domain" defaultValue={subDomain} ref="domain" placeholder="Domain" />
|
||||
</div>
|
||||
<p>{"Enter a new password for your " + this.props.teamDisplayName + " " + config.SiteName + " account."}</p>
|
||||
<div className={error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="password" className="form-control" name="password" ref="password" placeholder="Password" />
|
||||
</div>
|
||||
@@ -161,14 +125,15 @@ module.exports = React.createClass({
|
||||
if (this.props.isReset === "false") {
|
||||
return (
|
||||
<SendResetPasswordLink
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
teamName={this.props.teamName}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ResetPassword
|
||||
teamDisplayName={this.props.teamDisplayName}
|
||||
teamName={this.props.teamName}
|
||||
domain={this.props.domain}
|
||||
hash={this.props.hash}
|
||||
data={this.props.data}
|
||||
/>
|
||||
|
||||
@@ -10,6 +10,7 @@ var UserStore = require('../stores/user_store.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "Post",
|
||||
componentDidMount: function() {
|
||||
$('.modal').on('show.bs.modal', function () {
|
||||
$('.modal-body').css('overflow-y', 'auto');
|
||||
@@ -19,7 +20,7 @@ module.exports = React.createClass({
|
||||
handleCommentClick: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
data = {};
|
||||
var data = {};
|
||||
data.order = [this.props.post.id];
|
||||
data.posts = this.props.posts;
|
||||
|
||||
@@ -33,6 +34,10 @@ module.exports = React.createClass({
|
||||
results: null
|
||||
});
|
||||
},
|
||||
forceUpdateInfo: function() {
|
||||
this.refs.info.forceUpdate();
|
||||
this.refs.header.forceUpdate();
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
@@ -48,7 +53,6 @@ module.exports = React.createClass({
|
||||
|
||||
var commentCount = 0;
|
||||
var commentRootId = parentPost ? post.root_id : post.id;
|
||||
var rootUser = "";
|
||||
for (var postId in posts) {
|
||||
if (posts[postId].root_id == commentRootId) {
|
||||
commentCount += 1;
|
||||
@@ -57,12 +61,7 @@ module.exports = React.createClass({
|
||||
|
||||
var error = this.state.error ? <div className='form-group has-error'><label className='control-label'>{ this.state.error }</label></div> : null;
|
||||
|
||||
if (this.props.sameRoot){
|
||||
rootUser = "same--root";
|
||||
}
|
||||
else {
|
||||
rootUser = "other--root";
|
||||
}
|
||||
var rootUser = this.props.sameRoot ? "same--root" : "other--root";
|
||||
|
||||
var postType = "";
|
||||
if (type != "Post"){
|
||||
@@ -74,18 +73,20 @@ module.exports = React.createClass({
|
||||
currentUserCss = "current--user";
|
||||
}
|
||||
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id={post.id} className={"post " + this.props.sameUser + " " + rootUser + " " + postType + " " + currentUserCss}>
|
||||
{ !this.props.hideProfilePic ?
|
||||
<div className="post-profile-img__container">
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + post.user_id + "/image"} height="36" width="36" />
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + post.user_id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
</div>
|
||||
: "" }
|
||||
: null }
|
||||
<div className="post__content">
|
||||
<PostHeader post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} handleCommentClick={this.handleCommentClick} isLastComment={this.props.isLastComment} />
|
||||
<PostHeader ref="header" post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} handleCommentClick={this.handleCommentClick} isLastComment={this.props.isLastComment} />
|
||||
<PostBody post={post} sameRoot={this.props.sameRoot} parentPost={parentPost} posts={posts} handleCommentClick={this.handleCommentClick} />
|
||||
<PostInfo post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} handleCommentClick={this.handleCommentClick} allowReply="true" />
|
||||
<PostInfo ref="info" post={post} sameRoot={this.props.sameRoot} commentCount={commentCount} handleCommentClick={this.handleCommentClick} allowReply="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -71,11 +71,22 @@ module.exports = React.createClass({
|
||||
name = <a className="theme" onClick={function(){ utils.searchForTerm(profile.username); }}>{profile.username}</a>;
|
||||
}
|
||||
|
||||
var message = parentPost.message;
|
||||
var message = ""
|
||||
if(parentPost.message) {
|
||||
message = utils.replaceHtmlEntities(parentPost.message)
|
||||
} else if (parentPost.filenames.length) {
|
||||
message = parentPost.filenames[0].split('/').pop();
|
||||
|
||||
if (parentPost.filenames.length === 2) {
|
||||
message += " plus 1 other file";
|
||||
} else if (parentPost.filenames.length > 2) {
|
||||
message += " plus " + (parentPost.filenames.length - 1) + " other files";
|
||||
}
|
||||
}
|
||||
|
||||
comment = (
|
||||
<p className="post-link">
|
||||
<span>Commented on {name}{apostrophe} message: <a className="theme" onClick={this.props.handleCommentClick}>{utils.replaceHtmlEntities(message)}</a></span>
|
||||
<span>Commented on {name}{apostrophe} message: <a className="theme" onClick={this.props.handleCommentClick}>{message}</a></span>
|
||||
</p>
|
||||
);
|
||||
|
||||
@@ -120,7 +131,7 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<div className="post-body">
|
||||
{ comment }
|
||||
<p key={post.Id+"_message"} className={postClass}><span>{inner}</span></p>
|
||||
<p key={post.id+"_message"} className={postClass}><span>{inner}</span></p>
|
||||
{ filenames && filenames.length > 0 ?
|
||||
<div className="post-image__columns">
|
||||
{ postFiles }
|
||||
|
||||
@@ -11,6 +11,7 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
var post = this.props.post;
|
||||
var isOwner = UserStore.getCurrentId() == post.user_id;
|
||||
var isAdmin = UserStore.getCurrentUser().roles.indexOf("admin") > -1
|
||||
|
||||
var type = "Post"
|
||||
if (post.root_id.length > 0) {
|
||||
@@ -30,13 +31,11 @@ module.exports = React.createClass({
|
||||
<div className="dropdown">
|
||||
{ isOwner || (this.props.allowReply === "true" && type != "Comment") ?
|
||||
<div>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false">
|
||||
[...]
|
||||
</a>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
||||
<ul className="dropdown-menu" role="menu">
|
||||
{ isOwner ? <li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#edit_post" data-title={type} data-message={post.message} data-postid={post.id} data-channelid={post.channel_id} data-comments={type === "Post" ? this.props.commentCount : 0}>Edit</a></li>
|
||||
: "" }
|
||||
{ isOwner ? <li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#delete_post" data-title={type} data-postid={post.id} data-channelid={post.channel_id} data-comments={type === "Post" ? this.props.commentCount : 0}>Delete</a></li>
|
||||
{ isOwner || isAdmin ? <li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#delete_post" data-title={type} data-postid={post.id} data-channelid={post.channel_id} data-comments={type === "Post" ? this.props.commentCount : 0}>Delete</a></li>
|
||||
: "" }
|
||||
{ this.props.allowReply === "true" ? <li role="presentation"><a className="reply-link theme" href="#" onClick={this.props.handleCommentClick}>Reply</a></li>
|
||||
: "" }
|
||||
|
||||
@@ -6,8 +6,8 @@ var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var UserProfile = require( './user_profile.jsx' );
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var CreatePost = require('./create_post.jsx');
|
||||
var Post = require('./post.jsx');
|
||||
var LoadingScreen = require('./loading_screen.jsx');
|
||||
var SocketStore = require('../stores/socket_store.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var Client = require('../utils/client.jsx');
|
||||
@@ -26,37 +26,8 @@ function getStateFromStores() {
|
||||
};
|
||||
}
|
||||
|
||||
function changeColor(col, amt) {
|
||||
|
||||
var usePound = false;
|
||||
|
||||
if (col[0] == "#") {
|
||||
col = col.slice(1);
|
||||
usePound = true;
|
||||
}
|
||||
|
||||
var num = parseInt(col,16);
|
||||
|
||||
var r = (num >> 16) + amt;
|
||||
|
||||
if (r > 255) r = 255;
|
||||
else if (r < 0) r = 0;
|
||||
|
||||
var b = ((num >> 8) & 0x00FF) + amt;
|
||||
|
||||
if (b > 255) b = 255;
|
||||
else if (b < 0) b = 0;
|
||||
|
||||
var g = (num & 0x0000FF) + amt;
|
||||
|
||||
if (g > 255) g = 255;
|
||||
else if (g < 0) g = 0;
|
||||
|
||||
return (usePound?"#":"") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6);
|
||||
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: "PostList",
|
||||
scrollPosition: 0,
|
||||
preventScrollTrigger: false,
|
||||
gotMorePosts: false,
|
||||
@@ -69,7 +40,7 @@ module.exports = React.createClass({
|
||||
utils.changeCss('a.theme', 'color:'+user.props.theme+'; fill:'+user.props.theme+'!important;');
|
||||
utils.changeCss('div.theme', 'background-color:'+user.props.theme+';');
|
||||
utils.changeCss('.btn.btn-primary', 'background: ' + user.props.theme+';');
|
||||
utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + changeColor(user.props.theme, -10) +';');
|
||||
utils.changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background: ' + utils.changeColor(user.props.theme, -10) +';');
|
||||
utils.changeCss('.modal .modal-header', 'background: ' + user.props.theme+';');
|
||||
utils.changeCss('.mention', 'background: ' + user.props.theme+';');
|
||||
utils.changeCss('.mention-link', 'color: ' + user.props.theme+';');
|
||||
@@ -78,6 +49,7 @@ module.exports = React.createClass({
|
||||
|
||||
PostStore.addChangeListener(this._onChange);
|
||||
ChannelStore.addChangeListener(this._onChange);
|
||||
UserStore.addStatusesChangeListener(this._onTimeChange);
|
||||
SocketStore.addChangeListener(this._onSocketChange);
|
||||
|
||||
$(".post-list-holder-by-time").perfectScrollbar();
|
||||
@@ -157,28 +129,25 @@ module.exports = React.createClass({
|
||||
componentWillUnmount: function() {
|
||||
PostStore.removeChangeListener(this._onChange);
|
||||
ChannelStore.removeChangeListener(this._onChange);
|
||||
UserStore.removeStatusesChangeListener(this._onTimeChange);
|
||||
SocketStore.removeChangeListener(this._onSocketChange);
|
||||
$('body').off('click.userpopover');
|
||||
},
|
||||
resize: function() {
|
||||
var post_holder = $(".post-list-holder-by-time")[0];
|
||||
this.preventScrollTrigger = true;
|
||||
if (this.gotMorePosts) {
|
||||
this.gotMorePosts = false;
|
||||
var post_holder = $(".post-list-holder-by-time")[0];
|
||||
this.preventScrollTrigger = true;
|
||||
$(post_holder).scrollTop($(post_holder).scrollTop() + (post_holder.scrollHeight-this.oldScrollHeight) );
|
||||
$(post_holder).perfectScrollbar('update');
|
||||
} else {
|
||||
var post_holder = $(".post-list-holder-by-time")[0];
|
||||
this.preventScrollTrigger = true;
|
||||
if ($("#new_message")[0] && !this.scrolledToNew) {
|
||||
$(post_holder).scrollTop($(post_holder).scrollTop() + $("#new_message").offset().top - 63);
|
||||
$(post_holder).perfectScrollbar('update');
|
||||
this.scrolledToNew = true;
|
||||
} else {
|
||||
$(post_holder).scrollTop(post_holder.scrollHeight);
|
||||
$(post_holder).perfectScrollbar('update');
|
||||
}
|
||||
}
|
||||
$(post_holder).perfectScrollbar('update');
|
||||
},
|
||||
_onChange: function() {
|
||||
var newState = getStateFromStores();
|
||||
@@ -239,12 +208,8 @@ module.exports = React.createClass({
|
||||
var index = post_list.order.indexOf(msg.props.post_id);
|
||||
if (index > -1) post_list.order.splice(index, 1);
|
||||
|
||||
var scrollSave = $(".post-list-holder-by-time").scrollTop();
|
||||
|
||||
this.setState({ post_list: post_list });
|
||||
|
||||
$(".post-list-holder-by-time").scrollTop(scrollSave)
|
||||
|
||||
PostStore.storePosts(msg.channel_id, post_list);
|
||||
} else {
|
||||
AsyncClient.getPosts(true, msg.channel_id);
|
||||
@@ -253,10 +218,16 @@ module.exports = React.createClass({
|
||||
if (activeRootPostId === msg.props.post_id && UserStore.getCurrentId() != msg.user_id) {
|
||||
$('#post_deleted').modal('show');
|
||||
}
|
||||
} else if(msg.action == "new_user") {
|
||||
} else if (msg.action == "new_user") {
|
||||
AsyncClient.getProfiles();
|
||||
}
|
||||
},
|
||||
_onTimeChange: function() {
|
||||
for (var id in this.state.post_list.posts) {
|
||||
if (!this.refs[id]) continue;
|
||||
this.refs[id].forceUpdateInfo();
|
||||
}
|
||||
},
|
||||
getMorePosts: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -297,7 +268,7 @@ module.exports = React.createClass({
|
||||
},
|
||||
function(err) {
|
||||
$(self.refs.loadmore.getDOMNode()).text("Load more messages");
|
||||
dispatchError(err, "getPosts");
|
||||
AsyncClient.dispatchError(err, "getPosts");
|
||||
}
|
||||
);
|
||||
},
|
||||
@@ -338,16 +309,19 @@ module.exports = React.createClass({
|
||||
var teammate = utils.getDirectTeammate(channel.id)
|
||||
|
||||
if (teammate) {
|
||||
var teammate_name = teammate.full_name.length > 0 ? teammate.full_name : teammate.username;
|
||||
var teammate_name = teammate.nickname.length > 0 ? teammate.nickname : teammate.username;
|
||||
more_messages = (
|
||||
<div className="channel-intro">
|
||||
<div className="post-profile-img__container channel-intro-img">
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + teammate.id + "/image"} height="50" width="50" />
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + teammate.id + "/image?time=" + teammate.update_at} height="50" width="50" />
|
||||
</div>
|
||||
<div className="channel-intro-profile">
|
||||
<strong><UserProfile userId={teammate.id} /></strong>
|
||||
</div>
|
||||
<p className="channel-intro-text">{"This is the start of your private message history with " + teammate_name + "." }<br/>{"Private messages and files shared here are not shown to people outside this area."}</p>
|
||||
<p className="channel-intro-text">
|
||||
{"This is the start of your private message history with " + teammate_name + "." }<br/>
|
||||
{"Private messages and files shared here are not shown to people outside this area."}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
@@ -370,7 +344,7 @@ module.exports = React.createClass({
|
||||
}
|
||||
}
|
||||
|
||||
if (channel.name === Constants.DEFAULT_CHANNEL) {
|
||||
if (ChannelStore.isDefault(channel)) {
|
||||
more_messages = (
|
||||
<div className="channel-intro">
|
||||
<h4 className="channel-intro-title">Welcome</h4>
|
||||
@@ -410,7 +384,7 @@ module.exports = React.createClass({
|
||||
{ channel.type === 'P' ? " Only invited members can see this private group." : " Any member can join and read this channel." }
|
||||
<br/>
|
||||
<a className="intro-links" href="#" style={userStyle} data-toggle="modal" data-target="#edit_channel" data-desc={channel.description} data-title={channel.display_name} data-channelid={channel.id}><i className="fa fa-pencil"></i>Set a description</a>
|
||||
<a className="intro-links" style={userStyle} data-toggle="modal" data-target="#channel_invite"><i className="fa fa-user-plus"></i>Invite others to this {ui_type}</a>
|
||||
<a className="intro-links" href="#" style={userStyle} data-toggle="modal" data-target="#channel_invite"><i className="fa fa-user-plus"></i>Invite others to this {ui_type}</a>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
@@ -420,37 +394,35 @@ module.exports = React.createClass({
|
||||
|
||||
var postCtls = [];
|
||||
|
||||
if (posts != undefined) {
|
||||
if (posts) {
|
||||
var previousPostDay = posts[order[order.length-1]] ? utils.getDateForUnixTicks(posts[order[order.length-1]].create_at): new Date();
|
||||
var currentPostDay = new Date();
|
||||
var currentPostDay;
|
||||
|
||||
for (var i = order.length-1; i >= 0; i--) {
|
||||
var post = posts[order[i]];
|
||||
var parentPost;
|
||||
var parentPost = post.parent_id ? posts[post.parent_id] : null;
|
||||
|
||||
if (post.parent_id) {
|
||||
parentPost = posts[post.parent_id];
|
||||
} else {
|
||||
parentPost = null;
|
||||
var sameUser = '';
|
||||
var sameRoot = false;
|
||||
var hideProfilePic = false;
|
||||
var prevPost = (i < order.length - 1) ? posts[order[i + 1]] : null;
|
||||
|
||||
if (prevPost) {
|
||||
sameUser = (prevPost.user_id === post.user_id) && (post.create_at - prevPost.create_at <= 1000*60*5) ? "same--user" : "";
|
||||
sameRoot = utils.isComment(post) && (prevPost.id === post.root_id || prevPost.root_id === post.root_id);
|
||||
|
||||
// we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post
|
||||
hideProfilePic = (prevPost.user_id === post.user_id) && !utils.isComment(prevPost) && !utils.isComment(post);
|
||||
}
|
||||
|
||||
var sameUser = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && post.create_at - posts[order[i+1]].create_at <= 1000*60*5 ? "same--user" : "";
|
||||
var sameRoot = i < order.length-1 && post.root_id != "" && (posts[order[i+1]].id === post.root_id || posts[order[i+1]].root_id === post.root_id) ? true : false;
|
||||
|
||||
// we only hide the profile pic if the previous post is not a comment, the current post is not a comment, and the previous post was made by the same user as the current post
|
||||
var hideProfilePic = i < order.length-1 && posts[order[i+1]].user_id === post.user_id && posts[order[i+1]].root_id === '' && post.root_id === '';
|
||||
|
||||
// check if it's the last comment in a consecutive string of comments on the same post
|
||||
var isLastComment = false;
|
||||
if (utils.isComment(post)) {
|
||||
// it is the last comment if it is last post in the channel or the next post has a different root post
|
||||
isLastComment = (i === 0 || posts[order[i-1]].root_id != post.root_id);
|
||||
}
|
||||
// it is the last comment if it is last post in the channel or the next post has a different root post
|
||||
var isLastComment = utils.isComment(post) && (i === 0 || posts[order[i-1]].root_id != post.root_id);
|
||||
|
||||
var postCtl = <Post sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />;
|
||||
var postCtl = <Post ref={post.id} sameUser={sameUser} sameRoot={sameRoot} post={post} parentPost={parentPost} key={post.id} posts={posts} hideProfilePic={hideProfilePic} isLastComment={isLastComment} />;
|
||||
|
||||
currentPostDay = utils.getDateForUnixTicks(post.create_at);
|
||||
if(currentPostDay.getDate() !== previousPostDay.getDate() || currentPostDay.getMonth() !== previousPostDay.getMonth() || currentPostDay.getFullYear() !== previousPostDay.getFullYear()) {
|
||||
if (currentPostDay.toDateString() != previousPostDay.toDateString()) {
|
||||
postCtls.push(
|
||||
<div className="date-separator">
|
||||
<hr className="separator__hr" />
|
||||
@@ -469,20 +441,10 @@ module.exports = React.createClass({
|
||||
);
|
||||
}
|
||||
postCtls.push(postCtl);
|
||||
previousPostDay = utils.getDateForUnixTicks(post.create_at);
|
||||
previousPostDay = currentPostDay;
|
||||
}
|
||||
}
|
||||
else {
|
||||
postCtls.push(
|
||||
<div ref="loadingscreen" className="loading-screen">
|
||||
<div className="loading__content">
|
||||
<h3>Loading</h3>
|
||||
<div id="round_1" className="round"></div>
|
||||
<div id="round_2" className="round"></div>
|
||||
<div id="round_3" className="round"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
postCtls.push(<LoadingScreen position="absolute" />);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -497,5 +459,3 @@ module.exports = React.createClass({
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ RhsHeaderPost = React.createClass({
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var back = this.props.fromSearch ? <a href="#" onClick={this.handleBack} style={{color:"black"}}>{"< "}</a> : "";
|
||||
var back = this.props.fromSearch ? <a href="#" onClick={this.handleBack} className="sidebar--right__back"><i className="fa fa-chevron-left"></i></a> : "";
|
||||
|
||||
return (
|
||||
<div className="sidebar--right__header">
|
||||
@@ -67,6 +67,8 @@ RootPost = React.createClass({
|
||||
var message = utils.textToJsx(this.props.post.message);
|
||||
var filenames = this.props.post.filenames;
|
||||
var isOwner = UserStore.getCurrentId() == this.props.post.user_id;
|
||||
var timestamp = UserStore.getProfile(this.props.post.user_id).update_at;
|
||||
var channel = ChannelStore.get(this.props.post.channel_id);
|
||||
|
||||
var type = "Post";
|
||||
if (this.props.post.root_id.length > 0) {
|
||||
@@ -78,6 +80,10 @@ RootPost = React.createClass({
|
||||
currentUserCss = "current--user";
|
||||
}
|
||||
|
||||
if (channel) {
|
||||
channelName = (channel.type === 'D') ? "Private Message" : channel.display_name;
|
||||
}
|
||||
|
||||
if (filenames) {
|
||||
var postFiles = [];
|
||||
var images = [];
|
||||
@@ -117,8 +123,9 @@ RootPost = React.createClass({
|
||||
|
||||
return (
|
||||
<div className={"post post--root " + currentUserCss}>
|
||||
<div className="post-right-channel__name">{ channelName }</div>
|
||||
<div className="post-profile-img__container">
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
</div>
|
||||
<div className="post__content">
|
||||
<ul className="post-header">
|
||||
@@ -128,9 +135,7 @@ RootPost = React.createClass({
|
||||
<div className="dropdown">
|
||||
{ isOwner ?
|
||||
<div>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false">
|
||||
[...]
|
||||
</a>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
||||
<ul className="dropdown-menu" role="menu">
|
||||
<li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#edit_post" data-title={type} data-message={this.props.post.message} data-postid={this.props.post.id} data-channelid={this.props.post.channel_id}>Edit</a></li>
|
||||
<li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#delete_post" data-title={type} data-postid={this.props.post.id} data-channelid={this.props.post.channel_id} data-comments={this.props.commentCount}>Delete</a></li>
|
||||
@@ -227,11 +232,12 @@ CommentPost = React.createClass({
|
||||
}
|
||||
|
||||
var message = utils.textToJsx(this.props.post.message);
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
return (
|
||||
<div className={commentClass + " " + currentUserCss}>
|
||||
<div className="post-profile-img__container">
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
</div>
|
||||
<div className="post__content">
|
||||
<ul className="post-header">
|
||||
@@ -240,9 +246,7 @@ CommentPost = React.createClass({
|
||||
<li className="post-header-col post-header__reply">
|
||||
{ isOwner ?
|
||||
<div className="dropdown" onClick={function(e){$('.post-list-holder-by-time').scrollTop($(".post-list-holder-by-time").scrollTop() + 50);}}>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false">
|
||||
[...]
|
||||
</a>
|
||||
<a href="#" className="dropdown-toggle theme" type="button" data-toggle="dropdown" aria-expanded="false" />
|
||||
<ul className="dropdown-menu" role="menu">
|
||||
<li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#edit_post" data-title={type} data-message={this.props.post.message} data-postid={this.props.post.id} data-channelid={this.props.post.channel_id}>Edit</a></li>
|
||||
<li role="presentation"><a href="#" role="menuitem" data-toggle="modal" data-target="#delete_post" data-title={type} data-postid={this.props.post.id} data-channelid={this.props.post.channel_id} data-comments={0}>Delete</a></li>
|
||||
@@ -282,6 +286,7 @@ module.exports = React.createClass({
|
||||
componentDidMount: function() {
|
||||
PostStore.addSelectedPostChangeListener(this._onChange);
|
||||
PostStore.addChangeListener(this._onChangeAll);
|
||||
UserStore.addStatusesChangeListener(this._onTimeChange);
|
||||
this.resize();
|
||||
var self = this;
|
||||
$(window).resize(function(){
|
||||
@@ -294,6 +299,7 @@ module.exports = React.createClass({
|
||||
componentWillUnmount: function() {
|
||||
PostStore.removeSelectedPostChangeListener(this._onChange);
|
||||
PostStore.removeChangeListener(this._onChangeAll);
|
||||
UserStore.removeStatusesChangeListener(this._onTimeChange);
|
||||
},
|
||||
_onChange: function() {
|
||||
if (this.isMounted()) {
|
||||
@@ -304,7 +310,6 @@ module.exports = React.createClass({
|
||||
}
|
||||
},
|
||||
_onChangeAll: function() {
|
||||
|
||||
if (this.isMounted()) {
|
||||
|
||||
// if something was changed in the channel like adding a
|
||||
@@ -333,6 +338,12 @@ module.exports = React.createClass({
|
||||
this.setState(getStateFromStores());
|
||||
}
|
||||
},
|
||||
_onTimeChange: function() {
|
||||
for (var id in this.state.post_list.posts) {
|
||||
if (!this.refs[id]) continue;
|
||||
this.refs[id].forceUpdate();
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
return getStateFromStores();
|
||||
},
|
||||
@@ -392,7 +403,7 @@ module.exports = React.createClass({
|
||||
<RootPost post={root_post} commentCount={posts_array.length}/>
|
||||
<div className="post-right-comments-container">
|
||||
{ posts_array.map(function(cpost) {
|
||||
return <CommentPost key={cpost.id} post={cpost} selected={ (cpost.id == selected_post.id) } />
|
||||
return <CommentPost ref={cpost.id} key={cpost.id} post={cpost} selected={ (cpost.id == selected_post.id) } />
|
||||
})}
|
||||
</div>
|
||||
<div className="post-create__container">
|
||||
|
||||
@@ -6,6 +6,8 @@ var utils = require('../utils/utils.jsx');
|
||||
var Client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var TeamStore = require('../stores/team_store.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
@@ -60,12 +62,12 @@ module.exports = React.createClass({
|
||||
return;
|
||||
|
||||
Client.updateChannel(channel,
|
||||
function(data) {
|
||||
function(data, text, req) {
|
||||
this.refs.display_name.getDOMNode().value = "";
|
||||
this.refs.channel_name.getDOMNode().value = "";
|
||||
|
||||
$('#' + this.props.modalId).modal('hide');
|
||||
window.location.href = '/channels/' + this.state.channel_name;
|
||||
window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + this.state.channel_name;
|
||||
AsyncClient.getChannels(true);
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
|
||||
@@ -24,13 +24,13 @@ module.exports = React.createClass({
|
||||
if (!valid)
|
||||
return;
|
||||
|
||||
if (this.props.teamName === name)
|
||||
if (this.props.teamDisplayName === name)
|
||||
return;
|
||||
|
||||
var data = {};
|
||||
data["new_name"] = name;
|
||||
|
||||
Client.updateTeamName(data,
|
||||
Client.updateTeamDisplayName(data,
|
||||
function(data) {
|
||||
$('#rename_team_link').modal('hide');
|
||||
window.location.reload();
|
||||
@@ -47,11 +47,11 @@ module.exports = React.createClass({
|
||||
componentDidMount: function() {
|
||||
var self = this;
|
||||
$(this.refs.modal.getDOMNode()).on('hidden.bs.modal', function(e) {
|
||||
self.setState({ name: self.props.teamName });
|
||||
self.setState({ name: self.props.teamDisplayName });
|
||||
});
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { name: this.props.teamName };
|
||||
return { name: this.props.teamDisplayName };
|
||||
},
|
||||
render: function() {
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
var client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var PostStore = require('../stores/post_store.jsx');
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
@@ -10,14 +11,14 @@ var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
function getSearchTermStateFromStores() {
|
||||
term = PostStore.getSearchTerm();
|
||||
if (!term) term = "";
|
||||
var term = PostStore.getSearchTerm() || '';
|
||||
return {
|
||||
search_term: term
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SearchBar',
|
||||
componentDidMount: function() {
|
||||
PostStore.addSearchTermChangeListener(this._onChange);
|
||||
},
|
||||
@@ -58,14 +59,14 @@ module.exports = React.createClass({
|
||||
e.target.select();
|
||||
},
|
||||
performSearch: function(terms, isMentionSearch) {
|
||||
if (terms.length > 0) {
|
||||
$("#search-spinner").removeClass("hidden");
|
||||
if (terms.length) {
|
||||
this.setState({isSearching: true});
|
||||
client.search(
|
||||
terms,
|
||||
function(data) {
|
||||
$("#search-spinner").addClass("hidden");
|
||||
if(utils.isMobile()) {
|
||||
$('#search')[0].value = "";
|
||||
this.setState({isSearching: false});
|
||||
if (utils.isMobile()) {
|
||||
React.findDOMNode(this.refs.search).value = '';
|
||||
}
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
@@ -73,18 +74,17 @@ module.exports = React.createClass({
|
||||
results: data,
|
||||
is_mention_search: isMentionSearch
|
||||
});
|
||||
},
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
$("#search-spinner").addClass("hidden");
|
||||
dispatchError(err, "search");
|
||||
}
|
||||
this.setState({isSearching: false});
|
||||
AsyncClient.dispatchError(err, "search");
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
},
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
terms = this.state.search_term.trim();
|
||||
this.performSearch(terms);
|
||||
this.performSearch(this.state.search_term.trim());
|
||||
},
|
||||
getInitialState: function() {
|
||||
return getSearchTermStateFromStores();
|
||||
@@ -92,11 +92,18 @@ module.exports = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<div className="sidebar__collapse" onClick={this.handleClose}></div>
|
||||
<div className="sidebar__collapse" onClick={this.handleClose}>Cancel</div>
|
||||
<span className="glyphicon glyphicon-search sidebar__search-icon"></span>
|
||||
<form role="form" className="search__form relative-div" onSubmit={this.handleSubmit}>
|
||||
<input type="text" className="form-control search-bar-box" ref="search" id="search" placeholder="Search" value={this.state.search_term} onFocus={this.handleUserFocus} onChange={this.handleUserInput} />
|
||||
<span id="search-spinner" className="glyphicon glyphicon-refresh glyphicon-refresh-animate hidden"></span>
|
||||
<input
|
||||
type="text"
|
||||
ref="search"
|
||||
className="form-control search-bar-box"
|
||||
placeholder="Search"
|
||||
value={this.state.search_term}
|
||||
onFocus={this.handleUserFocus}
|
||||
onChange={this.handleUserInput} />
|
||||
{this.state.isSearching ? <span className={"glyphicon glyphicon-refresh glyphicon-refresh-animate"}></span> : null}
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -8,12 +8,13 @@ var UserStore = require('../stores/user_store.jsx');
|
||||
var UserProfile = require( './user_profile.jsx' );
|
||||
var SearchBox =require('./search_bar.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var client =require('../utils/client.jsx');
|
||||
var client = require('../utils/client.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
RhsHeaderSearch = React.createClass({
|
||||
var RhsHeaderSearch = React.createClass({
|
||||
handleClose: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -32,13 +33,13 @@ RhsHeaderSearch = React.createClass({
|
||||
return (
|
||||
<div className="sidebar--right__header">
|
||||
<span className="sidebar--right__title">{title}</span>
|
||||
<button type="button" className="sidebar--right__close" aria-label="Close" onClick={this.handleClose}></button>
|
||||
<button type="button" className="sidebar--right__close" aria-label="Close" title="Close" onClick={this.handleClose}></button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
SearchItem = React.createClass({
|
||||
var SearchItem = React.createClass({
|
||||
handleClick: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -62,39 +63,41 @@ SearchItem = React.createClass({
|
||||
});
|
||||
},
|
||||
function(err) {
|
||||
dispatchError(err, "getPost");
|
||||
AsyncClient.dispatchError(err, "getPost");
|
||||
}
|
||||
);
|
||||
|
||||
var postChannel = ChannelStore.get(this.props.post.channel_id);
|
||||
var teammate = postChannel.type === 'D' ? utils.getDirectTeammate(this.props.post.channel_id).username : "";
|
||||
var postChannel = ChannelStore.get(this.props.post.channel_id);
|
||||
var teammate = postChannel.type === 'D' ? utils.getDirectTeammate(this.props.post.channel_id).username : "";
|
||||
|
||||
utils.switchChannel(postChannel,teammate);
|
||||
utils.switchChannel(postChannel, teammate);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
||||
var message = utils.textToJsx(this.props.post.message, {searchTerm: this.props.term, noMentionHighlight: !this.props.isMentionSearch});
|
||||
var channelName = "";
|
||||
var channel = ChannelStore.get(this.props.post.channel_id)
|
||||
var channel = ChannelStore.get(this.props.post.channel_id);
|
||||
var timestamp = UserStore.getCurrentUser().update_at;
|
||||
|
||||
if (channel) {
|
||||
if (channel.type === 'D') {
|
||||
channelName = "Private Message";
|
||||
} else {
|
||||
channelName = channel.display_name;
|
||||
}
|
||||
channelName = (channel.type === 'D') ? "Private Message" : channel.display_name;
|
||||
}
|
||||
|
||||
return (
|
||||
return (
|
||||
<div className="search-item-container post" onClick={this.handleClick}>
|
||||
<div className="search-channel__name">{ channelName }</div>
|
||||
<div className="post-profile-img__container">
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image"} height="36" width="36" />
|
||||
<img className="post-profile-img" src={"/api/v1/users/" + this.props.post.user_id + "/image?time=" + timestamp} height="36" width="36" />
|
||||
</div>
|
||||
<div className="post__content">
|
||||
<ul className="post-header">
|
||||
<li className="post-header-col"><strong><UserProfile userId={this.props.post.user_id} /></strong></li>
|
||||
<li className="post-header-col"><time className="search-item-time">{ utils.displayDate(this.props.post.create_at)+' '+utils.displayTime(this.props.post.create_at) }</time></li>
|
||||
<li className="post-header-col">
|
||||
<time className="search-item-time">
|
||||
{ utils.displayDate(this.props.post.create_at) + ' ' + utils.displayTime(this.props.post.create_at) }
|
||||
</time>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="search-item-snippet"><span>{message}</span></div>
|
||||
</div>
|
||||
@@ -103,11 +106,13 @@ SearchItem = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function getStateFromStores() {
|
||||
return { results: PostStore.getSearchResults() };
|
||||
}
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'SearchResults',
|
||||
componentDidMount: function() {
|
||||
PostStore.addSearchChangeListener(this._onChange);
|
||||
this.resize();
|
||||
@@ -143,41 +148,24 @@ module.exports = React.createClass({
|
||||
|
||||
var results = this.state.results;
|
||||
var currentId = UserStore.getCurrentId();
|
||||
var searchForm = currentId == null ? null : <SearchBox />;
|
||||
var searchForm = currentId ? <SearchBox /> : null;
|
||||
var noResults = (!results || !results.order || !results.order.length);
|
||||
var searchTerm = PostStore.getSearchTerm();
|
||||
|
||||
if (results == null) {
|
||||
return (
|
||||
<div className="sidebar--right__header">
|
||||
<div className="sidebar__heading">Search Results</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!results.order || results.order.length == 0) {
|
||||
return (
|
||||
<div className="sidebar--right__content">
|
||||
<div className="search-bar__container">{searchForm}</div>
|
||||
<div className="sidebar-right__body">
|
||||
<RhsHeaderSearch />
|
||||
<div id="search-items-container" className="search-items-container">
|
||||
<div className="sidebar--right__subheader">No results</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
return (
|
||||
<div className="sidebar--right__content">
|
||||
<div className="search-bar__container sidebar--right__search-header">{searchForm}</div>
|
||||
<div className="sidebar-right__body">
|
||||
<RhsHeaderSearch isMentionSearch={this.props.isMentionSearch} />
|
||||
<div id="search-items-container" className="search-items-container">
|
||||
{results.order.map(function(id) {
|
||||
var post = results.posts[id];
|
||||
return <SearchItem key={post.id} post={post} term={PostStore.getSearchTerm()} isMentionSearch={self.props.isMentionSearch} />
|
||||
})}
|
||||
|
||||
{ noResults ? <div className="sidebar--right__subheader">No results</div>
|
||||
: results.order.map(function(id) {
|
||||
var post = results.posts[id];
|
||||
return <SearchItem key={post.id} post={post} term={searchTerm} isMentionSearch={this.props.isMentionSearch} />
|
||||
}, this)
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ var ChannelStore = require('../stores/channel_store.jsx');
|
||||
var AsyncClient = require('../utils/async_client.jsx');
|
||||
var SocketStore = require('../stores/socket_store.jsx');
|
||||
var UserStore = require('../stores/user_store.jsx');
|
||||
var TeamStore = require('../stores/team_store.jsx');
|
||||
var utils = require('../utils/utils.jsx');
|
||||
var SidebarHeader = require('./sidebar_header.jsx');
|
||||
var SearchBox = require('./search_bar.jsx');
|
||||
@@ -13,93 +14,6 @@ var SearchBox = require('./search_bar.jsx');
|
||||
var Constants = require('../utils/constants.jsx');
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
var SidebarLoginForm = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
var state = { }
|
||||
|
||||
var domain = this.refs.domain.getDOMNode().value.trim();
|
||||
if (!domain) {
|
||||
state.server_error = "A domain is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
var email = this.refs.email.getDOMNode().value.trim();
|
||||
if (!email) {
|
||||
state.server_error = "An email is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
var password = this.refs.password.getDOMNode().value.trim();
|
||||
if (!password) {
|
||||
state.server_error = "A password is required"
|
||||
this.setState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
state.server_error = "";
|
||||
this.setState(state);
|
||||
|
||||
client.loginByEmail(domain, email, password,
|
||||
function(data) {
|
||||
UserStore.setLastDomain(domain);
|
||||
UserStore.setLastEmail(email);
|
||||
UserStore.setCurrentUser(data);
|
||||
|
||||
var redirect = utils.getUrlParameter("redirect");
|
||||
if (redirect) {
|
||||
window.location.href = decodeURI(redirect);
|
||||
} else {
|
||||
window.location.href = '/channels/town-square';
|
||||
}
|
||||
|
||||
}.bind(this),
|
||||
function(err) {
|
||||
if (err.message == "Login failed because email address has not been verified") {
|
||||
window.location.href = '/verify?domain=' + encodeURIComponent(domain) + '&email=' + encodeURIComponent(email);
|
||||
return;
|
||||
}
|
||||
state.server_error = err.message;
|
||||
this.valid = false;
|
||||
this.setState(state);
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
render: function() {
|
||||
var server_error = this.state.server_error ? <label className="control-label">{this.state.server_error}</label> : null;
|
||||
|
||||
var subDomain = utils.getSubDomain();
|
||||
var subDomainClass = "form-control hidden";
|
||||
|
||||
if (subDomain == "") {
|
||||
subDomain = UserStore.getLastDomain();
|
||||
subDomainClass = "form-control";
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="" onSubmit={this.handleSubmit}>
|
||||
<a href="/find_team">{"Find your " + strings.Team}</a>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
{ server_error }
|
||||
<input type="text" className={subDomainClass} name="domain" defaultValue={subDomain} ref="domain" placeholder="Domain" />
|
||||
</div>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="text" className="form-control" name="email" defaultValue={UserStore.getLastEmail()} ref="email" placeholder="Email" />
|
||||
</div>
|
||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||
<input type="password" className="form-control" name="password" ref="password" placeholder="Password" />
|
||||
</div>
|
||||
<button type="submit" className="btn btn-default">Login</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function getStateFromStores() {
|
||||
var members = ChannelStore.getAllMembers();
|
||||
var team_member_map = UserStore.getActiveOnlyProfiles();
|
||||
@@ -131,7 +45,7 @@ function getStateFromStores() {
|
||||
var channel = ChannelStore.getByName(channelName);
|
||||
|
||||
if (channel != null) {
|
||||
channel.display_name = teammate.full_name.trim() != "" ? teammate.full_name : teammate.username;
|
||||
channel.display_name = utils.getDisplayName(teammate);
|
||||
channel.teammate_username = teammate.username;
|
||||
|
||||
channel.status = UserStore.getStatus(teammate.id);
|
||||
@@ -150,7 +64,7 @@ function getStateFromStores() {
|
||||
var tempChannel = {};
|
||||
tempChannel.fake = true;
|
||||
tempChannel.name = channelName;
|
||||
tempChannel.display_name = teammate.full_name.trim() != "" ? teammate.full_name : teammate.username;
|
||||
tempChannel.display_name = utils.getDisplayName(teammate);
|
||||
tempChannel.status = UserStore.getStatus(teammate.id);
|
||||
tempChannel.last_post_at = 0;
|
||||
readDirectChannels.push(tempChannel);
|
||||
@@ -192,7 +106,7 @@ function getStateFromStores() {
|
||||
};
|
||||
}
|
||||
|
||||
var SidebarLoggedIn = React.createClass({
|
||||
module.exports = React.createClass({
|
||||
componentDidMount: function() {
|
||||
ChannelStore.addChangeListener(this._onChange);
|
||||
UserStore.addChangeListener(this._onChange);
|
||||
@@ -249,11 +163,27 @@ var SidebarLoggedIn = React.createClass({
|
||||
|
||||
var repRegex = new RegExp("<br>", "g");
|
||||
var post = JSON.parse(msg.props.post);
|
||||
var msg = post.message.replace(repRegex, "\n").split("\n")[0].replace("<mention>", "").replace("</mention>", "");
|
||||
var msgProps = msg.props;
|
||||
var msg = post.message.replace(repRegex, "\n").replace(/\n+/g, " ").replace("<mention>", "").replace("</mention>", "");
|
||||
|
||||
if (msg.length > 50) {
|
||||
msg = msg.substring(0,49) + "...";
|
||||
}
|
||||
utils.notifyMe(title, username + " wrote: " + msg, channel);
|
||||
|
||||
if (msg.length === 0) {
|
||||
if (msgProps.image) {
|
||||
utils.notifyMe(title, username + " uploaded an image", channel);
|
||||
}
|
||||
else if (msgProps.otherFile) {
|
||||
utils.notifyMe(title, username + " uploaded a file", channel);
|
||||
}
|
||||
else {
|
||||
utils.notifyMe(title, username + " did something new", channel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
utils.notifyMe(title, username + " wrote: " + msg, channel);
|
||||
}
|
||||
if (!user.notify_props || user.notify_props.desktop_sound === "true") {
|
||||
utils.ding();
|
||||
}
|
||||
@@ -367,7 +297,7 @@ var SidebarLoggedIn = React.createClass({
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<li key={channel.name} className={active}><a className={"sidebar-channel " + titleClass} href={"/channels/"+channel.name}><span className="status" dangerouslySetInnerHTML={{__html: statusIcon}} /> {badge}{channel.display_name}</a></li>
|
||||
<li key={channel.name} className={active}><a className={"sidebar-channel " + titleClass} href={TeamStore.getCurrentTeamUrl() + "/channels/"+channel.name}><span className="status" dangerouslySetInnerHTML={{__html: statusIcon}} /> {badge}{channel.display_name}</a></li>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -398,7 +328,7 @@ var SidebarLoggedIn = React.createClass({
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<SidebarHeader teamName={this.props.teamName} teamType={this.props.teamType} />
|
||||
<SidebarHeader teamDisplayName={this.props.teamDisplayName} teamType={this.props.teamType} />
|
||||
<SearchBox />
|
||||
|
||||
<div className="nav-pills__container">
|
||||
@@ -424,25 +354,3 @@ var SidebarLoggedIn = React.createClass({
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var SidebarLoggedOut = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<SidebarHeader teamName={this.props.teamName} />
|
||||
<SidebarLoginForm />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = React.createClass({
|
||||
render: function() {
|
||||
var currentId = UserStore.getCurrentId();
|
||||
if (currentId != null) {
|
||||
return <SidebarLoggedIn teamName={this.props.teamName} teamType={this.props.teamType} />;
|
||||
} else {
|
||||
return <SidebarLoggedOut teamName={this.props.teamName} />;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,17 +37,13 @@ var NavbarDropdown = React.createClass({
|
||||
var invite_link = "";
|
||||
var manage_link = "";
|
||||
var rename_link = "";
|
||||
var currentUser = UserStore.getCurrentUser()
|
||||
var currentUser = UserStore.getCurrentUser();
|
||||
var isAdmin = false;
|
||||
|
||||
if (currentUser != null) {
|
||||
isAdmin = currentUser.roles.indexOf("admin") > -1;
|
||||
|
||||
invite_link = (
|
||||
<li>
|
||||
<a href="#" data-toggle="modal" data-target="#invite_member">Invite New Member</a>
|
||||
</li>
|
||||
);
|
||||
invite_link = ( <li> <a href="#" data-toggle="modal" data-target="#invite_member">Invite New Member</a> </li>);
|
||||
|
||||
if (this.props.teamType == "O") {
|
||||
team_link = (
|
||||
@@ -59,43 +55,31 @@ var NavbarDropdown = React.createClass({
|
||||
}
|
||||
|
||||
if (isAdmin) {
|
||||
manage_link = (
|
||||
<li>
|
||||
<a href="#" data-toggle="modal" data-target="#team_members">Manage Team</a>
|
||||
</li>
|
||||
);
|
||||
rename_link = (
|
||||
<li>
|
||||
<a href="#" data-toggle="modal" data-target="#rename_team_link">Rename</a>
|
||||
</li>
|
||||
);
|
||||
manage_link = ( <li> <a href="#" data-toggle="modal" data-target="#team_members">Manage Team</a> </li>);
|
||||
rename_link = ( <li> <a href="#" data-toggle="modal" data-target="#rename_team_link">Rename</a> </li>);
|
||||
}
|
||||
|
||||
var teams = [];
|
||||
|
||||
teams.push(<li className="divider" key="div"></li>);
|
||||
if (this.state.teams.length > 1) {
|
||||
for (var i = 0; i < this.state.teams.length; i++) {
|
||||
var domain = this.state.teams[i];
|
||||
var teamName = this.state.teams[i];
|
||||
|
||||
if (domain == utils.getSubDomain())
|
||||
continue;
|
||||
|
||||
if (teams.length == 0)
|
||||
teams.push(<li className="divider" key="div"></li>);
|
||||
|
||||
teams.push(<li key={ domain }><a href={window.location.protocol + "//" + domain + "." + utils.getDomainWithOutSub() }>Switch to { domain }</a></li>);
|
||||
teams.push(<li key={ teamName }><a href={window.location.origin + "/" + teamName }>Switch to { teamName }</a></li>);
|
||||
}
|
||||
}
|
||||
teams.push(<li><a href={window.location.origin + "/signup_team" }>Create a New Team</a></li>);
|
||||
|
||||
return (
|
||||
<ul className="nav navbar-nav navbar-right">
|
||||
<li className="dropdown">
|
||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
||||
<i className="dropdown__icon"></i>
|
||||
<span className="dropdown__icon" dangerouslySetInnerHTML={{__html: " <svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'width='4px' height='16px' viewBox='0 0 8 32' enable-background='new 0 0 8 32' xml:space='preserve'> <g> <circle cx='4' cy='4.062' r='4'/> <circle cx='4' cy='16' r='4'/> <circle cx='4' cy='28' r='4'/> </g> </svg>"}} />
|
||||
</a>
|
||||
<ul className="dropdown-menu" role="menu">
|
||||
<li><a href="#" data-toggle="modal" data-target="#user_settings1">Account Settings</a></li>
|
||||
{ isAdmin ? <li><a href="#" data-toggle="modal" data-target="#team_settings">Team Settings</a></li> : "" }
|
||||
{ isAdmin ? <li><a href="#" data-toggle="modal" data-target="#team_settings">Team Settings</a></li> : null }
|
||||
{ invite_link }
|
||||
{ team_link }
|
||||
{ manage_link }
|
||||
@@ -113,23 +97,32 @@ var NavbarDropdown = React.createClass({
|
||||
});
|
||||
|
||||
module.exports = React.createClass({
|
||||
handleSubmit: function(e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
displayName: 'SidebarHeader',
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
teamName: config.SiteName
|
||||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var teamName = this.props.teamName ? this.props.teamName : config.SiteName;
|
||||
var teamDisplayName = this.props.teamDisplayName ? this.props.teamDisplayName : config.SiteName;
|
||||
var me = UserStore.getCurrentUser()
|
||||
if (!me) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="team__header theme">
|
||||
<a className="team__name" href="/channels/town-square">{ teamName }</a>
|
||||
<a className="settings_link" href="#" data-toggle="modal" data-target="#user_settings1">
|
||||
<img className="user__picture" src={"/api/v1/users/" + me.id + "/image?time=" + me.update_at} />
|
||||
<div className="header__info">
|
||||
<div className="user__name">{ '@' + me.username}</div>
|
||||
<div className="team__name">{ teamDisplayName }</div>
|
||||
</div>
|
||||
</a>
|
||||
<NavbarDropdown teamType={this.props.teamType} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
var siteName = config.SiteName != null ? config.SiteName : "";
|
||||
var teamName = this.props.teamName ? this.props.teamName : siteName;
|
||||
var teamDisplayName = this.props.teamDisplayName ? this.props.teamDisplayName : siteName;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="team__header theme">
|
||||
<a className="team__name" href="/channels/town-square">{ teamName }</a>
|
||||
<a className="team__name" href="/channels/town-square">{ teamDisplayName }</a>
|
||||
</div>
|
||||
|
||||
<div className="nav-pills__container">
|
||||
|
||||
@@ -20,8 +20,8 @@ module.exports = React.createClass({
|
||||
state.email_error = "";
|
||||
}
|
||||
|
||||
team.name = this.refs.name.getDOMNode().value.trim();
|
||||
if (!team.name) {
|
||||
team.display_name = this.refs.name.getDOMNode().value.trim();
|
||||
if (!team.display_name) {
|
||||
state.name_error = "This field is required";
|
||||
state.inValid = true;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ module.exports = React.createClass({
|
||||
return;
|
||||
}
|
||||
|
||||
client.signupTeam(team.email, team.name,
|
||||
client.signupTeam(team.email, team.display_name,
|
||||
function(data) {
|
||||
if (data["follow_link"]) {
|
||||
window.location.href = data["follow_link"];
|
||||
@@ -61,7 +61,7 @@ module.exports = React.createClass({
|
||||
return (
|
||||
<form role="form" onSubmit={this.handleSubmit}>
|
||||
<div className={ email_error ? "form-group has-error" : "form-group" }>
|
||||
<input type="email" ref="email" className="form-control" placeholder="Email Address" maxLength="128" />
|
||||
<input autoFocus={true} type="email" ref="email" className="form-control" placeholder="Email Address" maxLength="128" />
|
||||
{ email_error }
|
||||
</div>
|
||||
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
||||
@@ -70,6 +70,9 @@ module.exports = React.createClass({
|
||||
</div>
|
||||
{ server_error }
|
||||
<button className="btn btn-md btn-primary" type="submit">Sign up for Free</button>
|
||||
<div className="form-group form-group--small">
|
||||
<span><a href="/find_team">{"Find my " + strings.Team}</a></span>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ WelcomePage = React.createClass({
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
this.props.state.wizard = "team_name";
|
||||
this.props.state.wizard = "team_display_name";
|
||||
this.props.updateParent(this.props.state);
|
||||
},
|
||||
handleDiffEmail: function (e) {
|
||||
@@ -57,6 +57,17 @@ WelcomePage = React.createClass({
|
||||
getInitialState: function() {
|
||||
return { use_diff: false };
|
||||
},
|
||||
handleKeyPress: function(event) {
|
||||
if (event.keyCode == 13) {
|
||||
this.submitNext(event);
|
||||
}
|
||||
},
|
||||
componentWillMount: function() {
|
||||
document.addEventListener("keyup", this.handleKeyPress, false);
|
||||
},
|
||||
componentWillUnmount: function() {
|
||||
document.removeEventListener("keyup", this.handleKeyPress, false);
|
||||
},
|
||||
render: function() {
|
||||
|
||||
client.track('signup', 'signup_team_01_welcome');
|
||||
@@ -77,7 +88,7 @@ WelcomePage = React.createClass({
|
||||
<span className="black">{ this.props.state.team.email }</span><br />
|
||||
</p>
|
||||
<div className="form-group">
|
||||
<button className="btn-primary btn form-group" onClick={this.submitNext}><i className="glyphicon glyphicon-ok"></i>Yes, this address is correct</button>
|
||||
<button className="btn-primary btn form-group" type="submit" onClick={this.submitNext}><i className="glyphicon glyphicon-ok"></i>Yes, this address is correct</button>
|
||||
{ storage_error }
|
||||
</div>
|
||||
<hr />
|
||||
@@ -92,15 +103,15 @@ WelcomePage = React.createClass({
|
||||
{ email_error }
|
||||
</div>
|
||||
{ server_error }
|
||||
<button className="btn btn-md btn-primary" onClick={this.handleDiffSubmit} type="submit">Use this instead</button>
|
||||
<button className="btn btn-md btn-primary" type="button" onClick={this.handleDiffSubmit} type="submit">Use this instead</button>
|
||||
</div>
|
||||
<button onClick={this.handleDiffEmail} className={ this.state.use_diff ? "btn-default btn hidden" : "btn-default btn" }>Use a different address</button>
|
||||
<button type="button" onClick={this.handleDiffEmail} className={ this.state.use_diff ? "btn-default btn hidden" : "btn-default btn" }>Use a different address</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
TeamNamePage = React.createClass({
|
||||
TeamDisplayNamePage = React.createClass({
|
||||
submitBack: function (e) {
|
||||
e.preventDefault();
|
||||
this.props.state.wizard = "welcome";
|
||||
@@ -109,19 +120,24 @@ TeamNamePage = React.createClass({
|
||||
submitNext: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var name = this.refs.name.getDOMNode().value.trim();
|
||||
if (!name) {
|
||||
var display_name = this.refs.name.getDOMNode().value.trim();
|
||||
if (!display_name) {
|
||||
this.setState({name_error: "This field is required"});
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.state.wizard = "team_url";
|
||||
this.props.state.team.name = name;
|
||||
this.props.state.team.display_name = display_name;
|
||||
this.props.updateParent(this.props.state);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
handleFocus: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
e.currentTarget.select();
|
||||
},
|
||||
render: function() {
|
||||
|
||||
client.track('signup', 'signup_team_02_name');
|
||||
@@ -130,29 +146,31 @@ TeamNamePage = React.createClass({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||
|
||||
<h2>{utils.toTitleCase(strings.Team) + " Name"}</h2>
|
||||
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
||||
<div className="row">
|
||||
<div className="col-sm-9">
|
||||
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.name} />
|
||||
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.display_name} autoFocus={true} onFocus={this.handleFocus} />
|
||||
</div>
|
||||
</div>
|
||||
{ name_error }
|
||||
</div>
|
||||
<p>{"Your " + strings.Team + " name shows in menus and headings. It may include the name of your " + strings.Company + ", but it's not required."}</p>
|
||||
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
<button type="button" className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button type="submit" className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
TeamUrlPage = React.createClass({
|
||||
TeamURLPage = React.createClass({
|
||||
submitBack: function (e) {
|
||||
e.preventDefault();
|
||||
this.props.state.wizard = "team_name";
|
||||
this.props.state.wizard = "team_display_name";
|
||||
this.props.updateParent(this.props.state);
|
||||
},
|
||||
submitNext: function (e) {
|
||||
@@ -172,18 +190,18 @@ TeamUrlPage = React.createClass({
|
||||
return;
|
||||
}
|
||||
else if (cleaned_name.length <= 3 || cleaned_name.length > 15) {
|
||||
this.setState({name_error: "Domain must be 4 or more characters up to a maximum of 15"})
|
||||
this.setState({name_error: "Name must be 4 or more characters up to a maximum of 15"})
|
||||
return;
|
||||
}
|
||||
|
||||
for (var index = 0; index < constants.RESERVED_DOMAINS.length; index++) {
|
||||
if (cleaned_name.indexOf(constants.RESERVED_DOMAINS[index]) == 0) {
|
||||
this.setState({name_error: "This Team URL name is unavailable"})
|
||||
for (var index = 0; index < constants.RESERVED_TEAM_NAMES.length; index++) {
|
||||
if (cleaned_name.indexOf(constants.RESERVED_TEAM_NAMES[index]) == 0) {
|
||||
this.setState({name_error: "This team name is unavailable"})
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
client.findTeamByDomain(name,
|
||||
client.findTeamByName(name,
|
||||
function(data) {
|
||||
if (!data) {
|
||||
if (config.AllowSignupDomainsWizard) {
|
||||
@@ -193,7 +211,7 @@ TeamUrlPage = React.createClass({
|
||||
this.props.state.team.type = 'O';
|
||||
}
|
||||
|
||||
this.props.state.team.domain = name;
|
||||
this.props.state.team.name = name;
|
||||
this.props.updateParent(this.props.state);
|
||||
}
|
||||
else {
|
||||
@@ -210,6 +228,11 @@ TeamUrlPage = React.createClass({
|
||||
getInitialState: function() {
|
||||
return { };
|
||||
},
|
||||
handleFocus: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
e.currentTarget.select();
|
||||
},
|
||||
render: function() {
|
||||
|
||||
client.track('signup', 'signup_team_03_url');
|
||||
@@ -218,14 +241,15 @@ TeamUrlPage = React.createClass({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||
<h2>{utils.toTitleCase(strings.Team) + " URL"}</h2>
|
||||
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
||||
<div className="row">
|
||||
<div className="col-sm-9">
|
||||
<div className="input-group">
|
||||
<input type="text" ref="name" className="form-control text-right" placeholder="" maxLength="128" defaultValue={this.props.state.team.domain} />
|
||||
<span className="input-group-addon">.{ utils.getDomainWithOutSub() }</span>
|
||||
<span className="input-group-addon">{ window.location.origin + "/" }</span>
|
||||
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.name} autoFocus={true} onFocus={this.handleFocus}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -233,8 +257,9 @@ TeamUrlPage = React.createClass({
|
||||
</div>
|
||||
<p className="black">{"Pick something short and memorable for your " + strings.Team + "'s web address."}</p>
|
||||
<p>{"Your " + strings.Team + " URL can only contain lowercase letters, numbers and dashes. Also, it needs to start with a letter and cannot end in a dash."}</p>
|
||||
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
<button type="button" className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button type="submit" className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -291,6 +316,7 @@ AllowedDomainsPage = React.createClass({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||
<h2>Email Domain</h2>
|
||||
<p>
|
||||
@@ -303,7 +329,7 @@ AllowedDomainsPage = React.createClass({
|
||||
<div className="col-sm-9">
|
||||
<div className="input-group">
|
||||
<span className="input-group-addon">@</span>
|
||||
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.allowed_domains} />
|
||||
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.allowed_domains} autoFocus={true} onFocus={this.handleFocus}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -313,8 +339,9 @@ AllowedDomainsPage = React.createClass({
|
||||
<p>
|
||||
<div className="checkbox"><label><input type="checkbox" ref="open_network" defaultChecked={this.props.state.team.type == 'O'} /> Allow anyone to signup to this domain without an invitation.</label></div>
|
||||
</p>
|
||||
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
<button type="button" className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button type="submit" className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -356,7 +383,7 @@ EmailItem = React.createClass({
|
||||
|
||||
return (
|
||||
<div className={ email_error ? "form-group has-error" : "form-group" }>
|
||||
<input type="email" ref="email" className="form-control" placeholder="Email Address" defaultValue={this.props.email} maxLength="128" />
|
||||
<input autoFocus={this.props.focus} type="email" ref="email" className="form-control" placeholder="Email Address" defaultValue={this.props.email} maxLength="128" />
|
||||
{ email_error }
|
||||
</div>
|
||||
);
|
||||
@@ -424,16 +451,22 @@ SendInivtesPage = React.createClass({
|
||||
var emails = [];
|
||||
|
||||
for (var i = 0; i < this.props.state.invites.length; i++) {
|
||||
emails.push(<EmailItem key={i} ref={'email_' + i} email={this.props.state.invites[i]} />);
|
||||
if (i == 0) {
|
||||
emails.push(<EmailItem focus={true} key={i} ref={'email_' + i} email={this.props.state.invites[i]} />);
|
||||
} else {
|
||||
emails.push(<EmailItem focus={false} key={i} ref={'email_' + i} email={this.props.state.invites[i]} />);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||
<h2>Send Invitations</h2>
|
||||
{ emails }
|
||||
<div className="form-group"><button className="btn-default btn" onClick={this.submitAddInvite}>Add Invitation</button></div>
|
||||
<div className="form btn-default-group"><button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button> <button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button></div>
|
||||
<div className="form-group"><button type="button" className="btn-default btn" onClick={this.submitAddInvite}>Add Invitation</button></div>
|
||||
<div className="form btn-default-group"><button type="button" className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button> <button type="submit" className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button></div>
|
||||
</form>
|
||||
<p>{"If you'd prefer, you can send invitations after you finish setting up the "+ strings.Team + "."}</p>
|
||||
<div><a href="#" onClick={this.submitSkip}>Skip this step</a></div>
|
||||
</div>
|
||||
@@ -477,20 +510,22 @@ UsernamePage = React.createClass({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||
<h2>Choose a username</h2>
|
||||
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
||||
<div className="row">
|
||||
<div className="col-sm-9">
|
||||
<input type="text" ref="name" className="form-control" placeholder="" defaultValue={this.props.state.user.username} maxLength="128" />
|
||||
<input autoFocus={true} type="text" ref="name" className="form-control" placeholder="" defaultValue={this.props.state.user.username} maxLength="128" />
|
||||
</div>
|
||||
</div>
|
||||
{ name_error }
|
||||
</div>
|
||||
<p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others."}</p>
|
||||
<p>It can be made of lowercase letters and numbers.</p>
|
||||
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
<button type="button" className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button type="submit" className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -531,18 +566,11 @@ PasswordPage = React.createClass({
|
||||
props.state.wizard = "finished";
|
||||
props.updateParent(props.state, true);
|
||||
|
||||
if (utils.isTestDomain()) {
|
||||
UserStore.setLastDomain(teamSignup.team.domain);
|
||||
UserStore.setLastEmail(teamSignup.team.email);
|
||||
window.location.href = window.location.protocol + '//' + utils.getDomainWithOutSub() + '/login?email=' + encodeURIComponent(teamSignup.team.email);
|
||||
}
|
||||
else {
|
||||
window.location.href = window.location.protocol + '//' + teamSignup.team.domain + '.' + utils.getDomainWithOutSub() + '/login?email=' + encodeURIComponent(teamSignup.team.email);
|
||||
}
|
||||
window.location.href = window.location.origin + '/' + props.state.team.name + '/login?email=' + encodeURIComponent(teamSignup.team.email);
|
||||
|
||||
// client.loginByEmail(teamSignup.team.domain, teamSignup.team.email, teamSignup.user.password,
|
||||
// function(data) {
|
||||
// UserStore.setLastDomain(teamSignup.team.domain);
|
||||
// TeamStore.setLastName(teamSignup.team.domain);
|
||||
// UserStore.setLastEmail(teamSignup.team.email);
|
||||
// UserStore.setCurrentUser(data);
|
||||
// window.location.href = '/channels/town-square';
|
||||
@@ -570,13 +598,14 @@ PasswordPage = React.createClass({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||
<h2>Choose a password</h2>
|
||||
<p>You'll use your email address ({this.props.state.team.email}) and password to log into {config.SiteName}.</p>
|
||||
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
||||
<div className="row">
|
||||
<div className="col-sm-9">
|
||||
<input type="password" ref="password" className="form-control" placeholder="" maxLength="128" />
|
||||
<input autoFocus={true} type="password" ref="password" className="form-control" placeholder="" maxLength="128" />
|
||||
</div>
|
||||
</div>
|
||||
{ name_error }
|
||||
@@ -585,10 +614,11 @@ PasswordPage = React.createClass({
|
||||
<label><input type="checkbox" ref="email_service" /> It's ok to send me occassional email with updates about the {config.SiteName} service.</label>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button className="btn-primary btn" id="finish-button" data-loading-text={"<span class='glyphicon glyphicon-refresh glyphicon-refresh-animate'></span> Creating "+strings.Team+"..."} onClick={this.submitNext}>Finish</button>
|
||||
<button type="button" className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||
<button type="submit" className="btn-primary btn" id="finish-button" data-loading-text={"<span class='glyphicon glyphicon-refresh glyphicon-refresh-animate'></span> Creating "+strings.Team+"..."} onClick={this.submitNext}>Finish</button>
|
||||
</div>
|
||||
<p>By proceeding to create your account and use { config.SiteName }, you agree to our <a href={ config.TermsLink }>Terms of Service</a> and <a href={ config.PrivacyLink }>Privacy Policy</a>. If you do not agree, you cannot use {config.SiteName}.</p>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -596,28 +626,23 @@ PasswordPage = React.createClass({
|
||||
|
||||
module.exports = React.createClass({
|
||||
updateParent: function(state, skipSet) {
|
||||
BrowserStore.setGlobalItem(this.props.hash, JSON.stringify(state));
|
||||
BrowserStore.setGlobalItem(this.props.hash, state);
|
||||
|
||||
if (!skipSet) {
|
||||
this.setState(state);
|
||||
}
|
||||
},
|
||||
getInitialState: function() {
|
||||
var props = null;
|
||||
try {
|
||||
props = JSON.parse(BrowserStore.getGlobalItem(this.props.hash));
|
||||
}
|
||||
catch(parse_error) {
|
||||
}
|
||||
var props = BrowserStore.getGlobalItem(this.props.hash);
|
||||
|
||||
if (!props) {
|
||||
props = {};
|
||||
props.wizard = "welcome";
|
||||
props.team = {};
|
||||
props.team.email = this.props.email;
|
||||
props.team.name = this.props.name;
|
||||
props.team.display_name = this.props.name;
|
||||
props.team.company_name = this.props.name;
|
||||
props.team.domain = utils.cleanUpUrlable(this.props.name);
|
||||
props.team.name = utils.cleanUpUrlable(this.props.name);
|
||||
props.team.allowed_domains = "";
|
||||
props.invites = [];
|
||||
props.invites.push("");
|
||||
@@ -628,19 +653,19 @@ module.exports = React.createClass({
|
||||
props.data = this.props.data;
|
||||
}
|
||||
|
||||
return props ;
|
||||
return props;
|
||||
},
|
||||
render: function() {
|
||||
if (this.state.wizard == "welcome") {
|
||||
return <WelcomePage state={this.state} updateParent={this.updateParent} />
|
||||
}
|
||||
|
||||
if (this.state.wizard == "team_name") {
|
||||
return <TeamNamePage state={this.state} updateParent={this.updateParent} />
|
||||
if (this.state.wizard == "team_display_name") {
|
||||
return <TeamDisplayNamePage state={this.state} updateParent={this.updateParent} />
|
||||
}
|
||||
|
||||
if (this.state.wizard == "team_url") {
|
||||
return <TeamUrlPage state={this.state} updateParent={this.updateParent} />
|
||||
return <TeamURLPage state={this.state} updateParent={this.updateParent} />
|
||||
}
|
||||
|
||||
if (this.state.wizard == "allowed_domains") {
|
||||
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user