Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
49 changes: 49 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy to EC2

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:

build:
name: Build
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master

- name: create env file
run: |
touch .env
echo "${{ secrets.ENV_VARS }}" >> .env

- name: create remote directory
uses: appleboy/ssh-action@v0.1.4
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.KEY }}
script: mkdir -p /home/ubuntu/srv/ubuntu

- name: copy source via ssh key
uses: burnett01/rsync-deployments@4.1
with:
switches: -avzr --delete
remote_path: /home/ubuntu/srv/ubuntu/
remote_host: ${{ secrets.HOST }}
remote_user: ubuntu
remote_key: ${{ secrets.KEY }}

- name: executing remote ssh commands using password
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ubuntu
key: ${{ secrets.KEY }}
script: |
sh /home/ubuntu/srv/ubuntu/config/scripts/deploy.sh
2 changes: 1 addition & 1 deletion .github/workflows/django.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: [3.7, 3.8, 3.9]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ ENV/
env.bak/
venv.bak/
newvenv.bak/
.env.prod
46 changes: 46 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# === Build stage ===
FROM python:3.11-alpine AS build

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app

# 빌드에 필요한 라이브러리(헤더/컴파일러 포함)
RUN apk add --no-cache --virtual .build-deps \
build-base \
gcc \
musl-dev \
python3-dev \
postgresql-dev \
libjpeg-turbo-dev \
zlib-dev

# pip 최신화 + 파이썬 패키지 설치
COPY requirements.txt .
RUN python -m pip install --upgrade pip setuptools wheel \
&& pip install --no-cache-dir -r requirements.txt

# 소스 복사
COPY . .

# === Runtime stage ===
FROM python:3.11-alpine AS runtime

ENV PYTHONUNBUFFERED=1
WORKDIR /app

# 런타임에만 필요한 라이브러리
RUN apk add --no-cache \
libpq \
libjpeg-turbo \
zlib \
tzdata \
netcat-openbsd

# 빌드 결과(설치된 site-packages 등)와 앱 복사
COPY --from=build /usr/local /usr/local
COPY --from=build /app /app

# 포트/명령은 compose에서 지정 (예: gunicorn)
# EXPOSE 8000
# CMD ["gunicorn", "drfproject.wsgi:application", "-b", "0.0.0.0:8000"]
40 changes: 40 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# === BUILDER ===
FROM python:3.11-alpine AS BUILDER
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
WORKDIR /app

# 빌드에 필요한 라이브러리 (psycopg2-binary는 보통 빌드 불필요지만 보험 겸)
RUN apk add --no-cache --virtual .build-deps \
build-base gcc musl-dev python3-dev postgresql-dev \
libjpeg-turbo-dev zlib-dev

COPY requirements.txt .
RUN python -m pip install --upgrade pip setuptools wheel \
&& pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt

# 소스 복사 (정적/엔트리포인트 포함)
COPY . .

# === RUNTIME ===
FROM python:3.11-alpine AS WEB
ENV PYTHONUNBUFFERED=1
WORKDIR /app

# 런타임 의존 패키지
RUN apk add --no-cache \
libpq \
libjpeg-turbo zlib \
tzdata \
netcat-openbsd

# 빌더에서 생성한 휠 + 소스 반영
COPY --from=BUILDER /wheels /wheels
COPY --from=BUILDER /app /app

# pip 최신화 후 로컬 휠 설치
RUN python -m pip install --upgrade pip setuptools wheel \
&& pip install --no-cache-dir /wheels/*

# 포트/커맨드는 compose에서 지정 (gunicorn)
# EXPOSE 8000
# CMD ["gunicorn","drfproject.wsgi:application","-b","0.0.0.0:8000"]
8 changes: 0 additions & 8 deletions LionDRF/blog/serializers.py

This file was deleted.

41 changes: 0 additions & 41 deletions a

This file was deleted.

File renamed without changes.
7 changes: 7 additions & 0 deletions api/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin
from .models import *

# Register your models here.


admin.site.register(User)
6 changes: 6 additions & 0 deletions api/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class ApiConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'api'
44 changes: 44 additions & 0 deletions api/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 5.1.7 on 2025-05-27 10:14

import django.contrib.auth.models
import django.contrib.auth.validators
import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]

operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('email', models.EmailField(max_length=100, unique=True)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]
File renamed without changes.
6 changes: 6 additions & 0 deletions api/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.
class User(AbstractUser):
email = models.EmailField(max_length=100, unique=True)
44 changes: 44 additions & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from rest_framework import serializers
from .models import User
from rest_framework_simplejwt.tokens import RefreshToken

class UserSerializer(serializers.ModelSerializer):
class Meta:
model=User
fields=['id', 'username', 'email', 'password']

def create(self, validated_data):
user = User.objects.create(
email=validated_data['email'],
username=validated_data['username'],
)
user.set_password(validated_data['password'])
user.save()

return user

class UserLoginSerializer(serializers.Serializer):
email = serializers.CharField(max_length=64)
password = serializers.CharField(max_length=128, write_only=True)

def validate(self, data):
email = data.get('email', None)
password = data.get("password", None)

if User.objects.filter(email=email).exists():
user = User.objects.get(email=email)
if not user.check_password(password):
raise serializers.ValidationError("비밀번호가 일치하지 않습니다.")
else:
token = RefreshToken.for_user(user)
refresh = str(token)
access = str(token.access_token)

data = {
'id': user.id,
'email': user.email,
'access_token': access
}
return data


File renamed without changes.
9 changes: 9 additions & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.urls import path
from .views import *

app_name = 'api'

urlpatterns = [
path('signup/', SignUpView.as_view()),
path('login/', LoginView.as_view()),
]
28 changes: 28 additions & 0 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from django.shortcuts import render
from django.shortcuts import render
from rest_framework import views
from rest_framework import status
from rest_framework.response import Response
from django.http import Http404
from .models import *
from .serializers import *
from django.shortcuts import get_object_or_404


# Create your views here.
class SignUpView(views.APIView):
def post(self, request):
serializer=UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': '회원가입 성공', 'data': serializer.data})
return Response({'message': '회원가입 실패', 'error': serializer.errors})

class LoginView(views.APIView):
serializer_class=UserLoginSerializer
def post(self, request):
serializer = UserLoginSerializer(data=request.data)

if serializer.is_valid():
return Response({'message': '로그인 성공', 'data': serializer.validated_data})
return Response({'message': '로그인 실패', 'error': serializer.errors})
Binary file added blog.zip
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions blog/migrations/0002_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 5.1.7 on 2025-05-27 09:36

import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('blog', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Comment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('username', models.CharField(max_length=20)),
('comment_text', models.TextField()),
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='blog.post')),
],
),
]
Empty file added blog/migrations/__init__.py
Empty file.
Loading