diff --git a/api/events.go b/api/events.go index d392ef41..b14a8371 100644 --- a/api/events.go +++ b/api/events.go @@ -8,7 +8,7 @@ import ( "github.com/gorilla/context" ) -//nolint: gocyclo +// nolint: gocyclo func getEvents(w http.ResponseWriter, r *http.Request, limit int) { user := context.Get(r, "user").(*db.User) projectObj, exists := context.GetOk(r, "project") @@ -19,7 +19,9 @@ func getEvents(w http.ResponseWriter, r *http.Request, limit int) { if exists { project := projectObj.(db.Project) - _, err = helpers.Store(r).GetProjectUser(project.ID, user.ID) + if !user.Admin { // check permissions to view events + _, err = helpers.Store(r).GetProjectUser(project.ID, user.ID) + } if err != nil { helpers.WriteError(w, err) diff --git a/api/projects/project.go b/api/projects/project.go index 6dcadede..d3c01a8d 100644 --- a/api/projects/project.go +++ b/api/projects/project.go @@ -26,7 +26,7 @@ func ProjectMiddleware(next http.Handler) http.Handler { // check if user in project's team projectUser, err := helpers.Store(r).GetProjectUser(projectID, user.ID) - if err != nil { + if !user.Admin && err != nil { helpers.WriteError(w, err) return } diff --git a/api/projects/projects.go b/api/projects/projects.go index 83f3f3e4..a3c219c1 100644 --- a/api/projects/projects.go +++ b/api/projects/projects.go @@ -14,7 +14,13 @@ import ( func GetProjects(w http.ResponseWriter, r *http.Request) { user := context.Get(r, "user").(*db.User) - projects, err := helpers.Store(r).GetProjects(user.ID) + var err error + var projects []db.Project + if user.Admin { + projects, err = helpers.Store(r).GetAllProjects() + } else { + projects, err = helpers.Store(r).GetProjects(user.ID) + } if err != nil { helpers.WriteError(w, err) diff --git a/api/projects/users.go b/api/projects/users.go index c185e604..46415cdc 100644 --- a/api/projects/users.go +++ b/api/projects/users.go @@ -1,6 +1,7 @@ package projects import ( + "fmt" "github.com/ansible-semaphore/semaphore/api/helpers" "github.com/ansible-semaphore/semaphore/db" "net/http" @@ -108,24 +109,30 @@ func AddUser(w http.ResponseWriter, r *http.Request) { // RemoveUser removes a user from a project team func RemoveUser(w http.ResponseWriter, r *http.Request) { project := context.Get(r, "project").(db.Project) - projectUser := context.Get(r, "projectUser").(db.User) + me := context.Get(r, "user").(*db.User) // logged in user + targetUser := context.Get(r, "projectUser").(db.User) // target user + targetUserRole := context.Get(r, "projectUserRole").(db.ProjectUserRole) - err := helpers.Store(r).DeleteProjectUser(project.ID, projectUser.ID) + if !me.Admin && targetUser.ID == me.ID && targetUserRole == db.ProjectOwner { + helpers.WriteError(w, fmt.Errorf("owner can not left the project")) + return + } + + err := helpers.Store(r).DeleteProjectUser(project.ID, targetUser.ID) if err != nil { helpers.WriteError(w, err) return } - user := context.Get(r, "user").(*db.User) objType := db.EventUser - desc := "User ID " + strconv.Itoa(projectUser.ID) + " removed from team" + desc := "User ID " + strconv.Itoa(targetUser.ID) + " removed from team" _, err = helpers.Store(r).CreateEvent(db.Event{ - UserID: &user.ID, + UserID: &me.ID, ProjectID: &project.ID, ObjectType: &objType, - ObjectID: &projectUser.ID, + ObjectID: &targetUser.ID, Description: &desc, }) @@ -138,7 +145,14 @@ func RemoveUser(w http.ResponseWriter, r *http.Request) { func UpdateUser(w http.ResponseWriter, r *http.Request) { project := context.Get(r, "project").(db.Project) - user := context.Get(r, "projectUser").(db.User) + me := context.Get(r, "user").(*db.User) // logged in user + targetUser := context.Get(r, "projectUser").(db.User) + targetUserRole := context.Get(r, "projectUserRole").(db.ProjectUserRole) + + if !me.Admin && targetUser.ID == me.ID && targetUserRole == db.ProjectOwner { + helpers.WriteError(w, fmt.Errorf("owner can not change his role in the project")) + return + } var projectUser struct { Role db.ProjectUserRole `json:"role"` @@ -154,7 +168,7 @@ func UpdateUser(w http.ResponseWriter, r *http.Request) { } err := helpers.Store(r).UpdateProjectUser(db.ProjectUser{ - UserID: user.ID, + UserID: targetUser.ID, ProjectID: project.ID, Role: projectUser.Role, }) diff --git a/api/users.go b/api/users.go index 5146dcdc..7b488a1d 100644 --- a/api/users.go +++ b/api/users.go @@ -73,7 +73,7 @@ func getUserMiddleware(next http.Handler) http.Handler { } func updateUser(w http.ResponseWriter, r *http.Request) { - oldUser := context.Get(r, "_user").(db.User) + targetUser := context.Get(r, "_user").(db.User) editor := context.Get(r, "user").(*db.User) var user db.UserWithPwd @@ -81,25 +81,25 @@ func updateUser(w http.ResponseWriter, r *http.Request) { return } - if !editor.Admin && editor.ID != oldUser.ID { + if !editor.Admin && editor.ID != targetUser.ID { log.Warn(editor.Username + " is not permitted to edit users") w.WriteHeader(http.StatusUnauthorized) return } - if editor.ID == oldUser.ID && oldUser.Admin != user.Admin { + if editor.ID == targetUser.ID && targetUser.Admin != user.Admin { log.Warn("User can't edit his own role") w.WriteHeader(http.StatusUnauthorized) return } - if oldUser.External && oldUser.Username != user.Username { + if targetUser.External && targetUser.Username != user.Username { log.Warn("Username is not editable for external users") w.WriteHeader(http.StatusBadRequest) return } - user.ID = oldUser.ID + user.ID = targetUser.ID if err := helpers.Store(r).UpdateUser(user); err != nil { log.Error(err.Error()) w.WriteHeader(http.StatusBadRequest) diff --git a/db/ProjectUser.go b/db/ProjectUser.go index a5a75714..7977e15c 100644 --- a/db/ProjectUser.go +++ b/db/ProjectUser.go @@ -7,6 +7,7 @@ const ( ProjectManager ProjectUserRole = "manager" ProjectTaskRunner ProjectUserRole = "task_runner" ProjectGuest ProjectUserRole = "guest" + ProjectNone ProjectUserRole = "" ) type ProjectUserPermission int @@ -37,11 +38,6 @@ type ProjectUser struct { Role ProjectUserRole `db:"role" json:"role"` } -func (u *ProjectUser) Can(permissions ProjectUserPermission) bool { - userPermissions := rolePermissions[u.Role] - return (userPermissions & permissions) == permissions -} - func (r ProjectUserRole) Can(permissions ProjectUserPermission) bool { return (rolePermissions[r] & permissions) == permissions } diff --git a/db/Store.go b/db/Store.go index 22d41cb2..fedb67ad 100644 --- a/db/Store.go +++ b/db/Store.go @@ -143,6 +143,7 @@ type Store interface { GetUserByLoginOrEmail(login string, email string) (User, error) GetProject(projectID int) (Project, error) + GetAllProjects() ([]Project, error) GetProjects(userID int) ([]Project, error) CreateProject(project Project) (Project, error) DeleteProject(projectID int) error diff --git a/db/bolt/project.go b/db/bolt/project.go index b36c0e20..45156808 100644 --- a/db/bolt/project.go +++ b/db/bolt/project.go @@ -17,6 +17,12 @@ func (d *BoltDb) CreateProject(project db.Project) (db.Project, error) { return newProject.(db.Project), nil } +func (d *BoltDb) GetAllProjects() (projects []db.Project, err error) { + err = d.getObjects(0, db.ProjectProps, db.RetrieveQueryParams{}, nil, &projects) + + return +} + func (d *BoltDb) GetProjects(userID int) (projects []db.Project, err error) { projects = make([]db.Project, 0) diff --git a/db/sql/project.go b/db/sql/project.go index 63e36e1e..4f787402 100644 --- a/db/sql/project.go +++ b/db/sql/project.go @@ -23,6 +23,21 @@ func (d *SqlDb) CreateProject(project db.Project) (newProject db.Project, err er return } +func (d *SqlDb) GetAllProjects() (projects []db.Project, err error) { + query, args, err := squirrel.Select("p.*"). + From("project as p"). + OrderBy("p.name"). + ToSql() + + if err != nil { + return + } + + _, err = d.selectAll(&projects, query, args...) + + return +} + func (d *SqlDb) GetProjects(userID int) (projects []db.Project, err error) { query, args, err := squirrel.Select("p.*"). From("project as p"). diff --git a/web/src/App.vue b/web/src/App.vue index 7e6c1d0e..353c22a8 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -314,11 +314,14 @@ v-on="on" > - mdi-account + mdi-account - {{ user.name }} + + {{ user.name }} + admin + @@ -366,6 +369,7 @@ :projectId="projectId" :userPermissions="userRole.permissions" :userId="user ? user.id : null" + :isAdmin="user ? user.admin : false" > diff --git a/web/src/components/ItemListPageBase.js b/web/src/components/ItemListPageBase.js index 979438ea..98064544 100644 --- a/web/src/components/ItemListPageBase.js +++ b/web/src/components/ItemListPageBase.js @@ -18,6 +18,7 @@ export default { projectId: Number, userId: Number, userPermissions: Number, + isAdmin: Boolean, }, data() { @@ -51,6 +52,9 @@ export default { }, can(permission) { + if (this.isAdmin) { + return true; + } // eslint-disable-next-line no-bitwise return (this.userPermissions & permission) === permission; }, diff --git a/web/src/views/project/New.vue b/web/src/views/project/New.vue index 8c61f6c7..fe052ad2 100644 --- a/web/src/views/project/New.vue +++ b/web/src/views/project/New.vue @@ -8,7 +8,7 @@
- +