2024-11-23 20:29:53 -05:00
package chore
import (
"context"
"errors"
config "donetick.com/core/config"
chModel "donetick.com/core/internal/chore/model"
lModel "donetick.com/core/internal/label/model"
"donetick.com/core/logging"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type LabelRepository struct {
db * gorm . DB
}
func NewLabelRepository ( db * gorm . DB , cfg * config . Config ) * LabelRepository {
return & LabelRepository { db : db }
}
func ( r * LabelRepository ) GetUserLabels ( ctx context . Context , userID int , circleID int ) ( [ ] * lModel . Label , error ) {
var labels [ ] * lModel . Label
if err := r . db . WithContext ( ctx ) . Where ( "created_by = ? OR circle_id = ? " , userID , circleID ) . Find ( & labels ) . Error ; err != nil {
return nil , err
}
return labels , nil
}
func ( r * LabelRepository ) CreateLabels ( ctx context . Context , labels [ ] * lModel . Label ) error {
if err := r . db . WithContext ( ctx ) . Create ( & labels ) . Error ; err != nil {
return err
}
return nil
}
func ( r * LabelRepository ) GetLabelsByIDs ( ctx context . Context , ids [ ] int ) ( [ ] * lModel . Label , error ) {
var labels [ ] * lModel . Label
if err := r . db . WithContext ( ctx ) . Where ( "id IN (?)" , ids ) . Find ( & labels ) . Error ; err != nil {
return nil , err
}
return labels , nil
}
func ( r * LabelRepository ) isLabelsAssignableByUser ( ctx context . Context , userID int , circleID int , toBeAdded [ ] int , toBeRemoved [ ] int ) bool {
// combine both toBeAdded and toBeRemoved:
labelIDs := append ( toBeAdded , toBeRemoved ... )
log := logging . FromContext ( ctx )
var count int64
if err := r . db . WithContext ( ctx ) . Model ( & lModel . Label { } ) . Where ( "id IN (?) AND (created_by = ? OR circle_id = ?) " , labelIDs , userID , circleID ) . Count ( & count ) . Error ; err != nil {
log . Error ( err )
return false
}
return count == int64 ( len ( labelIDs ) )
}
func ( r * LabelRepository ) AssignLabelsToChore ( ctx context . Context , choreID int , userID int , circleID int , toBeAdded [ ] int , toBeRemoved [ ] int ) error {
if len ( toBeAdded ) < 1 && len ( toBeRemoved ) < 1 {
return nil
}
if ! r . isLabelsAssignableByUser ( ctx , userID , circleID , toBeAdded , toBeRemoved ) {
return errors . New ( "labels are not assignable by user" )
}
var choreLabels [ ] * chModel . ChoreLabels
for _ , labelID := range toBeAdded {
choreLabels = append ( choreLabels , & chModel . ChoreLabels {
ChoreID : choreID ,
LabelID : labelID ,
UserID : userID ,
} )
}
return r . db . WithContext ( ctx ) . Transaction ( func ( tx * gorm . DB ) error {
2024-11-27 19:14:16 -05:00
if len ( toBeRemoved ) > 0 {
if err := r . db . WithContext ( ctx ) . Where ( "chore_id = ? AND user_id = ? AND label_id IN (?)" , choreID , userID , toBeRemoved ) . Delete ( & chModel . ChoreLabels { } ) . Error ; err != nil {
return err
}
2024-11-23 20:29:53 -05:00
}
2024-11-27 19:14:16 -05:00
if len ( toBeAdded ) > 0 {
if err := r . db . WithContext ( ctx ) . Clauses ( clause . OnConflict {
Columns : [ ] clause . Column { { Name : "chore_id" } , { Name : "label_id" } , { Name : "user_id" } } ,
DoNothing : true ,
} ) . Create ( & choreLabels ) . Error ; err != nil {
return err
}
2024-11-23 20:29:53 -05:00
}
return nil
} )
}
func ( r * LabelRepository ) DeassignLabelsFromChore ( ctx context . Context , choreID int , userID int , labelIDs [ ] int ) error {
if err := r . db . WithContext ( ctx ) . Where ( "chore_id = ? AND user_id = ? AND label_id IN (?)" , choreID , userID , labelIDs ) . Delete ( & chModel . ChoreLabels { } ) . Error ; err != nil {
return err
}
return nil
}
func ( r * LabelRepository ) DeassignLabelFromAllChoreAndDelete ( ctx context . Context , userID int , labelID int ) error {
// create one transaction to confirm if the label is owned by the user then delete all ChoreLabels record for this label:
return r . db . WithContext ( ctx ) . Transaction ( func ( tx * gorm . DB ) error {
log := logging . FromContext ( ctx )
var labelCount int64
if err := tx . Model ( & lModel . Label { } ) . Where ( "id = ? AND created_by = ?" , labelID , userID ) . Count ( & labelCount ) . Error ; err != nil {
log . Debug ( err )
return err
}
if labelCount < 1 {
return errors . New ( "label is not owned by user" )
}
if err := tx . Where ( "label_id = ?" , labelID ) . Delete ( & chModel . ChoreLabels { } ) . Error ; err != nil {
log . Debug ( "Error deleting chore labels" )
return err
}
// delete the actual label:
if err := tx . Where ( "id = ?" , labelID ) . Delete ( & lModel . Label { } ) . Error ; err != nil {
log . Debug ( "Error deleting label" )
return err
}
return nil
} )
}
func ( r * LabelRepository ) isLabelsOwner ( ctx context . Context , userID int , labelIDs [ ] int ) bool {
var count int64
r . db . WithContext ( ctx ) . Model ( & lModel . Label { } ) . Where ( "id IN (?) AND user_id = ?" , labelIDs , userID ) . Count ( & count )
return count == 1
}
func ( r * LabelRepository ) DeleteLabels ( ctx context . Context , userID int , ids [ ] int ) error {
// remove all ChoreLabels record for this:
if r . isLabelsOwner ( ctx , userID , ids ) {
return errors . New ( "labels are not owned by user" )
}
tx := r . db . WithContext ( ctx ) . Begin ( )
if err := tx . Where ( "label_id IN (?)" , ids ) . Delete ( & chModel . ChoreLabels { } ) . Error ; err != nil {
tx . Rollback ( )
return err
}
if err := tx . Where ( "id IN (?)" , ids ) . Delete ( & lModel . Label { } ) . Error ; err != nil {
tx . Rollback ( )
return err
}
if err := tx . Commit ( ) . Error ; err != nil {
tx . Rollback ( )
return err
}
return nil
}
func ( r * LabelRepository ) UpdateLabel ( ctx context . Context , userID int , label * lModel . Label ) error {
if err := r . db . WithContext ( ctx ) . Model ( & lModel . Label { } ) . Where ( "id = ? and created_by = ?" , label . ID , userID ) . Updates ( label ) . Error ; err != nil {
return err
}
return nil
}