Enregistrement et affichage d'un flux d'évènements

- Ajout d'une nouvelle entité "Event"
- Affichage d'une "timeline" sur le tableau de bord
- Création semi-automatique des évènements lors des modifications par
  les utilisateurs
This commit is contained in:
2020-10-02 16:37:24 +02:00
parent 61eacefd6c
commit f169169bc7
27 changed files with 692 additions and 98 deletions

View File

@ -1,19 +1,55 @@
package model
import (
"encoding/json"
"time"
"github.com/jinzhu/gorm"
"github.com/jinzhu/gorm/dialects/postgres"
errs "github.com/pkg/errors"
)
const ObjectTypeDecisionSupportFile = "dsf"
type DecisionSupportFile struct {
gorm.Model
Title string `json:"title"`
Sections postgres.Jsonb `json:"sections"`
Status string `json:"status"`
WorkgroupID uint `json:"-"`
Workgroup *Workgroup `json:"workgroup"`
VotedAt time.Time `json:"votedAt"`
ClosedAt time.Time `json:"closedAt"`
Title string `json:"title"`
SectionsJSON postgres.Jsonb `json:"-" gorm:"column:sections;"`
Sections map[string]interface{} `gorm:"-"`
Status string `json:"status"`
WorkgroupID uint `json:"-"`
Workgroup *Workgroup `json:"workgroup" gorm:"association_autoupdate:false"`
VotedAt time.Time `json:"votedAt"`
ClosedAt time.Time `json:"closedAt"`
}
func (f *DecisionSupportFile) ObjectID() uint {
return f.ID
}
func (f *DecisionSupportFile) ObjectType() string {
return ObjectTypeDecisionSupportFile
}
func (f *DecisionSupportFile) BeforeSave() error {
rawSections, err := json.Marshal(f.Sections)
if err != nil {
return errs.WithStack(err)
}
f.SectionsJSON = postgres.Jsonb{RawMessage: rawSections}
return nil
}
func (f *DecisionSupportFile) AfterFind() (err error) {
sections := make(map[string]interface{})
if err := json.Unmarshal(f.SectionsJSON.RawMessage, &sections); err != nil {
return errs.WithStack(err)
}
f.Sections = sections
return nil
}

View File

@ -2,11 +2,9 @@ package model
import (
"context"
"encoding/json"
"errors"
"github.com/jinzhu/gorm"
"github.com/jinzhu/gorm/dialects/postgres"
errs "github.com/pkg/errors"
)
@ -69,12 +67,7 @@ func (r *DSFRepository) updateFromChanges(dsf *DecisionSupportFile, changes *Dec
dsf.Workgroup = wg
if changes.Sections != nil {
rawSections, err := json.Marshal(changes.Sections)
if err != nil {
return errs.WithStack(err)
}
dsf.Sections = postgres.Jsonb{RawMessage: rawSections}
dsf.Sections = changes.Sections
}
if changes.Title != nil {

31
internal/model/event.go Normal file
View File

@ -0,0 +1,31 @@
package model
import (
"github.com/jinzhu/gorm"
)
type EventType string
const (
EventTypeCreated EventType = "created"
EventTypeUpdated EventType = "updated"
EventTypeLeaved EventType = "leaved"
EventTypeJoined EventType = "joined"
EventTypeClosed EventType = "closed"
EventTypeStatusChanged EventType = "status-changed"
EventTypeTitleChanged EventType = "title-changed"
)
type EventObject interface {
ObjectID() uint
ObjectType() string
}
type Event struct {
gorm.Model
UserID uint `json:"-"`
User *User `json:"user" gorm:"association_autoupdate:false"`
ObjectType string `json:"objectType"`
ObjectID uint `json:"objectId"`
Type EventType `json:"type"`
}

View File

@ -0,0 +1,73 @@
package model
import (
"context"
"github.com/jinzhu/gorm"
errs "github.com/pkg/errors"
)
type EventRepository struct {
db *gorm.DB
}
func (r *EventRepository) Add(ctx context.Context, user *User, eventType EventType, obj EventObject) (*Event, error) {
evt := &Event{
Type: eventType,
User: user,
ObjectID: obj.ObjectID(),
ObjectType: obj.ObjectType(),
}
if err := r.db.Save(&evt).Error; err != nil {
return nil, errs.WithStack(err)
}
return evt, nil
}
func (r *EventRepository) Search(ctx context.Context, filter *EventFilter) ([]*Event, error) {
query := r.db.Model(&Event{}).Preload("User")
if filter == nil {
filter = &EventFilter{}
}
if filter.ObjectID != nil {
query = query.Where("object_id = ?", filter.ObjectID)
}
if filter.ObjectType != nil {
query = query.Where("object_type = ?", filter.ObjectType)
}
if filter.UserID != nil {
query = query.Where("user_id = ?", filter.UserID)
}
if filter.Type != nil {
query = query.Where("type = ?", filter.Type)
}
if filter.From != nil {
query = query.Where("created_at >= ?", filter.From)
}
if filter.To != nil {
query = query.Where("created_at <= ?", filter.To)
}
query = query.Order("created_at DESC")
events := make([]*Event, 0)
if err := query.Find(&events).Error; err != nil {
return nil, errs.WithStack(err)
}
return events, nil
}
func NewEventRepository(db *gorm.DB) *EventRepository {
return &EventRepository{db}
}

View File

@ -11,7 +11,7 @@ type User struct {
Name *string `json:"name"`
Email string `json:"email" gorm:"unique;not null"`
ConnectedAt time.Time `json:"connectedAt"`
Workgroups []*Workgroup `gorm:"many2many:users_workgroups;"`
Workgroups []*Workgroup `gorm:"many2many:users_workgroups;association_autoupdate:false"`
}
type ProfileChanges struct {

View File

@ -6,11 +6,21 @@ import (
"github.com/jinzhu/gorm"
)
const ObjectTypeWorkgroup = "workgroup"
type Workgroup struct {
gorm.Model
Name *string `json:"name"`
ClosedAt time.Time `json:"closedAt"`
Members []*User `gorm:"many2many:users_workgroups;"`
Members []*User `gorm:"many2many:users_workgroups;association_autoupdate:false"`
}
func (w *Workgroup) ObjectID() uint {
return w.ID
}
func (w *Workgroup) ObjectType() string {
return ObjectTypeWorkgroup
}
type WorkgroupChanges struct {

View File

@ -106,29 +106,35 @@ func (r *WorkgroupRepository) AddUserToWorkgroup(ctx context.Context, userID, wo
}
func (r *WorkgroupRepository) RemoveUserFromWorkgroup(ctx context.Context, userID, workgroupID uint) (*Workgroup, error) {
user := &User{}
err := r.db.First(user, "id = ?", userID).Error
if err != nil {
return nil, errors.Wrap(err, "could not find user")
}
workgroup := &Workgroup{}
workgroup.ID = workgroupID
err = r.db.Model(user).
Association("Workgroups").
Delete(workgroup).
Error
err := r.db.Transaction(func(tx *gorm.DB) error {
user := &User{}
err := tx.First(user, "id = ?", userID).Error
if err != nil {
return errors.Wrap(err, "could not find user")
}
if err != nil {
return nil, errors.Wrap(err, "could not add user to workgroup")
}
err = tx.Model(user).
Association("Workgroups").
Delete(workgroup).
Error
err = r.db.Model(workgroup).
Preload("Members").
First(workgroup, "id = ?", workgroupID).
Error
if err != nil {
return errors.Wrap(err, "could not add user to workgroup")
}
err = tx.Model(workgroup).
Preload("Members").
First(workgroup, "id = ?", workgroupID).
Error
if err != nil {
return errors.WithStack(err)
}
return nil
})
if err != nil {
return nil, errors.WithStack(err)
}