diff --git a/A_core/__pycache__/telegram_utils.cpython-38.pyc b/A_core/__pycache__/telegram_utils.cpython-38.pyc
index a50912c..defed30 100644
Binary files a/A_core/__pycache__/telegram_utils.cpython-38.pyc and b/A_core/__pycache__/telegram_utils.cpython-38.pyc differ
diff --git a/A_core/settings.py b/A_core/settings.py
index 20b61e5..1be6b5e 100644
--- a/A_core/settings.py
+++ b/A_core/settings.py
@@ -38,6 +38,9 @@ TELEGRAM_BOT_TOKEN = "5094633886:AAF_Cy3mD-3rqKQMfbgpVO39jNZDXNFZN-o" # BotFath
TELEGRAM_CHAT_ID = "5085456424" # getUpdates로 얻은 chat_id
TELEGRAM_API_URL = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
+# 텔레그램 알림 전송 여부 설정
+TELEGRAM_NOTIFICATIONS_ENABLED = True # True: 텔레그램 알림 전송, False: 텔레그램 알림 비활성화
+
ALLOWED_HOSTS = ['www.sillaamp.com', 'sillaamp.com', '192.168.1.119', 'localhost', '127.0.0.1', '*']
CSRF_TRUSTED_ORIGINS = [
'http://www.sillaamp.com',
diff --git a/A_core/telegram_utils.py b/A_core/telegram_utils.py
index 8f8a7be..428501d 100644
--- a/A_core/telegram_utils.py
+++ b/A_core/telegram_utils.py
@@ -163,6 +163,11 @@ def send_telegram_message_async(message, chat_id=None):
message (str): 전송할 메시지
chat_id (str, optional): 채팅 ID
"""
+ # 텔레그램 알림이 비활성화된 경우 전송하지 않음
+ if not getattr(settings, 'TELEGRAM_NOTIFICATIONS_ENABLED', True):
+ print("[TELEGRAM_INFO] 텔레그램 알림이 비활성화되어 있습니다.")
+ return
+
def _send():
send_telegram_message(message, chat_id)
diff --git a/B_main/admin.py b/B_main/admin.py
index 106a807..41e7fe2 100644
--- a/B_main/admin.py
+++ b/B_main/admin.py
@@ -90,10 +90,10 @@ class PersonAdmin(admin.ModelAdmin):
@admin.register(AccessLog)
class AccessLogAdmin(admin.ModelAdmin):
- list_display = ['timestamp', '사용자명', 'action_display', 'ip_address', 'description']
+ list_display = ['timestamp', '사용자명', 'action_display', 'ip_address', '기기정보', '브라우저정보', 'description']
list_filter = ['action', 'timestamp', 'ip_address']
search_fields = ['user__username', 'person__이름', 'description', 'ip_address']
- readonly_fields = ['timestamp', 'user', 'person', 'action', 'description', 'ip_address', 'user_agent', 'session_key', 'metadata', '변경사항_상세보기']
+ readonly_fields = ['timestamp', 'user', 'person', 'action', 'description', 'ip_address', 'user_agent', 'session_key', 'metadata', '변경사항_상세보기', '기기정보', '브라우저정보']
date_hierarchy = 'timestamp'
ordering = ['-timestamp']
@@ -132,12 +132,52 @@ class AccessLogAdmin(admin.ModelAdmin):
action_display.short_description = '활동'
action_display.admin_order_field = 'action'
+ def 기기정보(self, obj):
+ if obj.metadata and 'device_info' in obj.metadata:
+ device_info = obj.metadata['device_info']
+ # 기기별 아이콘 추가
+ icons = {
+ 'iPhone': '📱',
+ 'iPad': '📱',
+ 'Android 폰': '📱',
+ 'Android 태블릿': '📱',
+ 'Windows 10/11': '💻',
+ 'Windows 8.1': '💻',
+ 'Windows 7': '💻',
+ 'Windows': '💻',
+ 'Mac': '💻',
+ 'Linux': '💻',
+ }
+ icon = icons.get(device_info, '🖥️')
+ return format_html('{} {}', icon, device_info)
+ return format_html('알 수 없음')
+ 기기정보.short_description = '기기'
+
+ def 브라우저정보(self, obj):
+ if obj.metadata and 'browser_info' in obj.metadata:
+ browser_info = obj.metadata['browser_info']
+ # 브라우저별 색상 추가
+ colors = {
+ 'Chrome': '#4285f4',
+ 'Firefox': '#ff7139',
+ 'Safari': '#1b88ca',
+ 'Microsoft Edge': '#0078d4',
+ 'Opera': '#ff1b2d',
+ }
+ color = colors.get(browser_info, '#6c757d')
+ return format_html(
+ '{}',
+ color, browser_info
+ )
+ return format_html('알 수 없음')
+ 브라우저정보.short_description = '브라우저'
+
fieldsets = (
('기본 정보', {
'fields': ('timestamp', 'user', 'person', 'action', 'description')
}),
('접속 정보', {
- 'fields': ('ip_address', 'user_agent', 'session_key')
+ 'fields': ('ip_address', '기기정보', '브라우저정보', 'user_agent', 'session_key')
}),
('상세 변경사항', {
'fields': ('변경사항_상세보기',),
diff --git a/B_main/log_utils.py b/B_main/log_utils.py
index 51219c8..4f1260c 100644
--- a/B_main/log_utils.py
+++ b/B_main/log_utils.py
@@ -6,13 +6,38 @@ from .models import AccessLog, Person
def get_client_ip(request):
- """클라이언트 IP 주소 가져오기"""
+ """
+ 클라이언트의 실제 IP 주소를 추출
+ 프록시, 로드밸런서, CDN 등을 고려하여 실제 IP를 찾음
+ """
+ # 프록시나 로드밸런서를 통한 실제 클라이언트 IP 확인
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
+ # 첫 번째 IP가 실제 클라이언트 IP (쉼표로 구분된 경우)
ip = x_forwarded_for.split(',')[0].strip()
- else:
- ip = request.META.get('REMOTE_ADDR')
- return ip
+ if ip and ip != '127.0.0.1':
+ return ip
+
+ # Cloudflare 등 CDN에서 사용하는 헤더
+ cf_connecting_ip = request.META.get('HTTP_CF_CONNECTING_IP')
+ if cf_connecting_ip and cf_connecting_ip != '127.0.0.1':
+ return cf_connecting_ip
+
+ # Nginx 등 리버스 프록시에서 사용
+ x_real_ip = request.META.get('HTTP_X_REAL_IP')
+ if x_real_ip and x_real_ip != '127.0.0.1':
+ return x_real_ip
+
+ # 기본 REMOTE_ADDR
+ remote_addr = request.META.get('REMOTE_ADDR', '알 수 없음')
+
+ # 로컬 환경 표시
+ if remote_addr == '127.0.0.1':
+ return f"{remote_addr} (로컬 개발환경)"
+ elif remote_addr.startswith('192.168.') or remote_addr.startswith('10.') or remote_addr.startswith('172.'):
+ return f"{remote_addr} (내부 네트워크)"
+
+ return remote_addr
def get_user_agent(request):
@@ -20,6 +45,63 @@ def get_user_agent(request):
return request.META.get('HTTP_USER_AGENT', '')
+def get_device_info(user_agent):
+ """User-Agent에서 기기 정보 추출"""
+ if not user_agent:
+ return "알 수 없음"
+
+ # 모바일 기기 체크
+ if any(mobile in user_agent for mobile in ['iPhone', 'iPad', 'Android', 'Mobile']):
+ if 'iPhone' in user_agent:
+ return "iPhone"
+ elif 'iPad' in user_agent:
+ return "iPad"
+ elif 'Android' in user_agent:
+ if 'Mobile' in user_agent:
+ return "Android 폰"
+ else:
+ return "Android 태블릿"
+ else:
+ return "모바일"
+
+ # 데스크톱 OS 체크
+ if 'Windows NT' in user_agent:
+ if 'Windows NT 10.0' in user_agent:
+ return "Windows 10/11"
+ elif 'Windows NT 6.3' in user_agent:
+ return "Windows 8.1"
+ elif 'Windows NT 6.1' in user_agent:
+ return "Windows 7"
+ else:
+ return "Windows"
+ elif 'Macintosh' in user_agent or 'Mac OS X' in user_agent:
+ return "Mac"
+ elif 'Linux' in user_agent and 'Android' not in user_agent:
+ return "Linux"
+
+ return "알 수 없음"
+
+
+def get_browser_info(user_agent):
+ """User-Agent에서 브라우저 정보 추출"""
+ if not user_agent:
+ return "알 수 없음"
+
+ # 브라우저 체크 (순서 중요 - Chrome이 Safari 문자열도 포함하므로)
+ if 'Edg/' in user_agent:
+ return "Microsoft Edge"
+ elif 'Chrome/' in user_agent and 'Safari/' in user_agent:
+ return "Chrome"
+ elif 'Firefox/' in user_agent:
+ return "Firefox"
+ elif 'Safari/' in user_agent and 'Chrome' not in user_agent:
+ return "Safari"
+ elif 'Opera' in user_agent or 'OPR/' in user_agent:
+ return "Opera"
+
+ return "알 수 없음"
+
+
def log_user_activity(request, action, description=None, user=None, metadata=None):
"""
사용자 활동 로그 기록
@@ -49,10 +131,13 @@ def log_user_activity(request, action, description=None, user=None, metadata=Non
metadata = {}
# 요청 정보 추가
+ user_agent = get_user_agent(request)
metadata.update({
'path': request.path,
'method': request.method,
'referer': request.META.get('HTTP_REFERER', ''),
+ 'device_info': get_device_info(user_agent),
+ 'browser_info': get_browser_info(user_agent),
})
# 로그 생성
diff --git a/C_accounts/__pycache__/views.cpython-38.pyc b/C_accounts/__pycache__/views.cpython-38.pyc
index 5d65620..b47fc80 100644
Binary files a/C_accounts/__pycache__/views.cpython-38.pyc and b/C_accounts/__pycache__/views.cpython-38.pyc differ
diff --git a/db.sqlite3 b/db.sqlite3
index f0798e5..c9a0ad0 100644
Binary files a/db.sqlite3 and b/db.sqlite3 differ