const crypto = require('crypto'); const jwt = require('jsonwebtoken'); /** * Sayfalama hesaplamaları * @param {number} page - Sayfa numarası * @param {number} limit - Sayfa başına öğe sayısı * @returns {object} Skip ve take değerleri */ const calculatePagination = (page = 1, limit = 10) => { const pageNum = Math.max(1, parseInt(page)); const limitNum = Math.min(100, Math.max(1, parseInt(limit))); return { skip: (pageNum - 1) * limitNum, take: limitNum, page: pageNum, limit: limitNum }; }; /** * Sayfalama meta bilgilerini oluştur * @param {number} total - Toplam öğe sayısı * @param {number} page - Mevcut sayfa * @param {number} limit - Sayfa başına öğe sayısı * @returns {object} Meta bilgileri */ const createPaginationMeta = (total, page, limit) => { const totalPages = Math.ceil(total / limit); return { total, page, limit, totalPages, hasNext: page < totalPages, hasPrev: page > 1 }; }; /** * API yanıt formatı * @param {boolean} success - İşlem başarılı mı * @param {string} message - Mesaj * @param {any} data - Veri * @param {object} meta - Meta bilgileri * @returns {object} Formatlanmış yanıt */ const createResponse = (success, message, data = null, meta = null) => { const response = { success, message, timestamp: new Date().toISOString() }; if (data !== null) { response.data = data; } if (meta !== null) { response.meta = meta; } return response; }; /** * Başarılı yanıt oluştur * @param {string} message - Mesaj * @param {any} data - Veri * @param {object} meta - Meta bilgileri * @returns {object} Başarılı yanıt */ const successResponse = (message, data = null, meta = null) => { return createResponse(true, message, data, meta); }; /** * Hata yanıtı oluştur * @param {string} message - Hata mesajı * @param {any} data - Hata detayları * @returns {object} Hata yanıtı */ const errorResponse = (message, data = null) => { return createResponse(false, message, data); }; /** * JWT token oluştur * @param {object} payload - Token içeriği * @param {string} expiresIn - Geçerlilik süresi * @returns {string} JWT token */ const generateToken = (payload, expiresIn = process.env.JWT_EXPIRES_IN || '7d') => { return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn }); }; /** * JWT token doğrula * @param {string} token - JWT token * @returns {object} Decoded token */ const verifyToken = (token) => { return jwt.verify(token, process.env.JWT_SECRET); }; /** * Rastgele string oluştur * @param {number} length - String uzunluğu * @returns {string} Rastgele string */ const generateRandomString = (length = 32) => { return crypto.randomBytes(length).toString('hex'); }; /** * Güvenli karşılaştırma * @param {string} a - İlk string * @param {string} b - İkinci string * @returns {boolean} Eşit mi */ const safeCompare = (a, b) => { if (a.length !== b.length) { return false; } return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)); }; /** * Slug oluştur * @param {string} text - Metin * @returns {string} Slug */ const createSlug = (text) => { return text .toLowerCase() .replace(/ç/g, 'c') .replace(/ğ/g, 'g') .replace(/ı/g, 'i') .replace(/ö/g, 'o') .replace(/ş/g, 's') .replace(/ü/g, 'u') .replace(/[^a-z0-9\s-]/g, '') .replace(/\s+/g, '-') .replace(/-+/g, '-') .trim('-'); }; /** * Tarih formatla * @param {Date} date - Tarih * @param {string} locale - Dil kodu * @returns {string} Formatlanmış tarih */ const formatDate = (date, locale = 'tr-TR') => { return new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit' }).format(new Date(date)); }; /** * Fiyat formatla * @param {number} price - Fiyat * @param {string} currency - Para birimi * @returns {string} Formatlanmış fiyat */ const formatPrice = (price, currency = 'TRY') => { return new Intl.NumberFormat('tr-TR', { style: 'currency', currency: currency }).format(price); }; /** * Dosya boyutu formatla * @param {number} bytes - Byte cinsinden boyut * @returns {string} Formatlanmış boyut */ const formatFileSize = (bytes) => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; /** * E-posta adresi maskele * @param {string} email - E-posta adresi * @returns {string} Maskelenmiş e-posta */ const maskEmail = (email) => { const [username, domain] = email.split('@'); const maskedUsername = username.charAt(0) + '*'.repeat(username.length - 2) + username.charAt(username.length - 1); return `${maskedUsername}@${domain}`; }; /** * Telefon numarası maskele * @param {string} phone - Telefon numarası * @returns {string} Maskelenmiş telefon */ const maskPhone = (phone) => { if (phone.length < 4) return phone; return phone.substring(0, 2) + '*'.repeat(phone.length - 4) + phone.substring(phone.length - 2); }; /** * Dizi elemanlarını karıştır * @param {Array} array - Karıştırılacak dizi * @returns {Array} Karıştırılmış dizi */ const shuffleArray = (array) => { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; }; /** * Dizi elemanlarını grupla * @param {Array} array - Gruplandırılacak dizi * @param {string} key - Gruplama anahtarı * @returns {object} Gruplandırılmış obje */ const groupBy = (array, key) => { return array.reduce((groups, item) => { const group = item[key]; groups[group] = groups[group] || []; groups[group].push(item); return groups; }, {}); }; /** * Debounce fonksiyonu * @param {Function} func - Debounce edilecek fonksiyon * @param {number} wait - Bekleme süresi (ms) * @returns {Function} Debounce edilmiş fonksiyon */ const debounce = (func, wait) => { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }; /** * Throttle fonksiyonu * @param {Function} func - Throttle edilecek fonksiyon * @param {number} limit - Limit süresi (ms) * @returns {Function} Throttle edilmiş fonksiyon */ const throttle = (func, limit) => { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }; /** * Renk hex kodunu RGB'ye çevir * @param {string} hex - Hex renk kodu * @returns {object} RGB değerleri */ const hexToRgb = (hex) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; }; /** * RGB değerlerini hex koduna çevir * @param {number} r - Kırmızı değeri * @param {number} g - Yeşil değeri * @param {number} b - Mavi değeri * @returns {string} Hex renk kodu */ const rgbToHex = (r, g, b) => { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); }; /** * URL'den query parametrelerini çıkar * @param {string} url - URL * @returns {object} Query parametreleri */ const parseQueryParams = (url) => { const params = {}; const urlObj = new URL(url); urlObj.searchParams.forEach((value, key) => { params[key] = value; }); return params; }; /** * Nesne değerlerini temizle (null, undefined, empty string) * @param {object} obj - Temizlenecek nesne * @returns {object} Temizlenmiş nesne */ const cleanObject = (obj) => { const cleaned = {}; Object.keys(obj).forEach(key => { if (obj[key] !== null && obj[key] !== undefined && obj[key] !== '') { cleaned[key] = obj[key]; } }); return cleaned; }; /** * İki tarih arasındaki farkı hesapla * @param {Date} date1 - İlk tarih * @param {Date} date2 - İkinci tarih * @returns {object} Tarih farkı */ const dateDifference = (date1, date2) => { const diffTime = Math.abs(date2 - date1); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); const diffHours = Math.ceil(diffTime / (1000 * 60 * 60)); const diffMinutes = Math.ceil(diffTime / (1000 * 60)); return { milliseconds: diffTime, minutes: diffMinutes, hours: diffHours, days: diffDays }; }; module.exports = { calculatePagination, createPaginationMeta, createResponse, successResponse, errorResponse, generateToken, verifyToken, generateRandomString, safeCompare, createSlug, formatDate, formatPrice, formatFileSize, maskEmail, maskPhone, shuffleArray, groupBy, debounce, throttle, hexToRgb, rgbToHex, parseQueryParams, cleanObject, dateDifference };