Jeongmin Seo

Add server

1 +"""
2 +Django settings for localpeople project.
3 +
4 +Generated by 'django-admin startproject' using Django 3.2.4.
5 +
6 +For more information on this file, see
7 +https://docs.djangoproject.com/en/3.2/topics/settings/
8 +
9 +For the full list of settings and their values, see
10 +https://docs.djangoproject.com/en/3.2/ref/settings/
11 +"""
12 +
13 +import os
14 +import json
15 +from pathlib import Path
16 +
17 +from django.core.exceptions import ImproperlyConfigured
18 +
19 +# Build paths inside the project like this: BASE_DIR / 'subdir'.
20 +BASE_DIR = Path(__file__).resolve().parent.parent
21 +
22 +# Quick-start development settings - unsuitable for production
23 +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
24 +"""
25 +# SECURITY WARNING: keep the secret key used in production secret!
26 +def get_secret(setting, secret_file):
27 + with open(secret_file) as f:
28 + secrets = json.loads(f.read())
29 + try:
30 + return secrets[setting]
31 + except KeyError:
32 + error_msg = "Set the {} environment variable".format(setting)
33 + raise ImproperlyConfigured(error_msg)
34 +
35 +secret_file = os.path.join(BASE_DIR, 'secrets.json')
36 +"""
37 +SECRET_KEY = "django-insecure-7!shg^w=52%#o6%0_ii-b+67ty&q-1@5cbws4=#hmwfltt22nx"
38 +
39 +# SECURITY WARNING: don't run with debug turned on in production!
40 +DEBUG = True
41 +
42 +ALLOWED_HOSTS = ['*']
43 +
44 +# Application definition
45 +
46 +INSTALLED_APPS = [
47 + 'django.contrib.admin',
48 + 'django.contrib.auth',
49 + 'django.contrib.contenttypes',
50 + 'django.contrib.sessions',
51 + 'django.contrib.messages',
52 + 'django.contrib.staticfiles',
53 + 'rest_framework',
54 + 'rest_framework.authtoken',
55 + 'posting',
56 + 'user',
57 + 'drf_yasg',
58 +]
59 +
60 +MIDDLEWARE = [
61 + 'django.middleware.security.SecurityMiddleware',
62 + 'django.contrib.sessions.middleware.SessionMiddleware',
63 + 'django.middleware.common.CommonMiddleware',
64 + # 'django.middleware.csrf.CsrfViewMiddleware',
65 + 'django.contrib.auth.middleware.AuthenticationMiddleware',
66 + 'django.contrib.messages.middleware.MessageMiddleware',
67 + 'django.middleware.clickjacking.XFrameOptionsMiddleware',
68 +]
69 +
70 +ROOT_URLCONF = 'localpeople.urls'
71 +
72 +TEMPLATES = [
73 + {
74 + 'BACKEND': 'django.template.backends.django.DjangoTemplates',
75 + 'DIRS': [],
76 + 'APP_DIRS': True,
77 + 'OPTIONS': {
78 + 'context_processors': [
79 + 'django.template.context_processors.debug',
80 + 'django.template.context_processors.request',
81 + 'django.contrib.auth.context_processors.auth',
82 + 'django.contrib.messages.context_processors.messages',
83 + ],
84 + },
85 + },
86 +]
87 +
88 +WSGI_APPLICATION = 'favoriterestaurant.wsgi.application'
89 +
90 +# Database
91 +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
92 +
93 +DATABASES = {
94 + 'default': {
95 + 'ENGINE': 'django.db.backends.sqlite3',
96 + 'NAME': BASE_DIR / 'db.sqlite3',
97 + }
98 +}
99 +
100 +# Password validation
101 +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
102 +
103 +AUTH_PASSWORD_VALIDATORS = [
104 + {
105 + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
106 + },
107 + {
108 + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
109 + },
110 + {
111 + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
112 + },
113 + {
114 + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
115 + },
116 +]
117 +
118 +REST_FRAMEWORK = {
119 + 'DEFAULT_PERMISSION_CLASSES': [
120 + 'rest_framework.permissions.IsAuthenticated',
121 + ],
122 + 'DEFAULT_AUTHENTICATION_CLASSES': [
123 + 'rest_framework.authentication.BasicAuthentication',
124 + 'rest_framework.authentication.TokenAuthentication'
125 + ]
126 +}
127 +
128 +AUTH_USER_MODEL = 'user.User'
129 +
130 +# Internationalization
131 +# https://docs.djangoproject.com/en/3.2/topics/i18n/
132 +
133 +LANGUAGE_CODE = 'en-us'
134 +
135 +TIME_ZONE = 'UTC'
136 +
137 +USE_I18N = True
138 +
139 +USE_L10N = True
140 +
141 +USE_TZ = True
142 +
143 +# Static files (CSS, JavaScript, Images)
144 +# https://docs.djangoproject.com/en/3.2/howto/static-files/
145 +
146 +STATIC_URL = '/static/'
147 +
148 +MEDIA_URL = '/media/'
149 +MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
150 +# Default primary key field type
151 +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
152 +
153 +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
1 +from django.contrib import admin
2 +from django.urls import path, include
3 +from django.conf import settings
4 +from django.conf.urls.static import static
5 +from django.urls.conf import re_path
6 +from rest_framework.permissions import AllowAny
7 +from drf_yasg.views import get_schema_view
8 +from drf_yasg import openapi
9 +
10 +schema_view = get_schema_view(
11 + openapi.Info(
12 + title="Favorite Restaurant API",
13 + default_version="v1",
14 + description="Favorite Restaurant 프로젝트 API docs 입니다.",
15 + terms_of_service="https://www.google.com/policies/terms/",
16 + contact=openapi.Contact(email="balljm@naver.com"),
17 + license=openapi.License(name="Favorite Restaurant"),
18 + ),
19 + validators=['flex'],
20 + public=True,
21 + permission_classes=(AllowAny,),
22 +)
23 +
24 +urlpatterns = [
25 + path('admin/', admin.site.urls),
26 + path('', include('posting.urls')),
27 + path('users/', include('user.urls')),
28 + path('api-auth/', include('rest_framework.urls')) # 로그인 기능 활성화
29 +]
30 +
31 +urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
32 +
33 +if settings.DEBUG:
34 + urlpatterns += [
35 + re_path(r'^swagger(?P<format>\.json|\.yaml)$',
36 + schema_view.without_ui(cache_timeout=0), name="schema-json"),
37 + re_path(r'^swagger/$', schema_view.with_ui('swagger',
38 + cache_timeout=0), name='schema-swagger-ui'),
39 + re_path(r'^redoc/$', schema_view.with_ui('redoc',
40 + cache_timeout=0), name='schema-redoc'),
41 + ]
1 +
2 +"""
3 +WSGI config for localpeople project.
4 +It exposes the WSGI callable as a module-level variable named ``application``.
5 +For more information on this file, see
6 +https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
7 +"""
8 +
9 +import os
10 +
11 +from django.core.wsgi import get_wsgi_application
12 +
13 +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'localpeople.settings')
14 +
15 +application = get_wsgi_application()
...\ No newline at end of file ...\ No newline at end of file
1 +#!/usr/bin/env python
2 +"""Django's command-line utility for administrative tasks."""
3 +import os
4 +import sys
5 +
6 +
7 +def main():
8 + """Run administrative tasks."""
9 + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'favoriterestaurant.settings')
10 + try:
11 + from django.core.management import execute_from_command_line
12 + except ImportError as exc:
13 + raise ImportError(
14 + "Couldn't import Django. Are you sure it's installed and "
15 + "available on your PYTHONPATH environment variable? Did you "
16 + "forget to activate a virtual environment?"
17 + ) from exc
18 + execute_from_command_line(sys.argv)
19 +
20 +
21 +if __name__ == '__main__':
22 + main()
...\ No newline at end of file ...\ No newline at end of file
1 +from django.db import models
2 +from django.conf import settings
3 +from django.db.models.deletion import SET_NULL
4 +from django.utils.translation import gettext as _
5 +
6 +class Posting(models.Model):
7 + user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL)
8 + image = models.ImageField(upload_to='images', blank=True, null=True)
9 + content = models.TextField(blank=True, null=True)
10 + category = models.CharField(choices=Category.choices, max_length=50)
11 + lat = models.FloatField(blank=False, null=False) # 위도
12 + lng = models.FloatField(blank=False, null=False) # 경도
13 + like = models.IntegerField(default=0)
14 + created_at = models.DateField(auto_now_add=True)
15 +
16 + def __str__(self):
17 + return str(self.pk)
18 +
19 +class Comment(models.Model):
20 + posting = models.ForeignKey(Posting, null=False, blank=False, on_delete=models.CASCADE)
21 + user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=False, on_delete=models.SET_NULL)
22 + comment = models.TextField()
23 + created_at = models.DateField(auto_now_add=True, null=False, blank=False)
24 + like = models.IntegerField(default=0)
25 +
26 + def __str__(self):
27 + return self.comment
...\ No newline at end of file ...\ No newline at end of file
1 +from rest_framework import permissions
2 +
3 +class IsOwnerOrReadOnly(permissions.BasePermission):
4 +
5 + def has_object_permission(self, request, view, obj):
6 + # 읽기 권한 요청이 들어오면 허용
7 + if request.method in permissions.SAFE_METHODS:
8 + return True
9 +
10 + # 요청자(request.user)가 객체(Blog)의 author와 동일한지 확인
11 + return obj.user == request.user
...\ No newline at end of file ...\ No newline at end of file
1 +from .models import Posting, Comment
2 +from rest_framework import serializers
3 +
4 +class PostingSerializer(serializers.ModelSerializer):
5 + image = serializers.ImageField(use_url=True, required=False, allow_null=True) # 둘 중 하나만 넣어도 됨
6 + like = serializers.ReadOnlyField()
7 + class Meta:
8 + model = Posting
9 + fields = ('pk', 'image', 'content', 'category', 'lat', 'lng', 'like', 'created_at')
10 +
11 +class CommentSerializer(serializers.ModelSerializer):
12 + user = serializers.ReadOnlyField(source='user.email')
13 + like = serializers.ReadOnlyField()
14 + class Meta:
15 + model = Comment
16 + fields = ('pk', 'posting', 'user', 'comment', 'like', 'created_at')
17 +
18 +class LikeSerializer():
19 + pass
...\ No newline at end of file ...\ No newline at end of file
1 +from django.urls import path, include
2 +from rest_framework.routers import DefaultRouter
3 +from .views import CommentViewSet, PostingViewSet, MyPostingViewSet
4 +
5 +router = DefaultRouter()
6 +router.register(r'^postings', PostingViewSet)
7 +router.register(r'^my-postings', MyPostingViewSet)
8 +router.register(r'^comments', CommentViewSet)
9 +
10 +urlpatterns = [
11 + path('', include(router.urls)),
12 +]
1 +import json
2 +from django.http import JsonResponse
3 +from django.core.checks import messages
4 +from .models import Posting, Comment
5 +from .serializers import PostingSerializer, CommentSerializer
6 +from rest_framework import viewsets, mixins
7 +from rest_framework.response import Response
8 +from rest_framework.filters import SearchFilter
9 +from rest_framework.authentication import TokenAuthentication, SessionAuthentication
10 +from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
11 +from .permissions import IsOwnerOrReadOnly
12 +
13 +
14 +class PostingViewSet(viewsets.ReadOnlyModelViewSet):
15 + permission_classes = [IsAuthenticatedOrReadOnly]
16 + queryset = Posting.objects.all()
17 + serializer_class = PostingSerializer
18 + filter_backends = [SearchFilter]
19 + search_fields = ('content', 'category') # only tuple
20 +
21 +
22 +class MyPostingViewSet(viewsets.ModelViewSet):
23 + permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]
24 + queryset = Posting.objects.all()
25 + serializer_class = PostingSerializer
26 +
27 + def perform_create(self, serializer):
28 + serializer.save(user=self.request.user)
29 +
30 + def get_queryset(self):
31 + qs = Posting.objects.all()
32 + qs = qs.filter(user=self.request.user)
33 + return qs
34 +
35 +
36 +class CommentViewSet(viewsets.ModelViewSet):
37 + permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
38 + queryset = Comment.objects.all()
39 + serializer_class = CommentSerializer
40 +
41 + def perform_create(self, serializer):
42 + serializer.save(user=self.request.user)
1 +asgiref==3.3.4
2 +certifi==2021.5.30
3 +chardet==4.0.0
4 +colorama==0.4.4
5 +coreapi==2.3.3
6 +coreschema==0.0.4
7 +Django==3.2.4
8 +djangorestframework==3.12.4
9 +drf-yasg==1.20.0
10 +httpie==2.4.0
11 +idna==2.10
12 +inflection==0.5.1
13 +itypes==1.2.0
14 +Jinja2==3.0.1
15 +MarkupSafe==2.0.1
16 +numpy==1.21.0
17 +packaging==20.9
18 +Pillow==8.2.0
19 +Pygments==2.9.0
20 +pyparsing==2.4.7
21 +PySocks==1.7.1
22 +pytz==2021.1
23 +requests==2.25.1
24 +requests-toolbelt==0.9.1
25 +ruamel.yaml==0.17.10
26 +ruamel.yaml.clib==0.2.4
27 +sqlparse==0.4.1
28 +uritemplate==3.0.1
29 +urllib3==1.26.6
1 +#!/bin/bash
2 +
3 +# find venv and run
4 +VENV=`find . -type d -name '*venv*'`
5 +echo $VENV
6 +source $VENV/bin/activate
7 +
8 +# run django server port 8080
9 +CMD="python3 manage.py runserver"
10 +$CMD &
1 +from django.contrib import admin
2 +
3 +# Register your models here.
1 +from django.apps import AppConfig
2 +
3 +
4 +class UserConfig(AppConfig):
5 + default_auto_field = 'django.db.models.BigAutoField'
6 + name = 'user'
1 +import os
2 +
3 +from django.db import models
4 +from django.conf import settings
5 +from django.contrib.auth.base_user import AbstractBaseUser
6 +from django.contrib.auth.base_user import BaseUserManager
7 +from django.contrib.auth.models import PermissionsMixin
8 +from django.db.models.signals import post_save
9 +from django.dispatch import receiver
10 +from rest_framework.authtoken.models import Token
11 +
12 +
13 +class UserManager(BaseUserManager):
14 + def create_user(self, email, password, **extra_fields):
15 + if not email:
16 + raise ValueError('email field required')
17 +
18 + user = self.model(email=self.normalize_email(email), **extra_fields)
19 + user.set_password(password)
20 + user.save()
21 +
22 + return user
23 +
24 + def create_superuser(self, email, password, **extra_fields):
25 + user = self.model(email=self.normalize_email(email), **extra_fields)
26 + user.set_password(password)
27 + user.is_admin = True
28 + user.save()
29 +
30 + return user
31 +
32 +
33 +def profile_image_path(instance, filename):
34 + return 'profile_image/{email}.jpeg'.format(email=instance.email)
35 +
36 +
37 +class User(AbstractBaseUser, PermissionsMixin):
38 + email = models.EmailField(unique=True, max_length=255)
39 + nick_name = models.CharField(default='', max_length=20)
40 + profile_image = models.ImageField(blank=True, upload_to=profile_image_path)
41 + region = models.IntegerField(default=-1)
42 + period = models.IntegerField(default=0)
43 + is_admin = models.BooleanField(default=False)
44 + is_active = models.BooleanField(default=True)
45 +
46 + objects = UserManager()
47 +
48 + USERNAME_FIELD = 'email'
49 + REQUIRED_FIELDS = []
50 +
51 + def save(self, *args, **kwargs):
52 + super(User, self).save(*args, **kwargs)
53 +
54 + def delete(self, using=None, keep_parents=False):
55 + try:
56 + os.remove('profile_image/{email}.jpeg'.format(email=self.email))
57 + except FileNotFoundError:
58 + pass
59 + super(User, self).delete()
60 +
61 + def __str__(self):
62 + return '{email}'.format(email=self.email)
63 +
64 + @property
65 + def is_staff(self):
66 + return self.is_admin
67 +
68 + def has_perm(self, perm, obj=None):
69 + return True
70 +
71 + def has_module_perms(self, app_label):
72 + return True
73 +
74 +@receiver(post_save, sender=settings.AUTH_USER_MODEL)
75 +def create_auth_token(sender, instance=None, created=False, **kwargs):
76 + if created:
77 + Token.objects.create(user=instance)
1 +from django.test import TestCase
2 +
3 +# Create your tests here.
1 +from django.urls import path
2 +from .views import UserView, sign_up
3 +
4 +urlpatterns = [
5 + path('', UserView.as_view()),
6 + path('sign-up', sign_up)
7 +]
1 +import json
2 +
3 +from django.db import IntegrityError
4 +from django.http import JsonResponse
5 +from django.views.decorators.http import require_http_methods
6 +from rest_framework.authtoken.models import Token
7 +from rest_framework.decorators import permission_classes
8 +from rest_framework.permissions import IsAuthenticated
9 +from rest_framework.views import APIView
10 +from .models import User
11 +
12 +
13 +class UserView(APIView):
14 + permission_classes(IsAuthenticated,)
15 +
16 + def put(self, request):
17 + email = request.data.get('email')
18 +
19 + updating = User.objects.get(email=email)
20 +
21 + nick_name = request.data.get('nick_name')
22 + profile_image = request.data.get('profile_image')
23 + region = request.data.get('region')
24 +
25 + if nick_name:
26 + updating.nick_name = nick_name
27 + if profile_image:
28 + updating.profile_image = profile_image
29 + if region:
30 + updating.region = region
31 +
32 + updating.save()
33 +
34 + return JsonResponse({'result': 'ok'})
35 +
36 + def delete(self, request):
37 + email = request.data.get('email')
38 +
39 + deleting = User.objects.get(email=email)
40 + deleting.delete()
41 +
42 + return JsonResponse({'result': 'ok'})
43 +
44 + def get(self, request):
45 + email = request.data.get('email')
46 +
47 + retrieved = User.objects.get(email=email)
48 +
49 + return JsonResponse({'result': 'ok', 'email': str(retrieved.email), 'nick_name': str(retrieved.nick_name),
50 + 'region': str(retrieved.region),'period': str(retrieved.period)})
51 +
52 +
53 +@require_http_methods(['POST'])
54 +def sign_up(request):
55 + data = json.loads(request.body.decode("utf-8"))
56 + email = data['email']
57 + password = data['password']
58 +
59 + try:
60 + user = User.objects.create_user(email, password)
61 + except ValueError:
62 + return JsonResponse({'result': 'ValueError'})
63 + except IntegrityError:
64 + return JsonResponse({'result': 'IntegrityError'})
65 +
66 + try:
67 + token = Token.objects.get(user=user)
68 + except Token.DoesNotExist:
69 + return JsonResponse({'result': 'Token does not exist'})
70 +
71 + return JsonResponse({'result': 'ok', 'id': str(user.pk), 'token': str(token.key)})
72 +