diff options
-rw-r--r-- | api/context.go | 10 | ||||
-rw-r--r-- | api/post.go | 11 | ||||
-rw-r--r-- | api/post_test.go | 14 | ||||
-rw-r--r-- | web/react/components/post_info.jsx | 3 | ||||
-rw-r--r-- | web/react/components/search_bar.jsx | 2 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_headers.scss | 7 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_modal.scss | 2 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_responsive.scss | 9 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_search.scss | 13 |
9 files changed, 51 insertions, 20 deletions
diff --git a/api/context.go b/api/context.go index bea0fbeff..054e42e2e 100644 --- a/api/context.go +++ b/api/context.go @@ -265,6 +265,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) diff --git a/api/post.go b/api/post.go index 02f997166..efca2f570 100644 --- a/api/post.go +++ b/api/post.go @@ -634,16 +634,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 @@ -655,7 +656,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 diff --git a/api/post_test.go b/api/post_test.go index 970307759..5009ff54d 100644 --- a/api/post_test.go +++ b/api/post_test.go @@ -483,6 +483,10 @@ func TestDeletePosts(t *testing.T) { team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + userAdmin := &model.User{TeamId: team.Id, Email: team.Email, FullName: "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", FullName: "Corey Hulen", Password: "pwd"} user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User) store.Must(Srv.Store.User().VerifyEmail(user1.Id)) @@ -521,8 +525,16 @@ 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.Domain, userAdmin.Email, "pwd") + + Client.Must(Client.DeletePost(channel1.Id, post4.Id)) } func TestEmailMention(t *testing.T) { diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index cf01747f0..48efa95ba 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -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) { @@ -36,7 +37,7 @@ module.exports = React.createClass({ <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> : "" } diff --git a/web/react/components/search_bar.jsx b/web/react/components/search_bar.jsx index ab7e99d60..f21f0cd58 100644 --- a/web/react/components/search_bar.jsx +++ b/web/react/components/search_bar.jsx @@ -92,7 +92,7 @@ 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 diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index d876d8b37..c2740891a 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -157,6 +157,7 @@ font-size: 14px; line-height: 50px; #member_popover { + margin-right: 5px; width: 45px; color: #999; cursor: pointer; @@ -232,12 +233,16 @@ vertical-align: top; display: inline-block; width: 15px; - margin: 9px 3px 3px 0; + margin: 9px 4px 3px 0; &:hover { svg { fill: #888; } } + a { + height: 100%; + display: block; + } svg { vertical-align: top; margin-top: 8px; diff --git a/web/sass-files/sass/partials/_modal.scss b/web/sass-files/sass/partials/_modal.scss index 1b0338884..f359037c5 100644 --- a/web/sass-files/sass/partials/_modal.scss +++ b/web/sass-files/sass/partials/_modal.scss @@ -155,7 +155,7 @@ position: relative; max-width: 90%; min-height: 50px; - min-width: 280px; + min-width: 320px; @include border-radius(3px); display: table; margin: 0 auto; diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss index 1f9643175..a33d69378 100644 --- a/web/sass-files/sass/partials/_responsive.scss +++ b/web/sass-files/sass/partials/_responsive.scss @@ -432,13 +432,16 @@ color: #fff; .search__form { border: none; - padding: 0 10px 0 30px; + padding: 0 60px 0 25px; .form-control { + line-height: 31px; background: none; color: #fff; - border-bottom: 1px solid rgba(#fff, 0.7); border-radius: 0; - padding: 0 10px 0 23px; + padding: 0 10px 0; + @include input-placeholder { + color: rgba(#fff, 0.6); + } } ::-webkit-input-placeholder { color: #fff; diff --git a/web/sass-files/sass/partials/_search.scss b/web/sass-files/sass/partials/_search.scss index 8d51d00c0..d4a4da243 100644 --- a/web/sass-files/sass/partials/_search.scss +++ b/web/sass-files/sass/partials/_search.scss @@ -2,21 +2,20 @@ padding: 8px 8px 8px 0; } .sidebar__collapse { - width: 20px; - height: 30px; + width: auto; + height: auto; position: absolute; - top: 10px; - left: 6px; + top: 17px; + right: 15px; cursor: pointer; - background: url("../images/arrow-left.png") center no-repeat; - @include background-size(10px 15px); z-index: 5; display: none; } .sidebar__search-icon { position: absolute; - left: 40px; + left: 15px; top: 18px; + font-size: 16px; @include opacity(0.8); display: none; } |