Rule
Модель предназначена для хранения правил доступа, которые могут быть глобальными или специфичными для пользователей или тарифных планов.
Полиморфные ассоциации позволяют этой модели динамически применять правила к различным целевым объектам.
Node.JS (sequelize)
const { DataTypes, Sequelize } = require('sequelize');
const sequelize = new Sequelize(/* ... */);
const Rule = sequelize.define('Rule', {
domain: {
type: DataTypes.STRING, // домен или ip
allowNull: false
},
action: {
type: DataTypes.BOOLEAN, // действие (true - блокировка | false - разблокировка)
allowNull: false
},
targetType: DataTypes.STRING, // тип полиморфной ассоциации (user | tariff)
targetId: DataTypes.INTEGER, // идентификатор полиморфной ассоциации
});
Go (GORM)
import "gorm.io/gorm"
type Rule struct {
gorm.Model
Domain string `gorm:"not null"`
Action bool `gorm:"not null"`
TargetID uint
TargetType string
}
func Получение списка заблокированных доменов
Node.JS
/**
* Retrieves a list of blocked domains for a specific user.
* @param {Object} user - The user object containing at least the user's ID.
* @returns {Promise<Array>} - A promise that resolves with a list of blocked domains.
*/
async function getBlockedDomainsForUser(user) {
const globalRules = await Rule.findAll({ where: { targetId: null, targetType: null } });
const blockedDomains = new Set(globalRules.filter(rule => rule.action).map(rule => rule.domain));
if (user.tariff && user.tariff.active) {
const tariffRules = await Rule.findAll({ where: { targetId: user.tariffId, targetType: 'tariff' } });
tariffRules.forEach(rule => rule.action ? blockedDomains.add(rule.domain) : blockedDomains.delete(rule.domain));
}
const userRules = await Rule.findAll({ where: { targetId: user.id, targetType: 'user' } });
userRules.forEach(rule => rule.action ? blockedDomains.add(rule.domain) : blockedDomains.delete(rule.domain));
return Array.from(blockedDomains);
}
Go
import "gorm.io/gorm"
// getBlockedDomainsForUser retrieves a list of blocked domains for a specific user.
// It accounts for global, tariff-related, and user-specific rules.
// Returns a slice of strings containing the domains and an error if any occurred.
func getBlockedDomainsForUser(db *gorm.DB, user User) ([]string, error) {
var rules []Rule
var blockedDomains []string
if err := db.Where("target_id IS NULL AND target_type IS NULL").Find(&rules).Error; err != nil {
return nil, err
}
for _, rule := range rules {
if rule.Action {
blockedDomains = append(blockedDomains, rule.Domain)
}
}
if user.Tariff != nil && user.Tariff.Active {
var tariffRules []Rule
if err := db.Where("target_id = ? AND target_type = ?", user.TariffID, "tariff").Find(&tariffRules).Error; err != nil {
return nil, err
}
for _, rule := range tariffRules {
if rule.Action {
blockedDomains = append(blockedDomains, rule.Domain)
} else {
blockedDomains = __removeDomain(blockedDomains, rule.Domain)
}
}
}
var userRules []Rule
if err := db.Where("target_id = ? AND target_type = ?", user.ID, "user").Find(&userRules).Error; err != nil {
return nil, err
}
for _, rule := range userRules {
if rule.Action {
blockedDomains = append(blockedDomains, rule.Domain)
} else {
blockedDomains = __removeDomain(blockedDomains, rule.Domain)
}
}
return blockedDomains, nil
}
// __removeDomain helps remove a domain from the list.
func __removeDomain(domains []string, domain string) []string {
var result []string
for _, d := range domains {
if d != domain {
result = append(result, d)
}
}
return result
}
