Skip to content

Commit

Permalink
Merge pull request #27 from jundm/feature/post
Browse files Browse the repository at this point in the history
Feature/post
  • Loading branch information
jundm authored Feb 26, 2022
2 parents 0454e80 + 2eb5962 commit b1dcdaa
Show file tree
Hide file tree
Showing 92 changed files with 29,474 additions and 3,079 deletions.
26 changes: 24 additions & 2 deletions backend/accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by Django 4.0.1 on 2022-01-08 12:53
# Generated by Django 4.0.1 on 2022-02-14 10:06

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


Expand Down Expand Up @@ -48,11 +49,32 @@ class Migration(migrations.Migration):
("name", models.CharField(max_length=30, verbose_name="실명")),
(
"username",
models.CharField(max_length=30, unique=True, verbose_name="닉네임"),
models.CharField(
blank=True, max_length=30, unique=True, verbose_name="닉네임"
),
),
(
"avatar",
models.ImageField(
blank=True,
help_text="개성을 표현할 수 있는 사진을 올려주세요!",
upload_to="accounts/avatar/%Y/%m/%d",
verbose_name="프로필 사진",
),
),
("is_active", models.BooleanField(default=True)),
("is_staff", models.BooleanField(default=False)),
("is_admin", models.BooleanField(default=False)),
("date_joined", models.DateTimeField(auto_now_add=True)),
("updated_on", models.DateTimeField(auto_now=True)),
(
"follower_set",
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
),
(
"following_set",
models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
),
(
"groups",
models.ManyToManyField(
Expand Down

This file was deleted.

9 changes: 4 additions & 5 deletions backend/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_("이메일 주소"), max_length=50, unique=True)
name = models.CharField(_("실명"), max_length=30)
username = models.CharField(_("닉네임"), max_length=30, unique=True)
username = models.CharField(_("닉네임"), max_length=30, unique=True, blank=True)
avatar = models.ImageField(
_("프로필 사진"),
blank=True,
upload_to="accounts/avatar/%Y/%m/%d",
help_text="개성을 표현할 수 있는 사진을 올려주세요!",
)
follower_set = models.ManyToManyField("self", blank=True)
following_set = models.ManyToManyField("self", blank=True)

is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False) # a admin user; non super-user
Expand All @@ -27,7 +29,7 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
updated_on = models.DateTimeField(auto_now=True)

USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username", "name"]
REQUIRED_FIELDS = ["name", "username"]

objects = CustomUserManager()

Expand Down Expand Up @@ -55,6 +57,3 @@ def avatar_url(self):
return self.avatar.url
else:
return resolve_url("pydenticon_image", self.username)


# 깃허브 테스트중입니다
11 changes: 9 additions & 2 deletions backend/accounts/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.auth import get_user_model
from djoser.serializers import UserCreateSerializer

from rest_framework.serializers import ModelSerializer
from accounts.models import CustomUser

User = get_user_model()

Expand All @@ -13,8 +14,14 @@ class Meta(UserCreateSerializer.Meta):
"name",
"username",
"email",
"follower_set",
"following_set",
)
REQUIRED_FIELDS = ["username"]
REQUIRED_FIELDS = ["name"]


# ------------- Basic User Info ------------- #
class UsernameUniqueCheckSerializer(ModelSerializer):
class Meta:
model = CustomUser
fields = ("username",)
8 changes: 5 additions & 3 deletions backend/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@


urlpatterns = [
# path("signup/", views.UserCreateView.as_view()),
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
# path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
# path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("info/follow/", views.user_follow, name="user_follow"),
path("info/unfollow/", views.user_unfollow, name="user_unfollow"),
path("username/", views.UsernameUniqueCheck.as_view()),
]
127 changes: 127 additions & 0 deletions backend/accounts/views.py
Original file line number Diff line number Diff line change
@@ -1 +1,128 @@
from django.contrib.auth import get_user_model
from drf_yasg.utils import swagger_auto_schema
from requests import Response
from rest_framework import serializers, status
from rest_framework.decorators import api_view
from rest_framework.generics import get_object_or_404, CreateAPIView
from rest_framework_simplejwt.views import (
TokenBlacklistView,
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
from accounts.serializers import UsernameUniqueCheckSerializer

# format=None https://www.django-rest-framework.org/tutorial/2-requests-and-responses/#adding-optional-format-suffixes-to-our-urls
class UsernameUniqueCheck(CreateAPIView):
serializer_class = UsernameUniqueCheckSerializer

def post(self, request, format=None):
print(request, "발발")
serializer = self.get_serializer(
data=request.data, context={"request": request}
)
if serializer.is_valid():
print(serializer.is_valid(), "성공")
# return Response(
# data={"detail": ["You can use this ID"]}, status=status.HTTP_200_OK
# )
else:
detail = dict()
detail["detail"] = serializer.errors["username"]
print(serializer.is_valid(), "실패")
# return Response(data=detail, status=status.HTTP_400_BAD_REQUEST)


@api_view(["POST"])
def user_follow(request):
username = request.data["username"]
follow_user = get_object_or_404(get_user_model(), username=username, is_active=True)
request.user.following_set.add(follow_user)
follow_user.follower_set.add(request.user)
return Response(status.HTTP_204.NO_CONTENT)


@api_view(["POST"])
def user_unfollow(request):
username = request.data["username"]
follow_user = get_object_or_404(get_user_model(), username=username, is_active=True)
request.user.following_set.remove(follow_user)
follow_user.follower_set.remove(request.user)
return Response(status.HTTP_204.NO_CONTENT)


class TokenObtainPairResponseSerializer(serializers.Serializer):
access = serializers.CharField()
refresh = serializers.CharField()

def create(self, validated_data):
raise NotImplementedError()

def update(self, instance, validated_data):
raise NotImplementedError()


class DecoratedTokenObtainPairView(TokenObtainPairView):
@swagger_auto_schema(
responses={
status.HTTP_200_OK: TokenObtainPairResponseSerializer,
}
)
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)


class TokenRefreshResponseSerializer(serializers.Serializer):
access = serializers.CharField()

def create(self, validated_data):
raise NotImplementedError()

def update(self, instance, validated_data):
raise NotImplementedError()


class DecoratedTokenRefreshView(TokenRefreshView):
@swagger_auto_schema(
responses={
status.HTTP_200_OK: TokenRefreshResponseSerializer,
}
)
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)


class TokenVerifyResponseSerializer(serializers.Serializer):
def create(self, validated_data):
raise NotImplementedError()

def update(self, instance, validated_data):
raise NotImplementedError()


class DecoratedTokenVerifyView(TokenVerifyView):
@swagger_auto_schema(
responses={
status.HTTP_200_OK: TokenVerifyResponseSerializer,
}
)
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)


class TokenBlacklistResponseSerializer(serializers.Serializer):
def create(self, validated_data):
raise NotImplementedError()

def update(self, instance, validated_data):
raise NotImplementedError()


class DecoratedTokenBlacklistView(TokenBlacklistView):
@swagger_auto_schema(
responses={
status.HTTP_200_OK: TokenBlacklistResponseSerializer,
}
)
def post(self, request, *args, **kwargs):
return super().post(request, *args, **kwargs)
2 changes: 1 addition & 1 deletion backend/backend/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings.prod")

application = get_asgi_application()
7 changes: 6 additions & 1 deletion backend/backend/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ def get_secret(common, secrets=secrets):
THIRD_PARTY_APPS = [
"corsheaders",
"djoser",
"django_filters",
"rest_framework",
"rest_framework_simplejwt",
"rest_framework_simplejwt.token_blacklist",
]
# account: 커스텀 유저 & 회원가입
PROJECT_APPS = [
Expand Down Expand Up @@ -201,11 +203,14 @@ def get_secret(common, secrets=secrets):
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 100,
"DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"],
}
# JWT
SIMPLE_JWT = {
"AUTH_HEADER_TYPES": ("JWT",),
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=500),
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=30),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ALGORITHM": "HS256",
"SIGNING_KEY": SECRET_KEY,
Expand Down
2 changes: 1 addition & 1 deletion backend/backend/settings/prod.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .common import *
from .common import *
1 change: 1 addition & 0 deletions backend/backend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

urlpatterns = [
path("admin/", admin.site.urls),
path("users/", include("accounts.urls")),
path("posts/", include("posts.urls")),
path("", include("djoser.urls")),
path("", include("djoser.urls.jwt")),
Expand Down
2 changes: 1 addition & 1 deletion backend/backend/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings.prod')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings.prod")

application = get_wsgi_application()
50 changes: 43 additions & 7 deletions backend/posts/admin.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@
# 수정 사항
# search_fields = ["title"]
#
# def short_content(self, post):
# return post.content[:15]
from django.contrib import admin

from .models import Post
from .models import Post, PostComment, Comment, Tag


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = (
"id",
"title",
"short_content",
"content",
"created_at",
"updated_at",
"category",
"author",
)
list_filter = ("created_at", "updated_at", "category", "author")
date_hierarchy = "created_at"


@admin.register(PostComment)
class PostCommentAdmin(admin.ModelAdmin):
list_display = (
"id",
"title",
"content",
"created_at",
"updated_at",
"answer",
"author",
)
list_filter = ("created_at", "updated_at", "answer", "author")
date_hierarchy = "created_at"


@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = (
"id",
"author",
"post",
"content",
"created_at",
"updated_at",
)
list_display_links = ("title", "short_content", "author")
list_filter = ("author", "created_at", "updated_at")
search_fields = ["title"]
list_filter = ("author", "post", "created_at", "updated_at")
date_hierarchy = "created_at"

def short_content(self, post):
return post.content[:15]

@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ("id", "name")
search_fields = ("name",)
Loading

0 comments on commit b1dcdaa

Please sign in to comment.