204 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package services
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"git.solsynth.dev/hypernet/nexus/pkg/nex/localize"
 | 
						|
	"git.solsynth.dev/hypernet/passport/pkg/authkit/models"
 | 
						|
	"git.solsynth.dev/hypernet/passport/pkg/internal/database"
 | 
						|
	"github.com/rs/zerolog/log"
 | 
						|
)
 | 
						|
 | 
						|
func NewPunishment(in models.Punishment, moderator ...models.Account) (models.Punishment, error) {
 | 
						|
	if len(moderator) > 0 {
 | 
						|
		in.Moderator = &moderator[0]
 | 
						|
		in.ModeratorID = &moderator[0].ID
 | 
						|
	}
 | 
						|
 | 
						|
	// If user got more than 2 strikes, it will upgrade to limited
 | 
						|
	if in.Type == models.PunishmentTypeStrike {
 | 
						|
		var count int64
 | 
						|
		if err := database.C.Model(&models.Punishment{}).
 | 
						|
			Where("account_id = ? AND type = ?", in.AccountID, models.PunishmentTypeStrike).
 | 
						|
			Count(&count).Error; err != nil {
 | 
						|
			return in, err
 | 
						|
		}
 | 
						|
		if count > 2 {
 | 
						|
			in.Type = models.PunishmentTypeLimited
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if err := database.C.Create(&in).Error; err != nil {
 | 
						|
		return in, err
 | 
						|
	} else {
 | 
						|
		moderator := "System"
 | 
						|
		if in.Moderator != nil {
 | 
						|
			moderator = fmt.Sprintf("@%s", in.Moderator.Name)
 | 
						|
		}
 | 
						|
		err = NewNotification(models.Notification{
 | 
						|
			Topic:     "passport.punishments",
 | 
						|
			Title:     localize.L.GetLocalizedString("subjectPunishmentCreated", in.Account.Language),
 | 
						|
			Subtitle:  fmt.Sprintf(localize.L.GetLocalizedString("subtitlePunishment", in.Account.Language), in.ID, moderator),
 | 
						|
			Body:      fmt.Sprintf(localize.L.GetLocalizedString("shortBodyPunishmentCreated", in.Account.Language), in.Reason),
 | 
						|
			Account:   in.Account,
 | 
						|
			AccountID: in.Account.ID,
 | 
						|
			Metadata:  map[string]any{"punishment": in},
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			log.Warn().Err(err).Uint("case", in.ID).Msg("Failed to delivery punishment via notify...")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return in, nil
 | 
						|
}
 | 
						|
 | 
						|
func EditPunishment(in models.Punishment) (models.Punishment, error) {
 | 
						|
	if err := database.C.Save(&in).Error; err != nil {
 | 
						|
		return in, err
 | 
						|
	} else {
 | 
						|
		moderator := "System"
 | 
						|
		if in.Moderator != nil {
 | 
						|
			moderator = fmt.Sprintf("@%s", in.Moderator.Name)
 | 
						|
		}
 | 
						|
		err = NewNotification(models.Notification{
 | 
						|
			Topic:     "passport.punishments",
 | 
						|
			Title:     localize.L.GetLocalizedString("subjectPunishmentUpdated", in.Account.Language),
 | 
						|
			Subtitle:  fmt.Sprintf(localize.L.GetLocalizedString("subtitlePunishment", in.Account.Language), in.ID, moderator),
 | 
						|
			Body:      fmt.Sprintf(localize.L.GetLocalizedString("shortBodyPunishmentUpdated", in.Account.Language), in.ID),
 | 
						|
			Account:   in.Account,
 | 
						|
			AccountID: in.Account.ID,
 | 
						|
			Metadata:  map[string]any{"punishment": in},
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			log.Warn().Err(err).Uint("case", in.ID).Msg("Failed to delivery punishment via notify...")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return in, nil
 | 
						|
}
 | 
						|
 | 
						|
func DeletePunishment(in models.Punishment) error {
 | 
						|
	if err := database.C.Delete(&in).Error; err != nil {
 | 
						|
		return err
 | 
						|
	} else {
 | 
						|
		moderator := "System"
 | 
						|
		if in.Moderator != nil {
 | 
						|
			moderator = fmt.Sprintf("@%s", in.Moderator.Name)
 | 
						|
		}
 | 
						|
		err = NewNotification(models.Notification{
 | 
						|
			Topic:     "passport.punishments",
 | 
						|
			Title:     localize.L.GetLocalizedString("subjectPunishmentDeleted", in.Account.Language),
 | 
						|
			Subtitle:  fmt.Sprintf(localize.L.GetLocalizedString("subtitlePunishment", in.Account.Language), in.ID, moderator),
 | 
						|
			Body:      fmt.Sprintf(localize.L.GetLocalizedString("shortBodyPunishmentDeleted", in.Account.Language), in.ID),
 | 
						|
			Account:   in.Account,
 | 
						|
			AccountID: in.Account.ID,
 | 
						|
			Metadata:  map[string]any{"punishment": in},
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			log.Warn().Err(err).Uint("case", in.ID).Msg("Failed to delivery punishment via notify...")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func GetPunishment(id uint, preload ...bool) (models.Punishment, error) {
 | 
						|
	tx := database.C
 | 
						|
	if len(preload) > 0 && preload[0] {
 | 
						|
		tx = tx.Preload("Moderator").Preload("Account")
 | 
						|
	}
 | 
						|
 | 
						|
	var punishment models.Punishment
 | 
						|
	if err := tx.First(&punishment, id).Error; err != nil {
 | 
						|
		return punishment, err
 | 
						|
	}
 | 
						|
	return punishment, nil
 | 
						|
}
 | 
						|
 | 
						|
func GetMadePunishment(id uint, moderator models.Account) (models.Punishment, error) {
 | 
						|
	var punishment models.Punishment
 | 
						|
	if err := database.C.Where("id = ? AND moderator_id = ?", id, moderator.ID).First(&punishment).Error; err != nil {
 | 
						|
		return punishment, err
 | 
						|
	}
 | 
						|
	return punishment, nil
 | 
						|
}
 | 
						|
 | 
						|
func ListPunishments(user models.Account) ([]models.Punishment, error) {
 | 
						|
	var punishments []models.Punishment
 | 
						|
	if err := database.C.
 | 
						|
		Where("account_id = ? AND (expired_at IS NULL OR expired_at > ?)", user.ID, time.Now()).
 | 
						|
		Preload("Moderator").
 | 
						|
		Order("created_at DESC").
 | 
						|
		Find(&punishments).Error; err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return punishments, nil
 | 
						|
}
 | 
						|
 | 
						|
func CountAllPunishments() (int64, error) {
 | 
						|
	var count int64
 | 
						|
	if err := database.C.
 | 
						|
		Model(&models.Punishment{}).
 | 
						|
		Count(&count).Error; err != nil {
 | 
						|
		return 0, err
 | 
						|
	}
 | 
						|
	return count, nil
 | 
						|
}
 | 
						|
 | 
						|
func ListAllPunishments(take, offset int) ([]models.Punishment, error) {
 | 
						|
	var punishments []models.Punishment
 | 
						|
	if err := database.C.
 | 
						|
		Preload("Account").
 | 
						|
		Preload("Moderator").
 | 
						|
		Order("created_at DESC").
 | 
						|
		Take(take).Offset(offset).
 | 
						|
		Find(&punishments).Error; err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return punishments, nil
 | 
						|
}
 | 
						|
 | 
						|
func CountMadePunishments(moderator models.Account) (int64, error) {
 | 
						|
	var count int64
 | 
						|
	if err := database.C.
 | 
						|
		Model(&models.Punishment{}).
 | 
						|
		Where("moderator_id = ?", moderator.ID).
 | 
						|
		Count(&count).Error; err != nil {
 | 
						|
		return 0, err
 | 
						|
	}
 | 
						|
	return count, nil
 | 
						|
}
 | 
						|
 | 
						|
func ListMadePunishments(moderator models.Account, take, offset int) ([]models.Punishment, error) {
 | 
						|
	var punishments []models.Punishment
 | 
						|
	if err := database.C.
 | 
						|
		Where("moderator_id = ?", moderator.ID).
 | 
						|
		Preload("Account").
 | 
						|
		Order("created_at DESC").
 | 
						|
		Take(take).Offset(offset).
 | 
						|
		Find(&punishments).Error; err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return punishments, nil
 | 
						|
}
 | 
						|
 | 
						|
func CheckLoginAbility(user models.Account) error {
 | 
						|
	var punishments []models.Punishment
 | 
						|
	if err := database.C.Where("account_id = ? AND (expired_at IS NULL OR expired_at > ?)", user.ID, time.Now()).
 | 
						|
		Find(&punishments).Error; err != nil {
 | 
						|
		return fmt.Errorf("failed to get punishments: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	for _, punishment := range punishments {
 | 
						|
		if punishment.Type == models.PunishmentTypeDisabled {
 | 
						|
			return fmt.Errorf("account has been fully disabled due to: %s (case #%d)", punishment.Reason, punishment.ID)
 | 
						|
		}
 | 
						|
		// Limited punishment with no permissions override is fully limited
 | 
						|
		// Refer https://solsynth.dev/terms/basic-law#provision-and-discontinuation-of-services
 | 
						|
		if punishment.Type == models.PunishmentTypeLimited && len(punishment.PermNodes) == 0 {
 | 
						|
			return fmt.Errorf("account has been limited login due to: %s (case #%d)", punishment.Reason, punishment.ID)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |