Commit 08a3acbb authored by =Corey Hulen's avatar =Corey Hulen

Adding team settings to admin console

parent f05a2c03
......@@ -83,7 +83,7 @@ func TestGetConfig(t *testing.T) {
} else {
cfg := result.Data.(*model.Config)
if len(cfg.ServiceSettings.SiteName) == 0 {
if len(cfg.TeamSettings.SiteName) == 0 {
t.Fatal()
}
}
......@@ -117,7 +117,7 @@ func TestSaveConfig(t *testing.T) {
} else {
cfg := result.Data.(*model.Config)
if len(cfg.ServiceSettings.SiteName) == 0 {
if len(cfg.TeamSettings.SiteName) == 0 {
t.Fatal()
}
}
......
......@@ -14,6 +14,7 @@ var Client *model.Client
func Setup() {
if Srv == nil {
utils.LoadConfig("config.json")
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
NewServer()
StartServer()
InitApi()
......
......@@ -471,7 +471,7 @@ func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request)
m := make(map[string]string)
m["Message"] = err.Message
m["Details"] = err.DetailedError
m["SiteName"] = utils.Cfg.ServiceSettings.SiteName
m["SiteName"] = utils.Cfg.TeamSettings.SiteName
m["SiteURL"] = SiteURL
w.WriteHeader(err.StatusCode)
......
......@@ -447,7 +447,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if !utils.Cfg.TeamSettings.AllowPublicLink {
if !utils.Cfg.ImageSettings.EnablePublicLink {
c.Err = model.NewAppError("getPublicLink", "Public links have been disabled", "")
c.Err.StatusCode = http.StatusForbidden
}
......
......@@ -25,7 +25,6 @@ func InitPost(r *mux.Router) {
sr := r.PathPrefix("/channels/{id:[A-Za-z0-9]+}").Subrouter()
sr.Handle("/create", ApiUserRequired(createPost)).Methods("POST")
sr.Handle("/valet_create", ApiUserRequired(createValetPost)).Methods("POST")
sr.Handle("/update", ApiUserRequired(updatePost)).Methods("POST")
sr.Handle("/posts/{offset:[0-9]+}/{limit:[0-9]+}", ApiUserRequiredActivity(getPosts, false)).Methods("GET")
sr.Handle("/posts/{time:[0-9]+}", ApiUserRequiredActivity(getPostsSince, false)).Methods("GET")
......@@ -60,75 +59,6 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
tchan := Srv.Store.Team().Get(c.Session.TeamId)
post := model.PostFromJson(r.Body)
if post == nil {
c.SetInvalidParam("createValetPost", "post")
return
}
cchan := Srv.Store.Channel().CheckOpenChannelPermissions(c.Session.TeamId, post.ChannelId)
// Any one with access to the team can post as valet to any open channel
if !c.HasPermissionsToChannel(cchan, "createValetPost") {
return
}
// Make sure this team has the valet feature enabled
if tResult := <-tchan; tResult.Err != nil {
c.Err = model.NewAppError("createValetPost", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
return
} else {
if !tResult.Data.(*model.Team).AllowValet {
c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your team administrator for details.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
}
if rp, err := CreateValetPost(c, post); err != nil {
c.Err = err
if strings.Contains(c.Err.Message, "parameter") {
c.Err.StatusCode = http.StatusBadRequest
}
return
} else {
w.Write([]byte(rp.ToJson()))
}
}
func CreateValetPost(c *Context, post *model.Post) (*model.Post, *model.AppError) {
post.Hashtags, _ = model.ParseHashtags(post.Message)
post.Filenames = []string{} // no files allowed in valet posts yet
if result := <-Srv.Store.User().GetByUsername(c.Session.TeamId, "valet"); result.Err != nil {
// if the bot doesn't exist, create it
if tresult := <-Srv.Store.Team().Get(c.Session.TeamId); tresult.Err != nil {
return nil, tresult.Err
} else {
post.UserId = (CreateValet(c, tresult.Data.(*model.Team))).Id
}
} else {
post.UserId = result.Data.(*model.User).Id
}
var rpost *model.Post
if result := <-Srv.Store.Post().Save(post); result.Err != nil {
return nil, result.Err
} else {
rpost = result.Data.(*model.Post)
}
fireAndForgetNotifications(rpost, c.Session.TeamId, c.GetSiteURL())
return rpost, nil
}
func CreatePost(c *Context, post *model.Post, doUpdateLastViewed bool) (*model.Post, *model.AppError) {
var pchan store.StoreChannel
if len(post.RootId) > 0 {
......
......@@ -123,98 +123,6 @@ func TestCreatePost(t *testing.T) {
}
}
func TestCreateValetPost(t *testing.T) {
Setup()
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{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", 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", 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.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)
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)
if utils.Cfg.TeamSettings.AllowValetDefault {
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).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)
}
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")
}
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", 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.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)
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.DoApiPost("/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")
}
}
}
func TestUpdatePost(t *testing.T) {
Setup()
......
......@@ -60,7 +60,6 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
subjectPage.Props["SiteURL"] = c.GetSiteURL()
bodyPage := NewServerTemplatePage("signup_team_body")
bodyPage.Props["SiteURL"] = c.GetSiteURL()
bodyPage.Props["TourUrl"] = utils.Cfg.TeamSettings.TourLink
props := make(map[string]string)
props["email"] = email
......@@ -124,8 +123,6 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
if result := <-Srv.Store.Team().Save(team); result.Err != nil {
c.Err = result.Err
return
......@@ -207,8 +204,6 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
teamSignup.Team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
c.Err = result.Err
return
......@@ -228,13 +223,6 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if teamSignup.Team.AllowValet {
CreateValet(c, rteam)
if c.Err != nil {
return
}
}
InviteMembers(c, rteam, ruser, teamSignup.Invites)
teamSignup.Team = *rteam
......@@ -286,13 +274,6 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
return nil
}
if rteam.AllowValet {
CreateValet(c, rteam)
if c.Err != nil {
return nil
}
}
return rteam
}
}
......@@ -301,7 +282,7 @@ func isTreamCreationAllowed(c *Context, email string) bool {
email = strings.ToLower(email)
if utils.Cfg.TeamSettings.DisableTeamCreation {
if !utils.Cfg.TeamSettings.EnableTeamCreation {
c.Err = model.NewAppError("isTreamCreationAllowed", "Team creation has been disabled. Please ask your systems administrator for details.", "")
return false
}
......@@ -567,8 +548,6 @@ func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
allowValet := allowValetStr == "true"
teamId := props["team_id"]
if len(teamId) > 0 && len(teamId) != 26 {
c.SetInvalidParam("updateValetFeature", "team_id")
......@@ -597,8 +576,6 @@ func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) {
team = tResult.Data.(*model.Team)
}
team.AllowValet = allowValet
if result := <-Srv.Store.Team().Update(team); result.Err != nil {
c.Err = result.Err
return
......
......@@ -330,79 +330,3 @@ func TestGetMyTeam(t *testing.T) {
}
}
}
func TestUpdateValetFeature(t *testing.T) {
Setup()
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", 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", 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{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", 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.Name, user2.Email, "pwd")
data := make(map[string]string)
data["allow_valet"] = "true"
if _, err := Client.UpdateValetFeature(data); err == nil {
t.Fatal("Should have errored, not admin")
}
Client.LoginByEmail(team.Name, user.Email, "pwd")
data["allow_valet"] = ""
if _, err := Client.UpdateValetFeature(data); err == nil {
t.Fatal("Should have errored, empty allow_valet field")
}
data["allow_valet"] = "true"
if _, err := Client.UpdateValetFeature(data); err != nil {
t.Fatal(err)
}
rteam := Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
if rteam.AllowValet != true {
t.Fatal("Should have errored - allow valet property not updated")
}
data["team_id"] = "junk"
if _, err := Client.UpdateValetFeature(data); err == nil {
t.Fatal("Should have errored, junk team id")
}
data["team_id"] = "12345678901234567890123456"
if _, err := Client.UpdateValetFeature(data); err == nil {
t.Fatal("Should have errored, bad team id")
}
data["team_id"] = team.Id
data["allow_valet"] = "false"
if _, err := Client.UpdateValetFeature(data); err != nil {
t.Fatal(err)
}
rteam = Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
if rteam.AllowValet != false {
t.Fatal("Should have errored - allow valet property not updated")
}
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
data["team_id"] = team.Id
data["allow_valet"] = "true"
if _, err := Client.UpdateValetFeature(data); err == nil {
t.Fatal("Should have errored, not part of team")
}
}
......@@ -155,19 +155,13 @@ func IsVerifyHashRequired(user *model.User, team *model.Team, hash string) bool
return shouldVerifyHash
}
func CreateValet(c *Context, team *model.Team) *model.User {
valet := &model.User{}
valet.TeamId = team.Id
valet.Email = utils.Cfg.EmailSettings.FeedbackEmail
valet.EmailVerified = true
valet.Username = model.BOT_USERNAME
valet.Password = model.NewId()
return CreateUser(c, team, valet)
}
func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
if !utils.Cfg.TeamSettings.EnableUserCreation {
c.Err = model.NewAppError("CreateUser", "User creation has been disabled. Please ask your systems administrator for details.", "")
return nil
}
channelRole := ""
if team.Email == user.Email {
user.Roles = model.ROLE_TEAM_ADMIN
......
......@@ -952,6 +952,7 @@ func TestUserUpdateNotify(t *testing.T) {
}
func TestFuzzyUserCreate(t *testing.T) {
Setup()
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
......
{
"ServiceSettings": {
"SiteName": "Mattermost",
"Mode": "dev",
"AllowTesting": false,
"UseSSL": false,
......@@ -16,12 +15,11 @@
"GoogleDeveloperKey": ""
},
"TeamSettings": {
"MaxUsersPerTeam": 150,
"AllowPublicLink": true,
"AllowValetDefault": false,
"TourLink": "",
"SiteName": "Mattermost",
"MaxUsersPerTeam": 50,
"DefaultThemeColor": "#2389D7",
"DisableTeamCreation": false,
"EnableTeamCreation": true,
"EnableUserCreation": true,
"RestrictCreationToDomains": ""
},
"SqlSettings": {
......@@ -44,6 +42,7 @@
"ImageSettings": {
"DriverName": "local",
"Directory": "./data/",
"EnablePublicLink": true,
"ThumbnailWidth": 120,
"ThumbnailHeight": 100,
"PreviewWidth": 1024,
......
......@@ -20,7 +20,6 @@ const (
)
type ServiceSettings struct {
SiteName string
Mode string
AllowTesting bool
UseSSL bool
......@@ -68,6 +67,7 @@ type LogSettings struct {
type ImageSettings struct {
DriverName string
Directory string
EnablePublicLink bool
ThumbnailWidth uint
ThumbnailHeight uint
PreviewWidth uint
......@@ -113,12 +113,11 @@ type PrivacySettings struct {
}
type TeamSettings struct {
SiteName string
MaxUsersPerTeam int
AllowPublicLink bool
AllowValetDefault bool
TourLink string
DefaultThemeColor string
DisableTeamCreation bool
EnableTeamCreation bool
EnableUserCreation bool
RestrictCreationToDomains string
}
......
......@@ -27,7 +27,6 @@ type Team struct {
Type string `json:"type"`
CompanyName string `json:"company_name"`
AllowedDomains string `json:"allowed_domains"`
AllowValet bool `json:"allow_valet"`
}
type Invites struct {
......
......@@ -311,26 +311,21 @@ func (ss SqlStore) CreateColumnIfNotExists(tableName string, columnName string,
}
}
// func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) bool {
func (ss SqlStore) RemoveColumnIfExists(tableName string, columnName string) bool {
// // XXX TODO FIXME this should be removed after 0.6.0
// if utils.Cfg.SqlSettings.DriverName == "postgres" {
// return false
// }
// if !ss.DoesColumnExist(tableName, columnName) {
// return false
// }
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)
// panic("Failed to drop column " + err.Error())
// }
_, 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)
panic("Failed to drop column " + err.Error())
}
// return true
// }
return true
}
// func (ss SqlStore) RenameColumnIfExists(tableName string, oldColumnName string, newColumnName string, colType string) bool {
......
......@@ -28,6 +28,7 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore {
}
func (s SqlTeamStore) UpgradeSchemaIfNeeded() {
s.RemoveColumnIfExists("Teams", "AllowValet")
}
func (s SqlTeamStore) CreateIndexesIfNotExists() {
......
......@@ -42,7 +42,7 @@ func TestUserStoreSave(t *testing.T) {
t.Fatal("should be unique username")
}
for i := 0; i < 150; i++ {
for i := 0; i < 50; i++ {
u1.Id = ""
u1.Email = model.NewId()
u1.Username = model.NewId()
......
......@@ -173,7 +173,7 @@ func getClientProperties(c *model.Config) map[string]string {
props["BuildDate"] = model.BuildDate
props["BuildHash"] = model.BuildHash
props["SiteName"] = c.ServiceSettings.SiteName
props["SiteName"] = c.TeamSettings.SiteName
props["AnalyticsUrl"] = c.ServiceSettings.AnalyticsUrl
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
......@@ -186,11 +186,10 @@ func getClientProperties(c *model.Config) map[string]string {
props["AllowSignUpWithGitLab"] = strconv.FormatBool(c.GitLabSettings.Allow)
props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress)
props["AllowPublicLink"] = strconv.FormatBool(c.TeamSettings.AllowPublicLink)
props["EnablePublicLink"] = strconv.FormatBool(c.ImageSettings.EnablePublicLink)
props["ProfileHeight"] = fmt.Sprintf("%v", c.ImageSettings.ProfileHeight)
props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth)
return props
}
......@@ -14,6 +14,8 @@ var PrivacySettingsTab = require('./privacy_settings.jsx');
var RateSettingsTab = require('./rate_settings.jsx');
var GitLabSettingsTab = require('./gitlab_settings.jsx');
var SqlSettingsTab = require('./sql_settings.jsx');
var TeamSettingsTab = require('./team_settings.jsx');
export default class AdminController extends React.Component {
constructor(props) {
......@@ -24,7 +26,7 @@ export default class AdminController extends React.Component {
this.state = {
config: null,
selected: 'sql_settings'
selected: 'team_settings'
};
}
......@@ -68,6 +70,8 @@ export default class AdminController extends React.Component {
tab = <GitLabSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'sql_settings') {
tab = <SqlSettingsTab config={this.state.config} />;
} else if (this.state.selected === 'team_settings') {
tab = <TeamSettingsTab config={this.state.config} />;
}
}
......
......@@ -38,6 +38,15 @@ export default class AdminSidebar extends React.Component {
<ul className='nav nav-pills nav-stacked'>
<li>
<ul className='nav nav__sub-menu'>
<li>
<a
href='#'
className={this.isSelected('team_settings')}
onClick={this.handleClick.bind(this, 'team_settings')}
>
{'Team Settings'}
</a>
</li>
<li>
<a
href='#'
......
......@@ -39,6 +39,7 @@ export default class ImageSettings extends React.Component {
config.ImageSettings.AmazonS3SecretAccessKey = React.findDOMNode(this.refs.AmazonS3SecretAccessKey).value;
config.ImageSettings.AmazonS3Bucket = React.findDOMNode(this.refs.AmazonS3Bucket).value;
config.ImageSettings.AmazonS3Region = React.findDOMNode(this.refs.AmazonS3Region).value;
config.ImageSettings.EnablePublicLink = React.findDOMNode(this.refs.EnablePublicLink).checked;
var thumbnailWidth = 120;
if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10))) {
......@@ -390,6 +391,39 @@ export default class ImageSettings extends React.Component {
</div>
</div>
<div className='form-group'>
<label
className='control-label col-sm-4'
htmlFor='EnablePublicLink'
>
{'Share Public File Link: '}
</label>
<div className='col-sm-8'>
<label className='radio-inline'>
<input
type='radio'
name='EnablePublicLink'
value='true'
ref='EnablePublicLink'
defaultChecked={this.props.config.ImageSettings.EnablePublicLink}
onChange={this.handleChange}
/>
{'true'}
</label>
<label className='radio-inline'>
<input
type='radio'
name='EnablePublicLink'
value='false'
defaultChecked={!this.props.config.ImageSettings.EnablePublicLink}
onChange={this.handleChange}
/>
{'false'}
</label>
<p className='help-text'>{'Allow users to share public links to files and images.'}</p>
</div>
</div>
<div className='form-group'>
<div className='col-sm-12'>