320 lines
20 KiB
HTML
320 lines
20 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}시스템 설정 - Dell Server Info{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/admin_settings.css') }}">
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container py-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2 class="fw-bold mb-0">
|
|
<i class="bi bi-gear-fill text-primary me-2"></i>시스템 설정
|
|
</h2>
|
|
<a href="{{ url_for('admin.admin_panel') }}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-left me-1"></i>관리자 패널로 돌아가기
|
|
</a>
|
|
</div>
|
|
|
|
<!-- 텔레그램 봇 설정 섹션 -->
|
|
<div class="card border shadow-sm mb-4">
|
|
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0 fw-bold">
|
|
<i class="bi bi-telegram text-info me-2"></i>텔레그램 봇 관리
|
|
</h5>
|
|
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addBotModal">
|
|
<i class="bi bi-plus-lg me-1"></i>봇 추가
|
|
</button>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="alert alert-info d-flex align-items-center" role="alert">
|
|
<i class="bi bi-info-circle-fill me-2 flex-shrink-0 fs-5"></i>
|
|
<div>
|
|
등록된 모든 <strong>활성(Active)</strong> 봇에게 알림이 동시에 전송됩니다.<br>
|
|
<small class="text-muted">알림 종류: 로그인, 회원가입, 로그아웃, 서버 작업 등</small>
|
|
</div>
|
|
</div>
|
|
|
|
{% if bots %}
|
|
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 g-4">
|
|
{% for bot in bots %}
|
|
<div class="col">
|
|
<div class="card h-100 border-0 shadow-sm hover-shadow transition-all">
|
|
<div
|
|
class="card-header bg-white border-0 pt-3 pb-0 d-flex justify-content-between align-items-start">
|
|
<div class="d-flex align-items-center">
|
|
<div class="avatar-circle bg-primary bg-opacity-10 text-primary me-2 rounded-circle d-flex align-items-center justify-content-center"
|
|
style="width: 40px; height: 40px;">
|
|
<i class="bi bi-robot fs-5"></i>
|
|
</div>
|
|
<div>
|
|
<h5 class="card-title fw-bold mb-0 text-truncate" style="max-width: 150px;"
|
|
title="{{ bot.name }}">
|
|
{{ bot.name }}
|
|
</h5>
|
|
<small class="text-muted" style="font-size: 0.75rem;">ID: {{ bot.id }}</small>
|
|
</div>
|
|
</div>
|
|
{% if bot.is_active %}
|
|
<span
|
|
class="badge bg-success-subtle text-success border border-success-subtle rounded-pill px-2">
|
|
<i class="bi bi-check-circle-fill me-1"></i>Active
|
|
</span>
|
|
{% else %}
|
|
<span
|
|
class="badge bg-secondary-subtle text-secondary border border-secondary-subtle rounded-pill px-2">
|
|
<i class="bi bi-dash-circle me-1"></i>Inactive
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<p class="card-text text-muted small mb-3 text-truncate-2" style="min-height: 2.5em;">
|
|
{{ bot.description or "설명이 없습니다." }}
|
|
</p>
|
|
|
|
<div class="bg-light rounded p-2 mb-2">
|
|
<div class="d-flex align-items-center text-secondary small mb-1">
|
|
<i class="bi bi-key me-2 text-primary"></i>
|
|
<span class="fw-semibold me-1">Token:</span>
|
|
<span class="font-monospace text-truncate">{{ bot.token[:10] }}...</span>
|
|
</div>
|
|
<div class="d-flex align-items-center text-secondary small">
|
|
<i class="bi bi-chat-dots me-2 text-success"></i>
|
|
<span class="fw-semibold me-1">Chat ID:</span>
|
|
<span class="font-monospace">{{ bot.chat_id }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
{% set types = (bot.notification_types or "").split(",") %}
|
|
{% if 'auth' in types %}
|
|
<span
|
|
class="badge bg-info-subtle text-info border border-info-subtle rounded-pill me-1"><i
|
|
class="bi bi-shield-lock-fill me-1"></i>인증</span>
|
|
{% endif %}
|
|
{% if 'activity' in types %}
|
|
<span
|
|
class="badge bg-warning-subtle text-warning border border-warning-subtle rounded-pill me-1"><i
|
|
class="bi bi-activity me-1"></i>활동</span>
|
|
{% endif %}
|
|
{% if 'system' in types %}
|
|
<span
|
|
class="badge bg-danger-subtle text-danger border border-danger-subtle rounded-pill me-1"><i
|
|
class="bi bi-gear-fill me-1"></i>시스템</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-footer bg-white border-0 pt-0 pb-3">
|
|
<div class="btn-group w-100 shadow-sm" role="group">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-toggle="modal"
|
|
data-bs-target="#editBotModal{{ bot.id }}">
|
|
<i class="bi bi-pencil me-1"></i>수정
|
|
</button>
|
|
|
|
<button type="submit" form="testForm{{ bot.id }}"
|
|
class="btn btn-outline-primary btn-sm">
|
|
<i class="bi bi-send me-1"></i>테스트
|
|
</button>
|
|
|
|
<button type="submit" form="deleteForm{{ bot.id }}"
|
|
class="btn btn-outline-danger btn-sm" onclick="return confirm('정말 삭제하시겠습니까?');">
|
|
<i class="bi bi-trash me-1"></i>삭제
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Hidden Forms -->
|
|
<form id="testForm{{ bot.id }}" action="{{ url_for('admin.test_bot', bot_id=bot.id) }}"
|
|
method="post" class="d-none">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
</form>
|
|
<form id="deleteForm{{ bot.id }}" action="{{ url_for('admin.delete_bot', bot_id=bot.id) }}"
|
|
method="post" class="d-none">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 수정 모달 -->
|
|
<div class="modal fade" id="editBotModal{{ bot.id }}" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content border-0 shadow">
|
|
<form action="{{ url_for('admin.edit_bot', bot_id=bot.id) }}" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div class="modal-header bg-light">
|
|
<h5 class="modal-title fw-bold">
|
|
<i class="bi bi-pencil-square me-2"></i>봇 설정 수정
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">이름 (식별용)</label>
|
|
<input type="text" class="form-control" name="name" value="{{ bot.name }}"
|
|
required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">Bot Token</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="bi bi-key"></i></span>
|
|
<input type="text" class="form-control font-monospace" name="token"
|
|
value="{{ bot.token }}" required>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">Chat ID</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="bi bi-chat-dots"></i></span>
|
|
<input type="text" class="form-control font-monospace" name="chat_id"
|
|
value="{{ bot.chat_id }}" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">알림 유형</label>
|
|
<div class="d-flex gap-3">
|
|
{% set types = (bot.notification_types or "").split(",") %}
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="notify_types"
|
|
value="auth" id="edit_auth_{{ bot.id }}" {{ 'checked' if 'auth' in
|
|
types else '' }}>
|
|
<label class="form-check-label" for="edit_auth_{{ bot.id }}">
|
|
인증
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="notify_types"
|
|
value="activity" id="edit_activity_{{ bot.id }}" {{ 'checked'
|
|
if 'activity' in types else '' }}>
|
|
<label class="form-check-label" for="edit_activity_{{ bot.id }}">
|
|
활동
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="notify_types"
|
|
value="system" id="edit_system_{{ bot.id }}" {{ 'checked'
|
|
if 'system' in types else '' }}>
|
|
<label class="form-check-label" for="edit_system_{{ bot.id }}">
|
|
시스템
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<small class="text-muted">선택한 알림 유형만 전송됩니다</small>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">설명</label>
|
|
<textarea class="form-control" name="description"
|
|
rows="2">{{ bot.description or '' }}</textarea>
|
|
</div>
|
|
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" name="is_active"
|
|
id="activeCheck{{ bot.id }}" {{ 'checked' if bot.is_active else '' }}>
|
|
<label class="form-check-label" for="activeCheck{{ bot.id }}">
|
|
활성화
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
|
|
<button type="submit" class="btn btn-primary px-4">저장</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-5">
|
|
<div class="mb-3">
|
|
<div class="d-inline-flex align-items-center justify-content-center bg-light rounded-circle"
|
|
style="width: 80px; height: 80px;">
|
|
<i class="bi bi-robot fs-1 text-secondary"></i>
|
|
</div>
|
|
</div>
|
|
<h5 class="text-muted fw-normal">등록된 텔레그램 봇이 없습니다.</h5>
|
|
<p class="text-muted small mb-4">우측 상단의 '봇 추가' 버튼을 눌러 알림을 설정하세요.</p>
|
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addBotModal">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content border-0 shadow">
|
|
<form action="{{ url_for('admin.add_bot') }}" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div class="modal-header bg-light">
|
|
<h5 class="modal-title fw-bold">
|
|
<i class="bi bi-plus-circle me-2"></i>새 텔레그램 봇 추가
|
|
</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">이름 (식별용)</label>
|
|
<input type="text" class="form-control" name="name" placeholder="예: 알림용 봇"
|
|
required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">Bot Token</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="bi bi-key"></i></span>
|
|
<input type="text" class="form-control font-monospace" name="token"
|
|
placeholder="123456:ABC..." required>
|
|
</div>
|
|
<div class="form-text">BotFather에게 받은 API Token</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">Chat ID</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text"><i class="bi bi-chat-dots"></i></span>
|
|
<input type="text" class="form-control font-monospace" name="chat_id"
|
|
placeholder="-100..." required>
|
|
</div>
|
|
<div class="form-text">메시지를 받을 채팅방 ID (그룹은 음수)</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">알림 유형</label>
|
|
<div class="d-flex gap-3">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="notify_types"
|
|
value="auth" id="add_auth" checked>
|
|
<label class="form-check-label" for="add_auth">
|
|
인증
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="notify_types"
|
|
value="activity" id="add_activity" checked>
|
|
<label class="form-check-label" for="add_activity">
|
|
활동
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="notify_types"
|
|
value="system" id="add_system" checked>
|
|
<label class="form-check-label" for="add_system">
|
|
시스템
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<small class="text-muted">선택한 알림 유형만 전송됩니다</small>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">설명</label>
|
|
<textarea class="form-control" name="description" rows="2"
|
|
placeholder="선택 사항"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
|
|
<button type="submit" class="btn btn-primary px-4">추가</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %} |