성능개선 문자인증오류수정 텔레그램메시포함 등
This commit is contained in:
parent
b2e0805880
commit
56d87eaa45
Binary file not shown.
@ -38,6 +38,9 @@ TELEGRAM_BOT_TOKEN = "5094633886:AAF_Cy3mD-3rqKQMfbgpVO39jNZDXNFZN-o" # BotFath
|
|||||||
TELEGRAM_CHAT_ID = "5085456424" # getUpdates로 얻은 chat_id
|
TELEGRAM_CHAT_ID = "5085456424" # getUpdates로 얻은 chat_id
|
||||||
TELEGRAM_API_URL = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
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', '*']
|
ALLOWED_HOSTS = ['www.sillaamp.com', 'sillaamp.com', '192.168.1.119', 'localhost', '127.0.0.1', '*']
|
||||||
CSRF_TRUSTED_ORIGINS = [
|
CSRF_TRUSTED_ORIGINS = [
|
||||||
'http://www.sillaamp.com',
|
'http://www.sillaamp.com',
|
||||||
|
|||||||
@ -163,6 +163,11 @@ def send_telegram_message_async(message, chat_id=None):
|
|||||||
message (str): 전송할 메시지
|
message (str): 전송할 메시지
|
||||||
chat_id (str, optional): 채팅 ID
|
chat_id (str, optional): 채팅 ID
|
||||||
"""
|
"""
|
||||||
|
# 텔레그램 알림이 비활성화된 경우 전송하지 않음
|
||||||
|
if not getattr(settings, 'TELEGRAM_NOTIFICATIONS_ENABLED', True):
|
||||||
|
print("[TELEGRAM_INFO] 텔레그램 알림이 비활성화되어 있습니다.")
|
||||||
|
return
|
||||||
|
|
||||||
def _send():
|
def _send():
|
||||||
send_telegram_message(message, chat_id)
|
send_telegram_message(message, chat_id)
|
||||||
|
|
||||||
|
|||||||
@ -90,10 +90,10 @@ class PersonAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(AccessLog)
|
@admin.register(AccessLog)
|
||||||
class AccessLogAdmin(admin.ModelAdmin):
|
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']
|
list_filter = ['action', 'timestamp', 'ip_address']
|
||||||
search_fields = ['user__username', 'person__이름', 'description', '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'
|
date_hierarchy = 'timestamp'
|
||||||
ordering = ['-timestamp']
|
ordering = ['-timestamp']
|
||||||
|
|
||||||
@ -132,12 +132,52 @@ class AccessLogAdmin(admin.ModelAdmin):
|
|||||||
action_display.short_description = '활동'
|
action_display.short_description = '활동'
|
||||||
action_display.admin_order_field = 'action'
|
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('<span style="color: #ccc;">알 수 없음</span>')
|
||||||
|
기기정보.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(
|
||||||
|
'<span style="color: {}; font-weight: bold;">{}</span>',
|
||||||
|
color, browser_info
|
||||||
|
)
|
||||||
|
return format_html('<span style="color: #ccc;">알 수 없음</span>')
|
||||||
|
브라우저정보.short_description = '브라우저'
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('기본 정보', {
|
('기본 정보', {
|
||||||
'fields': ('timestamp', 'user', 'person', 'action', 'description')
|
'fields': ('timestamp', 'user', 'person', 'action', 'description')
|
||||||
}),
|
}),
|
||||||
('접속 정보', {
|
('접속 정보', {
|
||||||
'fields': ('ip_address', 'user_agent', 'session_key')
|
'fields': ('ip_address', '기기정보', '브라우저정보', 'user_agent', 'session_key')
|
||||||
}),
|
}),
|
||||||
('상세 변경사항', {
|
('상세 변경사항', {
|
||||||
'fields': ('변경사항_상세보기',),
|
'fields': ('변경사항_상세보기',),
|
||||||
|
|||||||
@ -6,13 +6,38 @@ from .models import AccessLog, Person
|
|||||||
|
|
||||||
|
|
||||||
def get_client_ip(request):
|
def get_client_ip(request):
|
||||||
"""클라이언트 IP 주소 가져오기"""
|
"""
|
||||||
|
클라이언트의 실제 IP 주소를 추출
|
||||||
|
프록시, 로드밸런서, CDN 등을 고려하여 실제 IP를 찾음
|
||||||
|
"""
|
||||||
|
# 프록시나 로드밸런서를 통한 실제 클라이언트 IP 확인
|
||||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
if x_forwarded_for:
|
if x_forwarded_for:
|
||||||
|
# 첫 번째 IP가 실제 클라이언트 IP (쉼표로 구분된 경우)
|
||||||
ip = x_forwarded_for.split(',')[0].strip()
|
ip = x_forwarded_for.split(',')[0].strip()
|
||||||
else:
|
if ip and ip != '127.0.0.1':
|
||||||
ip = request.META.get('REMOTE_ADDR')
|
return ip
|
||||||
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):
|
def get_user_agent(request):
|
||||||
@ -20,6 +45,63 @@ def get_user_agent(request):
|
|||||||
return request.META.get('HTTP_USER_AGENT', '')
|
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):
|
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 = {}
|
metadata = {}
|
||||||
|
|
||||||
# 요청 정보 추가
|
# 요청 정보 추가
|
||||||
|
user_agent = get_user_agent(request)
|
||||||
metadata.update({
|
metadata.update({
|
||||||
'path': request.path,
|
'path': request.path,
|
||||||
'method': request.method,
|
'method': request.method,
|
||||||
'referer': request.META.get('HTTP_REFERER', ''),
|
'referer': request.META.get('HTTP_REFERER', ''),
|
||||||
|
'device_info': get_device_info(user_agent),
|
||||||
|
'browser_info': get_browser_info(user_agent),
|
||||||
})
|
})
|
||||||
|
|
||||||
# 로그 생성
|
# 로그 생성
|
||||||
|
|||||||
Binary file not shown.
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user