Skip to content

Commit

Permalink
🔀 Merge branch 'main' into feat/symbol-selection
Browse files Browse the repository at this point in the history
  • Loading branch information
sukchan-0811 committed Nov 2, 2023
2 parents 522ce5d + a0f3e33 commit 3bc31ea
Show file tree
Hide file tree
Showing 26 changed files with 864 additions and 212 deletions.
14 changes: 14 additions & 0 deletions backend/config/s3storages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from storages.backends.s3boto3 import S3Boto3Storage


# settings.py에서 static과 media에 storages.backends.s3boto3.S3Boto3Storage를 사용할 수 있지만
# 그러면 둘이 같은 경로에서 관리되므로 여기서 분리해줌 (저장 경로 관련된 부분)
# 우리 앱은 static 쓸 일 크게 없을 것 같긴 하지만..
class MediaStorage(S3Boto3Storage):
location = 'media'
file_overwrite = False


class StaticStorage(S3Boto3Storage):
location = 'static'
file_overwrite = False
62 changes: 44 additions & 18 deletions backend/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
"SECRET_KEY": os.environ.get("SECRET_KEY"),
"EMAIL_HOST_USER": os.environ.get("EMAIL_HOST_USER"),
"EMAIL_HOST_PASSWORD": os.environ.get("EMAIL_HOST_PASSWORD"),
"AWS_ACCESS_KEY_ID": os.environ.get("AWS_ACCESS_KEY_ID"),
"AWS_SECRET_ACCESS_KEY": os.environ.get("AWS_SECRET_ACCESS_KEY"),
"AWS_STORAGE_BUCKET_NAME": os.environ.get("AWS_STORAGE_BUCKET_NAME"),
"AWS_S3_REGION_NAME": os.environ.get("AWS_S3_REGION_NAME"),
}
else:
secret_file = os.path.join(BASE_DIR, 'secrets.json') # secrets.json 파일 위치를 명시
Expand All @@ -57,8 +61,34 @@ def get_secret(setting, secrets=secrets):
EMAIL_HOST_PASSWORD = get_secret("EMAIL_HOST_PASSWORD")
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

# AWS S3 settings
AWS_ACCESS_KEY_ID = get_secret("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = get_secret("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = get_secret("AWS_STORAGE_BUCKET_NAME")
AWS_S3_REGION_NAME = get_secret("AWS_S3_REGION_NAME")
AWS_QUERYSTRING_AUTH = False
AWS_S3_FILE_OVERWRITE = False
# AWS_DEFAULT_ACL = 'public-read' uncomment하면 s3에 이미지 업로드 못함
AWS_S3_CUSTOM_DOMAIN = "%s.s3.%s.amazonaws.com" % (AWS_STORAGE_BUCKET_NAME, AWS_S3_REGION_NAME)
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'max-age=86400',
}

# Static Setting
STATICFILES_STORAGE = "config.s3storages.StaticStorage" # 저장 루트 관련
STATIC_URL = "https://%s/static/" % AWS_S3_CUSTOM_DOMAIN # 저장 루트와 관련 X, 불러오는 루트
# STATICFILES_STORAGE 가 기본값(django.contrib.staticfiles.storage.StaticFilesStorage)일때 저장되는 곳
# STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

# Media Setting
DEFAULT_FILE_STORAGE = "config.s3storages.MediaStorage" # 저장 루트 관련
MEDIA_URL = "https://%s/media/" % AWS_S3_CUSTOM_DOMAIN # 저장 루트와 관련 X, 불러오는 루트
# DEFAULT_FILE_STORAGE 가 기본값(django.core.files.storage.FileSystemStorage)일때 저장되는 곳
# MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')


# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = False

ALLOWED_HOSTS = [
'ec2-54-180-112-72.ap-northeast-2.compute.amazonaws.com',
Expand All @@ -83,6 +113,7 @@ def get_secret(setting, secrets=secrets):
'user',
'entry',
'setup',
'storages',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -118,20 +149,20 @@ def get_secret(setting, secrets=secrets):
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases

# Local DB settings
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'sqlite3_for_dev'),
# }
# }

# Remote DB settings
# Add your own confidential.py
if not ("GITHUB_ACTIONS" in os.environ):
if "GITHUB_ACTIONS" in os.environ:
# Local DB settings
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'sqlite3_for_dev'),
}
}
else:
# Remote DB settings
# Add your own confidential.py
import confidential
DATABASES = confidential.DATABASES

DATABASES = confidential.DATABASES

# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
Expand Down Expand Up @@ -164,11 +195,6 @@ def get_secret(setting, secrets=secrets):

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/

STATIC_URL = "static/"

# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field

Expand Down
24 changes: 24 additions & 0 deletions backend/entry/migrations/0002_auto_20231027_1301.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 3.2.6 on 2023-10-27 04:01

from django.db import migrations, models
import entry.models


class Migration(migrations.Migration):

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

operations = [
migrations.AddField(
model_name='symbol',
name='image',
field=models.ImageField(blank=True, upload_to=entry.models.img_upload_func),
),
migrations.AddField(
model_name='symbol',
name='is_valid',
field=models.BooleanField(default=False),
),
]
21 changes: 21 additions & 0 deletions backend/entry/migrations/0003_auto_20231028_1742.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.6 on 2023-10-28 08:42

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('entry', '0002_auto_20231027_1301'),
]

operations = [
migrations.AlterField(
model_name='symbol',
name='category',
field=models.IntegerField(),
),
migrations.DeleteModel(
name='Category',
),
]
18 changes: 18 additions & 0 deletions backend/entry/migrations/0004_alter_symbol_text.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2023-10-28 11:07

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('entry', '0003_auto_20231028_1742'),
]

operations = [
migrations.AlterField(
model_name='symbol',
name='text',
field=models.CharField(max_length=20),
),
]
21 changes: 21 additions & 0 deletions backend/entry/migrations/0005_alter_symbol_created_by.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.6 on 2023-10-29 04:35

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('entry', '0004_alter_symbol_text'),
]

operations = [
migrations.AlterField(
model_name='symbol',
name='created_by',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='symbols', to=settings.AUTH_USER_MODEL),
),
]
21 changes: 21 additions & 0 deletions backend/entry/migrations/0006_alter_symbol_created_by.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.6 on 2023-10-29 05:51

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('entry', '0005_alter_symbol_created_by'),
]

operations = [
migrations.AlterField(
model_name='symbol',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='symbols', to=settings.AUTH_USER_MODEL),
),
]
33 changes: 21 additions & 12 deletions backend/entry/models.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
import os
from django.utils import timezone
from uuid import uuid4

from django.db import models

from user.models import User


# Create your models here.
# 저장 경로 설정
def img_upload_func(instance, filename):
prefix = 'symbol/user_{}/'.format(instance.created_by.id)
ymd_path = timezone.now().strftime('%Y%m%d')
file_name = uuid4().hex # random string
extension = os.path.splitext(filename)[-1].lower() # 확장자 추출
return "".join(
[prefix, ymd_path, file_name, extension, ]
)


class Symbol(models.Model):
text = models.CharField(max_length=15, null=False, blank=False)
category = models.ForeignKey('Category', related_name='symbols', on_delete=models.CASCADE) # Would it be better to use SET_NULL/DEFAULT?
# image = models.ImageField
created_by = models.ForeignKey('user.User', related_name='symbols', on_delete=models.CASCADE)
text = models.CharField(max_length=20, null=False, blank=False)
category = models.IntegerField(null=False, blank=False)
image = models.ImageField(blank=True, upload_to=img_upload_func)
created_by = models.ForeignKey('user.User', related_name='symbols', on_delete=models.CASCADE, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
is_valid = models.BooleanField(default=False)


class FavoriteSymbol(models.Model):
symbol = models.ForeignKey('Symbol', related_name='favorites', on_delete=models.CASCADE)
user = models.ForeignKey('user.User', related_name='favorites', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)


# Would it be better to remove this category table?
# doesn't seem so useful..
class Category(models.Model):
text = models.CharField(max_length=15, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
64 changes: 61 additions & 3 deletions backend/entry/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ class FavoriteBackupSerializer(serializers.Serializer):

def validate(self, data):
id = data.get('symbol_id')
# Symbol table에 저장된 마지막 symbol의 id
last_symbol_id = Symbol.objects.latest('id').id
user = self.context['user']

if id not in list(range(1, last_symbol_id+1)):
all_symbols = list(Symbol.objects.values_list('id', flat=True))
if id not in all_symbols:
raise ValidationError({"id": ["Invalid symbol (no such symbol)"]})

# Default symbol이 아니라면
if id > 500:
symbol = Symbol.objects.get(id=id)
if symbol.created_by != user:
raise ValidationError({"not_mine": ["the requested symbol is created by another user"]})

return data

def create(self, validated_data):
Expand All @@ -28,3 +34,55 @@ def create(self, validated_data):
FavoriteSymbol.objects.create(user=user, symbol=symbol)


class MySymbolBackupSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
text = serializers.CharField(required=True)
category = serializers.IntegerField(required=True)
image = serializers.ImageField(required=True)
created_at = serializers.DateTimeField(read_only=True)

def validate(self, data):
text = data.get('text')
category = data.get('category')

# To send custom error message
if len(text) > 20:
raise ValidationError({"long_text": ["word text is too long"]})

if not (1 <= category <= 24):
raise ValidationError({"category": ["No such category"]})

return data

def create(self, validated_data):
user = self.context['user']

text = validated_data['text']
category = validated_data['category']
image = validated_data['image']

symbol = Symbol.objects.create(text=text, category=category, image=image, created_by=user)

return symbol


class MySymbolEnableSerializer(serializers.Serializer):
id = serializers.IntegerField(required=True)

def validate(self, data):
id = data.get('id')
user = self.context['user']

all_symbols = list(Symbol.objects.values_list('id', flat=True))
if id not in all_symbols:
raise ValidationError({"id": ["Invalid symbol (no such symbol)"]})

if id <= 500:
raise ValidationError({"id": ["Default symbol"]})

# Default symbol이 아닌 경우
symbol = Symbol.objects.get(id=id)
if symbol.created_by != user:
raise ValidationError({"not_mine": ["the requested symbol is created by another user"]})

return data
6 changes: 5 additions & 1 deletion backend/entry/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@

app_name = 'entry'
urlpatterns = [
path('backup/', views.MySymbolBackupView.as_view(), name='backup my symbol'),
path('', views.MySymbolRetrieveView.as_view(), name='get all of my symbols'),
path('<int:pk>/', views.MySymbolRetrieveView.as_view(), name='get my specific symbol'),
path('favorite/backup/', views.FavoriteBackupView.as_view(), name='backup favorite symbol'),
]
path('enable/', views.MySymbolEnableView.as_view(), name='enable my symbol'),
]
Loading

0 comments on commit 3bc31ea

Please sign in to comment.