v0.0.21 | NHN Cloud 멀티 프로젝트 지원 추가
Some checks failed
Build And Test / build-and-push (push) Failing after 34s

- NHNCloudProject 모델 추가 (사용자별 여러 프로젝트 관리)
- 프로젝트 목록/추가/삭제/활성화 API 추가
- 프로젝트별 비밀번호 복호화 API 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-14 20:59:37 +09:00
parent 18901938c7
commit c97b3c6c3b
5 changed files with 311 additions and 4 deletions

View File

@ -142,3 +142,58 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
self.save(update_fields=[
'nhn_tenant_id', 'nhn_username', 'encrypted_nhn_api_password', 'nhn_storage_account'
])
# ============================================
# NHN Cloud 프로젝트 (멀티 프로젝트 지원)
# ============================================
class NHNCloudProject(models.Model):
"""
사용자별 NHN Cloud 프로젝트 관리 (멀티 프로젝트 지원)
"""
user = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
related_name='nhn_projects',
verbose_name="사용자"
)
name = models.CharField(max_length=100, verbose_name="프로젝트 별칭")
tenant_id = models.CharField(max_length=64, verbose_name="NHN Cloud Tenant ID")
username = models.EmailField(verbose_name="NHN Cloud Username")
encrypted_password = models.BinaryField(verbose_name="NHN Cloud API Password (암호화)")
storage_account = models.CharField(max_length=128, blank=True, null=True, verbose_name="Storage Account")
is_active = models.BooleanField(default=False, verbose_name="활성 프로젝트")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "NHN Cloud 프로젝트"
verbose_name_plural = "NHN Cloud 프로젝트"
unique_together = ['user', 'tenant_id'] # 동일 사용자가 같은 tenant 중복 등록 방지
ordering = ['-is_active', '-created_at']
def __str__(self):
return f"{self.name} ({self.tenant_id})"
def get_encryption_key(self) -> bytes:
"""SECRET_KEY 기반 Fernet 키 생성"""
hashed = hashlib.sha256(settings.SECRET_KEY.encode()).digest()
return base64.urlsafe_b64encode(hashed[:32])
def encrypt_password(self, password: str) -> bytes:
"""비밀번호 암호화"""
cipher = Fernet(self.get_encryption_key())
return cipher.encrypt(password.encode())
def decrypt_password(self) -> str:
"""비밀번호 복호화"""
if self.encrypted_password:
cipher = Fernet(self.get_encryption_key())
return cipher.decrypt(self.encrypted_password).decode()
return ""
def save_credentials(self, password: str):
"""자격증명 저장 (비밀번호 암호화)"""
self.encrypted_password = self.encrypt_password(password)
self.save()