fix(filters): add task to buckets of saved filters when creating the task
This commit is contained in:
parent
327905bb90
commit
5cc420b289
@ -23,7 +23,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
|
|
||||||
"code.vikunja.io/api/pkg/db"
|
"code.vikunja.io/api/pkg/db"
|
||||||
"code.vikunja.io/api/pkg/events"
|
"code.vikunja.io/api/pkg/events"
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
@ -66,6 +65,7 @@ func RegisterListeners() {
|
|||||||
events.RegisterListener((&TaskAttachmentDeletedEvent{}).Name(), &HandleTaskUpdateLastUpdated{})
|
events.RegisterListener((&TaskAttachmentDeletedEvent{}).Name(), &HandleTaskUpdateLastUpdated{})
|
||||||
events.RegisterListener((&TaskRelationCreatedEvent{}).Name(), &HandleTaskUpdateLastUpdated{})
|
events.RegisterListener((&TaskRelationCreatedEvent{}).Name(), &HandleTaskUpdateLastUpdated{})
|
||||||
events.RegisterListener((&TaskRelationDeletedEvent{}).Name(), &HandleTaskUpdateLastUpdated{})
|
events.RegisterListener((&TaskRelationDeletedEvent{}).Name(), &HandleTaskUpdateLastUpdated{})
|
||||||
|
events.RegisterListener((&TaskCreatedEvent{}).Name(), &UpdateTaskInSavedFilterViews{})
|
||||||
if config.TypesenseEnabled.GetBool() {
|
if config.TypesenseEnabled.GetBool() {
|
||||||
events.RegisterListener((&TaskDeletedEvent{}).Name(), &RemoveTaskFromTypesense{})
|
events.RegisterListener((&TaskDeletedEvent{}).Name(), &RemoveTaskFromTypesense{})
|
||||||
events.RegisterListener((&TaskCreatedEvent{}).Name(), &AddTaskToTypesense{})
|
events.RegisterListener((&TaskCreatedEvent{}).Name(), &AddTaskToTypesense{})
|
||||||
@ -671,6 +671,91 @@ func (s *DecreaseAttachmentCounter) Handle(_ *message.Message) (err error) {
|
|||||||
return keyvalue.DecrBy(metrics.AttachmentsCountKey, 1)
|
return keyvalue.DecrBy(metrics.AttachmentsCountKey, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateTaskInSavedFilterViews represents a listener
|
||||||
|
type UpdateTaskInSavedFilterViews struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name defines the name for the UpdateTaskInSavedFilterViews listener
|
||||||
|
func (l *UpdateTaskInSavedFilterViews) Name() string {
|
||||||
|
return "task.set.saved.filter.views"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle is executed when the event UpdateTaskInSavedFilterViews listens on is fired
|
||||||
|
func (l *UpdateTaskInSavedFilterViews) Handle(msg *message.Message) (err error) {
|
||||||
|
event := &TaskCreatedEvent{}
|
||||||
|
err = json.Unmarshal(msg.Payload, event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// This operation is potentially very resource-heavy, because we don't know if a task is included
|
||||||
|
// in a filter until we evaluate that filter. We need to evaluate each filter individually - since
|
||||||
|
// there can be many filters, this can take a while to execute.
|
||||||
|
// For this reason, we do this in an asynchronous event listener.
|
||||||
|
|
||||||
|
s := db.NewSession()
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
// Get all saved filters with a manual kanban view
|
||||||
|
kanbanFilterViews := []*ProjectView{}
|
||||||
|
err = s.Where("project_id < 0 and view_kind = ? and bucket_configuration_mode = ?", ProjectViewKindKanban, BucketConfigurationModeManual).
|
||||||
|
Find(&kanbanFilterViews)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filterIDs := []int64{}
|
||||||
|
for _, view := range kanbanFilterViews {
|
||||||
|
filterIDs = append(filterIDs, getSavedFilterIDFromProjectID(view.ProjectID))
|
||||||
|
}
|
||||||
|
|
||||||
|
filters := map[int64]*SavedFilter{}
|
||||||
|
err = s.In("id", filterIDs).Find(&filters)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := user.GetUserByID(s, event.Doer.GetID())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
doerTimezone := u.Timezone
|
||||||
|
|
||||||
|
taskBuckets := []*TaskBucket{}
|
||||||
|
taskPositions := []*TaskPosition{}
|
||||||
|
|
||||||
|
for _, view := range kanbanFilterViews {
|
||||||
|
filter, exists := filters[getSavedFilterIDFromProjectID(view.ProjectID)]
|
||||||
|
if !exists {
|
||||||
|
log.Debugf("Did not find filter for view %d", view.ID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
taskBucket, taskPosition, err := addTaskToFilter(s, filter, view, doerTimezone, event.Task)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if taskBucket != nil && taskPosition != nil {
|
||||||
|
taskBuckets = append(taskBuckets, taskBucket)
|
||||||
|
taskPositions = append(taskPositions, taskPosition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(taskBuckets) > 0 || len(taskPositions) > 0 {
|
||||||
|
_, err = s.Insert(taskBuckets)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = s.Insert(taskPositions)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
///////
|
///////
|
||||||
// Project Event Listeners
|
// Project Event Listeners
|
||||||
|
|
||||||
|
@ -18,8 +18,11 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
"xorm.io/builder"
|
||||||
|
|
||||||
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/user"
|
"code.vikunja.io/api/pkg/user"
|
||||||
|
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
@ -214,3 +217,54 @@ func (sf *SavedFilter) Delete(s *xorm.Session, _ web.Auth) error {
|
|||||||
Delete(sf)
|
Delete(sf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addTaskToFilter(s *xorm.Session, filter *SavedFilter, view *ProjectView, fallbackTimezone string, task *Task) (taskBucket *TaskBucket, taskPosition *TaskPosition, err error) {
|
||||||
|
|
||||||
|
filterString := filter.Filters.Filter
|
||||||
|
|
||||||
|
if filter.Filters.FilterTimezone == "" {
|
||||||
|
filter.Filters.FilterTimezone = fallbackTimezone
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedFilters, err := getTaskFiltersFromFilterString(filterString, filter.Filters.FilterTimezone)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Could not parse filter string '%s' from view %d and saved filter %d: %v", filterString, view.ID, filter.ID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filterCond, err := convertFiltersToDBFilterCond(parsedFilters, filter.Filters.FilterIncludeNulls)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Could not convert filter string '%s' from view %d and saved filter %d to db conditions: %v", filterString, view.ID, filter.ID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
taskIsInCurrentFilterAndView, err := s.Where(builder.And(
|
||||||
|
filterCond,
|
||||||
|
builder.Eq{"id": task.ID},
|
||||||
|
)).Exist(&Task{})
|
||||||
|
if !taskIsInCurrentFilterAndView {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketID, err := getDefaultBucketID(s, view)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
taskBucket = &TaskBucket{
|
||||||
|
BucketID: bucketID,
|
||||||
|
TaskID: task.ID,
|
||||||
|
ProjectViewID: view.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
taskPosition = &TaskPosition{
|
||||||
|
TaskID: task.ID,
|
||||||
|
ProjectViewID: view.ID,
|
||||||
|
Position: calculateDefaultPosition(task.Index, task.Position),
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user