diff --git a/blog/templates/blog/create_post_default.html b/blog/templates/blog/_unarchived_create_post_default.html
similarity index 100%
rename from blog/templates/blog/create_post_default.html
rename to blog/templates/blog/_unarchived_create_post_default.html
diff --git a/blog/templates/blog/create_post.html b/blog/templates/blog/create_post.html
index e5736cd..d97db32 100644
--- a/blog/templates/blog/create_post.html
+++ b/blog/templates/blog/create_post.html
@@ -23,10 +23,8 @@
Contents
+
-
- {{ form.contents }}
-
@@ -75,6 +73,56 @@
hljs.highlightElement(block);
});
});
+
+ // Ctrl+V로 이미지 붙여넣기 처리
+ textarea.addEventListener("paste", async function (event) {
+ const items = (event.clipboardData || event.originalEvent.clipboardData).items;
+
+ for (const item of items) {
+ if (item.type.startsWith("image/")) {
+ const file = item.getAsFile();
+ if (!file)
+ return;
+
+ const formData = new FormData();
+ formData.append("image", file);
+
+ try {
+ // 이미지 업로드 API 호출
+ const response = await fetch("/obs_minio/upload/", {
+ method: "POST",
+ body: formData
+ });
+
+ if (response.ok) {
+ const data = await response.json();
+ const imageUrl = data.url; // 업로드된 이미지 URL
+
+ // 마크다운 에디터에 이미지 삽입
+ const markdownImage = `\n`;
+ textarea.value += markdownImage;
+
+ // 미리보기 업데이트
+ const markdownContent = textarea.value;
+ const renderedContent = md.render(markdownContent);
+ preview.innerHTML = renderedContent;
+
+ // Highlight.js로 코드 블록 강조
+ document
+ .querySelectorAll("#preview pre code")
+ .forEach((block) => {
+ hljs.highlightElement(block);
+ });
+ } else {
+ alert("Image upload failed. Please try again.");
+ }
+ } catch (error) {
+ console.error("Error uploading image:", error);
+ alert("An error occurred during image upload.");
+ }
+ }
+ }
+ });
{% endblock %}
diff --git a/blog/templates/blog/create_post_bakcup.html b/blog/templates/blog/create_post_bakcup.html
new file mode 100644
index 0000000..e5736cd
--- /dev/null
+++ b/blog/templates/blog/create_post_bakcup.html
@@ -0,0 +1,80 @@
+{% extends "components/base.html" %}
+{% block title %}Create Post{% endblock %}
+
+{% block main_area %}
+ Create New Post
+
+{% endblock %}
diff --git a/butler/migrations/0004_delete_noticeboard.py b/butler/migrations/0004_delete_noticeboard.py
new file mode 100644
index 0000000..f561588
--- /dev/null
+++ b/butler/migrations/0004_delete_noticeboard.py
@@ -0,0 +1,16 @@
+# Generated by Django 4.2.14 on 2025-01-25 19:23
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('butler', '0003_rename_desc_ipmanagementrecord_contents'),
+ ]
+
+ operations = [
+ migrations.DeleteModel(
+ name='NoticeBoard',
+ ),
+ ]
diff --git a/butler_ddochi/settings.py b/butler_ddochi/settings.py
index b86905c..aa46220 100644
--- a/butler_ddochi/settings.py
+++ b/butler_ddochi/settings.py
@@ -51,6 +51,7 @@ INSTALLED_APPS = [
'nhnc_mgmt',
'mm_msg',
'ansible_manager',
+ 'obs_minio',
]
MIDDLEWARE = [
diff --git a/butler_ddochi/urls.py b/butler_ddochi/urls.py
index 949e2b3..fcd3c32 100644
--- a/butler_ddochi/urls.py
+++ b/butler_ddochi/urls.py
@@ -30,6 +30,7 @@ urlpatterns = [
path('nhnc_mgmt/', include('nhnc_mgmt.urls')),
path('mm_msg/', include('mm_msg.urls')),
path('ansible_manager/', include('ansible_manager.urls')),
+ path('obs_minio/', include('obs_minio.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/obs_minio/__init__.py b/obs_minio/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/obs_minio/admin.py b/obs_minio/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/obs_minio/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/obs_minio/apps.py b/obs_minio/apps.py
new file mode 100644
index 0000000..d2bea7c
--- /dev/null
+++ b/obs_minio/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class ObsMinioConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'obs_minio'
diff --git a/obs_minio/migrations/__init__.py b/obs_minio/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/obs_minio/models.py b/obs_minio/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/obs_minio/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/obs_minio/tests.py b/obs_minio/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/obs_minio/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/obs_minio/urls.py b/obs_minio/urls.py
new file mode 100644
index 0000000..9b719ea
--- /dev/null
+++ b/obs_minio/urls.py
@@ -0,0 +1,8 @@
+from django.urls import path
+from . import views
+
+app_name = 'obs_minio'
+
+urlpatterns = [
+ path('upload/', views.upload_image, name='upload_image'),
+]
diff --git a/obs_minio/views.py b/obs_minio/views.py
new file mode 100644
index 0000000..dd5ad2c
--- /dev/null
+++ b/obs_minio/views.py
@@ -0,0 +1,47 @@
+import uuid
+from django.http import JsonResponse
+from django.views.decorators.csrf import csrf_exempt
+from minio import Minio
+from minio.error import S3Error
+import urllib3
+
+# MinIO 설정
+MINIO_ENDPOINT = 'minio.icurfer.com:9000'
+MINIO_ACCESS_KEY = 'h5gOXcQieSE0kReVlpDa'
+MINIO_SECRET_KEY = '2S5vtc7DtrnUjqsAO6CF3kPVEqDtqmHgnt3OPIPY'
+BUCKET_NAME = 'butler-ddochi-image'
+
+@csrf_exempt
+def upload_image(request):
+ print("이미지업로드 동작시작")
+ if request.method == 'POST' and 'image' in request.FILES:
+ image = request.FILES['image']
+ unique_filename = f"uploads/{uuid.uuid4()}_{image.name}"
+
+ # MinIO 클라이언트 생성
+ client = Minio(
+ MINIO_ENDPOINT,
+ access_key=MINIO_ACCESS_KEY,
+ secret_key=MINIO_SECRET_KEY,
+ secure=True,
+ http_client=urllib3.PoolManager(cert_reqs='CERT_NONE') # SSL 검증 비활성화
+ )
+
+ try:
+ # MinIO에 파일 업로드
+ client.put_object(
+ bucket_name=BUCKET_NAME,
+ object_name=unique_filename,
+ data=image,
+ length=image.size,
+ content_type=image.content_type
+ )
+
+ # Presigned URL 생성
+ presigned_url = client.presigned_get_object(BUCKET_NAME, unique_filename)
+ return JsonResponse({"url": presigned_url}, status=201)
+
+ except S3Error as e:
+ return JsonResponse({"error": str(e)}, status=500)
+
+ return JsonResponse({"error": "Invalid request"}, status=400)