Ubuntu

add front

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