Compare commits

...

2 Commits

Author SHA1 Message Date
06d1853fb0 url link 저장 및 변경 관리 계정에서 할수 있도록 추가
All checks were successful
Build And Test / build-and-push (push) Successful in 4m8s
2025-01-25 01:30:48 +09:00
sdjo
d34d4f8def landing페이지 수정, 카테고리 리스트 정리
All checks were successful
Build And Test / build-and-push (push) Successful in 5m13s
2025-01-23 14:19:27 +09:00
14 changed files with 451 additions and 79 deletions

View File

@ -0,0 +1,13 @@
{% extends "components/base.html" %}
{% block title %}Landing Page{% endblock %}
{% block main_area %}
<article class="pt-3">
<h2 class="fw-bold pb-2">Welcome!</h2>
<h3>IT Infra 및 DevOps 자원관리 도구</h3>
* IP리스트 관리기능 제공 <br>
* Public NHN Cloud API 기능 일부 제공
<p>계속 기능 구현 중 입니다.</p>
</article>
{% endblock %}

View File

@ -3,11 +3,46 @@
{% block title %}Landing Page{% endblock %} {% block title %}Landing Page{% endblock %}
{% block main_area %} {% block main_area %}
<article class="pt-3"> <div class="container mt-5">
<h2 class="fw-bold pb-2">Welcome!</h2> <div class="row">
<h3>IT Infra 및 DevOps 자원관리 도구</h3> <!-- NoticeBoard Section -->
* IP리스트 관리기능 제공 <br> <div class="col-md-6">
* Public NHN Cloud API 기능 일부 제공 <h2>Latest Notices</h2>
<p>계속 기능 구현 중 입니다.</p> <div class="row">
</article> {% for notice in notices %}
<div class="col-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ notice.title }}</h5>
<p class="card-text">{{ notice.content|truncatewords:20 }}</p>
<a href="{% url 'butler:notice_detail' notice.id %}" class="btn btn-primary">View Notice</a>
</div>
</div>
</div>
{% empty %}
<p>No notices available.</p>
{% endfor %}
</div>
</div>
<!-- Blog Posts Section -->
<div class="col-md-6">
<h2>Latest Blog Posts</h2>
<div class="row">
{% for post in blog_posts %}
<div class="col-12 mb-3">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<p class="card-text">{{ post.summary|truncatewords:20 }}</p>
<a href="{% url 'blog:post_detail' post.id %}" class="btn btn-primary">Read More</a>
</div>
</div>
</div>
{% empty %}
<p>No blog posts available.</p>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -4,7 +4,10 @@ from . import views
app_name = 'butler' app_name = 'butler'
urlpatterns = [ urlpatterns = [
path('', views.hello_view, name='landing'), # 루트 경로에서 hello_view 호출 # path('', views.hello_view, name='landing'), # 루트 경로에서 hello_view 호출
# Landing Page
path('', views.LandingPageView.as_view(), name='landing'), # 클래스 기반 뷰(CBV) 호출
path('notice', views.notice_list, name='notice_list'), path('notice', views.notice_list, name='notice_list'),
path('create_notice/', views.create_notice, name='create_notice'), # 포스트 작성 path('create_notice/', views.create_notice, name='create_notice'), # 포스트 작성
path('notice/<int:pk>/', views.notice_detail_view, name='notice_detail'), path('notice/<int:pk>/', views.notice_detail_view, name='notice_detail'),

View File

@ -1,18 +1,23 @@
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.views.generic import TemplateView
from pathlib import Path from pathlib import Path
import markdown import markdown
import os import os
from .models import NoticeBoard, IPManagementRecord from .models import NoticeBoard, IPManagementRecord
from blog.models import Post
from .forms import PostForm from .forms import PostForm
from django.db.models import Q from django.db.models import Q
def hello_view(request): class LandingPageView(TemplateView):
return render( template_name = "butler/landing.html"
request,
"butler/landing.html", def get_context_data(self, **kwargs):
) context = super().get_context_data(**kwargs)
context['blog_posts'] = Post.objects.order_by('-created_at')[:3]
context['notices'] = NoticeBoard.objects.order_by('-created_at')[:3]
return context
# --- notice --- # --- notice ---
@login_required @login_required

View File

@ -1,40 +1,38 @@
<div class="container-fluid d-flex justify-content-between align-items-center"> <div class="container-fluid d-flex justify-content-between align-items-center">
<h1 class="d-flex align-items-center fs-4 text-white mb-0"> <h1 class="d-flex align-items-center fs-4 text-white mb-0">
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="/">
<i class="fa-solid fa-dog"></i> DDoCHI</a> <i class="fa-solid fa-dog"></i>
DDoCHI</a>
</h1> </h1>
<!-- 로그인/로그아웃 및 회원가입 버튼 --> <!-- 로그인/로그아웃 및 회원가입 버튼 -->
<ul class="navbar-nav flex-row"> <ul class="navbar-nav flex-row">
{% if user.is_authenticated and user.is_superuser %} {% if user.is_authenticated and user.is_superuser %}
<!-- 관리자 콘솔 버튼 --> <!-- 관리자 콘솔 버튼 -->
<li class="nav-item me-3"> <li class="nav-item me-3">
<a href="/admin" target="_blank" class="btn btn-outline-warning mb-2">ADMIN</a> <a href="/admin" target="_blank" class="btn btn-outline-warning mb-2">ADMIN</a>
</li> </li>
{% endif %} {% endif %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<!-- 회원정보 변경 버튼 --> <!-- 회원정보 변경 버튼 -->
<li class="nav-item me-3"> <li class="nav-item me-3">
<button type="button" class="btn btn-outline-info mb-2" data-bs-toggle="modal" <button type="button" class="btn btn-outline-info mb-2" data-bs-toggle="modal" data-bs-target="#editProfileModal">Edit Profile</button>
data-bs-target="#editProfileModal">Edit Profile</button> </li>
</li> <!-- 로그아웃 버튼 -->
<!-- 로그아웃 버튼 --> <li class="nav-item">
<li class="nav-item"> <form method="post" action="{% url 'custom_auth:logout' %}">
<form method="post" action="{% url 'custom_auth:logout' %}"> {% csrf_token %}
{% csrf_token %} <button type="submit" class="btn btn-outline-danger w-100">Logout</button>
<button type="submit" class="btn btn-outline-danger w-100">Logout</button> </form>
</form> </li>
</li>
{% else %} {% else %}
<!-- 로그인 버튼 --> <!-- 로그인 버튼 -->
<li class="nav-item me-3"> <li class="nav-item me-3">
<button type="button" class="btn btn-outline-primary mb-2" data-bs-toggle="modal" <button type="button" class="btn btn-outline-primary mb-2" data-bs-toggle="modal" data-bs-target="#loginModal">Login</button>
data-bs-target="#loginModal">Login</button> </li>
</li> <!-- 회원가입 버튼 -->
<!-- 회원가입 버튼 --> <li class="nav-item me-3">
<li class="nav-item me-3"> <button type="button" class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#signupModal">Sign Up</button>
<button type="button" class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#signupModal">Sign </li>
Up</button>
</li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
@ -50,11 +48,11 @@
<div class="modal-body"> <div class="modal-body">
<!-- 로그인 실패 메시지 표시 --> <!-- 로그인 실패 메시지 표시 -->
{% if messages %} {% if messages %}
{% for message in messages %} {% for message in messages %}
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
{{ message }} {{ message }}
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<!-- 로그인 폼 --> <!-- 로그인 폼 -->
@ -123,7 +121,7 @@
{% csrf_token %} {% csrf_token %}
<div class="mb-3"> <div class="mb-3">
<label for="emailEdit" class="form-label">Email</label> <label for="emailEdit" class="form-label">Email</label>
<input type="email" class="form-control" id="emailEdit" name="email" value="{{ request.user.email }}" required> <input type="email" class="form-control" id="emailEdit" name="email" value="{{ request.user.email }}" required="required">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="nhncIdEdit" class="form-label">NHNC ID</label> <label for="nhncIdEdit" class="form-label">NHNC ID</label>
@ -133,6 +131,52 @@
<label for="nhncApiTenantIdEdit" class="form-label">NHNC API Tenant ID</label> <label for="nhncApiTenantIdEdit" class="form-label">NHNC API Tenant ID</label>
<input type="text" class="form-control" id="nhncApiTenantIdEdit" name="nhnc_api_tenant_id" value="{{ request.user.nhnc_api_tenant_id }}"> <input type="text" class="form-control" id="nhncApiTenantIdEdit" name="nhnc_api_tenant_id" value="{{ request.user.nhnc_api_tenant_id }}">
</div> </div>
<!-- 추가된 URL 필드 -->
<div class="mb-3">
<label for="urlGiteaEdit" class="form-label">Gitea URL</label>
<input type="url" class="form-control" id="urlGiteaEdit" name="url_gitea" value="{{ request.user.url_gitea }}">
</div>
<div class="mb-3">
<label for="urlHarborEdit" class="form-label">Harbor URL</label>
<input type="url" class="form-control" id="urlHarborEdit" name="url_harbor" value="{{ request.user.url_harbor }}">
</div>
<div class="mb-3">
<label for="urlArgoCDEdit" class="form-label">ArgoCD URL</label>
<input type="url" class="form-control" id="urlArgoCDEdit" name="url_argocd" value="{{ request.user.url_argocd }}">
</div>
<div class="mb-3">
<label for="urlWebIdeEdit" class="form-label">Web IDE URL</label>
<input type="url" class="form-control" id="urlWebIdeEdit" name="url_web_ide" value="{{ request.user.url_web_ide }}">
</div>
<div class="mb-3">
<label for="urlRancherEdit" class="form-label">Rancher URL</label>
<input type="url" class="form-control" id="urlRancherEdit" name="url_rancher" value="{{ request.user.url_rancher }}">
</div>
<div class="mb-3">
<label for="urlGrafanaEdit" class="form-label">Grafana URL</label>
<input type="url" class="form-control" id="urlGrafanaEdit" name="url_grafana" value="{{ request.user.url_grafana }}">
</div>
<div class="mb-3">
<label for="urlPrometheusEdit" class="form-label">Prometheus URL</label>
<input type="url" class="form-control" id="urlPrometheusEdit" name="url_prometheus" value="{{ request.user.url_prometheus }}">
</div>
<div class="mb-3">
<label for="urlOpensearchEdit" class="form-label">OpenSearch URL</label>
<input type="url" class="form-control" id="urlOpensearchEdit" name="url_opensearch" value="{{ request.user.url_opensearch }}">
</div>
<div class="mb-3">
<label for="urlKialiEdit" class="form-label">Kiali URL</label>
<input type="url" class="form-control" id="urlKialiEdit" name="url_kiali" value="{{ request.user.url_kiali }}">
</div>
<div class="mb-3">
<label for="urlNexusEdit" class="form-label">Nexus URL</label>
<input type="url" class="form-control" id="urlNexusEdit" name="url_nexus" value="{{ request.user.url_nexus }}">
</div>
<div class="mb-3">
<label for="urlMattermostEdit" class="form-label">Mattermost URL</label>
<input type="url" class="form-control" id="urlMattermostEdit" name="url_mattermost" value="{{ request.user.url_mattermost }}">
</div>
<!-- 비밀번호 변경 -->
<div class="mb-3"> <div class="mb-3">
<label for="passwordEdit" class="form-label">새 비밀번호</label> <label for="passwordEdit" class="form-label">새 비밀번호</label>
<input type="password" class="form-control" id="passwordEdit" name="password"> <input type="password" class="form-control" id="passwordEdit" name="password">

View File

@ -2,15 +2,16 @@
<nav class="sticky-xl-top small" id="toc"> <nav class="sticky-xl-top small" id="toc">
<ul class="list-unstyled"> <ul class="list-unstyled">
<li class="my-2"> <li class="my-2">
<button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#about-collapse" aria-controls="about-collapse">About</button> <button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#about-collapse" aria-controls="about-collapse">About</button>
<ul class="list-unstyled ps-3 collapse" id="about-collapse"> <ul class="list-unstyled ps-3 collapse" id="about-collapse">
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="/notice">공지사항</a> <a class="d-inline-flex align-items-center rounded" href="/notice">공지사항</a>
</li> </li>
</ul> </ul>
</li> </li>
<hr>
<li class="my-2"> <li class="my-2">
<button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#contents-collapse" aria-controls="contents-collapse">Contents</button> <button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#contents-collapse" aria-controls="contents-collapse">Contents</button>
<ul class="list-unstyled ps-3 collapse" id="contents-collapse"> <ul class="list-unstyled ps-3 collapse" id="contents-collapse">
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="/blog">Post</a> <a class="d-inline-flex align-items-center rounded" href="/blog">Post</a>
@ -30,9 +31,8 @@
</li> </li>
<hr> <hr>
<li class="my-2"> <li class="my-2">
<button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#nhnc-collapse" aria-controls="nhnc-collapse">NHN Cloud API</button> <button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#nhnc-collapse" aria-controls="nhnc-collapse">NHN Cloud API</button>
<ul class="list-unstyled ps-3 collapse" id="nhnc-collapse"> <ul class="list-unstyled ps-3 collapse" id="nhnc-collapse">
<span>가이드</span>
{% if request.user.is_authenticated and request.user.is_staff %} {% if request.user.is_authenticated and request.user.is_staff %}
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="/nhncloud/test">출력결과 검토</a> <a class="d-inline-flex align-items-center rounded" href="/nhncloud/test">출력결과 검토</a>
@ -78,56 +78,51 @@
</li> </li>
<hr> <hr>
<li class="my-2"> <li class="my-2">
<button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#components-collapse" aria-controls="components-collapse">DevOpsTools</button> <button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#components-collapse" aria-controls="components-collapse">DevOpsTools</button>
<ul class="list-unstyled ps-3 collapse" id="components-collapse"> <ul class="list-unstyled ps-3 collapse" id="components-collapse">
<span>Dev</span> <span>Dev</span>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://gitea.icurfer.com/icurfer" target="_blank">Repository - Gitea</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_gitea}}" target="_blank">Repository - Gitea</a>
</li> </li>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://harbor.icurfer.com/" target="_blank">Registry - Harbor</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_harbor}}" target="_blank">Registry - Harbor</a>
</li> </li>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://argocd.icurfer.com/" target="_blank">Deploy - ArgoCD</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_argocd}}" target="_blank">Deploy - ArgoCD</a>
</li> </li>
<hr> <hr>
<span>Ops</span> <span>Ops</span>
{% if request.user.is_authenticated and request.user.is_staff %} {% if request.user.is_authenticated and request.user.is_staff %}
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://code.icurfer.com/" target="_blank">Web VScode - CodeServer</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_web_ide}}" target="_blank">Web VScode - CodeServer</a>
</li> </li>
{% endif %} {% endif %}
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://rancher.icurfer.com/" target="_blank">Cluster Management - Rancher</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_rancher}}" target="_blank">Cluster Management - Rancher</a>
</li> </li>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://grafana.icurfer.com/" target="_blank">Monitoring - Grafana</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_grafana}}" target="_blank">Monitoring - Grafana</a>
</li> </li>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://prometheus.icurfer.com/" target="_blank">Metrics - Prometheus</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_prometheus}}" target="_blank">Metrics - Prometheus</a>
</li> </li>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://os.icurfer.com/" target="_blank">Container Log - OpenSearch</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_opensearch}}" target="_blank">Container Log - OpenSearch</a>
</li> </li>
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="https://kiali.icurfer.com/" target="_blank">Main Cluster Traffic - Kiali</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_kiali}}" target="_blank">Main Cluster Traffic - Kiali</a>
</li>
</ul>
</li>
<li class="my-2">
<button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#other-collapse" aria-controls="other-collapse">Other Tools</button>
<ul class="list-unstyled ps-3 collapse" id="other-collapse">
<li>
<a class="d-inline-flex align-items-center rounded" href="https://mm.icurfer.com/" target="_blank">Messenger - Mattermost</a>
</li> </li>
</ul> </ul>
</li> </li>
<hr> <hr>
<li class="my-2"> <li class="my-2">
<button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#forms-collapse" aria-controls="forms-collapse">Documents</button> <button class="btn d-inline-flex align-items-center collapsed" data-bs-toggle="collapse" aria-expanded="false" data-bs-target="#other-collapse" aria-controls="other-collapse">Other Tools ▽</button>
<ul class="list-unstyled ps-3 collapse" id="forms-collapse"> <ul class="list-unstyled ps-3 collapse" id="other-collapse">
<li> <li>
<a class="d-inline-flex align-items-center rounded" href="#">사용가이드</a> <a class="d-inline-flex align-items-center rounded" href="{{request.user.url_mattermost}}" target="_blank">Messenger - Mattermost</a>
</li>
<li>
<a class="d-inline-flex align-items-center rounded" href="{{request.user.url_nexus}}" target="_blank">Nexus</a>
</li> </li>
</ul> </ul>
</li> </li>

View File

@ -0,0 +1,149 @@
<div class="container-fluid d-flex justify-content-between align-items-center">
<h1 class="d-flex align-items-center fs-4 text-white mb-0">
<a class="navbar-brand" href="/">
<i class="fa-solid fa-dog"></i> DDoCHI</a>
</h1>
<!-- 로그인/로그아웃 및 회원가입 버튼 -->
<ul class="navbar-nav flex-row">
{% if user.is_authenticated and user.is_superuser %}
<!-- 관리자 콘솔 버튼 -->
<li class="nav-item me-3">
<a href="/admin" target="_blank" class="btn btn-outline-warning mb-2">ADMIN</a>
</li>
{% endif %}
{% if request.user.is_authenticated %}
<!-- 회원정보 변경 버튼 -->
<li class="nav-item me-3">
<button type="button" class="btn btn-outline-info mb-2" data-bs-toggle="modal"
data-bs-target="#editProfileModal">Edit Profile</button>
</li>
<!-- 로그아웃 버튼 -->
<li class="nav-item">
<form method="post" action="{% url 'custom_auth:logout' %}">
{% csrf_token %}
<button type="submit" class="btn btn-outline-danger w-100">Logout</button>
</form>
</li>
{% else %}
<!-- 로그인 버튼 -->
<li class="nav-item me-3">
<button type="button" class="btn btn-outline-primary mb-2" data-bs-toggle="modal"
data-bs-target="#loginModal">Login</button>
</li>
<!-- 회원가입 버튼 -->
<li class="nav-item me-3">
<button type="button" class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#signupModal">Sign
Up</button>
</li>
{% endif %}
</ul>
</div>
<!-- 로그인 모달 -->
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="loginModalLabel">Login</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- 로그인 실패 메시지 표시 -->
{% if messages %}
{% for message in messages %}
<div class="alert alert-danger" role="alert">
{{ message }}
</div>
{% endfor %}
{% endif %}
<!-- 로그인 폼 -->
<form method="post" action="{% url 'custom_auth:login' %}">
{% csrf_token %}
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control" id="username" name="username" required="required">
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" name="password" required="required">
</div>
<button type="submit" class="btn btn-primary w-100">Login</button>
</form>
</div>
</div>
</div>
</div>
<!-- 회원가입 모달 -->
<div class="modal fade" id="signupModal" tabindex="-1" aria-labelledby="signupModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="signupModalLabel">Sign Up</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- 회원가입 폼 -->
<form method="post" action="{% url 'custom_auth:signup' %}">
{% csrf_token %}
<div class="mb-3">
<label for="usernameSignup" class="form-label">Username</label>
<input type="text" class="form-control" id="usernameSignup" name="username" required="required">
</div>
<div class="mb-3">
<label for="passwordSignup" class="form-label">Password</label>
<input type="password" class="form-control" id="passwordSignup" name="password1" required="required">
</div>
<div class="mb-3">
<label for="passwordConfirmSignup" class="form-label">Confirm Password</label>
<input type="password" class="form-control" id="passwordConfirmSignup" name="password2" required="required">
</div>
<a href="{% url 'butler:privacy' %}" class="text-dark" target="_blank">개인정보 처리방침</a>
<p class="text-danger">회원 가입후 권한 신청 메일을 보내주세요.</p>
<p class="text-danger">회원 가입시 본 개인정보 처리방침에 동의하는 것으로 간주됩니다.</p>
<button type="submit" class="btn btn-success w-100">Sign Up</button>
</form>
</div>
</div>
</div>
</div>
<!-- 회원정보 변경 모달 -->
<div class="modal fade" id="editProfileModal" tabindex="-1" aria-labelledby="editProfileModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editProfileModalLabel">Edit Profile</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- 회원정보 변경 폼 -->
<form method="post" action="{% url 'custom_auth:edit_profile' %}">
{% csrf_token %}
<div class="mb-3">
<label for="emailEdit" class="form-label">Email</label>
<input type="email" class="form-control" id="emailEdit" name="email" value="{{ request.user.email }}" required>
</div>
<div class="mb-3">
<label for="nhncIdEdit" class="form-label">NHNC ID</label>
<input type="text" class="form-control" id="nhncIdEdit" name="nhnc_id" value="{{ request.user.nhnc_id }}">
</div>
<div class="mb-3">
<label for="nhncApiTenantIdEdit" class="form-label">NHNC API Tenant ID</label>
<input type="text" class="form-control" id="nhncApiTenantIdEdit" name="nhnc_api_tenant_id" value="{{ request.user.nhnc_api_tenant_id }}">
</div>
<div class="mb-3">
<label for="passwordEdit" class="form-label">새 비밀번호</label>
<input type="password" class="form-control" id="passwordEdit" name="password">
</div>
<div class="mb-3">
<label for="passwordConfirmEdit" class="form-label">비밀번호 확인</label>
<input type="password" class="form-control" id="passwordConfirmEdit" name="password_confirm">
</div>
<button type="submit" class="btn btn-primary w-100">Save Changes</button>
</form>
</div>
</div>
</div>
</div>

View File

@ -12,14 +12,32 @@ class CustomUserAdmin(UserAdmin):
# 사용자 필드 구성 # 사용자 필드 구성
fieldsets = ( fieldsets = (
(None, {'fields': ('username', 'password')}), (None, {'fields': ('username', 'password')}),
('Personal Info', {'fields': ('email', 'encrypted_private_key')}), ('Personal Info', {
'fields': (
'email',
'encrypted_private_key',
'nhnc_id',
'nhnc_api_tenant_id',
'url_gitea',
'url_harbor',
'url_argocd',
'url_web_ide',
'url_rancher',
'url_grafana',
'url_prometheus',
'url_opensearch',
'url_kiali',
'url_nexus',
'url_mattermost',
)
}),
('Permissions', {'fields': ('is_staff', 'is_active')}), ('Permissions', {'fields': ('is_staff', 'is_active')}),
) )
# 읽기 전용 필드 추가 # 읽기 전용 필드 추가
readonly_fields = ('encrypted_private_key',) readonly_fields = ('encrypted_private_key',)
search_fields = ('username', 'email') search_fields = ('username', 'email', 'nhnc_id', 'nhnc_api_tenant_id')
ordering = ('username',) ordering = ('username',)

View File

@ -23,7 +23,22 @@ class CustomUserChangeForm(UserChangeForm):
class Meta: class Meta:
model = CustomUser model = CustomUser
fields = ["email", "nhnc_id", "nhnc_api_tenant_id"] fields = [
'email',
'nhnc_id',
'nhnc_api_tenant_id',
'url_gitea',
'url_harbor',
'url_argocd',
'url_web_ide',
'url_rancher',
'url_grafana',
'url_prometheus',
'url_opensearch',
'url_kiali',
'url_nexus',
'url_mattermost',
]
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()

View File

@ -0,0 +1,58 @@
# Generated by Django 4.2.14 on 2025-01-25 00:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('custom_auth', '0005_customuser_encrypted_private_key'),
]
operations = [
migrations.AddField(
model_name='customuser',
name='url_argocd',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_gitea',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_grafana',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_harbor',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_kiali',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_opensearch',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_prometheus',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_rancher',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_web_ide',
field=models.URLField(blank=True, null=True),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.14 on 2025-01-25 01:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('custom_auth', '0006_customuser_url_argocd_customuser_url_gitea_and_more'),
]
operations = [
migrations.AddField(
model_name='customuser',
name='url_mattermost',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='customuser',
name='url_nexus',
field=models.URLField(blank=True, null=True),
),
]

View File

@ -5,15 +5,29 @@ from cryptography.fernet import Fernet
class CustomUser(AbstractUser): class CustomUser(AbstractUser):
"""사용자 모델 - 기존 필드 + SSH Private Key 관리 필드""" # 사용자 모델 - 기존 필드 + SSH Private Key 관리 필드
# 기존 필드 유지
grade = models.CharField(max_length=50, blank=True, null=True) grade = models.CharField(max_length=50, blank=True, null=True)
nhnc_id = models.CharField(max_length=100, blank=True, null=True) nhnc_id = models.CharField(max_length=100, blank=True, null=True)
nhnc_api_tenant_id = models.CharField(max_length=100, blank=True, null=True) nhnc_api_tenant_id = models.CharField(max_length=100, blank=True, null=True)
"""사용자 모델 - SSH Private Key 관리 필드""" # 사용자 모델 - SSH Private Key 관리 필드
encrypted_private_key = models.BinaryField(blank=True, null=True) # 암호화된 SSH 키 encrypted_private_key = models.BinaryField(blank=True, null=True) # 암호화된 SSH 키
# Custom URL 필드 - 2025-01-25
# 여기 추가하면 components/_nav.html 수정
# custom_auth/forms.py 수정, custom_auth/views.py 수정
url_gitea = models.URLField(max_length=200, blank=True, null=True)
url_harbor = models.URLField(max_length=200, blank=True, null=True)
url_argocd = models.URLField(max_length=200, blank=True, null=True)
url_web_ide = models.URLField(max_length=200, blank=True, null=True)
url_rancher = models.URLField(max_length=200, blank=True, null=True)
url_grafana = models.URLField(max_length=200, blank=True, null=True)
url_prometheus = models.URLField(max_length=200, blank=True, null=True)
url_opensearch = models.URLField(max_length=200, blank=True, null=True)
url_kiali = models.URLField(max_length=200, blank=True, null=True)
url_nexus = models.URLField(max_length=200, blank=True, null=True)
url_mattermost = models.URLField(max_length=200, blank=True, null=True)
def encrypt_private_key(self, private_key: str) -> bytes: def encrypt_private_key(self, private_key: str) -> bytes:
"""SSH Private Key 암호화""" """SSH Private Key 암호화"""

View File

@ -1 +1 @@
dev_0.0.22 dev_0.0.24