continue admin area and api
This commit is contained in:
parent
b4e9f2ae9b
commit
8b345515ab
@ -2,8 +2,9 @@ import { ApiModelProperty } from '@nestjs/swagger';
|
||||
|
||||
export class AuthJwtDto {
|
||||
@ApiModelProperty()
|
||||
access_token: string;
|
||||
token: {
|
||||
accessToken: string;
|
||||
|
||||
@ApiModelProperty()
|
||||
refresh_token: string;
|
||||
refreshToken: string;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,20 +51,22 @@ export class AuthService {
|
||||
const payload = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
roles: user.roles,
|
||||
scope: user.roles,
|
||||
};
|
||||
return {
|
||||
access_token: this.jwtService.sign(payload),
|
||||
// TODO add refresh token invalidation uppon usage! They should only work once
|
||||
refresh_token: this.jwtService.sign(
|
||||
{
|
||||
...payload,
|
||||
refresh: true
|
||||
},
|
||||
{
|
||||
expiresIn: '30days',
|
||||
}
|
||||
),
|
||||
token: {
|
||||
accessToken: this.jwtService.sign(payload),
|
||||
// TODO add refresh token invalidation uppon usage! They should only work once
|
||||
refreshToken: this.jwtService.sign(
|
||||
{
|
||||
...payload,
|
||||
refresh: true
|
||||
},
|
||||
{
|
||||
expiresIn: '30days',
|
||||
}
|
||||
),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,8 +13,6 @@ export class RegisterService {
|
||||
) {}
|
||||
|
||||
async register (username: string, email: string, password: string): Promise<void> {
|
||||
// TODO actually create user
|
||||
|
||||
let user = new User()
|
||||
user.email = email
|
||||
user.username = username
|
||||
|
||||
@ -12,9 +12,12 @@ export class FormController {
|
||||
|
||||
@Get()
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
async list(@Request() req): Promise<any> {
|
||||
throw new NotImplementedException()
|
||||
async list(@Request() req): Promise<FormDto[]> {
|
||||
// TODO calculate total forms, add for pagination
|
||||
const results = await this.formService.findBy({})
|
||||
return results.map(form => new FormDto(form))
|
||||
}
|
||||
|
||||
@Post()
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
async create(@Request() req): Promise<FormDto> {
|
||||
|
||||
@ -8,10 +8,32 @@ export class FormDto {
|
||||
@ApiModelProperty()
|
||||
title: string;
|
||||
|
||||
fields: [];
|
||||
@ApiModelProperty()
|
||||
live: boolean;
|
||||
|
||||
@ApiModelProperty()
|
||||
created: Date;
|
||||
|
||||
@ApiModelProperty()
|
||||
lastModified: Date;
|
||||
|
||||
@ApiModelProperty()
|
||||
fields: any;
|
||||
|
||||
@ApiModelProperty()
|
||||
info: {
|
||||
responses: number;
|
||||
}
|
||||
|
||||
constructor(partial: Partial<Form>) {
|
||||
this.id = partial._id.toString();
|
||||
this.id = partial._id.toString()
|
||||
this.title = partial.title
|
||||
this.live = partial.isLive
|
||||
this.created = partial.created
|
||||
this.lastModified = partial.lastModified
|
||||
this.fields = partial.form_fields
|
||||
this.info = {
|
||||
responses: 0 // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,8 +17,10 @@ export class Form extends Typegoose {
|
||||
})
|
||||
readonly title: string;
|
||||
|
||||
@prop()
|
||||
readonly created: any;
|
||||
|
||||
@prop()
|
||||
readonly lastModified: any;
|
||||
|
||||
@prop({
|
||||
|
||||
@ -2,6 +2,7 @@ import {Injectable} from '@nestjs/common';
|
||||
import { InjectModel } from 'nestjs-typegoose';
|
||||
import { ModelType } from 'typegoose';
|
||||
import {Form} from "../models/form.model"
|
||||
import {User} from "../../user/models/user.model"
|
||||
|
||||
@Injectable()
|
||||
export class FormService {
|
||||
@ -10,4 +11,8 @@ export class FormService {
|
||||
async findById(id: string): Promise<Form> {
|
||||
return await this.formModel.findById(id).exec()
|
||||
}
|
||||
|
||||
async findBy(conditions): Promise<Form[]> {
|
||||
return await this.formModel.find(conditions).exec()
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,10 +6,7 @@ import { useContainer } from "class-validator"
|
||||
const pkg = require('../package.json')
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
// app.enableCors({ origin: '*' });
|
||||
// app.getHttpAdapter().options('*', cors());
|
||||
const app = await NestFactory.create(AppModule, { cors: true });
|
||||
|
||||
useContainer(app.select(AppModule), { fallbackOnErrors: true });
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import { AuthGuard } from '@nestjs/passport';
|
||||
import { ApiBearerAuth, ApiImplicitQuery, ApiResponse, ApiUseTags } from "@nestjs/swagger"
|
||||
import { UserService } from "../services/user.service"
|
||||
import { UserDto } from "../dto/user.dto"
|
||||
import {FormDto} from "../../form/dto/form.dto"
|
||||
|
||||
@ApiUseTags('users')
|
||||
@ApiBearerAuth()
|
||||
@ -12,8 +13,10 @@ export class UserController {
|
||||
|
||||
@Get()
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
async list(@Request() req): Promise<any> {
|
||||
throw new NotImplementedException()
|
||||
async list(@Request() req): Promise<UserDto[]> {
|
||||
// TODO calculate total forms, add for pagination
|
||||
const results = await this.userService.findBy({})
|
||||
return results.map(form => new UserDto(form))
|
||||
}
|
||||
|
||||
@ApiResponse({ status: 200, description: 'User Object', type: UserDto})
|
||||
|
||||
@ -8,8 +8,20 @@ export class UserDto {
|
||||
@ApiModelProperty()
|
||||
username: string;
|
||||
|
||||
@ApiModelProperty()
|
||||
email: string;
|
||||
|
||||
@ApiModelProperty()
|
||||
roles: string[];
|
||||
|
||||
@ApiModelProperty()
|
||||
created: Date;
|
||||
|
||||
constructor(partial: Partial<User>) {
|
||||
this.id = partial._id.toString();
|
||||
this.id = partial._id.toString()
|
||||
this.username = partial.username
|
||||
this.email = partial.email
|
||||
this.roles = partial.roles
|
||||
this.created = partial.created
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,10 @@ export class UserService {
|
||||
return await this.userModel.findOne(conditions).exec()
|
||||
}
|
||||
|
||||
async findBy(conditions): Promise<User[]> {
|
||||
return await this.userModel.find(conditions).exec()
|
||||
}
|
||||
|
||||
async save(user: User): Promise<User> {
|
||||
let model = new this.userModel(user)
|
||||
return await model.save()
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
$accent: #fae596;
|
||||
$primary: #3fb0ac;
|
||||
|
||||
html {
|
||||
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
|
||||
|
||||
1html {
|
||||
font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||
Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
@ -13,6 +15,23 @@ html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
&.navbar-dark,
|
||||
&.dark {
|
||||
background-color: #173e43 !important;
|
||||
}
|
||||
|
||||
&.dark {
|
||||
a {
|
||||
color: #dddfd4;
|
||||
|
||||
&:hover {
|
||||
color: #fae596;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: $primary;
|
||||
|
||||
@ -1,5 +1,57 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-navbar variant="primary" toggleable="sm" type="dark">
|
||||
<b-navbar-brand href="https://ohmyform.com">
|
||||
<img src="../assets/img/logo_white_small.png" style="height: 27px" />
|
||||
</b-navbar-brand>
|
||||
|
||||
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
|
||||
|
||||
<b-collapse id="nav-collapse" is-nav>
|
||||
<b-navbar-nav>
|
||||
<b-nav-item
|
||||
:active="/\/admin\/forms/.test($route.fullPath)"
|
||||
to="/admin/forms"
|
||||
>
|
||||
Forms
|
||||
</b-nav-item>
|
||||
<b-nav-item
|
||||
:active="/\/admin\/users/.test($route.fullPath)"
|
||||
to="/admin/users"
|
||||
>
|
||||
Users
|
||||
</b-nav-item>
|
||||
<b-nav-item
|
||||
:active="/\/admin\/configuration/.test($route.fullPath)"
|
||||
to="/admin/configuration"
|
||||
>
|
||||
Configuration
|
||||
</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
|
||||
<b-navbar-nav class="ml-auto">
|
||||
<b-nav-item-dropdown right>
|
||||
<template slot="button-content">
|
||||
<font-awesome-icon icon="user-circle" />
|
||||
</template>
|
||||
<b-dropdown-item to="/admin/me">Profile</b-dropdown-item>
|
||||
<b-dropdown-item @click="logout">Sign Out</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
</b-navbar-nav>
|
||||
</b-collapse>
|
||||
</b-navbar>
|
||||
<nuxt />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
async logout() {
|
||||
await this.$auth.logout()
|
||||
|
||||
this.$router.push('/login')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="screen">
|
||||
<div class="screen bg-primary dark">
|
||||
<div class="content">
|
||||
<nuxt />
|
||||
</div>
|
||||
@ -16,7 +16,6 @@
|
||||
<style lang="scss" scoped>
|
||||
.screen {
|
||||
min-height: 100vh;
|
||||
background: #173e43;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -33,13 +32,8 @@
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: #dddfd4;
|
||||
padding-right: 16px;
|
||||
padding-left: 16px;
|
||||
|
||||
&:hover {
|
||||
color: #fae596;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,10 +16,38 @@ export default {
|
||||
link: [{ rel: 'icon', type: 'image/png', href: '/favicon.png' }]
|
||||
},
|
||||
|
||||
proxy: {
|
||||
'/api': { target: 'http://localhost:3000', pathRewrite: { '/api/': '/' } }
|
||||
},
|
||||
|
||||
router: {
|
||||
middleware: ['auth']
|
||||
},
|
||||
|
||||
server: {
|
||||
port: 3100
|
||||
},
|
||||
|
||||
auth: {
|
||||
strategies: {
|
||||
local: {
|
||||
endpoints: {
|
||||
login: { url: '/api/auth/login', method: 'post', propertyName: 'token.accessToken' },
|
||||
logout: { url: '/api/auth/logout', method: 'post' },
|
||||
user: false
|
||||
},
|
||||
tokenRequired: true,
|
||||
tokenType: 'Bearer'
|
||||
}
|
||||
},
|
||||
|
||||
redirect: {
|
||||
login: '/login',
|
||||
logout: '/',
|
||||
home: '/admin'
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
** Customize the progress-bar color
|
||||
*/
|
||||
@ -35,15 +63,18 @@ export default {
|
||||
/*
|
||||
** Plugins to load before mounting the App
|
||||
*/
|
||||
plugins: [],
|
||||
plugins: [
|
||||
'@/plugins/font-awesome.js',
|
||||
'@/plugins/fab.js'
|
||||
],
|
||||
|
||||
/*
|
||||
** Nuxt.js modules
|
||||
*/
|
||||
modules: [
|
||||
// Doc: https://axios.nuxtjs.org/usage
|
||||
'@nuxtjs/auth',
|
||||
'@nuxtjs/proxy',
|
||||
'@nuxtjs/axios',
|
||||
// Doc: https://bootstrap-vue.js.org/docs/
|
||||
'bootstrap-vue/nuxt'
|
||||
],
|
||||
/*
|
||||
|
||||
@ -13,13 +13,19 @@
|
||||
"precommit": "npm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.22",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.10.2",
|
||||
"@fortawesome/vue-fontawesome": "^0.1.7",
|
||||
"@nuxtjs/auth": "^4.8.1",
|
||||
"@nuxtjs/axios": "^5.3.6",
|
||||
"@nuxtjs/proxy": "^1.3.3",
|
||||
"bootstrap": "^4.1.3",
|
||||
"bootstrap-vue": "^2.0.0-rc.11",
|
||||
"cross-env": "^5.2.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"nuxt": "^2.4.0",
|
||||
"sass-loader": "^8.0.0"
|
||||
"sass-loader": "^8.0.0",
|
||||
"vue-fab": "^2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/eslint-config": "^0.0.1",
|
||||
|
||||
11
ui/pages/admin/configuration/index.vue
Normal file
11
ui/pages/admin/configuration/index.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
config XD
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin'
|
||||
}
|
||||
</script>
|
||||
22
ui/pages/admin/forms/_id.vue
Normal file
22
ui/pages/admin/forms/_id.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>Form: {{ form }}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin',
|
||||
data() {
|
||||
return {
|
||||
form: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.load()
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
this.form = await this.$axios.$get(`/api/forms/${this.$route.params.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
46
ui/pages/admin/forms/index.vue
Normal file
46
ui/pages/admin/forms/index.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-alert show variant="info" class="m-3">
|
||||
All created forms, they are publicly visible if live is true
|
||||
</b-alert>
|
||||
|
||||
<fab bg-color="#173e43" />
|
||||
<b-table striped hover :items="provider" :fields="fields">
|
||||
<template slot="[menu]" slot-scope="data">
|
||||
<nuxt-link :to="'/admin/forms/' + data.item.id">Open</nuxt-link>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin',
|
||||
data() {
|
||||
return {
|
||||
fields: [
|
||||
{
|
||||
key: 'title'
|
||||
},
|
||||
{
|
||||
key: 'created'
|
||||
},
|
||||
{
|
||||
key: 'live'
|
||||
},
|
||||
{
|
||||
key: 'responses'
|
||||
},
|
||||
{
|
||||
key: 'menu'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
provider(ctx) {
|
||||
return this.$axios.$get('/api/forms')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -3,3 +3,9 @@
|
||||
ADMIN
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin'
|
||||
}
|
||||
</script>
|
||||
|
||||
11
ui/pages/admin/me.vue
Normal file
11
ui/pages/admin/me.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
My Profile XD
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin'
|
||||
}
|
||||
</script>
|
||||
22
ui/pages/admin/users/_id.vue
Normal file
22
ui/pages/admin/users/_id.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>User: {{ user }}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin',
|
||||
data() {
|
||||
return {
|
||||
user: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.load()
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
this.user = await this.$axios.$get(`/api/users/${this.$route.params.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
45
ui/pages/admin/users/index.vue
Normal file
45
ui/pages/admin/users/index.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-alert show variant="info" class="m-3">
|
||||
Available Users, since you are an admin you can edit them
|
||||
</b-alert>
|
||||
|
||||
<b-table striped hover :items="provider" :fields="fields">
|
||||
<template slot="[menu]" slot-scope="data">
|
||||
<nuxt-link :to="'/admin/users/' + data.item.id">Open</nuxt-link>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin',
|
||||
data() {
|
||||
return {
|
||||
fields: [
|
||||
{
|
||||
key: 'username'
|
||||
},
|
||||
{
|
||||
key: 'email'
|
||||
},
|
||||
{
|
||||
key: 'roles'
|
||||
},
|
||||
{
|
||||
key: 'created'
|
||||
},
|
||||
{
|
||||
key: 'menu'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
provider(ctx) {
|
||||
return this.$axios.$get('/api/users')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
FORM
|
||||
</div>
|
||||
</template>
|
||||
22
ui/pages/forms/_id.vue
Normal file
22
ui/pages/forms/_id.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>Form: {{ form }}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'admin',
|
||||
data() {
|
||||
return {
|
||||
form: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.load()
|
||||
},
|
||||
methods: {
|
||||
async load() {
|
||||
this.form = await this.$axios.$get(`/public/${this.$route.params.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -6,7 +6,8 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'screen'
|
||||
layout: 'screen',
|
||||
auth: 'guest'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<img src="../assets/img/logo_white_small.png" alt="OhMyForm" />
|
||||
|
||||
<b-form class="box" @submit="submit">
|
||||
<b-form class="box" @submit.prevent="submit">
|
||||
<b-form-group label-for="username">
|
||||
<b-form-input
|
||||
id="username"
|
||||
@ -22,6 +22,12 @@
|
||||
></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label-for="session">
|
||||
<b-form-checkbox id="session" v-model="session">
|
||||
Login only for current Tab
|
||||
</b-form-checkbox>
|
||||
</b-form-group>
|
||||
|
||||
<b-button type="submit" block variant="primary">Login</b-button>
|
||||
<nuxt-link to="/recover" class="recover">Forgot your password?</nuxt-link>
|
||||
</b-form>
|
||||
@ -31,15 +37,28 @@
|
||||
<script>
|
||||
export default {
|
||||
layout: 'screen',
|
||||
auth: 'guest',
|
||||
data() {
|
||||
return {
|
||||
username: '',
|
||||
password: ''
|
||||
password: '',
|
||||
session: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
// TODO
|
||||
async submit() {
|
||||
try {
|
||||
await this.$auth.loginWith('local', {
|
||||
data: {
|
||||
username: this.username,
|
||||
password: this.password
|
||||
}
|
||||
})
|
||||
|
||||
this.$router.push('/admin')
|
||||
} catch (e) {
|
||||
// TODO failed login
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,6 +71,15 @@ img {
|
||||
}
|
||||
.box {
|
||||
margin-top: 60px;
|
||||
height: 400px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
|
||||
/deep/ .custom-checkbox {
|
||||
.custom-control-label {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.recover {
|
||||
display: block;
|
||||
|
||||
71
ui/pages/recover.vue
Normal file
71
ui/pages/recover.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div>
|
||||
<img src="../assets/img/logo_white_small.png" alt="OhMyForm" />
|
||||
|
||||
<b-form class="box" @submit.prevent="submit">
|
||||
<b-form-group label-for="username">
|
||||
<b-form-input
|
||||
id="username"
|
||||
v-model="username"
|
||||
trim
|
||||
placeholder="Username or Email"
|
||||
></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-button type="submit" block variant="primary">Request Reset</b-button>
|
||||
<nuxt-link to="/login" class="recover">
|
||||
Just remembered your password? Sign in here
|
||||
</nuxt-link>
|
||||
</b-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
layout: 'screen',
|
||||
auth: 'guest',
|
||||
data() {
|
||||
return {
|
||||
username: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async submit() {
|
||||
try {
|
||||
await this.$axios.$post('/auth/recover', {
|
||||
username: this.username
|
||||
})
|
||||
|
||||
// TODO success
|
||||
} catch (e) {
|
||||
// TODO show error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
img {
|
||||
max-width: 80%;
|
||||
width: 300px;
|
||||
}
|
||||
.box {
|
||||
margin-top: 60px;
|
||||
height: 400px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
|
||||
/deep/ .custom-checkbox {
|
||||
.custom-control-label {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.recover {
|
||||
display: block;
|
||||
padding-top: 15px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
@ -42,6 +42,7 @@
|
||||
<script>
|
||||
export default {
|
||||
layout: 'screen',
|
||||
auth: 'guest',
|
||||
data() {
|
||||
return {
|
||||
username: '',
|
||||
@ -64,6 +65,9 @@ img {
|
||||
}
|
||||
.box {
|
||||
margin-top: 60px;
|
||||
height: 400px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.recover {
|
||||
display: block;
|
||||
|
||||
6
ui/plugins/fab.js
Normal file
6
ui/plugins/fab.js
Normal file
@ -0,0 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import fab from 'vue-fab'
|
||||
|
||||
export default () => {
|
||||
Vue.component('fab', fab)
|
||||
}
|
||||
10
ui/plugins/font-awesome.js
Normal file
10
ui/plugins/font-awesome.js
Normal file
@ -0,0 +1,10 @@
|
||||
import Vue from 'vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faUserCircle } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
|
||||
export default () => {
|
||||
library.add(faUserCircle)
|
||||
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
||||
}
|
||||
106
ui/yarn.lock
106
ui/yarn.lock
@ -703,6 +703,30 @@
|
||||
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
|
||||
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
|
||||
|
||||
"@fortawesome/fontawesome-common-types@^0.2.22":
|
||||
version "0.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.22.tgz#3f1328d232a0fd5de8484d833c8519426f39f016"
|
||||
integrity sha512-QmEuZsipX5/cR9JOg0fsTN4Yr/9lieYWM8AQpmRa0eIfeOcl/HLYoEa366BCGRSrgNJEexuvOgbq9jnJ22IY5g==
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@^1.2.22":
|
||||
version "1.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.22.tgz#9a6117c96c8b823c7d531000568ac75c3c02e123"
|
||||
integrity sha512-Q941E4x8UfnMH3308n0qrgoja+GoqyiV846JTLoCcCWAKokLKrixCkq6RDBs8r+TtAWaLUrBpI+JFxQNX/WNPQ==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.22"
|
||||
|
||||
"@fortawesome/free-solid-svg-icons@^5.10.2":
|
||||
version "5.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.10.2.tgz#61bcecce3aa5001fd154826238dfa840de4aa05a"
|
||||
integrity sha512-9Os/GRUcy+iVaznlg8GKcPSQFpIQpAg14jF0DWsMdnpJfIftlvfaQCWniR/ex9FoOpSEOrlXqmUCFL+JGeciuA==
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types" "^0.2.22"
|
||||
|
||||
"@fortawesome/vue-fontawesome@^0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.7.tgz#121867297cafd141af78c67d92ab9f1ad4b7328b"
|
||||
integrity sha512-YCw2Q2m4fxzyFsPOH3uDYMoJztTD+pT+AAyse4LFpbdrBg+r8ueaVT8BFnXEjrGwMDJJeXrwJ5AOC6q/JWBI4w==
|
||||
|
||||
"@nuxt/babel-preset-app@2.9.2":
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@nuxt/babel-preset-app/-/babel-preset-app-2.9.2.tgz#e8d2ac841db845ef88ca2687093a95a480106e5d"
|
||||
@ -953,7 +977,21 @@
|
||||
webpack-node-externals "^1.7.2"
|
||||
webpackbar "^4.0.0"
|
||||
|
||||
"@nuxtjs/axios@^5.3.6":
|
||||
"@nuxtjs/auth@^4.8.1":
|
||||
version "4.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/auth/-/auth-4.8.1.tgz#e554bbd032fdcd08d9fddcb159f30ff2c7de5b1a"
|
||||
integrity sha512-EsBiiWXnojOxQ1ouK07tsXMP8pLFiAc+L4NLd1NGr3Z45iGRrjwLLy/weOH65vJGqNYX3lIQBGYscUyzGaaAyg==
|
||||
dependencies:
|
||||
"@nuxtjs/axios" "^5.5.4"
|
||||
consola "^2.9.0"
|
||||
cookie "^0.4.0"
|
||||
dotprop "^1.2.0"
|
||||
is-https "^1.0.0"
|
||||
js-cookie "^2.2.0"
|
||||
lodash "^4.17.11"
|
||||
nanoid "^2.0.3"
|
||||
|
||||
"@nuxtjs/axios@^5.3.6", "@nuxtjs/axios@^5.5.4":
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.6.0.tgz#30fd28c8a409ea32c92c76b26202e5da068f814c"
|
||||
integrity sha512-Rl4nnudm+sSkMtgfSEAeA5bq6aFpbBoYVXLXWaDxfydslukRd2SdEDdGv0gHE7F/jtIw+JfptWDHCHnzuoO/Ng==
|
||||
@ -2406,7 +2444,7 @@ cookie-signature@1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
|
||||
|
||||
cookie@0.4.0:
|
||||
cookie@0.4.0, cookie@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
|
||||
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
|
||||
@ -2993,6 +3031,11 @@ dot-prop@^4.1.0, dot-prop@^4.1.1:
|
||||
dependencies:
|
||||
is-obj "^1.0.0"
|
||||
|
||||
dotprop@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/dotprop/-/dotprop-1.2.0.tgz#8fdf345c757da479ec8af218ae4239a73df721a7"
|
||||
integrity sha512-mVQb8y5u3UkzNua2Hc8Ut/uKyCjm9GG2MRk/0fxJ9Mxo8Nb8XyWqaP0wVXerMucmu0mQmlcZm3S1mjOdcbCwQA==
|
||||
|
||||
duplexer3@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||
@ -4632,6 +4675,11 @@ is-glob@^4.0.0, is-glob@^4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-https@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-https/-/is-https-1.0.0.tgz#9c1dde000dc7e7288edb983bef379e498e7cb1bf"
|
||||
integrity sha512-1adLLwZT9XEXjzhQhZxd75uxf0l+xI9uTSFaZeSESjL3E1eXSPpO+u5RcgqtzeZ1KCaNvtEwZSTO2P4U5erVqQ==
|
||||
|
||||
is-installed-globally@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
|
||||
@ -4784,6 +4832,11 @@ js-base64@^2.1.8:
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
|
||||
integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
|
||||
|
||||
js-cookie@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
|
||||
|
||||
js-levenshtein@^1.1.3:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
|
||||
@ -5073,7 +5126,7 @@ lodash@^4.0.0, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
|
||||
loose-envify@^1.0.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
@ -5406,6 +5459,11 @@ nan@^2.12.1, nan@^2.13.2:
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||
|
||||
nanoid@^2.0.3:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.0.tgz#3de3dbd68cfb2f3bd52550e2bfd439cf75040eb2"
|
||||
integrity sha512-g5WwS+p6Cm+zQhO2YOpRbQThZVnNb7DDq74h8YDCLfAGynrEOrbx2E16dc8ciENiP1va5sqaAruqn2sN+xpkWg==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||
@ -6158,7 +6216,7 @@ pkg-dir@^4.1.0:
|
||||
dependencies:
|
||||
find-up "^4.0.0"
|
||||
|
||||
popper.js@^1.15.0:
|
||||
popper.js@^1.0.2, popper.js@^1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
|
||||
integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==
|
||||
@ -8215,6 +8273,13 @@ toidentifier@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
tooltip.js@^1.1.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/tooltip.js/-/tooltip.js-1.3.2.tgz#ccfe450ffd7332ce5f254033778649526c1db542"
|
||||
integrity sha512-DeDr9JxYx/lSvQ53ZCRFLxXrmrSyU3fLz6k+ITUTw69AIYtpWij/NmOJQscJ7BwY5lcEwWJWSfqqQWVvTMYZiw==
|
||||
dependencies:
|
||||
popper.js "^1.0.2"
|
||||
|
||||
toposort@^1.0.0:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
|
||||
@ -8538,6 +8603,13 @@ uuid@^3.3.2:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
|
||||
v-tooltip@2.0.0-beta.1:
|
||||
version "2.0.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.0.0-beta.1.tgz#9d09a4ea96054ebfe268bf0b50c7845fd5d64b5b"
|
||||
integrity sha1-nQmk6pYFTr/iaL8LUMeEX9XWS1s=
|
||||
dependencies:
|
||||
tooltip.js "^1.1.2"
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
||||
@ -8570,6 +8642,13 @@ vm-browserify@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
|
||||
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
|
||||
|
||||
vue-clickaway@^2.1.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vue-clickaway/-/vue-clickaway-2.2.2.tgz#cecf6839575e8b2afc5d3edb3efb616d293dbb44"
|
||||
integrity sha512-25SpjXKetL06GLYoLoC8pqAV6Cur9cQ//2g35GRFBV4FgoljbZZjTINR8g2NuVXXDMLSUXaKx5dutgO4PaDE7A==
|
||||
dependencies:
|
||||
loose-envify "^1.2.0"
|
||||
|
||||
vue-client-only@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-client-only/-/vue-client-only-2.0.0.tgz#ddad8d675ee02c761a14229f0e440e219de1da1c"
|
||||
@ -8587,6 +8666,16 @@ vue-eslint-parser@^5.0.0:
|
||||
esquery "^1.0.1"
|
||||
lodash "^4.17.11"
|
||||
|
||||
vue-fab@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-fab/-/vue-fab-2.3.1.tgz#5f36c8595f6ceff576b01b97a40817fdf262bd85"
|
||||
integrity sha512-suC4T0gfvDussE1HQ5+ts8D4VknKTiKJqZqDXCtaAc5ithkZYDk5HN7+qS/Svoj2GTaJc3jpG91aLWUgdd+YUw==
|
||||
dependencies:
|
||||
v-tooltip "2.0.0-beta.1"
|
||||
vue "^2.2.1"
|
||||
vue-clickaway "^2.1.0"
|
||||
vue-ripple-directive "^1.0.0"
|
||||
|
||||
vue-functional-data-merge@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz#08a7797583b7f35680587f8a1d51d729aa1dc657"
|
||||
@ -8620,6 +8709,13 @@ vue-no-ssr@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/vue-no-ssr/-/vue-no-ssr-1.1.1.tgz#875f3be6fb0ae41568a837f3ac1a80eaa137b998"
|
||||
integrity sha512-ZMjqRpWabMPqPc7gIrG0Nw6vRf1+itwf0Itft7LbMXs2g3Zs/NFmevjZGN1x7K3Q95GmIjWbQZTVerxiBxI+0g==
|
||||
|
||||
vue-ripple-directive@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-ripple-directive/-/vue-ripple-directive-1.1.1.tgz#3399ea5c49f28899eea53d226f51ccacd27f202b"
|
||||
integrity sha512-W25CDdrgopuRdAwmjEeBtmJMTvbHkoze7jn8qWVwLHXBj8yBRZc05O4OCTYqjwZLO1hrclMQ467wahb6wbRCZg==
|
||||
dependencies:
|
||||
vue "^2.2.1"
|
||||
|
||||
vue-router@~3.0.7:
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b"
|
||||
@ -8660,7 +8756,7 @@ vue-template-es2015-compiler@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||
|
||||
vue@^2.6.10:
|
||||
vue@^2.2.1, vue@^2.6.10:
|
||||
version "2.6.10"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
|
||||
integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user