summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/command.go6
-rw-r--r--api/file.go2
-rw-r--r--api/post.go6
-rw-r--r--api/post_test.go98
-rw-r--r--api/team.go8
-rw-r--r--api/user.go4
-rw-r--r--config/config.json1
-rw-r--r--utils/config.go1
-rw-r--r--web/react/components/settings_sidebar.jsx6
-rw-r--r--web/react/components/user_settings.jsx5
-rw-r--r--web/react/components/view_image.jsx2
-rw-r--r--web/react/utils/client.jsx4
-rw-r--r--web/templates/head.html33
13 files changed, 109 insertions, 67 deletions
diff --git a/api/command.go b/api/command.go
index 9efc79b49..449483bbf 100644
--- a/api/command.go
+++ b/api/command.go
@@ -19,12 +19,16 @@ var commands = []commandHandler{
logoutCommand,
joinCommand,
loadTestCommand,
- echoCommand,
}
func InitCommand(r *mux.Router) {
l4g.Debug("Initializing command api routes")
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
+
+ if utils.Cfg.TeamSettings.AllowValet {
+ commands = append(commands, echoCommand)
+ }
+
hub.Start()
}
diff --git a/api/file.go b/api/file.go
index c7c3b7b3e..10167c6ff 100644
--- a/api/file.go
+++ b/api/file.go
@@ -114,7 +114,7 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- fileUrl := c.TeamUrl + "/api/v1/files/get/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + files[i].Filename
+ fileUrl := c.TeamUrl + "/api/v1/files/get/" + channelId + "/" + c.Session.UserId + "/" + uid + "/" + url.QueryEscape(files[i].Filename)
resStruct.Filenames = append(resStruct.Filenames, fileUrl)
}
diff --git a/api/post.go b/api/post.go
index 25a68304d..36607c231 100644
--- a/api/post.go
+++ b/api/post.go
@@ -58,6 +58,12 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
}
func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
+ if !utils.Cfg.TeamSettings.AllowValet {
+ c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your system administrator for details.", "")
+ c.Err.StatusCode = http.StatusNotImplemented
+ return
+ }
+
post := model.PostFromJson(r.Body)
if post == nil {
c.SetInvalidParam("createValetPost", "post")
diff --git a/api/post_test.go b/api/post_test.go
index 4b40bc06a..b322a5017 100644
--- a/api/post_test.go
+++ b/api/post_test.go
@@ -147,62 +147,70 @@ func TestCreateValetPost(t *testing.T) {
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
- post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
- rpost1, err := Client.CreateValetPost(post1)
- if err != nil {
- t.Fatal(err)
- }
+ if utils.Cfg.TeamSettings.AllowValet {
+ post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
+ rpost1, err := Client.CreateValetPost(post1)
+ if err != nil {
+ t.Fatal(err)
+ }
- if rpost1.Data.(*model.Post).Message != post1.Message {
- t.Fatal("message didn't match")
- }
+ if rpost1.Data.(*model.Post).Message != post1.Message {
+ t.Fatal("message didn't match")
+ }
- if rpost1.Data.(*model.Post).Hashtags != "#hashtag" {
- t.Fatal("hashtag didn't match")
- }
+ if rpost1.Data.(*model.Post).Hashtags != "#hashtag" {
+ t.Fatal("hashtag didn't match")
+ }
- post2 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
- rpost2, err := Client.CreateValetPost(post2)
- if err != nil {
- t.Fatal(err)
- }
+ post2 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
+ rpost2, err := Client.CreateValetPost(post2)
+ if err != nil {
+ t.Fatal(err)
+ }
- post3 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: rpost2.Data.(*model.Post).Id}
- _, err = Client.CreateValetPost(post3)
- if err != nil {
- t.Fatal(err)
- }
+ post3 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id, ParentId: rpost2.Data.(*model.Post).Id}
+ _, err = Client.CreateValetPost(post3)
+ if err != nil {
+ t.Fatal(err)
+ }
- post4 := &model.Post{ChannelId: "junk", Message: "a" + model.NewId() + "a"}
- _, err = Client.CreateValetPost(post4)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
+ post4 := &model.Post{ChannelId: "junk", Message: "a" + model.NewId() + "a"}
+ _, err = Client.CreateValetPost(post4)
+ if err.StatusCode != http.StatusForbidden {
+ t.Fatal("Should have been forbidden")
+ }
- Client.LoginByEmail(team.Domain, user2.Email, "pwd")
- post5 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
- _, err = Client.CreateValetPost(post5)
- if err != nil {
- t.Fatal(err)
- }
+ Client.LoginByEmail(team.Domain, 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 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
- Srv.Store.User().VerifyEmail(user3.Id)
+ user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
+ user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
+ Srv.Store.User().VerifyEmail(user3.Id)
- Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
+ Client.LoginByEmail(team2.Domain, 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)
+ 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)
- post6 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
- _, err = Client.CreateValetPost(post6)
- if err.StatusCode != http.StatusForbidden {
- t.Fatal("Should have been forbidden")
- }
+ post6 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
+ _, err = Client.CreateValetPost(post6)
+ if err.StatusCode != http.StatusForbidden {
+ t.Fatal("Should have been forbidden")
+ }
- if _, err = Client.DoPost("/channels/"+channel3.Id+"/create", "garbage"); err == nil {
- t.Fatal("should have been an error")
+ if _, err = Client.DoPost("/channels/"+channel3.Id+"/create", "garbage"); err == nil {
+ t.Fatal("should have been an error")
+ }
+ } else {
+ post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
+ _, err := Client.CreateValetPost(post1)
+ if err.StatusCode != http.StatusNotImplemented {
+ t.Fatal("Should have failed with 501 - Not Implemented")
+ }
}
}
diff --git a/api/team.go b/api/team.go
index b04d8c588..cb60602c6 100644
--- a/api/team.go
+++ b/api/team.go
@@ -157,9 +157,11 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
- CreateValet(c, rteam)
- if c.Err != nil {
- return
+ if utils.Cfg.TeamSettings.AllowValet {
+ CreateValet(c, rteam)
+ if c.Err != nil {
+ return
+ }
}
InviteMembers(rteam, ruser, teamSignup.Invites)
diff --git a/api/user.go b/api/user.go
index c0ebc05e0..83e29b28e 100644
--- a/api/user.go
+++ b/api/user.go
@@ -145,6 +145,10 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
}
func CreateValet(c *Context, team *model.Team) *model.User {
+ if !utils.Cfg.TeamSettings.AllowValet {
+ return &model.User{}
+ }
+
valet := &model.User{}
valet.TeamId = team.Id
valet.Email = utils.Cfg.EmailSettings.FeedbackEmail
diff --git a/config/config.json b/config/config.json
index 4eab907f7..a6c79efac 100644
--- a/config/config.json
+++ b/config/config.json
@@ -72,6 +72,7 @@
"TeamSettings": {
"MaxUsersPerTeam": 150,
"AllowPublicLink": true,
+ "AllowValet": false,
"TermsLink": "/static/help/configure_links.html",
"PrivacyLink": "/static/help/configure_links.html",
"AboutLink": "/static/help/configure_links.html",
diff --git a/utils/config.go b/utils/config.go
index b6688de68..1060c7550 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -96,6 +96,7 @@ type PrivacySettings struct {
type TeamSettings struct {
MaxUsersPerTeam int
AllowPublicLink bool
+ AllowValet bool
TermsLink string
PrivacyLink string
AboutLink string
diff --git a/web/react/components/settings_sidebar.jsx b/web/react/components/settings_sidebar.jsx
index 34e3c9203..a1546890f 100644
--- a/web/react/components/settings_sidebar.jsx
+++ b/web/react/components/settings_sidebar.jsx
@@ -14,11 +14,13 @@ module.exports = React.createClass({
<li className={this.props.activeTab == 'general' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("general");}}><i className="glyphicon glyphicon-cog"></i>General</a></li>
<li className={this.props.activeTab == 'security' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("security");}}><i className="glyphicon glyphicon-lock"></i>Security</a></li>
<li className={this.props.activeTab == 'notifications' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("notifications");}}><i className="glyphicon glyphicon-exclamation-sign"></i>Notifications</a></li>
- <li className={this.props.activeTab == 'sessions' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("sessions");}}><i className="glyphicon glyphicon-globe"></i>Sessions</a></li>
- <li className={this.props.activeTab == 'activity_log' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("activity_log");}}><i className="glyphicon glyphicon-time"></i>Activity Log</a></li>
<li className={this.props.activeTab == 'appearance' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("appearance");}}><i className="glyphicon glyphicon-wrench"></i>Appearance</a></li>
</ul>
</div>
);
+ /* Temporarily removing sessions and activity logs
+ <li className={this.props.activeTab == 'sessions' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("sessions");}}><i className="glyphicon glyphicon-globe"></i>Sessions</a></li>
+ <li className={this.props.activeTab == 'activity_log' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("activity_log");}}><i className="glyphicon glyphicon-time"></i>Activity Log</a></li>
+ */
}
});
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index b165a59ad..a9c2433f2 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -1126,6 +1126,9 @@ module.exports = React.createClass({
<NotificationsTab user={this.state.user} activeSection={this.props.activeSection} updateSection={this.props.updateSection} />
</div>
);
+
+ /* Temporarily removing sessions and activity_log tabs
+
} else if (this.props.activeTab === 'sessions') {
return (
<div>
@@ -1138,6 +1141,8 @@ module.exports = React.createClass({
<AuditTab activeSection={this.props.activeSection} updateSection={this.props.updateSection} />
</div>
);
+ */
+
} else if (this.props.activeTab === 'appearance') {
return (
<div>
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index 7d0f0d8a9..4cb30e1d3 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -165,7 +165,7 @@ module.exports = React.createClass({
<span className="text"> | </span>
</div>
: "" }
- <a href={this.props.filenames[id]} download={name} className="text">Download</a>
+ <a href={this.props.filenames[id]} download={decodeURIComponent(name)} className="text">Download</a>
</div>
</div>
{loading}
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
index b83ee22e7..786e6dcea 100644
--- a/web/react/utils/client.jsx
+++ b/web/react/utils/client.jsx
@@ -4,12 +4,12 @@
module.exports.track = function(category, action, label, prop, val) {
global.window.snowplow('trackStructEvent', category, action, label, prop, val);
- if (global.window.analytics != null) global.window.analytics.track(action, {category: category, label: label, property: prop, value: val});
+ global.window.analytics.track(action, {category: category, label: label, property: prop, value: val});
};
module.exports.trackPage = function() {
global.window.snowplow('trackPageView');
- if (global.window.analytics != null) global.window.analytics.page();
+ global.window.analytics.page();
};
function handleError(method_name, xhr, status, err) {
diff --git a/web/templates/head.html b/web/templates/head.html
index 5fd3ee104..5eb7a7333 100644
--- a/web/templates/head.html
+++ b/web/templates/head.html
@@ -36,6 +36,7 @@
window._LTracker = _LTracker;
_LTracker.push({'logglyKey': config.LogglyWriteKey, 'sendConsoleErrors' : config.LogglyConsoleErrors });
} else {
+ window._LTracker = [];
console.warn("config.js missing LogglyWriteKey, Loggly analytics is not reporting");
}
</script>
@@ -58,26 +59,34 @@
analytics.page();
}}();
} else {
+ analytics = {};
+ analytics.page = function(){};
+ analytics.track = function(){};
console.warn("config.js missing SegmentWriteKey, SegmentIO analytics is not tracking");
}
</script>
<!-- Snowplow starts plowing -->
<script type="text/javascript">
- ;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
- p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
- };p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
- n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","snowplow"));
+ if ('{{ .Props.AnalyticsUrl }}'.trim() !== '') {
+ ;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
+ p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
+ };p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
+ n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","snowplow"));
- window.snowplow('newTracker', 'cf', '{{ .Props.AnalyticsUrl }}', {
- appId: '{{ .SiteName }}'
- });
+ window.snowplow('newTracker', 'cf', '{{ .Props.AnalyticsUrl }}', {
+ appId: '{{ .SiteName }}'
+ });
- var user = window.UserStore.getCurrentUser(true);
- if (user) {
- window.snowplow('setUserId', user.id);
- }
+ var user = window.UserStore.getCurrentUser(true);
+ if (user) {
+ window.snowplow('setUserId', user.id);
+ }
- window.snowplow('trackPageView');
+ window.snowplow('trackPageView');
+ } else {
+ window.snowplow = function(){};
+ console.warn("config.json missing AnalyticsUrl, Snowplow analytics is not tracking");
+ }
</script>
<!-- Snowplow stops plowing -->
</head>