Flare-k

Modified Model and Serializers

Showing 61 changed files with 2041 additions and 92 deletions
# 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
node_modules/
# frontend
> My incredible Nuxt.js project
## Build Setup
```bash
# install dependencies
$ npm install
# serve with hot reload at localhost:3000
$ npm run dev
# build for production and launch server
$ npm run build
$ npm run start
# generate static project
$ npm run generate
```
For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org).
# 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-btn
text
@click="$refs.fileInput.click()">
<v-icon>vertical_align_top</v-icon>
<span class="caption">업로드</span>
</v-btn>
<input
v-show="false"
type="file"
ref="fileInput"
multiple="multiple"
@change="uploadFile">
</div>
</template>
<script>
import 'material-design-icons-iconfont/dist/material-design-icons.css'
export default {
name: "CreateFileFormComponent",
data() {
return {
filepath: '',
}
},
methods: {
async uploadFile(e) {
try {
const formData = new FormData();
const now = Date.now();
Array.prototype.forEach.call(e.target.files, (file) => {
formData.append('file', file);
formData.append('name', file.name);
formData.append('isFolder', true);
formData.append('path', this.filepath);
formData.append('fileSize', file.size);
formData.append('createdDate', now);
formData.append('updatedDate', now);
formData.append('share', false);
console.log(file);
});
await this.$store.dispatch('file/uploadFile', {formData});
return this.$router.replace('/');
} catch (e) {
console.error(e);
}
}
}
}
</script>
<style scoped>
</style>
<template>
<v-dialog max-width="400px">
<template v-slot:activator="{on}">
<v-btn
flat slot="activator"
text
v-on="on">
<v-icon>add</v-icon>
<span overline class="caption">새로 만들기</span>
</v-btn>
</template>
<v-card>
<v-card-title>
<p class="title font-weight-light">폴더</p>
</v-card-title>
<v-form class="px-3" @submit.prevent="uploadFolder">
<v-card-text>
<v-text-field
outlined
label="폴더 이름"
v-model="folderName"
color="blue"
/>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn
depressed
class="mr-3 mb-3 text-lowercase font-weight-light"
type="submit">
만들기
</v-btn>
</v-card-actions>
</v-form>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: "CreateFolderFormComponent",
data() {
return {
valid: false,
folderName: '',
folderPath: '/',
}
},
methods: {
async uploadFolder() {
try {
console.log('폴더이름 test', this.folderName);
const now = Date.now();
const formData = new FormData();
formData.append('name', this.folderName);
formData.append('owner', 'owner');
formData.append('path', this.folderPath);
formData.append('isFolder', true);
formData.append('createdAt', now);
formData.append('fileSize', 0);
formData.append('share', false);
console.log(now, this.folderPath);
await this.$store.dispatch('file/uploadFolder', {formData});
// await this.$router.replace('/');
} catch (e) {
console.error(e);
}
},
}
}
</script>
<style scoped>
</style>
<template>
<v-layout justify-center="center" class="my-10">
<v-flex
xs12 md10>
<v-data-table
:headers="headers"
:items="files"
hide-actions
hide-default-footer
>
<template slot="items" slot-scope="props">
<td>
<v-btn
icon>
<v-icon>folder</v-icon>
</v-btn>
</td>
<td>
{{ props.item.name }}
</td>
<td class="text-xs-right">{{ props.item.modifiedDate }}</td>
<td class="text-xs-right">{{ props.item.owner }}</td>
<td class="text-xs-right">{{ props.item.fileSize }}</td>
<td class="text-xs-right">{{ props.item.share }}</td>
</template>
</v-data-table>
</v-flex>
</v-layout>
</template>
<script>
import 'material-design-icons-iconfont/dist/material-design-icons.css'
export default {
name: 'DataTableComponent',
data() {
return {
currentPath: 'root',
fileTypeIcon: '',
headers: [
{text: '', value: 'icon'},
{
text: '이름',
align: 'left',
sortable: 'false',
value: 'name'
},
{text: '수정한 날짜', value: 'modifiedDate'},
{text: '수정한 사람', value: 'owner'},
{text: '파일 크기', value: 'fileSize'},
{text: '공유', value: 'share'}
],
files: [
{
name: '90.944339.pdf',
modifiedDate: '2020-02-08',
owner: 'tjddus',
fileSize: '1000',
share: false
}
]
}
}
}
</script>
<template>
<v-system-bar
:height="55">
<create-folder-form-component/>
<create-file-form-component/>
<v-spacer/>
<v-menu offset-y>
<template
v-slot:activator="{on}">
<v-btn
text
v-on="on"
>
<v-icon>sort</v-icon>
<span class="caption">정렬</span>
</v-btn>
</template>
<v-list>
<v-list-item v-for="view in views" :key="view.title" @click="changeCurrentView(view.title)">
<v-list-action>
<v-icon small>{{view.icon}}</v-icon>
</v-list-action>
<v-list-title class="ml-1 body-2">{{view.title}}</v-list-title>
</v-list-item>
</v-list>
</v-menu>
</v-system-bar>
</template>
<script>
import 'material-design-icons-iconfont/dist/material-design-icons.css'
import CreateFolderFormComponent from "./CreateFolderFormComponent";
import CreateFileFormComponent from "./CreateFileFormComponent";
export default {
name: "FileNavbarComponent",
components: {CreateFolderFormComponent, CreateFileFormComponent},
data() {
return {
currentView: 0,
views: [
{value: 0, icon: 'format_align_left', title: '목록'},
{value: 1, icon: 'border_all', title: '타일'}
],
}
},
methods: {
changeCurrentView(value) {
this.currentView = value;
console.log(this.currentView);
},
}
}
</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="grey"
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');
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>
<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>
<v-layout class="py-10" justify-center="center">
<v-flex
xs12 md10>
<v-data-table
:headers="headers"
:items="files"
hide-actions
hide-default-footer
>
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.shareDate }}</td>
<td class="text-xs-right">{{ props.item.sharePerson }}</td>
<td class="text-xs-right">{{ props.item.acitivity }}</td>
</template>
</v-data-table>
</v-flex>
</v-layout>
</template>
<script>
export default {
name: 'ShareTableComponent',
// computed: {
// files: this.$store.state.file.files
// },
data () {
return {
headers: [
{
text: '이름',
align: 'left',
sortable: 'false',
value: 'name'
},
{ text: '공유된 날짜', value: 'shareDate'},
{ text: '공유한 사람', value: 'sharePerson'},
{ text: '활동', value: 'activity'}
],
files: [
]
}
}
}
</script>
<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="grey"
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: '',
username: '',
password: '',
checkpassword: '',
rules: {
email: v => (v || '').match(/@/) || 'Please enter a valid email',
username: v => !!v || 'username 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>
<v-layout justify-center="center" class="my-10">
<v-flex xs12 md10>
<v-data-table :headers="headers" :items="files" hide-actions hide-default-footer>
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td class="text-xs-right">{{ props.item.deletedDate }}</td>
<td class="text-xs-right">{{ props.item.deletePerson }}</td>
<td class="text-xs-right">{{ props.item.makePerson }}</td>
<td class="text-xs-right">{{ props.item.originalPath }}</td>
</template>
</v-data-table>
</v-flex>
</v-layout>
</template>
<script>
export default {
name: 'TrashTableComponent',
data() {
return {
headers: [
{
text: '이름',
align: 'left',
sortable: 'false',
value: 'name'
},
{text: '삭제된 날짜', value: 'deletedDate'},
{text: '삭제한 사람', value: 'deletePerson'},
{text: '만든 사람', value: 'makePerson'},
{text: '원래 위치', value: 'originalPath'}
],
files: []
}
}
}
</script>
<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>
<v-navigation-drawer
v-model="drawer"
app
clipped
>
<v-list dense>
<v-list-item v-for="item in items" :key="item.title" router :to="item.route">
<v-list-item-action :to="item.to">
<v-icon>{{item.icon}}</v-icon>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>{{item.title}}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-navigation-drawer>
<v-app-bar
app
clipped-left
:height="55"
>
<v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon>
<v-toolbar-title small>KHULOUD</v-toolbar-title>
<v-spacer/>
<v-btn icon class="mr-2" nuxt to="inspire">
<v-icon flat small>person</v-icon>
</v-btn>
</v-app-bar>
<v-content>
<nuxt/>
</v-content>
<v-footer app>
<span>&copy; 2020</span>
</v-footer>
</v-app>
</template>
<script>
import 'material-design-icons-iconfont/dist/material-design-icons.css'
export default {
props: {
source: String,
},
data() {
return {
drawer: null,
items: [
{title: 'Khuloud', icon: 'school', route: '/'},
{title: '내 파일', icon: 'folder', route: '/drive/file'},
{title: '최근 항목', icon: 'list', route: '/'},
{title: '사진', icon: 'image', route: '/inspire'},
{title: '공유됨', icon: 'get_app', route: '/drive/shared-with-me'},
{title: '휴지통', icon: 'delete', route: '/drive/trash'}
]
}
}
}
</script>
<style scoped>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
</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: 'localhost',
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>
<div>
<file-navbar-component/>
<data-table-component/>
</div>
</template>
<script>
import FileNavbarComponent from "../../components/FileNavbarComponent";
import DataTableComponent from "../../components/DataTableComponent";
export default {
name: "file",
components: {
FileNavbarComponent,
DataTableComponent,
}
}
</script>
<style scoped>
</style>
<template>
<div>
<file-navbar-component/>
<share-table-component/>
</div>
</template>
<script>
import FileNavbarComponent from "../../components/FileNavbarComponent";
import ShareTableComponent from "../../components/ShareTableComponent";
export default {
name: "shared-with-me.vue",
components: {FileNavbarComponent, ShareTableComponent},
}
</script>
<style scoped>
</style>
<template>
<div>
<trash-table-component/>
</div>
</template>
<script>
import TrashTableComponent from "../../components/TrashTableComponent";
export default {
name: 'trash',
components: {
TrashTableComponent
}
}
</script>
<template>
<div>
<div v-if="!me">
Do login
</div>
<div v-else>
{{me.username}}님 환영합니다
</div>
</div>
</template>
<script>
export default {
name: "home",
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>
<PaddingMarginGrid/>
</v-flex>
</v-layout>
</template>
<script>
import LoginComponent from "../components/LoginComponent";
import SignUpComponent from "../components/SignUpComponent";
import PaddingMarginGrid from "../components/PaddingMarginGrid";
export default {
data() {
return {
tryLogin: true,
}
},
computed: {
me() {
return this.$store.state.user.me
}
},
components: {
LoginComponent,
SignUpComponent,
PaddingMarginGrid,
},
methods: {
changeTryLogin() {
this.tryLogin = !this.tryLogin
},
async logout() {
try {
await this.$store.dispatch('user/logout');
await this.$router.replace('/');
} catch (e) {
console.error(e);
}
}
}
}
</script>
<template>
<div>
<PaddingMarginGrid/>
</div>
</template>
<script>
import PaddingMarginGrid from "../components/PaddingMarginGrid";
export default {
name: "vuetifyT",
components: {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).
export const state = () => ({
files: [],
file: null,
});
export const mutation = {
loadFiles(state, payload) {
const {files} = payload;
state.files = files;
},
uploadFolder({commit}, payload) {
const {file} = payload;
state.files.push(file);
},
uploadFiles(state, payload) {
const {files} = payload;
state.files.concat(files);
},
deleteFile(state, payload) {
const {fileId} = payload;
state.file = null;
state.files.splice(state.files.findIndex(file => file.id === fileId), 1);
},
};
export const actions = {
loadFiles({commit}, payload) {
return new Promise(async (resolve, reject) => {
try {
const res = await this.$axios.get('http://127.0.0.1:8000/files/loadFiles', {
withCredentials: true
});
const {files} = res.data;
commit('loadFiles', {files});
return resolve();
} catch (e) {
console.error(e);
return reject(e);
}
})
},
uploadFolder({commit}, payload) {
return new Promise(async (resolve, reject) => {
try {
const {formData} = payload;
// const res = await this.$axios.post('http://127.0.0.1:8000/files/uploadFolder', formData, {
// withCredentials: true
// });
let res = {
file: {
name: '90.944339.pdf',
modifiedDate: '2020-02-08',
owner: 'tjddus',
fileSize: '1000',
share: false
}
};
const {file} = res;
commit('uploadFiles', {file});
return resolve();
} catch (e) {
console.error(e);
return reject(e);
}
})
},
uploadFiles({commit}, payload) {
return new Promise(async (resolve, reject) => {
try {
const {formData} = payload;
const res = await this.$axios.post('http:/127.0.0.1:8000/files/uploadFiles', formData, {
withCredentials: true
});
const {files} = res.data;
commit('uploadFiles', files);
return resolve();
} catch (e) {
console.error(e);
return reject(e);
}
});
},
deleteFolder({commit}, payload) {
return new Promise(async (resolve, reject) => {
try {
const {folderId} = payload;
await this.$axios.get('http://127.0.0.1/files/deleteFile', {
fileId: folderId
}, {
withCredentials: true
});
commit('deleteFile', {fileId: folderId});
} catch (e) {
console.error(e);
return reject(e);
}
});
},
deleteFile({commit}, payload) {
return new Promise(async (resolve, reject) => {
try {
const {fileId} = payload;
await this.$axios.get('http://127.0.0.1/files/deleteFile', {
fileId: fileId
}, {
withCredentials: true
});
commit('deleteFile', {fileId: fileId});
} catch (e) {
console.error(e);
return reject(e);
}
})
},
// updateFolder({commit}, payload) {
//
// },
// updateFile({commit}, payload) {
//
// }
};
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);
}
}
};
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://localhost:8000/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://127.0.0.1:8000/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 {
const {username, password} = payload;
const res = await this.$axios.post('http://127.0.0.1:8000/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);
}
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);
}
})
}
};
'''
import boto3
import sys
from django.conf import settings
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
s3_client = boto3.client(
's3',
aws_access_key_id=config['aws']['AWS_ACCESS_KEY_ID'],
aws_secret_access_key=config['aws']['AWS_SECRET_ACCESS_KEY']
)
s3 = boto3.resource('s3', aws_access_key_id=config['aws']['AWS_ACCESS_KEY_ID'],
aws_secret_access_key=config['aws']['AWS_SECRET_ACCESS_KEY'])
def get_folder_with_items(self, main_folder):
print("HI~~~~")
try:
result = self.s3_client.list_objects(
Bucket="opijaeclouds", Prefix=main_folder[1:], Delimiter="/")
result_files = get_files(main_folder, result.get(
'Contents')) if result.get('Contents') else []
result_folders = get_folders(main_folder, result.get('CommonPrefixes')) if result.get(
'CommonPrefixes') else []
return result_folders + result_files # return files and folders
except Exception as e:
print('Error on line {}'.format(
sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
def get_files(main_folder, result):
try:
files_list = []
for obj in result:
# main_folder[1:] exp; -folder1/folder2 => delete "-"
if main_folder[1:] != obj.get('Key'): # if obj is not folder item
object_url = "https://s3.console.amazonaws.com/s3/buckets/{0}/{1}".format(
"opijaeclouds", obj.get('Key'))
# for template file icon
icon_list = [
'ai.png', 'audition.png', 'avi.png', 'bridge.png', 'css.png', 'csv.png', 'dbf.png', 'doc.png',
'dreamweaver.png', 'dwg.png', 'exe.png', 'file.png', 'fireworks.png', 'fla.png', 'flash.png',
'folder_icon.png', 'html.png', 'illustrator.png', 'indesign.png', 'iso.png', 'javascript.png',
'jpg.png', 'json-file.png', 'mp3.png', 'mp4.png', 'pdf.png', 'photoshop.png', 'png.png',
'ppt.png', 'prelude.png', 'premiere.png', 'psd.png', 'rtf.png', 'search.png', 'svg.png',
'txt.png', 'xls.png', 'xml.png', 'zip.png', 'zip-1.png']
img_file_list = ['ani', 'bmp', 'cal', 'fax', 'gif', 'img', 'jbg', 'jpg', 'jpe', 'mac', 'pbm',
'pcd', 'pcx', 'pct', 'pgm', 'png', 'jpeg', 'ppm', 'psd', 'ras', 'tag', 'tif',
'wmf']
extension, icon = str(obj['Key'].split('.')[-1]).lower(), None
if extension in img_file_list:
icon = object_url if extension in ['bmp', 'jpg', 'jpeg', 'png',
'gif'] else "/static/images/jpg.png"
if not icon:
icon = "/static/images/" + extension + ".png" if extension + \
".png" in icon_list else "/static/images/file.png"
item_type = "folder" if obj.get(
'Key')[-1] == "/" else "other" # for show template
files_list.append(
{'key': obj.get('Key'), 'url': object_url, 'icon': icon,
'text': obj.get('Key')[len(main_folder) - 1:], 'type': item_type})
return sorted(files_list, key=lambda k: str(k['key']).lower(), reverse=no)
except Exception as e:
print('Error on line {}'.format(
sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
def get_folders(main_folder, result):
try:
files_list = []
for obj in result:
icon = "/static/images/folder_icon.png"
item_type = "folder" # for show template
url = obj.get('Prefix')
files_list.append(
{'key': obj.get('Prefix'), 'url': url, 'icon': icon,
'text': obj.get('Prefix')[len(main_folder) - 1:], 'type': item_type})
return sorted(files_list, key=lambda k: str(k['key']).lower(), reverse=no)
except Exception as e:
print('Error on line {}'.format(
sys.exc_info()[-1].tb_lineno), type(e).__name__, e)
'''
......@@ -2,7 +2,18 @@ from django.db import models
from django.utils import timezone
# Create your models here.
class File(models.Model):
path=models.CharField(max_length=300)
created_date = models.DateTimeField(default=timezone.now)
modified_date = models.DateTimeField(blank=True, null=True)
\ No newline at end of file
file = models.FileField(upload_to=None, max_length=100, )
name = models.CharField(max_length=50)
isFolder = models.BooleanField(default=False)
path = models.FilePathField(
path=None, match=None, recursive=False, max_length=100)
owner = models.CharField(max_length=30)
fileSize = models.IntegerField()
createdDate = models.DateTimeField(auto_now_add=True)
modifiedDate = models.DateTimeField(blank=True, null=True)
class Meta:
ordering = ['createdDate']
......
from rest_framework import serializers
from .models import File
class FileSerializer(serializers.FileSerializer):
class Meta:
model = File
fields = ['file', 'name', 'isFolder', 'path', 'owner',
'fileSize', 'createdDate', 'modifiedDate']
......@@ -14,6 +14,7 @@ import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# class FileToURL(View):
# s3_client = boto3.client(
# 's3',
......@@ -89,9 +90,6 @@ class FileList(View):
bucket = "opijaeclouds"
bucketMy = self.s3.Bucket(bucket)
# Iterates through all the objects, doing the pagination for you. Each obj
# is an ObjectSummary, so it doesn't contain the body. You'll need to call
# get to get the whole body.
for obj in bucketMy.objects.all():
key = obj.key
body = obj.get()['Body'].read()
......
*.pyc
*~
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'
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"]
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.')
\ No newline at end of file
from django.test import TestCase
# Create your tests here.
from django.urls import path, include
from rest_framework import routers
from accounts.views import LoginAPI, UserAPI, SignUpAPI
# 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()),
]
from django.shortcuts import render
from rest_framework.authtoken.models import Token
from accounts.serializers import (
UserSerializer,
LoginSerializer,
SignUpSerializer,
)
from rest_framework import viewsets, permissions, generics, status
from rest_framework.response import Response
from django.contrib.auth.models import User
# LoadUserAPI
# ssr user loading
# used for read_only endpoints to represent a single model instance.
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
# SignUpAPI
# 회원가입 API
class SignUpAPI(generics.GenericAPIView):
serializer_class = SignUpSerializer
def post(self, request, *args, **kwargs):
print(request.data)
serializer = self.get_serializer(data=request.data)
print(serializer)
serializer.is_valid(raise_exception=True)
user = serializer.save()
print(user)
token, created = Token.objects.get_or_create(user=user)
return Response({
'user': UserSerializer(
user, context = self.get_serializer_context()
).data,
'token': token.key
})
# LoginAPI: req.data(username, password)=>deserializer=>valid(authenticate)=>serializer
# 로그인 API
class LoginAPI(generics.GenericAPIView):
# field : username, password
serializer_class = LoginSerializer
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
token, created = Token.objects.get_or_create(user=user)
print(user, token)
return Response({
'user': UserSerializer(
user, context = self.get_serializer_context()
).data,
'token': token.key
})
\ No newline at end of file
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
"""
ASGI config for mysite project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_asgi_application()
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 3.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
import datetime
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '&041&h2k89h+l=^#)0fgf*df-4crdid&fw_duhy5(i#-#g+xaj'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
]
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
'accounts',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_ALLOWED_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = [
'http://localhost:3001',
'http://127.0.0.1:3001',
]
ROOT_URLCONF = 'mysite.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mysite.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'ko'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
REST_FRAMEWORK = {
# 권한 인증
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
}
"""mysite URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('accounts.urls')),
]
"""
WSGI config for mysite project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
application = get_wsgi_application()