Compare commits

...

2 Commits

Author SHA1 Message Date
99a3db95a8 README.md update
All checks were successful
Build And Test / build-and-push (push) Successful in 4m21s
2025-04-10 00:23:13 +09:00
ff2e624fc8 ip mgmt view template update 2025-04-10 00:22:05 +09:00
3 changed files with 170 additions and 178 deletions

View File

@ -49,9 +49,5 @@ docker 또는 kubernetes를 이용하여 배포 합니다.
* MM_URL=https://mm.example.com/hooks/${hash} * MM_URL=https://mm.example.com/hooks/${hash}
* (기능 미구현)MINIO_URL=https://minio.example.com/ * (기능 미구현)MINIO_URL=https://minio.example.com/
## 특이사항 ## 가이드
### markdown에디터에 삽입된 이미지 렌더링할때 404에러가 발생하지만, 실제 동작은 잘 되는 이유. * https://butler.icurfer.com/notice/
* MinIO와 연결하여 이미지 저장 기능을 사용 할 수 있도록 구현되어 있습니다.
* Bucket을 private로 설정하는 것을 선호하므로 Presigned URL로 호출해 오도록 설정되어 있습니다.
* 게시물에는 Presigned URL이 아닌 버킷에 저장된 이미지의 이름만 들어있으므로 get_presigned_url을 이용하여 Presigned URL을 호출하기전에 렌더링이 발생하는 에러 메세지입니다.
* 에러가 아니니 기능상 문제 없이 사용 가능합니다.

View File

@ -3,29 +3,28 @@
{% block title %}IP Management{% endblock %} {% block title %}IP Management{% endblock %}
{% block main_area %} {% block main_area %}
<h2 class="fw-bold pt-3 pb-2">IP 관리 대장</h2> <h2 class="fw-bold pt-3 pb-2">IP 관리 대장</h2>
{% if not request.user.is_authenticated %} {% if not request.user.is_authenticated %}
<p class="text-danger">비로그인 익명사용자로 접근 중입니다. <p class="text-danger">비로그인 익명사용자로 접근 중입니다.
<br>로그인시 로그인 사용자가 등록한 데이터만 조회됩니다. <br>로그인시 로그인 사용자가 등록한 데이터만 조회됩니다.
</p> </p>
{% endif %} {% endif %}
<!-- 검색 폼 --> <!-- 검색 폼 -->
<div class="row"> <div class="row">
<div class="col-4"></div> <div class="col-4"></div>
<div class="col-4"></div> <div class="col-4"></div>
<div class="col-4"> <div class="col-4">
<form method="get" class="mb-3"> <form method="get" class="mb-3">
<div class="input-group"> <div class="input-group">
<input type="text" name="var_search" class="form-control" placeholder="Search by Author or Network Name..." <input type="text" name="var_search" class="form-control" placeholder="Search by Author or Network Name..." value="{{ var_search }}">
value="{{ var_search }}">
<button type="submit" class="btn btn-outline-primary">Search</button> <button type="submit" class="btn btn-outline-primary">Search</button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
<!-- IP 레코드 목록 --> <!-- IP 레코드 목록 -->
<form id="recordForm" method="post" action=""> <form id="recordForm" method="post" action="">
{% csrf_token %} {% csrf_token %}
<table class="table table-striped table-hover table-bordered"> <table class="table table-striped table-hover table-bordered">
<thead class="table-dark"> <thead class="table-dark">
@ -44,12 +43,11 @@
{% for record in records %} {% for record in records %}
<tr data-record-id="{{ record.id }}"> <tr data-record-id="{{ record.id }}">
<td class="text-center"> <td class="text-center">
<input type="checkbox" name="selected_records" value="{{ record.id }}" <input type="checkbox" name="selected_records" value="{{ record.id }}" class="form-check-input record-checkbox">
class="form-check-input record-checkbox">
</td> </td>
<td>{{ record.network_nm }}</td> <td>{{ record.network_nm }}</td>
<td>{{ record.contents }}</td>
<td>{{ record.svr_nm }}</td> <td>{{ record.svr_nm }}</td>
<td>{{ record.contents }}</td>
<td>{{ record.ip_addrs }}</td> <td>{{ record.ip_addrs }}</td>
<td>{{ record.remark }}</td> <td>{{ record.remark }}</td>
<td>{{ record.author }}</td> <td>{{ record.author }}</td>
@ -65,22 +63,24 @@
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addDataModal"> <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addDataModal">
<i class="bi bi-plus-lg"></i> Add New IP Record <i class="bi bi-plus-lg"></i>
Add New IP Record
</button> </button>
<button type="submit" formaction="{% url 'butler:ip_mgmt_delete' %}" class="btn btn-danger"> <button type="submit" formaction="{% url 'butler:ip_mgmt_delete' %}" class="btn btn-danger">
<i class="bi bi-trash"></i> Delete Selected <i class="bi bi-trash"></i>
Delete Selected
</button> </button>
<button type="button" id="editSelectedButton" class="btn btn-warning" disabled="disabled"> <button type="button" id="editSelectedButton" class="btn btn-warning" disabled="disabled">
<i class="bi bi-pencil-square"></i> Edit Selected <i class="bi bi-pencil-square"></i>
Edit Selected
</button> </button>
</div> </div>
{% endif %} {% endif %}
</form> </form>
<!-- 수정 모달들 (form 중첩 제거) --> <!-- 수정 모달들 (form 중첩 제거) -->
{% for record in records %} {% for record in records %}
<div class="modal fade" id="editDataModal-{{ record.id }}" tabindex="-1" <div class="modal fade" id="editDataModal-{{ record.id }}" tabindex="-1" aria-labelledby="editDataModalLabel-{{ record.id }}" aria-hidden="true">
aria-labelledby="editDataModalLabel-{{ record.id }}" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header bg-warning text-dark"> <div class="modal-header bg-warning text-dark">
@ -88,24 +88,20 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form id="editDataForm-{{ record.id }}" method="post" <form id="editDataForm-{{ record.id }}" method="post" action="{% url 'butler:ip_mgmt_edit' record.id %}{% if var_search %}?var_search={{ var_search }}{% endif %}">
action="{% url 'butler:ip_mgmt_edit' record.id %}{% if var_search %}?var_search={{ var_search }}{% endif %}">
{% csrf_token %} {% csrf_token %}
{% if var_search %}<input type="hidden" name="var_search" value="{{ var_search }}">{% endif %} {% if var_search %}<input type="hidden" name="var_search" value="{{ var_search }}">{% endif %}
<div class="mb-3"> <div class="mb-3">
<label for="networkNm-{{ record.id }}" class="form-label">Network Name</label> <label for="networkNm-{{ record.id }}" class="form-label">Network Name</label>
<input type="text" class="form-control" id="networkNm-{{ record.id }}" name="network_nm" <input type="text" class="form-control" id="networkNm-{{ record.id }}" name="network_nm" value="{{ record.network_nm }}" required="required">
value="{{ record.network_nm }}" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="ipAddrs-{{ record.id }}" class="form-label">IP Address</label> <label for="ipAddrs-{{ record.id }}" class="form-label">IP Address</label>
<input type="text" class="form-control" id="ipAddrs-{{ record.id }}" name="ip_addrs" <input type="text" class="form-control" id="ipAddrs-{{ record.id }}" name="ip_addrs" value="{{ record.ip_addrs }}" required="required">
value="{{ record.ip_addrs }}" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="svrNm-{{ record.id }}" class="form-label">Server Name</label> <label for="svrNm-{{ record.id }}" class="form-label">Server Name</label>
<input type="text" class="form-control" id="svrNm-{{ record.id }}" name="svr_nm" <input type="text" class="form-control" id="svrNm-{{ record.id }}" name="svr_nm" value="{{ record.svr_nm }}" required="required">
value="{{ record.svr_nm }}" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="contents-{{ record.id }}" class="form-label">Location</label> <label for="contents-{{ record.id }}" class="form-label">Location</label>
@ -120,11 +116,11 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
<!-- 등록 모달 --> <!-- 등록 모달 -->
<div class="modal fade" id="addDataModal" tabindex="-1" aria-labelledby="addDataModalLabel" aria-hidden="true"> <div class="modal fade" id="addDataModal" tabindex="-1" aria-labelledby="addDataModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header bg-success text-white"> <div class="modal-header bg-success text-white">
@ -136,15 +132,15 @@
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="networkNm" class="form-label">Network Name</label> <label for="networkNm" class="form-label">Network Name</label>
<input type="text" class="form-control" id="networkNm" name="network_nm" required> <input type="text" class="form-control" id="networkNm" name="network_nm" required="required">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="ipAddrs" class="form-label">IP Address</label> <label for="ipAddrs" class="form-label">IP Address</label>
<input type="text" class="form-control" id="ipAddrs" name="ip_addrs" required> <input type="text" class="form-control" id="ipAddrs" name="ip_addrs" required="required">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="svrNm" class="form-label">Server Name</label> <label for="svrNm" class="form-label">Server Name</label>
<input type="text" class="form-control" id="svrNm" name="svr_nm" required> <input type="text" class="form-control" id="svrNm" name="svr_nm" required="required">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="contents" class="form-label">Location</label> <label for="contents" class="form-label">Location</label>
@ -159,9 +155,9 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const editButton = document.getElementById('editSelectedButton'); const editButton = document.getElementById('editSelectedButton');
const checkboxes = document.querySelectorAll('.record-checkbox'); const checkboxes = document.querySelectorAll('.record-checkbox');
@ -185,5 +181,5 @@
} }
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1 +1 @@
dev_0.0.36 dev_0.0.37