in internal/repo/activity_common/follow.go [164:265]
func (ar *FollowRepo) MigrateFollowers(ctx context.Context, sourceObjectID, targetObjectID, action string) error {
// if source object id and target object id are same type
sourceObjectTypeStr, err := obj.GetObjectTypeStrByObjectID(sourceObjectID)
if err != nil {
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
targetObjectTypeStr, err := obj.GetObjectTypeStrByObjectID(targetObjectID)
if err != nil {
return errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
if sourceObjectTypeStr != targetObjectTypeStr {
return errors.InternalServer(reason.DisallowFollow).WithMsg("not same object type")
}
activityType, err := ar.activityRepo.GetActivityTypeByObjectType(ctx, sourceObjectTypeStr, action)
if err != nil {
return err
}
// 1. get all user ids who follow the source object
userIDs, err := ar.GetFollowUserIDs(ctx, sourceObjectID)
if err != nil {
log.Errorf("MigrateFollowers: failed to get user ids who follow %s: %v", sourceObjectID, err)
return err
}
_, err = ar.data.DB.Transaction(func(session *xorm.Session) (result any, err error) {
session = session.Context(ctx)
// 1. delete all follows of the source object
_, err = session.Table(entity.Activity{}.TableName()).
Where(builder.Eq{
"object_id": sourceObjectID,
"activity_type": activityType,
}).
Delete(&entity.Activity{})
if err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
// 2. update cancel status to active for target tag if source tag followers is active
_, err = session.Table(entity.Activity{}.TableName()).
Where(builder.Eq{
"object_id": targetObjectID,
"activity_type": activityType,
}).
And(builder.In("user_id", userIDs)).
Cols("cancelled").
Update(&entity.Activity{
Cancelled: entity.ActivityAvailable,
})
if err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
// 3. get existing follows of the target object
targetFollowers := make([]string, 0)
err = session.Table(entity.Activity{}.TableName()).
Where(builder.Eq{
"object_id": targetObjectID,
"activity_type": activityType,
"cancelled": entity.ActivityAvailable,
}).
Cols("user_id").
Find(&targetFollowers)
if err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
// 4. filter out user ids that already follow the target object and create new activity
// Create a map for faster lookup of existing followers
existingFollowers := make(map[string]bool)
for _, uid := range targetFollowers {
existingFollowers[uid] = true
}
// Filter out users who already follow the target
newFollowers := make([]string, 0)
for _, uid := range userIDs {
if !existingFollowers[uid] {
newFollowers = append(newFollowers, uid)
}
}
// Create new activities for the filtered users
for _, uid := range newFollowers {
activity := &entity.Activity{
UserID: uid,
ObjectID: targetObjectID,
OriginalObjectID: targetObjectID,
ActivityType: activityType,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Cancelled: entity.ActivityAvailable,
}
if _, err = session.Insert(activity); err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
}
return nil, nil
})
return err
}