o
    i3                     @   sD  d dl Z d dlZd dlZd dlZd dlmZmZ d dlmZ d dlm	Z	m
Z
mZmZmZmZmZ e	eZdZdZdZe jesGe jedd	 d
Zdd Zdd Zdd Zdd Zdd Zejdddgdedd Zejddgdedd Z ejddgddd  Z!ejd!dgdd"d# Z"ed$krej#d%d&d'd( eZ$dS ))    N)datetime	timedeltawraps)FlaskrequestResponsejsonifyrender_template_stringredirecturl_forz/opt/api/apilogadminadmin123i  )modeu&  
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>API Logs Viewer</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Courier New', monospace;
            background: #1e1e1e;
            color: #d4d4d4;
            line-height: 1.6;
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        .header {
            background: #2d2d2d;
            padding: 15px;
            border-radius: 5px;
            margin-bottom: 20px;
            border-left: 4px solid #4caf50;
            position: sticky;
            top: 0;
            z-index: 10;
        }
        
        .header h1 {
            color: #4caf50;
            font-size: 1.5em;
        }
        
        .date-badge {
            display: inline-block;
            background: #3e3e3e;
            padding: 5px 10px;
            border-radius: 3px;
            font-size: 0.9em;
            margin-top: 10px;
        }
        
        .logs-container {
            background: #252526;
            border-radius: 5px;
            overflow: hidden;
        }
        
        .log-entry {
            padding: 10px 15px;
            border-bottom: 1px solid #3e3e3e;
            font-family: monospace;
            font-size: 0.9em;
            white-space: pre-wrap;
            word-break: break-all;
        }
        
        .log-entry:hover {
            background: #2d2d2d;
        }
        
        .loading {
            text-align: center;
            padding: 20px;
            color: #888;
        }
        
        .no-more {
            text-align: center;
            padding: 20px;
            color: #888;
            font-style: italic;
        }
        
        .scroll-to-bottom {
            position: fixed;
            bottom: 30px;
            right: 30px;
            width: 50px;
            height: 50px;
            background: #4caf50;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            box-shadow: 0 2px 10px rgba(0,0,0,0.3);
            transition: transform 0.2s, background 0.2s;
            z-index: 1000;
        }
        
        .scroll-to-bottom:hover {
            background: #45a049;
            transform: scale(1.1);
        }
        
        .scroll-to-bottom:active {
            transform: scale(0.95);
        }
        
        .scroll-to-bottom svg {
            width: 24px;
            height: 24px;
            fill: white;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .spinner {
            display: inline-block;
            width: 16px;
            height: 16px;
            border: 2px solid #4caf50;
            border-top-color: transparent;
            border-radius: 50%;
            animation: spin 0.6s linear infinite;
            margin-left: 10px;
        }
        
        .error-message {
            background: #5a1e1e;
            color: #ff6b6b;
            padding: 10px;
            border-radius: 5px;
            margin: 10px 0;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>📋 API Logs Viewer</h1>
            <div class="date-badge" id="current-date">Текущий день: {{ current_date }}</div>
        </div>
        <div class="logs-container" id="logs-container">
            <div class="loading">Загрузка логов...</div>
        </div>
    </div>
    
    <div class="scroll-to-bottom" id="scroll-to-bottom" title="Вниз">
        <svg viewBox="0 0 24 24">
            <path d="M7.41,8.59L12,13.17L16.59,8.59L18,10L12,16L6,10L7.41,8.59Z"/>
        </svg>
    </div>
    
    <script>
        let currentDate = '{{ current_date }}';
        let loading = false;
        let noMoreData = false;
        let container = document.getElementById('logs-container');
        let initialLoad = true;
        
        async function loadLogs(date, append = false) {
            if (loading || (noMoreData && append)) return;
            
            loading = true;
            if (!append) {
                container.innerHTML = '<div class="loading">Загрузка логов...</div>';
            } else {
                const loadingDiv = document.createElement('div');
                loadingDiv.className = 'loading';
                loadingDiv.id = 'loading-more';
                loadingDiv.innerHTML = 'Загрузка предыдущих записей...<span class="spinner"></span>';
                container.insertBefore(loadingDiv, container.firstChild);
            }
            
            try {
                const response = await fetch(`/api/logs/${date}`);
                const data = await response.json();
                
                if (data.error) {
                    if (!append) {
                        container.innerHTML = `<div class="error-message">Ошибка: ${data.error}</div>`;
                    }
                    if (data.no_more) {
                        noMoreData = true;
                        if (append) {
                            const loadingDiv = document.getElementById('loading-more');
                            if (loadingDiv) loadingDiv.remove();
                            const noMoreDiv = document.createElement('div');
                            noMoreDiv.className = 'no-more';
                            noMoreDiv.innerHTML = '📄 Больше записей нет';
                            container.insertBefore(noMoreDiv, container.firstChild);
                        }
                    }
                    return;
                }
                
                if (data.logs && data.logs.length > 0) {
                    if (append) {
                        const loadingDiv = document.getElementById('loading-more');
                        if (loadingDiv) loadingDiv.remove();
                        
                        const logEntries = data.logs.map(log => `<div class="log-entry">${escapeHtml(log)}</div>`).join('');
                        const tempDiv = document.createElement('div');
                        tempDiv.innerHTML = logEntries;
                        const newEntries = Array.from(tempDiv.children);
                        
                        const oldScrollHeight = document.documentElement.scrollHeight;
                        const oldScrollTop = window.scrollY;
                        
                        newEntries.reverse().forEach(entry => {
                            container.insertBefore(entry, container.firstChild);
                        });
                        
                        const newScrollHeight = document.documentElement.scrollHeight;
                        window.scrollTo(0, oldScrollTop + (newScrollHeight - oldScrollHeight));
                    } else {
                        container.innerHTML = data.logs.map(log => `<div class="log-entry">${escapeHtml(log)}</div>`).join('');
                        setTimeout(() => scrollToBottom(), 100);
                    }
                } else if (!append) {
                    container.innerHTML = '<div class="no-more">📭 Нет записей за этот день</div>';
                }
            } catch (error) {
                console.error('Error loading logs:', error);
                if (!append) {
                    container.innerHTML = '<div class="error-message">Ошибка загрузки логов</div>';
                }
            } finally {
                loading = false;
                initialLoad = false;
            }
        }
        
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }
        
        function scrollToBottom() {
            window.scrollTo({
                top: document.documentElement.scrollHeight,
                behavior: 'smooth'
            });
        }
        
        function handleScroll() {
            if (window.scrollY === 0 && !loading && !noMoreData && !initialLoad) {
                const prevDate = getPreviousDate(currentDate);
                if (prevDate) {
                    currentDate = prevDate;
                    loadLogs(currentDate, true);
                } else {
                    noMoreData = true;
                }
            }
        }
        
        function getPreviousDate(dateStr) {
            const [year, month, day] = dateStr.split('-').map(Number);
            const date = new Date(year, month - 1, day);
            date.setDate(date.getDate() - 1);
            const prevYear = date.getFullYear();
            const prevMonth = String(date.getMonth() + 1).padStart(2, '0');
            const prevDay = String(date.getDate()).padStart(2, '0');
            return `${prevYear}-${prevMonth}-${prevDay}`;
        }
        
        loadLogs(currentDate);
        
        let scrollTimeout;
        window.addEventListener('scroll', function() {
            if (scrollTimeout) clearTimeout(scrollTimeout);
            scrollTimeout = setTimeout(handleScroll, 100);
        });
        
        document.getElementById('scroll-to-bottom').addEventListener('click', scrollToBottom);
    </script>
</body>
</html>
c                 C   s   | t ko|tkS N)USERNAMEPASSWORD)usernamepassword r   /opt/api/app.py
check_auth9  s   r   c                   C   s   t ddddiS )NzZCould not verify your access level for that URL.
You have to login with proper credentialsi  zWWW-AuthenticatezBasic realm="API Logs Viewer")r   r   r   r   r   authenticate<  s
   r   c                    s   t   fdd}|S )Nc                     s,   t j}|rt|j|jst S  | i |S r   )r   authorizationr   r   r   r   )argskwargsauthfr   r   	decoratedE  s   z requires_auth.<locals>.decoratedr   )r   r   r   r   r   requires_authD  s   r    c              
   C   s   t  d}tjtd| d}z#t|ddd}|| d  W d    W dS 1 s.w   Y  W dS  t	yO } zt
d	|  W Y d }~d
S d }~ww )Nz%Y%m%dapi_.logautf-8encoding
TzError writing log: F)r   nowstrftimeospathjoinLOG_DIRopenwrite	Exceptionprint)messagetodaylog_filer   er   r   r   	write_logM  s   
r6   c              
   C   s   zAt | d tjtd| dd d}tj|sg W S t|ddd}|	 }W d    n1 s5w   Y  d	d
 |D W S  t
y^ } ztd|  d|  W Y d }~d S d }~ww )N%Y-%m-%dr!   - r"   rr$   r%   c                 S   s   g | ]
}|  r|  qS r   )strip).0logr   r   r   
<listcomp>d  s    z&read_logs_for_date.<locals>.<listcomp>zError reading logs for z: )r   strptimer*   r+   r,   r-   replaceexistsr.   	readlinesr0   r1   )date_strr4   r   logsr5   r   r   r   read_logs_for_dateY  s   
rE   /GETPOST)methodsc                  C   s   t  d} tt| dS )Nr7   current_date)r   r(   r)   r
   HTML_TEMPLATErJ   r   r   r   indexi  s   rM   z/api/logs/<date_str>c                 C   s.   t | }|d u rtddidfS t|| dS )Nerroru$   Ошибка чтения файла  )rD   date)rE   r	   )rC   rD   r   r   r   get_logso  s   rQ   z/sendc                  C   sV   t jdpt jd} | stddidfS t| r#tddddfS tdd	id
fS )NtextrN   zNo message providedi  successzMessage logged)statusr2      zFailed to write logrO   )r   formgetr   r	   r6   )r2   r   r   r   
send_alerty  s   rX   z/healthc                   C   s   t dt  dS )Nok)rT   	timestamp)r	   r   r(   	isoformatr   r   r   r   health_check  s   r\   __main__z0.0.0.0i  F)hostportdebug)%r*   jsonglobbase64r   r   	functoolsr   flaskr   r   r   r	   r
   r   r   __name__appr-   r   r   r+   rA   makedirsrL   r   r   r    r6   rE   routerM   rQ   rX   r\   runapplicationr   r   r   r   <module>   sD   $  "	

