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 = `![Image](${imageUrl})\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

+
+
+
+
+ {% csrf_token %} +
+ {{ form.title.label_tag }} + {{ form.title }} +
+
+ {{ form.summary.label_tag }} + {{ form.summary }} +
+
+ {{ form.tags.label_tag }} + {{ form.tags }} +
+ + +

Contents

+ +
+ {{ form.contents }} +
+ +
+ + Cancel +
+
+
+
+
+
+
+ + + + + + +
+{% 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)