mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
fix: allow to create labels for aliased projects (resolve #231)
This commit is contained in:
parent
03b104a390
commit
67f0d19a65
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,11 @@ func (m *AliasServiceMock) GetByUser(s string) ([]*models.Alias, error) {
|
|||||||
return args.Get(0).([]*models.Alias), args.Error(1)
|
return args.Get(0).([]*models.Alias), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *AliasServiceMock) GetByUserAndType(s string, u uint8) ([]*models.Alias, error) {
|
||||||
|
args := m.Called(s, u)
|
||||||
|
return args.Get(0).([]*models.Alias), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *AliasServiceMock) GetByUserAndKeyAndType(s string, s2 string, u uint8) ([]*models.Alias, error) {
|
func (m *AliasServiceMock) GetByUserAndKeyAndType(s string, s2 string, u uint8) ([]*models.Alias, error) {
|
||||||
args := m.Called(s, s2, u)
|
args := m.Called(s, s2, u)
|
||||||
return args.Get(0).([]*models.Alias), args.Error(1)
|
return args.Get(0).([]*models.Alias), args.Error(1)
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/muety/wakapi/middlewares"
|
"github.com/muety/wakapi/middlewares"
|
||||||
"github.com/muety/wakapi/models"
|
"github.com/muety/wakapi/models"
|
||||||
"github.com/muety/wakapi/models/view"
|
"github.com/muety/wakapi/models/view"
|
||||||
|
routeutils "github.com/muety/wakapi/routes/utils"
|
||||||
"github.com/muety/wakapi/services"
|
"github.com/muety/wakapi/services"
|
||||||
"github.com/muety/wakapi/services/imports"
|
"github.com/muety/wakapi/services/imports"
|
||||||
"github.com/muety/wakapi/utils"
|
"github.com/muety/wakapi/utils"
|
||||||
@ -669,12 +670,11 @@ func (h *SettingsHandler) buildViewModel(r *http.Request) *view.SettingsViewMode
|
|||||||
})
|
})
|
||||||
|
|
||||||
// projects
|
// projects
|
||||||
projects, err := h.heartbeatSrvc.GetEntitySetByUser(models.SummaryProject, user)
|
projects, err := routeutils.GetEffectiveProjectsList(user, h.heartbeatSrvc, h.aliasSrvc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conf.Log().Request(r).Error("error while fetching projects - %v", err)
|
conf.Log().Request(r).Error("error while fetching projects - %v", err)
|
||||||
return &view.SettingsViewModel{Error: criticalError}
|
return &view.SettingsViewModel{Error: criticalError}
|
||||||
}
|
}
|
||||||
sort.Strings(projects)
|
|
||||||
|
|
||||||
return &view.SettingsViewModel{
|
return &view.SettingsViewModel{
|
||||||
User: user,
|
User: user,
|
||||||
|
53
routes/utils/project_utils.go
Normal file
53
routes/utils/project_utils.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/muety/wakapi/models"
|
||||||
|
"github.com/muety/wakapi/services"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEffectiveProjectsList returns the user's projects, including all alias targets and excluding all remapped project names (alias sources)
|
||||||
|
// Example: "A" mapped to "AB" using an alias
|
||||||
|
// -> "A" itself should not appear as a project anymore
|
||||||
|
// -> Instead, the "virtual" project "AB" shall appear
|
||||||
|
// See https://github.com/muety/wakapi/issues/231
|
||||||
|
func GetEffectiveProjectsList(user *models.User, heartbeatSrvc services.IHeartbeatService, aliasSrvc services.IAliasService) ([]string, error) {
|
||||||
|
projectsMap := make(map[string]bool) // proper sets as part of stdlib would be nice...
|
||||||
|
|
||||||
|
// extract actual projects from heartbeats
|
||||||
|
realProjects, err := heartbeatSrvc.GetEntitySetByUser(models.SummaryProject, user)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a "set" / lookup table
|
||||||
|
for _, p := range realProjects {
|
||||||
|
projectsMap[p] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch aliases
|
||||||
|
projectAliases, err := aliasSrvc.GetByUserAndType(user.ID, models.SummaryProject)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove alias values (source of a mapping)
|
||||||
|
// add alias key (target of a mapping) instead
|
||||||
|
for _, a := range projectAliases {
|
||||||
|
if projectsMap[a.Value] {
|
||||||
|
projectsMap[a.Value] = false
|
||||||
|
}
|
||||||
|
projectsMap[a.Key] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
projects := make([]string, 0, len(projectsMap))
|
||||||
|
for key, val := range projectsMap {
|
||||||
|
if !val {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
projects = append(projects, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(projects)
|
||||||
|
return projects, nil
|
||||||
|
}
|
@ -56,21 +56,18 @@ func (srv *AliasService) GetByUser(userId string) ([]*models.Alias, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srv *AliasService) GetByUserAndType(userId string, summaryType uint8) ([]*models.Alias, error) {
|
||||||
|
check := func(a *models.Alias) bool {
|
||||||
|
return a.Type == summaryType
|
||||||
|
}
|
||||||
|
return srv.getFiltered(userId, check)
|
||||||
|
}
|
||||||
|
|
||||||
func (srv *AliasService) GetByUserAndKeyAndType(userId, key string, summaryType uint8) ([]*models.Alias, error) {
|
func (srv *AliasService) GetByUserAndKeyAndType(userId, key string, summaryType uint8) ([]*models.Alias, error) {
|
||||||
if !srv.IsInitialized(userId) {
|
check := func(a *models.Alias) bool {
|
||||||
srv.MayInitializeUser(userId)
|
return a.Key == key && a.Type == summaryType
|
||||||
}
|
|
||||||
if aliases, ok := userAliases.Load(userId); ok {
|
|
||||||
filteredAliases := make([]*models.Alias, 0, len(aliases.([]*models.Alias)))
|
|
||||||
for _, a := range aliases.([]*models.Alias) {
|
|
||||||
if a.Key == key && a.Type == summaryType {
|
|
||||||
filteredAliases = append(filteredAliases, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filteredAliases, nil
|
|
||||||
} else {
|
|
||||||
return nil, errors.New(fmt.Sprintf("no user aliases loaded for user %s", userId))
|
|
||||||
}
|
}
|
||||||
|
return srv.getFiltered(userId, check)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *AliasService) GetAliasOrDefault(userId string, summaryType uint8, value string) (string, error) {
|
func (srv *AliasService) GetAliasOrDefault(userId string, summaryType uint8, value string) (string, error) {
|
||||||
@ -94,7 +91,11 @@ func (srv *AliasService) Create(alias *models.Alias) (*models.Alias, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// manually update cache
|
||||||
|
srv.updateCache(alias, false)
|
||||||
|
// reload entire cache (async, though)
|
||||||
go srv.MayInitializeUser(alias.UserID)
|
go srv.MayInitializeUser(alias.UserID)
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +104,14 @@ func (srv *AliasService) Delete(alias *models.Alias) error {
|
|||||||
return errors.New("no user id specified")
|
return errors.New("no user id specified")
|
||||||
}
|
}
|
||||||
err := srv.repository.Delete(alias.ID)
|
err := srv.repository.Delete(alias.ID)
|
||||||
|
|
||||||
|
// manually update cache
|
||||||
|
if err == nil {
|
||||||
|
srv.updateCache(alias, false)
|
||||||
|
}
|
||||||
|
// reload entire cache (async, though)
|
||||||
go srv.MayInitializeUser(alias.UserID)
|
go srv.MayInitializeUser(alias.UserID)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,9 +128,53 @@ func (srv *AliasService) DeleteMulti(aliases []*models.Alias) error {
|
|||||||
|
|
||||||
err := srv.repository.DeleteBatch(ids)
|
err := srv.repository.DeleteBatch(ids)
|
||||||
|
|
||||||
|
// manually update cache
|
||||||
|
if err == nil {
|
||||||
|
for _, a := range aliases {
|
||||||
|
srv.updateCache(a, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reload entire cache (async, though)
|
||||||
for k := range affectedUsers {
|
for k := range affectedUsers {
|
||||||
go srv.MayInitializeUser(k)
|
go srv.MayInitializeUser(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srv *AliasService) updateCache(reason *models.Alias, removal bool) {
|
||||||
|
if !removal {
|
||||||
|
if aliases, ok := userAliases.Load(reason.UserID); ok {
|
||||||
|
updatedAliases := aliases.([]*models.Alias)
|
||||||
|
updatedAliases = append(updatedAliases, reason)
|
||||||
|
userAliases.Store(reason.UserID, updatedAliases)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if aliases, ok := userAliases.Load(reason.UserID); ok {
|
||||||
|
updatedAliases := make([]*models.Alias, 0, len(aliases.([]*models.Alias))) // if we only had generics...
|
||||||
|
for _, a := range aliases.([]*models.Alias) {
|
||||||
|
if a.ID != reason.ID {
|
||||||
|
updatedAliases = append(updatedAliases, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userAliases.Store(reason.UserID, updatedAliases)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *AliasService) getFiltered(userId string, check func(alias *models.Alias) bool) ([]*models.Alias, error) {
|
||||||
|
if !srv.IsInitialized(userId) {
|
||||||
|
srv.MayInitializeUser(userId)
|
||||||
|
}
|
||||||
|
if aliases, ok := userAliases.Load(userId); ok {
|
||||||
|
filteredAliases := make([]*models.Alias, 0, len(aliases.([]*models.Alias)))
|
||||||
|
for _, a := range aliases.([]*models.Alias) {
|
||||||
|
if check(a) {
|
||||||
|
filteredAliases = append(filteredAliases, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredAliases, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(fmt.Sprintf("no user aliases loaded for user %s", userId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ type IAliasService interface {
|
|||||||
IsInitialized(string) bool
|
IsInitialized(string) bool
|
||||||
InitializeUser(string) error
|
InitializeUser(string) error
|
||||||
GetByUser(string) ([]*models.Alias, error)
|
GetByUser(string) ([]*models.Alias, error)
|
||||||
|
GetByUserAndType(string, uint8) ([]*models.Alias, error)
|
||||||
GetByUserAndKeyAndType(string, string, uint8) ([]*models.Alias, error)
|
GetByUserAndKeyAndType(string, string, uint8) ([]*models.Alias, error)
|
||||||
GetAliasOrDefault(string, uint8, string) (string, error)
|
GetAliasOrDefault(string, uint8, string) (string, error)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user