Ubuntu

add front

Showing 62 changed files with 1568 additions and 132 deletions
No preview for this file type
1 -# -*- coding: utf-8 -*-
2 -from __future__ import unicode_literals
3 -
4 -from django.db import models
5 -
6 -# Create your models here.
1 +from django.contrib.auth.models import User
2 +from django.contrib.auth import authenticate
3 +from rest_framework import serializers
4 +
5 +# 접속 유지 확인 및 사용자 확인
6 +class UserSerializer(serializers.ModelSerializer):
7 + class Meta:
8 + model = User
9 + fields = ['id', 'username', 'email']
10 +
11 +# 회원가입
12 +class SignUpSerializer(serializers.ModelSerializer):
13 + class Meta:
14 + model = User
15 + fields = ['username', 'email', 'password']
16 + extra_kwargs = {"password": {"write_only": True}}
17 +
18 + def create(self, validated_data):
19 + user = User.objects.create_user(
20 + validated_data['username'], validated_data['email'], validated_data['password']
21 + )
22 +
23 + return user
24 +
25 +
26 +# 로그인 (커스터마이징 => Serializer)
27 +class LoginSerializer(serializers.Serializer):
28 + username = serializers.CharField()
29 + password = serializers.CharField()
30 +
31 + def validate(self, data):
32 + print('validate data',data)
33 + user = authenticate(**data)
34 + if user and user.is_active:
35 + return user
36 + raise serializers.validationError('Unable to log in with provided credentials.')
37 +
38 +
39 +"""
40 +class GoogleSerializer(serializers.Serializer):
41 + Access token = serializers.CharField()
42 + Code = serializers.CharField()
43 +
44 + def validate(self, data):
45 + print('validate data',data)
46 + user = authenticate(**data)
47 + if user and user.is_active:
48 + return user
49 + raise serializers.validationError('Unable to log in with provided credentials.')
50 +"""
1 {% extends 'layout.html' %} 1 {% extends 'layout.html' %}
2 {% block content %} 2 {% block content %}
3 -<!--이것을 써줘야 socicalaccount기능을 사용할수있음.--> 3 +{% load socialaccount %}
4 - {%load socialaccount %} 4 +{% providers_media_js %}
5 - {% providers_media_js %} 5 +{% load static %}
6 - {% load static %} 6 +{% static 'blog/img/naver_login_green.png' as naver_button %}
7 - {% static 'blog/img/naver_login_green.png' as naver_button %} 7 +{% static 'blog/img/naver_login_white.png' as naver_button_hover %}
8 - {% static 'blog/img/naver_login_white.png' as naver_button_hover %} 8 +{% static 'blog/img/google_login_normal.png' as google_button %}
9 - {% static 'blog/img/google_login_normal.png' as google_button %} 9 +{% static 'blog/img/google_login_preesed.png' as google_button_hover %}
10 - {% static 'blog/img/google_login_preesed.png' as google_button_hover %} 10 +
11 <div class="col-md-8 col-md-offset-2"> 11 <div class="col-md-8 col-md-offset-2">
12 <div class="panel panel-default"> 12 <div class="panel panel-default">
13 <div class="panel-heading">로그인</div> 13 <div class="panel-heading">로그인</div>
14 <div class="panel-body"> 14 <div class="panel-body">
15 <form class="form-horizontal" role="form" method="POST" action="/login/"> 15 <form class="form-horizontal" role="form" method="POST" action="/login/">
16 +
16 <div class="form-group"> 17 <div class="form-group">
17 <div class="col-md-12"> 18 <div class="col-md-12">
18 <label for="userid">아이디</label> 19 <label for="userid">아이디</label>
19 <input id="userid" type="userid" class="form-control" name="username" required autofocus> 20 <input id="userid" type="userid" class="form-control" name="username" required autofocus>
20 </div> 21 </div>
21 </div> 22 </div>
23 +
22 <div class="form-group"> 24 <div class="form-group">
23 <div class="col-md-12"> 25 <div class="col-md-12">
24 <label for="password">비밀번호</label> 26 <label for="password">비밀번호</label>
25 <input id="password" type="password" class="form-control" name="password" required> 27 <input id="password" type="password" class="form-control" name="password" required>
26 </div> 28 </div>
27 </div> 29 </div>
30 +
28 <div class="form-group"> 31 <div class="form-group">
29 <div class="col-md-12"> 32 <div class="col-md-12">
30 <button type="submit" class="btn btn-success"> 33 <button type="submit" class="btn btn-success">
...@@ -34,26 +37,17 @@ ...@@ -34,26 +37,17 @@
34 회원가입 37 회원가입
35 </button> 38 </button>
36 </div> 39 </div>
37 - <a href="{% provider_login_url 'naver' %}">
38 - <img src="{{ naver_button }}"
39 - onmouseover="this.src='{{ naver_button_hover }}'"
40 - onmouseleave="this.src='{{ naver_button }}'"height="34">
41 - </a>
42 - <br>
43 - <a href="{% provider_login_url 'google' %}">
44 - <img src="{{ google_button }}"
45 - onmouseover="this.src='{{ google_button_hover }}'"
46 - onmouseleave="this.src='{{ google_button }}'"height="34">
47 - </a>
48 - <br>
49 </div> 40 </div>
41 +
50 <div class="form-group"> 42 <div class="form-group">
51 <div class="col-md-12 text-center"> 43 <div class="col-md-12 text-center">
52 <h5>{{ message }}</h5> 44 <h5>{{ message }}</h5>
53 </div> 45 </div>
54 </div> 46 </div>
47 +
55 </form> 48 </form>
56 </div> 49 </div>
57 </div> 50 </div>
58 </div> 51 </div>
52 +
59 {% endblock %} 53 {% endblock %}
......
1 +from django.urls import path, include
2 +from rest_framework import routers
3 +from blog.views import LoginAPI,SignUpAPI,UserAPI,GoogleLogin,social_login
4 +
5 +# router = routers.DefaultRouter()
6 +# router.register(r'user', views.login)
7 +
8 +urlpatterns = [
9 + path("api/auth/signUp", SignUpAPI.as_view()),
10 + path("api/auth/login", LoginAPI.as_view()),
11 + path("api/auth/loadMe", UserAPI.as_view()),
12 + path('rest-auth/google', GoogleLogin.as_view()),
13 + # path('accounts/', GoogleLogin.as_view()),
14 + path('accounts/google/login/callback/main/', social_login)
15 +]
...@@ -2,6 +2,7 @@ from django.contrib.auth.models import User ...@@ -2,6 +2,7 @@ from django.contrib.auth.models import User
2 from django.contrib.auth import authenticate 2 from django.contrib.auth import authenticate
3 from django.shortcuts import render, redirect 3 from django.shortcuts import render, redirect
4 from django.core.exceptions import PermissionDenied 4 from django.core.exceptions import PermissionDenied
5 +from rest_framework.authtoken.models import Token
5 from khuloud import settings 6 from khuloud import settings
6 from blog import cognito 7 from blog import cognito
7 from django.views.decorators.csrf import csrf_exempt 8 from django.views.decorators.csrf import csrf_exempt
...@@ -9,115 +10,107 @@ from django.http import HttpResponse, JsonResponse ...@@ -9,115 +10,107 @@ from django.http import HttpResponse, JsonResponse
9 from django.views.decorators.csrf import csrf_exempt 10 from django.views.decorators.csrf import csrf_exempt
10 from django.utils.decorators import method_decorator 11 from django.utils.decorators import method_decorator
11 from rest_framework.response import Response 12 from rest_framework.response import Response
12 -from rest_framework import status 13 +from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
14 +from rest_auth.registration.views import SocialLoginView
15 +from rest_auth.registration.serializers import SocialLoginSerializer,SocialAccountSerializer
16 +from allauth.socialaccount.models import SocialToken
17 +from allauth.socialaccount.providers.oauth2.client import OAuth2Client
18 +from blog.serializers import (
19 + LoginSerializer,
20 + SignUpSerializer,
21 + UserSerializer,
22 +)
23 +
24 +from rest_framework import viewsets, permissions, generics, status
13 from cloud import views 25 from cloud import views
26 +from django.views.generic import View
14 import hashlib 27 import hashlib
15 import json 28 import json
16 import django 29 import django
17 import requests 30 import requests
18 -@csrf_exempt 31 +def social_login(request):
19 -def main(request): 32 + print('zzz')
20 - if request.user.is_authenticated: 33 + # token=request.POST["access_token"]
21 - return render(request, "main.html") 34 + user=request.user
22 - else: 35 + token, created = Token.objects.get_or_create(user=user)
23 - return render(request, "login.html") 36 + # res=JsonResponse({'token': token.key})
24 -@csrf_exempt 37 + temp=(request.COOKIES['sessionid'])
25 -def login(request): 38 + # print(request.COOKIES['sessionid'])
26 - if request.user.is_authenticated: 39 + # response = HttpResponse('blah')
27 - raise PermissionDenied 40 + # response.set_cookie(key='access_token',value=temp, max_age=None)
28 - else: 41 + # res.set_cookie('access_token',
29 - if request.method == "POST": 42 + response =redirect("http://54.180.112.94:3001/",cookies=temp)
30 - data=request.POST 43 +
31 - if not all(i in data for i in ('username', 'password')): 44 + response.set_cookie('username',temp,max_age=1000)
32 - return render(request, "login.html", { 45 + print(token.key)
33 - "message": "아이디와 비밀번호를 입력해 주세요" 46 + # return redirect('http://54.180.112.94:3001/')
34 - }) 47 + request.session['zzz']=token.key
35 - un = data['username'] 48 + """
36 - pw = data['password'] 49 + return JsonResponse({
37 - user = authenticate(username=un, password=pw) 50 + 'token': token.key
38 - if user is not None: 51 +
39 - auth = django.contrib.auth.login(request, user)
40 - hashcode = hashlib.md5(request.POST['password'].encode('utf-8')).hexdigest()
41 - cog = cognito.Cognito()
42 - cog.sign_in_admin(username=un, password=hashcode)
43 - return JsonResponse({'user':{
44 - 'username' :un,
45 - 'password' :pw,
46 - }}, safe=False)
47 - else:
48 - return render(request, "login.html", {
49 - "message": "아이디와 비밀번호를 확인해 주세요"
50 }) 52 })
53 + """
54 + return response
51 55
52 - else: 56 +class GoogleLogin(SocialLoginView):
57 + adapter_class=GoogleOAuth2Adapter
58 +class LoginAPI(generics.GenericAPIView):
59 + # field : username, password
60 + serializer_class = LoginSerializer
61 + client_class=OAuth2Client
62 + print(client_class)
63 + def post(self, request, *args, **kwargs):
64 + print('login request가 들어왔으면 말좀 해줘', request.data)
65 + serializer = self.get_serializer(data=request.data)
66 + serializer.is_valid(raise_exception=True)
67 + user = serializer.validated_data # complex type data
68 + print(user.username)
69 + token, created = Token.objects.get_or_create(user=user)
70 + return Response({
71 + 'user': UserSerializer(
72 + user, context = self.get_serializer_context()
73 + ).data,
74 + 'token': token.key
53 75
54 - return render(request, "login.html") 76 + })
55 -def logout(request):
56 - if request.user.is_authenticated:
57 - django.contrib.auth.logout(request)
58 - return redirect("/main")
59 77
60 -def register(request): 78 +class SignUpAPI(generics.GenericAPIView):
79 + serializer_class = SignUpSerializer
80 + def post(self, req, *args, **kwargs):
61 Cog = cognito.Cognito() 81 Cog = cognito.Cognito()
62 reg=views.FileView() 82 reg=views.FileView()
63 - if request.user.is_authenticated: raise PermissionDenied 83 + print(req.data)
64 - if request.method == "POST": 84 + serializer = self.get_serializer(data = req.data)
65 - require_keys = ('username', 'password', 'first_name', 'last_name', 'email') 85 + hashcode = hashlib.md5(req.data['password'].encode('utf-8')).hexdigest()
66 - if all(i in request.POST for i in require_keys):
67 - if User.objects.filter(username=request.POST['username']).count():
68 - return render(request, 'register.html', {
69 - "message": 'alreadt exist username!'
70 - })
71 - if User.objects.filter(email=request.POST['email']).count():
72 - return render(request, 'register.html', {
73 - "message": 'alreadt exist email!'
74 - })
75 - userobj = User.objects.create_user(
76 - username=request.POST['username'],
77 - password=request.POST['password'],
78 - first_name=request.POST['first_name'],
79 - last_name=request.POST['last_name'],
80 - email=request.POST['email']
81 - )
82 - hashcode = hashlib.md5(request.POST['password'].encode('utf-8')).hexdigest()
83 Cog.sign_up( 86 Cog.sign_up(
84 - username=request.POST['username'], 87 + username=req.data['username'],
85 password=hashcode, 88 password=hashcode,
86 UserAttributes=[ 89 UserAttributes=[
87 { 90 {
88 'Name' : 'email', 91 'Name' : 'email',
89 - 'Value' : request.POST['email'], 92 + 'Value' : req.data['email'],
90 - },
91 - {
92 - 'Name' : 'family_name',
93 - 'Value': request.POST['first_name'],
94 - },
95 - {
96 - 'Name' : 'given_name',
97 - 'Value': request.POST['last_name'],
98 }, 93 },
99 ]) 94 ])
100 - Cog.confirm_sign_up(username=request.POST['username']); 95 + Cog.confirm_sign_up(username=req.data['username'])
101 - print(reg.create_bucket(request)) 96 + serializer.is_valid(raise_exception=True)
102 - return redirect('/main') 97 + user = serializer.save()
103 - else: 98 + print(user)
104 - return render(request, 'register.html', { 99 + reg.create_bucket(req)
105 - "message": 'error.' 100 + token, created = Token.objects.get_or_create(user=user)
101 + return Response({
102 + 'user': UserSerializer(
103 + user, context=self.get_serializer_context()).data,
104 + 'token': token.key
106 }) 105 })
107 - else: 106 +class UserAPI(generics.RetrieveAPIView):
108 - return render(request, 'register.html') 107 + permission_classes = [
109 - 108 + permissions.IsAuthenticated,
110 -def delete(request): 109 + ]
110 + serializer_class = UserSerializer
111 + def get_object(self):
112 + print('Load Me 인증 성공', self.request.user)
113 + user = UserSerializer(self.request.user).data
114 + return self.request.user
111 115
112 - if request.user.is_authenticated:
113 116
114 - if request.method == 'POST':
115 -
116 - request.user.delete()
117 -
118 - return redirect('/main')
119 - else:
120 - return rendet(request,'delete.html',{
121 - "message": 'login required!'
122 - })
123 - return render(request, 'delete.html')
......
...@@ -50,7 +50,7 @@ class FileView(View): ...@@ -50,7 +50,7 @@ class FileView(View):
50 """ 50 """
51 bucket=self.s3_client.create_bucket( 51 bucket=self.s3_client.create_bucket(
52 ACL='public-read-write', 52 ACL='public-read-write',
53 - Bucket=request.POST['username'], 53 + Bucket=request.data['username'],
54 CreateBucketConfiguration={ 54 CreateBucketConfiguration={
55 'LocationConstraint':'ap-northeast-2'}, 55 'LocationConstraint':'ap-northeast-2'},
56 ) 56 )
......
...@@ -44,7 +44,9 @@ INSTALLED_APPS = [ ...@@ -44,7 +44,9 @@ INSTALLED_APPS = [
44 'blog.apps.BlogConfig', 44 'blog.apps.BlogConfig',
45 'corsheaders', 45 'corsheaders',
46 'rest_framework', 46 'rest_framework',
47 + 'knox',
47 'django.contrib.sites', 48 'django.contrib.sites',
49 + 'rest_framework.authtoken',
48 'cloud', 50 'cloud',
49 # allauth 51 # allauth
50 'allauth', 52 'allauth',
...@@ -53,6 +55,7 @@ INSTALLED_APPS = [ ...@@ -53,6 +55,7 @@ INSTALLED_APPS = [
53 # provider 55 # provider
54 'allauth.socialaccount.providers.naver', 56 'allauth.socialaccount.providers.naver',
55 'allauth.socialaccount.providers.google', 57 'allauth.socialaccount.providers.google',
58 + 'rest_auth.registration',
56 ] 59 ]
57 60
58 MIDDLEWARE = [ 61 MIDDLEWARE = [
...@@ -69,15 +72,13 @@ MIDDLEWARE = [ ...@@ -69,15 +72,13 @@ MIDDLEWARE = [
69 ] 72 ]
70 CORS_ORIGIN_ALLOWED_ALL = True 73 CORS_ORIGIN_ALLOWED_ALL = True
71 CORS_ALLOW_CREDENTIALS = True 74 CORS_ALLOW_CREDENTIALS = True
72 -"""
73 CORS_ORIGIN_WHITELIST = [ 75 CORS_ORIGIN_WHITELIST = [
74 - 76 + 'http://0.0.0.0:3001',
75 -'http://localhost:3001/', 77 + 'http://54.180.112.94:3001',
76 - 78 + 'http://127.0.0.1:3001',
77 -'http://127.0.0.1:3001/', 79 + 'http://localhost:3001',
78 - 80 + 'http://172.31.39.245:3001',
79 ] 81 ]
80 -"""
81 ROOT_URLCONF = 'khuloud.urls' 82 ROOT_URLCONF = 'khuloud.urls'
82 83
83 TEMPLATES = [ 84 TEMPLATES = [
...@@ -141,14 +142,31 @@ USE_I18N = True ...@@ -141,14 +142,31 @@ USE_I18N = True
141 USE_L10N = True 142 USE_L10N = True
142 143
143 USE_TZ = True 144 USE_TZ = True
144 - 145 +REST_FRAMEWORK = {
146 + # 권한 인증
147 + 'DEFAULT_AUTHENTICATION_CLASSES': (
148 + 'rest_framework.authentication.TokenAuthentication',
149 + # 'rest_framework.authentication.SessionAuthentication',
150 + ),
151 +}
152 +SOCIALACCOUNT_PROVIDERS = {
153 + 'google': {
154 + 'SCOPE': [
155 + 'profile',
156 + 'email',
157 + ],
158 + 'AUTH_PARAMS': {
159 + 'access_type': 'online',
160 + }
161 + }
162 +}
145 163
146 # Static files (CSS, JavaScript, Images) 164 # Static files (CSS, JavaScript, Images)
147 # https://docs.djangoproject.com/en/1.11/howto/static-files/ 165 # https://docs.djangoproject.com/en/1.11/howto/static-files/
148 AUTHENTICATION_BACKENDS = ( 166 AUTHENTICATION_BACKENDS = (
149 'django.contrib.auth.backends.ModelBackend',#Needed to login by username in Django admin, regardless of 'allauth' 167 'django.contrib.auth.backends.ModelBackend',#Needed to login by username in Django admin, regardless of 'allauth'
150 'allauth.account.auth_backends.AuthenticationBackend',#'allauth' specific authentication method, such as login by e-mail 168 'allauth.account.auth_backends.AuthenticationBackend',#'allauth' specific authentication method, such as login by e-mail
151 - 169 + 'django.contrib.auth.backends.ModelBackend',
152 ) 170 )
153 STATIC_URL = '/static/' 171 STATIC_URL = '/static/'
154 SITE_ID = 1 172 SITE_ID = 1
......
...@@ -21,11 +21,10 @@ from django.conf.urls import include, url ...@@ -21,11 +21,10 @@ from django.conf.urls import include, url
21 from django.urls import path, include 21 from django.urls import path, include
22 urlpatterns = [ 22 urlpatterns = [
23 url(r'^admin/', admin.site.urls), 23 url(r'^admin/', admin.site.urls),
24 - url('main/',blog.views.main, name='main'), 24 + path('',include('blog.urls')),
25 - url(r'^login/', blog.views.login, name='login'),
26 - url(r'^logout/', blog.views.logout, name='logout'),
27 - url(r'^register/', blog.views.register, name='register'),
28 # url(r'^delete/',blog.views.delete, name='delete'), 25 # url(r'^delete/',blog.views.delete, name='delete'),
29 url(r'^accounts/', include('allauth.urls')), 26 url(r'^accounts/', include('allauth.urls')),
30 - path('cloud/',include('cloud.urls')) 27 + path('cloud/',include('cloud.urls')),
28 + url(r'^rest-auth/', include('rest_auth.urls')),
29 + url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))
31 ]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 30 ]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
......
1 +# editorconfig.org
2 +root = true
3 +
4 +[*]
5 +indent_style = space
6 +indent_size = 2
7 +end_of_line = lf
8 +charset = utf-8
9 +trim_trailing_whitespace = true
10 +insert_final_newline = true
11 +
12 +[*.md]
13 +trim_trailing_whitespace = false
1 +# Created by .ignore support plugin (hsz.mobi)
2 +### Node template
3 +# Logs
4 +/logs
5 +*.log
6 +npm-debug.log*
7 +yarn-debug.log*
8 +yarn-error.log*
9 +
10 +# Runtime data
11 +pids
12 +*.pid
13 +*.seed
14 +*.pid.lock
15 +
16 +# Directory for instrumented libs generated by jscoverage/JSCover
17 +lib-cov
18 +
19 +# Coverage directory used by tools like istanbul
20 +coverage
21 +
22 +# nyc test coverage
23 +.nyc_output
24 +
25 +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 +.grunt
27 +
28 +# Bower dependency directory (https://bower.io/)
29 +bower_components
30 +
31 +# node-waf configuration
32 +.lock-wscript
33 +
34 +# Compiled binary addons (https://nodejs.org/api/addons.html)
35 +build/Release
36 +
37 +# Dependency directories
38 +node_modules/
39 +jspm_packages/
40 +
41 +# TypeScript v1 declaration files
42 +typings/
43 +
44 +# Optional npm cache directory
45 +.npm
46 +
47 +# Optional eslint cache
48 +.eslintcache
49 +
50 +# Optional REPL history
51 +.node_repl_history
52 +
53 +# Output of 'npm pack'
54 +*.tgz
55 +
56 +# Yarn Integrity file
57 +.yarn-integrity
58 +
59 +# dotenv environment variables file
60 +.env
61 +
62 +# parcel-bundler cache (https://parceljs.org/)
63 +.cache
64 +
65 +# next.js build output
66 +.next
67 +
68 +# nuxt.js build output
69 +.nuxt
70 +
71 +# Nuxt generate
72 +dist
73 +
74 +# vuepress build output
75 +.vuepress/dist
76 +
77 +# Serverless directories
78 +.serverless
79 +
80 +# IDE / Editor
81 +.idea
82 +
83 +# Service worker
84 +sw.*
85 +
86 +# macOS
87 +.DS_Store
88 +
89 +# Vim swap files
90 +*.swp
1 +# frontend
2 +
3 +> Khuloud Nuxt.js project
4 +
5 +## Build Setup
6 +
7 +node version: v12.16.0
8 +npm version: 6.13.4
9 +
10 +
11 +#### frontend 실행방법
12 +```bash
13 +
14 +# install dependencies
15 +# frontend 폴더 내부에서 해당 명령어를 실행하면 package.json에 올려놓았던 모듈 설치
16 +$ cd frontend/
17 +$ npm install
18 +
19 +# run nuxt project
20 +# load http://localhost:3001
21 +$ npm run start
22 +
23 +# django project
24 +$ cd user_server
25 +$ python manage.py runserver
26 +
27 +```
28 +
29 +#### django server와 통신하는 부분
30 +```bash
31 +# frontend/store/user.js
32 +this.$axios.get('본인이 만든 장고 url', withCredentials: true);
33 +this.$axios.post('본인이 만든 장고 url',{json 데이터}, withCredentials: true);
34 +
35 +
36 +## 현재 만든 frontend는 user_server django 파일로 요청이 가게 했습니다.
37 +```
1 +# ASSETS
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +This directory contains your un-compiled assets such as LESS, SASS, or JavaScript.
6 +
7 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked).
1 +// Ref: https://github.com/nuxt-community/vuetify-module#customvariables
2 +//
3 +// The variables you want to modify
4 +// $font-size-root: 20px;
1 +<template>
2 + <div>
3 + <v-btn class="pink white--text">click me</v-btn>
4 + <v-btn depressed class="pink">click me</v-btn>
5 + <v-btn flat class="pink">click me</v-btn>
6 +
7 + <v-btn depressed class="pink white--text">
8 + <v-icon left>email</v-icon>
9 + <span>email me</span>
10 + </v-btn>
11 +
12 + <v-btn depressed small class="pink white--text">
13 + <v-icon left small>email</v-icon>
14 + <span>email me</span>
15 + </v-btn>
16 +
17 + <v-btn fab small dark class="purple">
18 + <v-icon>favorite</v-icon>
19 + </v-btn>
20 +
21 +
22 + <h1>HomePage</h1>
23 + <v-btn class="hidden-md-and-down">click me</v-btn>
24 + <v-btn class="hidden-md-and-up">click me</v-btn>
25 + <v-btn class="hidden-sm-only">click me</v-btn>
26 +
27 + </div>
28 +</template>
29 +
30 +<script>
31 + export default {
32 + name: "ButtonIconVisibility"
33 + }
34 +</script>
35 +
36 +<style scoped>
37 +
38 +</style>
1 +<template>
2 + <div>
3 + <v-row
4 + align="center"
5 + justify="center">
6 + <v-col
7 + cols="12"
8 + sm="8"
9 + md="4"
10 + >
11 + <v-card>
12 + <v-form v-model="valid" @submit.prevent="login">
13 + <v-card-text>
14 + <v-text-field
15 + v-model="username"
16 + :rules="[rules.username]"
17 + label="username"
18 + prepend-icon="person">
19 + </v-text-field>
20 + <v-text-field
21 + v-model="password"
22 + :rules="[rules.password]"
23 + type="password"
24 + label="password"
25 + prepend-icon="lock">
26 + </v-text-field>
27 + </v-card-text>
28 + <v-card-actions>
29 + <v-spacer/>
30 + <v-btn
31 + color="yellow"
32 + type="submit">
33 + 로그인
34 + </v-btn>
35 + </v-card-actions>
36 + </v-form>
37 + </v-card>
38 + </v-col>
39 + </v-row>
40 + </div>
41 +</template>
42 +
43 +
44 +<script>
45 + export default {
46 + name: "loginComponent",
47 + data() {
48 + return {
49 + valid: false,
50 + tryLogin: true,
51 + username: '',
52 + password: '',
53 + rules: {
54 + username: v => !!v || 'username is required',
55 + password: v => !!v || 'password is required',
56 + }
57 + }
58 + },
59 + methods: {
60 + async login() {
61 + try {
62 + console.log('login Method');
63 + //$store.dispatch -> action의 login 함수를 불러 쓸 수 있음
64 + await this.$store.dispatch('user/login', {
65 + username: this.username,
66 + password: this.password
67 + });
68 + await this.$router.replace('/');
69 + } catch (e) {
70 + console.error(e);
71 + }
72 + },
73 + changeTryLogin() {
74 + this.tryLogin = !this.tryLogin;
75 + }
76 + }
77 + }
78 +</script>
1 +<template>
2 + <div class="VueToNuxtLogo">
3 + <div class="Triangle Triangle--two" />
4 + <div class="Triangle Triangle--one" />
5 + <div class="Triangle Triangle--three" />
6 + <div class="Triangle Triangle--four" />
7 + </div>
8 +</template>
9 +
10 +<style>
11 +.VueToNuxtLogo {
12 + display: inline-block;
13 + animation: turn 2s linear forwards 1s;
14 + transform: rotateX(180deg);
15 + position: relative;
16 + overflow: hidden;
17 + height: 180px;
18 + width: 245px;
19 +}
20 +
21 +.Triangle {
22 + position: absolute;
23 + top: 0;
24 + left: 0;
25 + width: 0;
26 + height: 0;
27 +}
28 +
29 +.Triangle--one {
30 + border-left: 105px solid transparent;
31 + border-right: 105px solid transparent;
32 + border-bottom: 180px solid #41b883;
33 +}
34 +
35 +.Triangle--two {
36 + top: 30px;
37 + left: 35px;
38 + animation: goright 0.5s linear forwards 3.5s;
39 + border-left: 87.5px solid transparent;
40 + border-right: 87.5px solid transparent;
41 + border-bottom: 150px solid #3b8070;
42 +}
43 +
44 +.Triangle--three {
45 + top: 60px;
46 + left: 35px;
47 + animation: goright 0.5s linear forwards 3.5s;
48 + border-left: 70px solid transparent;
49 + border-right: 70px solid transparent;
50 + border-bottom: 120px solid #35495e;
51 +}
52 +
53 +.Triangle--four {
54 + top: 120px;
55 + left: 70px;
56 + animation: godown 0.5s linear forwards 3s;
57 + border-left: 35px solid transparent;
58 + border-right: 35px solid transparent;
59 + border-bottom: 60px solid #fff;
60 +}
61 +
62 +@keyframes turn {
63 + 100% {
64 + transform: rotateX(0deg);
65 + }
66 +}
67 +
68 +@keyframes godown {
69 + 100% {
70 + top: 180px;
71 + }
72 +}
73 +
74 +@keyframes goright {
75 + 100% {
76 + left: 70px;
77 + }
78 +}
79 +</style>
80 +
1 +<template>
2 + <nav>
3 + <v-toolbar flat app>
4 + <v-toolbar-side-icon class="grey--text" @click="drawer = !drawer">nav</v-toolbar-side-icon>
5 + <v-toolbar-title class="text-uppercase grey--text">
6 + <span class="font-weight-light">Todo</span>
7 + <span>Ninja</span>
8 + </v-toolbar-title>
9 + <v-spacer/>
10 + <v-btn flat fab small color="grey">
11 + <v-icon small>exit_to_app</v-icon>
12 + </v-btn>
13 + </v-toolbar>
14 +
15 + <!-- color success(녹색), primary(파랑), warning(빨강)-->
16 + <v-navigation-drawer app v-model="drawer" class="success">
17 + <v-list>
18 + <v-list-tile v-for="link in links" :key="link.text" router :to="link.route">
19 + <v-list-tile-action>
20 + <v-icon class="white--text">{{link.icon}}</v-icon>
21 + </v-list-tile-action>
22 + <v-list-tile-content>
23 + <v-list-tile-title class="white--text">{{link.text}}</v-list-tile-title>
24 + </v-list-tile-content>
25 + </v-list-tile>
26 + </v-list>
27 + </v-navigation-drawer>
28 + </nav>
29 +</template>
30 +<script>
31 + import inspire from "../pages/inspire";
32 + import index from "../pages/index";
33 +
34 + export default {
35 + name: "NavBar",
36 + data() {
37 + return {
38 + drawer: false,
39 + links: [
40 + {icon: 'dashboard', text: 'Dashboard', route: '/'},
41 + {icon: 'folder', text: 'MyProfile', route: '/inspire'},
42 + {icon: 'person', text: 'Team', route: '/'},
43 + ]
44 + }
45 + }
46 + }
47 +</script>
48 +
49 +<style scoped>
50 +
51 +</style>
1 +<template>
2 + <div class="mx-4 mb-4">
3 + <h1 class="subheading grey--text">Team</h1>
4 +
5 + <v-container fluid class="my-5">
6 + <v-layout row wrap>
7 + <v-flex xs12 md6>
8 + <v-btn outline block class="primary">1</v-btn>
9 + </v-flex>
10 + <v-flex xs4 md2>
11 + <v-btn outline block class="primary">2</v-btn>
12 + </v-flex>
13 + <v-flex xs4 md2>
14 + <v-btn outline block class="primary">2</v-btn>
15 + </v-flex>
16 + <v-flex xs4 md2>
17 + <v-btn outline block class="primary">2</v-btn>
18 + </v-flex>
19 + </v-layout>
20 +
21 + <!-- justify-end, center, space-around-->
22 +
23 + <v-layout row wrap justify-end>
24 + <v-flex xs4 md3>
25 + <v-btn outline block class="success">1</v-btn>
26 + </v-flex>
27 + <v-flex xs4 md3>
28 + <v-btn outline block class="success">2</v-btn>
29 + </v-flex>
30 + </v-layout>
31 + </v-container>
32 +
33 +
34 + <v-container class="my-5">
35 +
36 + <v-layout row class="mb-3">
37 + <v-tooltip top>
38 + <template v-slot:activator="{ on }">
39 + <v-btn small flat color="grey" @click="sortBy('title')" v-on="on">
40 + <v-icon left small>folder</v-icon>
41 + <span class="caption text-lowercase">By project name</span>
42 + </v-btn>
43 + </template>
44 + <span>Sort projects by project name</span>
45 + </v-tooltip>
46 +
47 + <v-tooltip top>
48 + <template v-slot:activator="{ on }">
49 + <v-btn small flat color="grey" @click="sortBy('person')" v-on="on">
50 + <v-icon left small>person</v-icon>
51 + <span class="caption text-lowercase">By person</span>
52 + </v-btn>
53 + </template>
54 + <span>Sort projects by person</span>
55 + </v-tooltip>
56 + </v-layout>
57 +
58 +
59 + <v-card flat class="pa-3" v-for="project in projects" :key="project.title">
60 + <v-layout row wrap :class="`pa-3 project ${project.status}`">
61 + <v-flex xs12 md6>
62 + <div class="caption grey--text">project title</div>
63 + <div>{{project.title}}</div>
64 + </v-flex>
65 + <v-flex xs4 md2>
66 + <div class="caption grey--text">Person</div>
67 + <div>{{project.person}}</div>
68 + </v-flex>
69 + <v-flex xs4 md2>
70 + <div class="caption grey--text">Due by</div>
71 + <div>{{project.due}}</div>
72 + </v-flex>
73 + <v-flex xs4 md2>
74 + <v-chip small :class="`${project.status} white--text caption my-2`">{{project.status}}</v-chip>
75 + </v-flex>
76 + </v-layout>
77 + </v-card>
78 + </v-container>
79 + </div>
80 +</template>
81 +
82 +<script>
83 + export default {
84 + name: "PaddingMarginGrid",
85 + data() {
86 + return {
87 + projects: [
88 + {title: 'Design a new website', person: 'The Net Ninja', due: '1st Jan 2019', status: 'ongoing'},
89 + {title: 'Write a new website', person: 'Net Ninja', due: '1st Jan 2019', status: 'complete'},
90 + {title: 'Create a new website', person: 'Ninja', due: '1st Jan 2019', status: 'ongoing'},
91 + {title: 'Update a new website', person: 'tjddus', due: '1st Jan 2019', status: 'overdue'}
92 + ]
93 + }
94 + },
95 + methods: {
96 + sortBy(props) {
97 + this.projects.sort((a, b) => a[props] < b[props] ? -1 : 1);
98 + }
99 + }
100 + }
101 +</script>
102 +
103 +<style scoped>
104 + .project.complete {
105 + border-left: 4px solid #3cd1c2;
106 + }
107 +
108 + .project.ongoing {
109 + border-left: 4px solid orange;
110 + }
111 +
112 + .project.overdue {
113 + border-left: 4px solid tomato;
114 + }
115 +
116 + .v-chip.complete {
117 + background: #3cd1c2;
118 + }
119 +
120 + .v-chip.ongoing {
121 + background: orange;
122 + }
123 +
124 + .v-chip.overdue {
125 + background: tomato;
126 + }
127 +</style>
1 +# COMPONENTS
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +The components directory contains your Vue.js Components.
6 +
7 +_Nuxt.js doesn't supercharge these components._
1 +<template>
2 + <div>
3 + <v-row
4 + align="center"
5 + justify="center"
6 + >
7 + <v-col
8 + cols="12"
9 + sm="8"
10 + md="4"
11 + >
12 + <v-card>
13 + <v-form v-model="valid" @submit.prevent="signUp">
14 + <v-card-text>
15 + <v-text-field
16 + v-model="email"
17 + :rules="[rules.email]"
18 + prepend-icon="email"
19 + label="email">
20 + </v-text-field>
21 + <v-text-field
22 + v-model="username"
23 + :rules="[rules.username]"
24 + prepend-icon="person"
25 + label="username">
26 + </v-text-field>
27 + <v-text-field
28 + v-model="password"
29 + :rules="[rules.password]"
30 + prepend-icon="lock"
31 + type="password"
32 + label="password">
33 + </v-text-field>
34 + <v-text-field
35 + v-model="checkpassword"
36 + :rules="[rules.checkpassword]"
37 + prepend-icon="lock"
38 + type="password"
39 + label="checkpassword">
40 + </v-text-field>
41 + </v-card-text>
42 + <v-card-actions>
43 + <v-spacer/>
44 + <v-btn
45 + color="yellow"
46 + type="submit">
47 + 회원가입
48 + </v-btn>
49 + </v-card-actions>
50 + </v-form>
51 + </v-card>
52 + </v-col>
53 + </v-row>
54 + </div>
55 +</template>
56 +
57 +<script>
58 + export default {
59 + name: "SignUpComponent",
60 + data() {
61 + return {
62 + valid: false,
63 + email: '',
64 + name: '',
65 + password: '',
66 + checkpassword: '',
67 + rules: {
68 + email: v => (v || '').match(/@/) || 'Please enter a valid email',
69 + username: v => !!v || 'usrename is required',
70 + password: v => !!v || 'password is required',
71 + checkpassword: v => v == this.password || 'checkpassword is incorrect'
72 + }
73 + }
74 + },
75 + methods: {
76 + async signUp() {
77 + try {
78 + console.log('signUp Method');
79 + //$store.dispatch -> action의 signUp 함수를 불러올 수 있음
80 + await this.$store.dispatch('user/signUp', {
81 + email: this.email,
82 + username: this.username,
83 + password: this.password
84 + });
85 + await this.$router.replace('/');
86 + } catch (e) {
87 + console.error(e);
88 + }
89 + }
90 + }
91 + }
92 +</script>
93 +
94 +<style scoped>
95 +
96 +</style>
97 +
98 +
1 +<template>
2 + <img
3 + class="VuetifyLogo"
4 + alt="Vuetify Logo"
5 + src="/vuetify-logo.svg"
6 + >
7 +</template>
8 +
9 +<style>
10 +.VuetifyLogo {
11 + height:180px;
12 + width: 180px;
13 + transform: rotateY(560deg);
14 + animation: turn 3.5s ease-out forwards 1s;
15 +}
16 +
17 +@keyframes turn {
18 + 100% {
19 + transform: rotateY(0deg);
20 + }
21 +}
22 +</style>
1 +# LAYOUTS
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +This directory contains your Application Layouts.
6 +
7 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts).
1 +<template>
2 + <v-app id="keep">
3 + <v-app-bar
4 + app
5 + clipped-left
6 + color="amber"
7 + >
8 + <v-app-bar-nav-icon @click="drawer = !drawer"/>
9 + <span class="title ml-3 mr-5">KHUloud&nbsp;</span>
10 + <v-text-field
11 + solo-inverted
12 + flat
13 + hide-details
14 + label="Search"
15 + prepend-inner-icon="search"
16 + />
17 + <v-spacer/>
18 + <v-btn
19 + icon
20 + to="/inspire">
21 + <v-icon>account_circle</v-icon>
22 + </v-btn>
23 + </v-app-bar>
24 +
25 + <v-navigation-drawer
26 + v-model="drawer"
27 + app
28 + clipped
29 + color="grey lighten-4"
30 + >
31 + <v-list
32 + dense
33 + class="grey lighten-4"
34 + >
35 + <template v-for="(item, i) in items">
36 + <v-row
37 + v-if="item.heading"
38 + :key="i"
39 + align="center"
40 + >
41 + <v-col cols="6">
42 + <v-subheader v-if="item.heading">
43 + {{ item.heading }}
44 + </v-subheader>
45 + </v-col>
46 + <v-col
47 + cols="6"
48 + class="text-right"
49 + >
50 + <v-btn
51 + small
52 + text
53 + >edit
54 + </v-btn>
55 + </v-col>
56 + </v-row>
57 + <v-divider
58 + v-else-if="item.divider"
59 + :key="i"
60 + dark
61 + class="my-4"
62 + />
63 + <v-list-item
64 + v-else
65 + :key="i"
66 + link
67 + >
68 + <v-list-item-action>
69 + <v-icon>{{ item.icon }}</v-icon>
70 + </v-list-item-action>
71 + <v-list-item-content>
72 + <v-list-item-title class="grey--text">
73 + {{ item.text }}
74 + </v-list-item-title>
75 + </v-list-item-content>
76 + </v-list-item>
77 + </template>
78 + </v-list>
79 + </v-navigation-drawer>
80 +
81 + <v-content>
82 + <nuxt/>
83 + </v-content>
84 + </v-app>
85 +</template>
86 +
87 +<script>
88 + import 'material-design-icons-iconfont/dist/material-design-icons.css'
89 +
90 + export default {
91 + props: {
92 + source: String,
93 + },
94 + data: () => ({
95 + drawer: false,
96 + items: [
97 + {icon: 'lightbulb_outline', text: 'Notes'},
98 + {icon: 'touch_app', text: 'Reminders'},
99 + {divider: true},
100 + {heading: 'Labels'},
101 + {icon: 'add', text: 'Create new folder'},
102 + {divider: true},
103 + {icon: 'archive', text: 'Archive'},
104 + {icon: 'delete', text: 'Trash'},
105 + {divider: true},
106 + {icon: 'settings', text: 'Settings'},
107 + {icon: 'chat_bubble', text: 'Trash'},
108 + {icon: 'help', text: 'Help'},
109 + {icon: 'phonelink', text: 'App downloads'},
110 + {icon: 'keyboard', text: 'Keyboard shortcuts'},
111 + ],
112 + }),
113 + methods: {
114 + account() {
115 + this.$router.push('inspire');
116 + }
117 + }
118 + }
119 +</script>
120 +
121 +<style>
122 + #keep .v-navigation-drawer__border {
123 + display: none
124 + }
125 +</style>
1 +<template>
2 + <v-app dark>
3 + <h1 v-if="error.statusCode === 404">
4 + {{ pageNotFound }}
5 + </h1>
6 + <h1 v-else>
7 + {{ otherError }}
8 + </h1>
9 + <NuxtLink to="/">
10 + Home page
11 + </NuxtLink>
12 + </v-app>
13 +</template>
14 +
15 +<script>
16 +export default {
17 + layout: 'empty',
18 + props: {
19 + error: {
20 + type: Object,
21 + default: null
22 + }
23 + },
24 + data () {
25 + return {
26 + pageNotFound: '404 Not Found',
27 + otherError: 'An error occurred'
28 + }
29 + },
30 + head () {
31 + const title =
32 + this.error.statusCode === 404 ? this.pageNotFound : this.otherError
33 + return {
34 + title
35 + }
36 + }
37 +}
38 +</script>
39 +
40 +<style scoped>
41 +h1 {
42 + font-size: 20px;
43 +}
44 +</style>
1 +# MIDDLEWARE
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +This directory contains your application middleware.
6 +Middleware let you define custom functions that can be run before rendering either a page or a group of pages.
7 +
8 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware).
1 +// import colors from 'vuetify/es5/util/colors'
2 +//
3 +// export default {
4 +// mode: 'universal',
5 +// /*
6 +// ** Headers of the page
7 +// */
8 +// head: {
9 +// titleTemplate: '%s - ' + process.env.npm_package_name,
10 +// title: process.env.npm_package_name || '',
11 +// meta: [
12 +// { charset: 'utf-8' },
13 +// { name: 'viewport', content: 'width=device-width, initial-scale=1' },
14 +// { hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
15 +// ],
16 +// link: [
17 +// { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
18 +// ]
19 +// },
20 +// /*
21 +// ** Customize the progress-bar color
22 +// */
23 +// loading: { color: '#fff' },
24 +// /*
25 +// ** Global CSS
26 +// */
27 +// css: [
28 +// ],
29 +// /*
30 +// ** Plugins to load before mounting the App
31 +// */
32 +// plugins: [
33 +// ],
34 +// /*
35 +// ** Nuxt.js dev-modules
36 +// */
37 +// buildModules: [
38 +// '@nuxtjs/vuetify',
39 +// '@nuxtjs/moment',
40 +// ],
41 +// /*
42 +// ** Nuxt.js modules
43 +// */
44 +// modules: [
45 +// '@nuxtjs/axios',
46 +// '@nuxtjs/pwa'
47 +// ],
48 +// /*
49 +// ** Build configuration
50 +// */
51 +// build: {
52 +// /*
53 +// ** You can extend webpack config here
54 +// */
55 +// extend (config, ctx) {
56 +// }
57 +// }
58 +// }
59 +
60 +
61 +import webpack from 'webpack'
62 +
63 +module.exports = {
64 +
65 + server: {
66 + host: '0.0.0.0',
67 + port: 3001
68 + },
69 + head: {
70 + meta: [{
71 + charset: 'utf-8',
72 + }, {
73 + name: 'viewport',
74 + content: 'width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no',
75 + }],
76 + cookie: {}
77 + },
78 + modules: [
79 + '@nuxtjs/axios',
80 + '@nuxtjs/pwa',
81 + ],
82 + buildModules: [
83 + '@nuxtjs/vuetify',
84 + '@nuxtjs/moment',
85 + ],
86 +
87 + // pwa: {
88 + // icon: {
89 + // iconSrc: 'static/icon.png'
90 + // },
91 + // manifest: {
92 + // name: 'node_express_study_final'
93 + // },
94 + // workbox: {
95 + // dev: true,
96 + // runtimeCaching: [{
97 + // urlPattern: 'http://localhost:4001/.*',
98 + // method: 'GET'
99 + // }, {
100 + // urlPattern: 'http://localhost:5001/.*',
101 + // method: 'GET'
102 + // }]
103 + // },
104 + // }
105 +};
This diff could not be displayed because it is too large.
1 +{
2 + "name": "frontend",
3 + "scripts": {
4 + "start": "nuxt"
5 + },
6 + "dependencies": {
7 + "@nuxtjs/axios": "^5.9.5",
8 + "@nuxtjs/moment": "^1.6.0",
9 + "@nuxtjs/pwa": "^3.0.0-beta.20",
10 + "@nuxtjs/vuetify": "^1.11.0",
11 + "jquery": "^3.4.1",
12 + "js-cookie": "^2.2.1",
13 + "loadsh": "0.0.4",
14 + "lodash.throttle": "^4.1.1",
15 + "material-design-icons-iconfont": "^5.0.1",
16 + "nuxt": "^2.11.0",
17 + "socket.io-client": "^2.3.0",
18 + "webpack": "^4.43.0"
19 + }
20 +}
1 +# PAGES
2 +
3 +This directory contains your Application Views and Routes.
4 +The framework reads all the `*.vue` files inside this directory and creates the router of your application.
5 +
6 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing).
1 +<template>
2 + <v-layout
3 + column
4 + justify-center
5 + align-center
6 + >
7 + <v-flex
8 + xs12
9 + sm8
10 + md1
11 + >
12 + <div v-if="!me">
13 + Do login
14 + </div>
15 + <div v-else>
16 + {{me.username}}님 환영합니다
17 + <v-data-table
18 + :headers="headers"
19 + :items="files"
20 + :items-per-page="10"
21 + class="elevation-1"
22 + />
23 + </div>
24 + </v-flex>
25 + </v-layout>
26 +</template>
27 +
28 +<script>
29 + import Navbar from "../components/Navbar";
30 +
31 + export default {
32 + name: "home",
33 + components: {Navbar},
34 + data() {
35 + return {
36 + headers: [
37 + {
38 + text: '이름',
39 + }, {
40 + text: '수정한 날짜',
41 + }, {
42 + text: '공유',
43 + }, {
44 + text: '크기',
45 + }
46 + ],
47 + files: []
48 + }
49 + },
50 + computed: {
51 + me() {
52 + return this.$store.state.user.me;
53 + }
54 + }
55 + }
56 +</script>
57 +
1 +<template>
2 + <v-layout>
3 + <v-flex class="text-center">
4 + <div
5 + v-if="me">
6 + <v-btn @click="logout">로그아웃</v-btn>
7 + </div>
8 + <div
9 + v-else>
10 + <div
11 + v-if="tryLogin">
12 + <login-component/>
13 + <v-btn @click="changeTryLogin">회원가입</v-btn>
14 + </div>
15 + <div
16 + v-else>
17 + <sign-up-component/>
18 + <v-btn @click="changeTryLogin">로그인</v-btn>
19 + </div>
20 + </div>
21 + <v-btn @click="socialLogin">소셜로그인</v-btn>
22 + </v-flex>
23 + </v-layout>
24 +</template>
25 +
26 +<script>
27 + import LoginComponent from "../components/LoginComponent";
28 + import SignUpComponent from "../components/SignUpComponent";
29 +
30 + export default {
31 + data() {
32 + return {
33 + tryLogin: true,
34 + }
35 + },
36 + computed: {
37 + me() {
38 + return this.$store.state.user.me
39 + }
40 + },
41 + components: {
42 + LoginComponent,
43 + SignUpComponent,
44 + },
45 + methods: {
46 + changeTryLogin() {
47 + this.tryLogin = !this.tryLogin
48 + },
49 + async logout() {
50 + try {
51 + await this.$store.dispatch('user/logout');
52 + await this.$router.replace('/');
53 + } catch (e) {
54 + console.error(e);
55 + }
56 + },
57 + async socialLogin(){
58 + try{
59 + if(process.client){
60 + console.log('zzz')
61 + window.open('http://ec2-54-180-112-94.ap-northeast-2.compute.amazonaws.com:8080/accounts/google/login/')
62 + }
63 + console.log('z')
64 + await this.$store.dispatch('user/socialLogin');
65 + await this.$router.replace('/');
66 + }catch(e){
67 + console.error(e);
68 + }
69 + },
70 + }
71 + }
72 +
73 +</script>
1 +<template>
2 + <div>
3 + <PaddingMarginGrid/>
4 + </div>
5 +</template>
6 +
7 +<script>
8 + import Navbar from "../components/Navbar";
9 + import PaddingMarginGrid from "../components/PaddingMarginGrid";
10 +
11 + export default {
12 + name: "vuetifyT",
13 + components: {Navbar, PaddingMarginGrid}
14 + }
15 +</script>
16 +
17 +<style scoped>
18 +
19 +</style>
1 +# PLUGINS
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
6 +
7 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
1 +# STATIC
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +This directory contains your static files.
6 +Each file inside this directory is mapped to `/`.
7 +Thus you'd want to delete this README.md before deploying to production.
8 +
9 +Example: `/static/robots.txt` is mapped as `/robots.txt`.
10 +
11 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).
No preview for this file type
1 +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>
1 +# STORE
2 +
3 +**This directory is not required, you can delete it if you don't want to use it.**
4 +
5 +This directory contains your Vuex Store files.
6 +Vuex Store option is implemented in the Nuxt.js framework.
7 +
8 +Creating a file in this directory automatically activates the option in the framework.
9 +
10 +More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).
1 +import Cookie from 'js-cookie';
2 +
3 +export const state = () => ({});
4 +export const mutations = {};
5 +export const actions = {
6 + //새로고침마다 호출되는 함수
7 + async nuxtServerInit({dispatch}, {req}) {
8 + try {
9 + const cookie = req.headers.cookie.split('=')[1];
10 + console.log(cookie);
11 + await dispatch('user/loadMe', {cookie});
12 + // await dispatch('post/loadPosts', {reset: true});
13 + // await dispatch('waitingRoom/loadChatMe');
14 + } catch (e) {
15 + console.error(e);
16 + }
17 + }
18 +};
19 +
20 +
21 +// 1) state : 데이터 정의
22 +// users, groups, user,files, file
23 +// 2) mutation : state에 있는 데이터들을 수정하는 작업
24 +// user => 이름이 바뀌면 state에 있는 user 정보를 가지고 와서 수정하는 곳
25 +// 3) action: 서버에다가 데이터를 요청하는 작업
26 +// 서버에서 user 정보를 받아서 mutation에 state에 있는 user 정보를 내가 받은 정보로 수정하라고 요청
27 +
28 +
29 +// state에서 데이터를 정의할 때 username, password 이런식으로 작은 단위로는 정의를 잘 안해
30 +// user정보로 묶음으로 정의하는 거든
31 +// user: { 'username' : '정수연', 'password': 'wjdtndus'}
32 +// file: { 'filename': , 'createdAt', 'deletedAt', 'isFolder'}
33 +// user: null, '', 0, True, False
34 +
1 +import Cookie from 'js-cookie';
2 +
3 +export const state = () => ({
4 + me: null,
5 +});
6 +
7 +export const mutations = {
8 + loadMe(state, payload) {
9 + const {user} = payload;
10 + state.me = user;
11 + },
12 + login(state, payload) {
13 + const {user} = payload;
14 + state.me = user;
15 + },
16 + logout(state) {
17 + state.me = null;
18 + }
19 +};
20 +
21 +export const actions = {
22 +//mutation{commit} 호출
23 + loadMe({commit}, payload) {
24 + return new Promise(async (resolve, reject) => {
25 + try {
26 + const {cookie} = payload;
27 + this.$axios.defaults.headers.common['Authorization'] = `Token ${cookie}`;
28 + const res = await this.$axios.get('http://54.180.112.94:8080/api/auth/loadMe', {
29 + withCredentials: true
30 + });
31 + commit('loadMe', {user: res.data});
32 + return resolve();
33 + } catch (e) {
34 + console.error(e);
35 + return reject(e);
36 + }
37 + })
38 + },
39 +
40 + /* signUp */
41 + signUp({commit}, payload) {
42 + return new Promise(async (resolve, reject) => {
43 + try {
44 + const {email, username, password} = payload;
45 + const res = await this.$axios.post('http://54.180.112.94:8080/api/auth/signUp', {
46 + email, username, password
47 + }, {
48 + withCredentials: true
49 + });
50 + const {user, token} = res.data;
51 + if (process.browser) {
52 + localStorage.setItem('accessToken', token);
53 + Cookie.set('accessToken', token);
54 + console.log(localStorage);
55 + }
56 +
57 + commit('login', {user});
58 + return resolve();
59 +
60 + } catch (e) {
61 + console.log(res.data);
62 + console.error(e);
63 + return reject(e);
64 + }
65 + })
66 + },
67 +
68 + /* login */
69 + login({commit}, payload) {
70 + return new Promise(async (resolve, reject) => {
71 + try {
72 + console.log(payload)
73 + const {username, password} = payload;
74 + console.log('login 실행');
75 + const res = await this.$axios.post('http://54.180.112.94:8080/api/auth/login', {
76 + username,password
77 + }, {
78 + withCredentials: true
79 + });
80 + console.log(res);
81 + // # 접근 성공 시, 토큰 값이 반환된다.
82 + // 토큰을 헤더 정보에 포함시켜서 유저 정보를 요청
83 + // 토큰을 로컬 스토리지에 저장
84 + const {user, token} = res.data;
85 + // console.log(user, token);
86 + if (process.browser) {
87 + localStorage.setItem('accessToken', token);
88 + Cookie.set('accessToken', token);
89 + console.log(localStorage);
90 + }
91 +/*
92 + login({commit}, payload) {
93 + return new Promise(async (resolve, reject) => {
94 + try {
95 + const {username, password} = payload;
96 + console.log('login 실행');
97 + const res = await this.$axios.post('ec2-54-180-112-94.ap-northeast-2.compute.amazonaws.com:8000/rest-a
98 +uth/google', {
99 + username, password
100 + }, {
101 + withCredentials: true
102 + });
103 +
104 + console.log(res);
105 + // # 접근 성공 시, 토큰 값이 반환된다.
106 + // 토큰을 헤더 정보에 포함시켜서 유저 정보를 요청
107 + // 토큰을 로컬 스토리지에 저장
108 + const {user, token} = res.data;
109 + console.log(user, token);
110 + if (process.browser) {
111 + localStorage.setItem('accessToken', token);
112 + Cookie.set('accessToken', token);
113 + console.log(localStorage);
114 + }
115 +*/
116 +
117 +
118 + commit('login', {user});
119 + return resolve();
120 +
121 + } catch (e) {
122 + console.error(e);
123 + return reject(e);
124 + }
125 + });
126 + },
127 +
128 + /* logout */
129 + logout({commit}) {
130 + return new Promise(async (resolve, reject) => {
131 + try {
132 + // await this.$axios.get('http://127.0.0.1:8000/user/logout', {
133 + // withCredentials: true
134 + // });
135 + if (process.browser) {
136 + localStorage.removeItem('accessToken');
137 + Cookie.remove('accessToken');
138 + }
139 + commit('logout');
140 + return resolve();
141 +
142 + } catch (e) {
143 + console.error(e);
144 + return reject(e);
145 + }
146 + })
147 + },
148 +
149 +
150 + socialLogin({commit}){
151 + console.log('zz')
152 + console.log(this)
153 + return new Promise(async (resolve, reject) => {
154 + try{
155 + const res = await this.$axios.post('http://ec2-54-180-112-94.ap-northeast-2.compute.amazonaws.com:8080/accounts/google/login/callback/main/',{ withCredentials: true });
156 + console.log(res);
157 +
158 + }catch(e){
159 + console.error(e);
160 + return reject(e);
161 + }
162 + })
163 + }
164 +
165 +
166 +};
167 +
168 +
169 +// mutations -> 함수 인자로 (state, payload) => state / payload -> actions
170 +// actions -> 함수 인자로 ({commit}, payload) => commit mutations / payload
171 +
172 +// new Promise -> 비동기, 동기
173 +
174 +// 동기
175 +// 동시에 처리된다는 말은 실행되고 결과가 무조건 동시에 나와야한다는 뜻이야
176 +// print(1) print(2) print(3) => 1, 2, 3
177 +
178 +// 비동기
179 +// print(1) print(2, => 1초) print(3) => 1,3,2 (default)
180 +
181 +// Promise 비동기식 작업을 처리한다
182 +// 로그인 요청 => 서버로 로그인 데이터를 보내주세요 => 서버로부터 온 데이터를 mutation을 통해 state.me의 값을 수정해주세요
183 +// 그 작업을 비동기적으로 실행되는 작업을 처리하겠다 => Promise ( 순차적으로 실행되게 하는거야 ) =>
184 +// Username, password => user 정보가 오지 않았어 (성공, 실패) => user: null 인 상태에서 state.me 수정해버리는 거야 => user 정보가 오는거야
185 +// 그래서 뭐를 하냐 new Promise => 내부에 로직같은걸로 무조건 기다려야 하는 작업에 기다리라는 속성을 줘! 서버에서 user 정보를 받아와야 하는 작업에 user정보가 올때까지 기다려 라는 로직같은 걸 줘!
186 +
187 +// return new Promise( async(resolve, reject)=> {
188 +// try{
189 +//
190 +// }catch (e) {
191 +//
192 +// }
193 +// })
194 +