Add 'project' to user table, add 'manager' role, conditional web render

- Addresses issues #40 #45 #82
- Reworked Navigation Header for all roles
- 'Manager' role added, can be assigned a project-id in config by admins
- BREAKING! -> Added 'project' column in SQLite3 table 'user'
- Manager-Assigned project will be added to all graphql filters: Only show Jobs and Users of given project
- 'My Jobs' Tab for all Roles
- Switched from Bool "isAdmin" to integer authLevels
- Removed critical data frontend logging
- Reworked repo.query.SecurityCheck()
This commit is contained in:
Christoph Kluge
2023-01-27 18:36:58 +01:00
parent 834f9d9085
commit b2aed2f16b
33 changed files with 433 additions and 92 deletions

View File

@@ -21,16 +21,17 @@ import (
func (auth *Authentication) GetUser(username string) (*User, error) {
user := &User{Username: username}
var hashedPassword, name, rawRoles, email sql.NullString
if err := sq.Select("password", "ldap", "name", "roles", "email").From("user").
var hashedPassword, name, rawRoles, email, project sql.NullString
if err := sq.Select("password", "ldap", "name", "roles", "email", "project").From("user").
Where("user.username = ?", username).RunWith(auth.db).
QueryRow().Scan(&hashedPassword, &user.AuthSource, &name, &rawRoles, &email); err != nil {
QueryRow().Scan(&hashedPassword, &user.AuthSource, &name, &rawRoles, &email, &project); err != nil {
return nil, err
}
user.Password = hashedPassword.String
user.Name = name.String
user.Email = email.String
user.Project = project.String
if rawRoles.Valid {
if err := json.Unmarshal([]byte(rawRoles.String), &user.Roles); err != nil {
return nil, err
@@ -54,6 +55,10 @@ func (auth *Authentication) AddUser(user *User) error {
cols = append(cols, "email")
vals = append(vals, user.Email)
}
if user.Project != "" {
cols = append(cols, "project")
vals = append(vals, user.Project)
}
if user.Password != "" {
password, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
@@ -67,7 +72,7 @@ func (auth *Authentication) AddUser(user *User) error {
return err
}
log.Infof("new user %#v created (roles: %s, auth-source: %d)", user.Username, rolesJson, user.AuthSource)
log.Infof("new user %#v created (roles: %s, auth-source: %d, project: %s)", user.Username, rolesJson, user.AuthSource, user.Project)
return nil
}
@@ -79,7 +84,7 @@ func (auth *Authentication) DelUser(username string) error {
func (auth *Authentication) ListUsers(specialsOnly bool) ([]*User, error) {
q := sq.Select("username", "name", "email", "roles").From("user")
q := sq.Select("username", "name", "email", "roles", "project").From("user")
if specialsOnly {
q = q.Where("(roles != '[\"user\"]' AND roles != '[]')")
}
@@ -94,8 +99,8 @@ func (auth *Authentication) ListUsers(specialsOnly bool) ([]*User, error) {
for rows.Next() {
rawroles := ""
user := &User{}
var name, email sql.NullString
if err := rows.Scan(&user.Username, &name, &email, &rawroles); err != nil {
var name, email, project sql.NullString
if err := rows.Scan(&user.Username, &name, &email, &rawroles, &project); err != nil {
return nil, err
}
@@ -105,6 +110,7 @@ func (auth *Authentication) ListUsers(specialsOnly bool) ([]*User, error) {
user.Name = name.String
user.Email = email.String
user.Project = project.String
users = append(users, user)
}
return users, nil
@@ -145,6 +151,10 @@ func (auth *Authentication) RemoveRole(ctx context.Context, username string, rol
return fmt.Errorf("invalid user role: %#v", role)
}
if (role == RoleManager && len(user.Project) != 0) {
return fmt.Errorf("Cannot remove role 'manager' while user %#v still has an assigned project!", username)
}
var exists bool
var newroles []string
for _, r := range user.Roles {
@@ -166,9 +176,53 @@ func (auth *Authentication) RemoveRole(ctx context.Context, username string, rol
}
}
func (auth *Authentication) AddProject(
ctx context.Context,
username string,
project string) error {
user, err := auth.GetUser(username)
if err != nil {
return err
}
if !user.HasRole(RoleManager) {
return fmt.Errorf("user '%#v' is not a manager!", username)
}
if user.HasProject(project) {
return fmt.Errorf("user '%#v' already manages project '%#v'", username, project)
}
if _, err := sq.Update("user").Set("project", project).Where("user.username = ?", username).RunWith(auth.db).Exec(); err != nil {
return err
}
return nil
}
func (auth *Authentication) RemoveProject(ctx context.Context, username string, project string) error {
user, err := auth.GetUser(username)
if err != nil {
return err
}
if !user.HasRole(RoleManager) {
return fmt.Errorf("user '%#v' is not a manager!", username)
}
if !user.HasProject(project) {
return fmt.Errorf("user '%#v': Cannot remove project '%#v' - Does not match!", username, project)
}
if _, err := sq.Update("user").Set("project", "").Where("user.username = ?", username).Where("user.project = ?", project).RunWith(auth.db).Exec(); err != nil {
return err
}
return nil
}
func FetchUser(ctx context.Context, db *sqlx.DB, username string) (*model.User, error) {
me := GetUser(ctx)
if me != nil && me.Username != username && me.HasNotRoles([]string{RoleAdmin, RoleSupport}) {
if me != nil && me.Username != username && me.HasNotRoles([]string{RoleAdmin, RoleSupport, RoleManager}) {
return nil, errors.New("forbidden")
}
@@ -185,5 +239,6 @@ func FetchUser(ctx context.Context, db *sqlx.DB, username string) (*model.User,
user.Name = name.String
user.Email = email.String
// user.Project = project.String
return user, nil
}