Compare commits

...

7 commits

18 changed files with 113 additions and 287 deletions

View file

@ -99,14 +99,13 @@ class FFTCGDB
stmt.finalize()
if err
logger.warn "reg: FAIL db '#{err.code}' for '#{login}'"
reject messages.exists # user already exists
# user already exists
reject messages.exists
else
logger.info "reg: OK '#{login}'"
# registration successful
resolve
user: @lastID
login: login
resolve null
.catch ->
reject messages.empty
@ -117,7 +116,7 @@ class FFTCGDB
@validate login, password
.then =>
# get users table row
stmt = @db.prepare 'SELECT user, login, pwdhash FROM users WHERE login = ?'
stmt = @db.prepare 'SELECT * FROM users WHERE login = ?'
stmt.get [login], (err, row) =>
stmt.finalize()
if err
@ -139,9 +138,7 @@ class FFTCGDB
if res == true
logger.debug "login: OK '#{row.login}'"
# login successful
resolve
user: row.user
login: row.login
resolve row.user
else
logger.debug "login: FAIL password for '#{login}'"
@ -150,6 +147,26 @@ class FFTCGDB
.catch ->
reject messages.empty
get: (user) ->
new Promise (resolve, reject) =>
# get users table row
stmt = @db.prepare 'SELECT * FROM users WHERE user = ?'
stmt.get [user], (err, row) =>
stmt.finalize()
if err
logger.warn "get: FAIL db '#{err.code}' for '#{user}'"
reject messages.db
else if not row
logger.debug "get: FAIL nonexistent '#{user}'"
reject messages.noexists # user doesnt exist
else
resolve
user: row.user
login: row.login
settings: row.settings
addDeck: (user, deckCards) ->
new Promise (resolve, reject) =>
# try creating row in decks table

View file

@ -0,0 +1,34 @@
logger = (require 'logging').default '/user/info'
# session storage (volatile data)
session = (require '../../session')
# fftcg.db (persistent data)
fftcgdb = (require '../../db')
module.exports =
url: '/user/info'
method: 'POST'
schema: (require './info.schema')
handler: (request, reply) ->
session.check request.body.session ? ""
.then (userid) ->
# active session found, get associated user
fftcgdb.get (userid)
.then (user) ->
logger.debug "OK '#{user.login}' got info"
reply.send
success: true
user: user
.catch (err) ->
# couldnt get user details
logger.warn "FAIL '#{err}' for user id '#{userid}'"
reply.send
success: false
.catch ->
# no session found
logger.info "FAIL '#{request.body.session}' session not found"
reply.send
success: false

View file

@ -0,0 +1,24 @@
module.exports =
body:
session: type: 'string'
response:
200:
type: 'object'
required: ['success']
properties:
success: type: 'boolean'
user:
type: 'object'
required: ['user', 'login', 'settings']
properties:
user: type: 'integer'
login: type: 'string'
settings: type: 'string'
# user is required iff success
if:
properties:
success:
const: true
then:
required: ['user']
else: true

View file

@ -1,4 +1,4 @@
logger = (require 'logging').default 'login'
logger = (require 'logging').default '/user/login'
# session storage (volatile data)
session = (require '../../session')

View file

@ -1,4 +1,4 @@
logger = (require 'logging').default 'logout'
logger = (require 'logging').default '/user/logout'
# session storage (volatile data)
session = (require '../../session')
@ -6,17 +6,7 @@ session = (require '../../session')
module.exports =
url: '/user/logout'
method: 'POST'
schema:
body:
session: type: 'string'
response:
200:
type: 'object'
required: ['success']
properties:
success:
type: 'boolean'
const: true
schema: (require './logout.schema')
handler: (request, reply) ->
new Promise (resolve) ->

View file

@ -0,0 +1,11 @@
module.exports =
body:
session: type: 'string'
response:
200:
type: 'object'
required: ['success']
properties:
success:
type: 'boolean'
const: true

View file

@ -1,4 +1,4 @@
logger = (require 'logging').default 'register'
logger = (require 'logging').default '/user/register'
# fftcg.db (persistent data)
fftcgdb = (require '../../db')
@ -10,7 +10,7 @@ module.exports =
handler: (request, reply) ->
fftcgdb.register(request.body.login, request.body.password)
.then (user) ->
.then ->
logger.info "OK '#{request.body.login}'"
reply.send
success: true

View file

@ -14,6 +14,8 @@ fastify.route (require "./routes/#{route}") for route in [
'test'
# log in user
'user/login'
# user info
'user/info'
# log out user
'user/logout'
# register user

View file

@ -57,6 +57,6 @@ class FFTCGSESSION
else
@db.get digest, (err, res) ->
logger.info "OK '#{digest}' resumed"
resolve digest
resolve (JSON.parse res)
module.exports = new FFTCGSESSION

View file

@ -61,7 +61,7 @@ export default {
let cookie_data = JSON.parse(response.data.message)
Cookies.set('session', cookie_data.value, cookie_data.properties)
this.$refs.main.showSnackbar('Login successful!', 'success')
this.$router.push('about')
this.$router.push('usercp')
} else {
this.$refs.main.showSnackbar(response.data.message, 'error')
}

View file

@ -14,13 +14,13 @@ export default new Router({
component: Home
},
{
path: '/about',
name: 'about',
path: '/usercp',
name: 'usercp',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// this generates a separate chunk (usercp.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ './views/About.vue')
import(/* webpackChunkName: "usercp" */ './views/UserCP.vue')
},
{
path: '/game',

View file

@ -18,12 +18,6 @@ import RegisterForm from '@/components/forms/Register.vue'
export default {
name: 'Home',
data() {
return {
dialog: false
}
},
components: {
Header,
LoginForm,
@ -38,7 +32,7 @@ export default {
})
.then(response => {
if (response.data.success) {
this.$router.push({ name: 'about' })
this.$router.push({ name: 'usercp' })
}
})
}

View file

@ -2,7 +2,7 @@
<v-container>
<Header />
<p>user session: {{ sessionID }}</p>
<p>user logged in: {{ user.login }}</p>
<v-btn @click.native="logout">Logout</v-btn>
</v-container>
</template>
@ -14,14 +14,14 @@ import axios from '@/plugins/axios'
import Header from '@/components/Header.vue'
export default {
name: 'About',
name: 'UserCP',
components: {
Header
},
data: () => ({
sessionID: ''
user: ''
}),
methods: {
@ -45,12 +45,12 @@ export default {
mounted() {
axios
.post('/user/login', {
.post('/user/info', {
session: Cookies.get('session')
})
.then(response => {
if (response.data.success) {
this.sessionID = response.data.message
this.user = response.data.user
} else {
this.goHome()
}

View file

@ -1,71 +0,0 @@
# libs
window.$ = require('jquery')
# on load
$ ->
# libs requiring full DOM
require 'craftyjs/dist/crafty'
io = require 'socket.io-client'
# style sheet
require './style/custom.scss'
# fftcg libs
require './game/config.coffee'
require './game/components/Card.coffee'
require './game/scenes/Battle.coffee'
# init Socket.IO
socket = io()
# init CraftyJS framework
Crafty.init()
# Load base scene
Crafty.scene "Battle"
# Testing some entities
Crafty.sprite 480, 670, '//www.fftcgmognet.com/images/cards/hd/1/1/107.jpg',
shantotto: [
0
0
]
backups = [
Crafty.e 'shantotto, AllyCard'
.attr {
card:
type: 'backup'
}
Crafty.e 'shantotto, AllyCard'
.attr {
card:
type: 'backup'
}
Crafty.e 'shantotto, AllyCard'
.attr {
card:
type: 'backup'
}
]
Crafty 'AllyCard'
.each (index) ->
switch @card.type
when 'backup'
@trigger 'Place',
x: CONF.coord.x.main + index * CONF.coord.x.step
y: CONF.coord.y.bkup
return
Crafty.e 'shantotto, EnemyCard'
.trigger 'Place',
x: 900
y: 0
return

View file

@ -1,105 +0,0 @@
# libs
window.$ = require('jquery')
# import bootstrap
require './style/custom.scss'
require 'bootstrap/js/dist/alert'
window.showAlert = (level, content) ->
($ '.alert').alert 'close'
($ '#alert-area').append ($ '<div>',
class: "alert alert-#{level} alert-dismissible fade show"
role: 'alert'
.append content, ($ '<button>',
type: 'button'
class: 'close'
'data-dismiss': 'alert',
'aria-label': 'Close'
.append ($ '<span>',
'aria-hidden': 'true'
.append '&times;'
)))
# on load
$ ->
# reset forms
$('form').each ->
@fullReset = ->
$('input', @).each ->
$(@).removeClass 'is-invalid'
$(@).removeClass 'is-valid'
@reset()
# login form
$('form[name="login"]').submit (event) ->
that = @
# inhibit normal form submission
event.preventDefault()
# gather form data
login = $('input[name="login"]', @)
password = $('input[name="password"]', @)
# transmit form data
$.post '/login',
login: login.val()
password: password.val()
.done (data) ->
if data.status == 'ok'
that.fullReset()
showAlert 'success', "successfully logged in '#{data.login}'"
location.reload()
else
switch data.text
when 'login'
showAlert 'warning', 'Invalid username and/or password.'
login.addClass 'is-invalid'
password.addClass 'is-invalid'
when 'db' or 'hash'
showAlert 'danger', 'Internal failure, try again later.'
else
showAlert 'danger', 'Unknown failure. Can you reproduce this?'
# registration form
$('form[name="register"]').submit (event) ->
that = @
# inhibit normal form submission
event.preventDefault()
# gather form data
login = $('input[name="login"]', @)
password = $('input[name="password"]', @)
confirm = $('input[name="confirm"]', @)
# check form data
if password.val() != confirm.val()
confirm.addClass 'is-invalid'
confirm.focus()
else
# transmit form data
$.post '/register',
login: login.val()
password: password.val()
.done (data) ->
if data.status == 'ok'
that.fullReset()
showAlert 'success', "successfully registered '#{data.login}'"
else
switch data.text
when 'invalid'
showAlert 'warning', 'Invalid user input. Please provide username AND password.'
login.addClass 'is-invalid'
password.addClass 'is-invalid'
login.focus()
when 'hash'
showAlert 'danger', 'Internal failure, try again later.'
when 'db'
showAlert 'danger', 'Internal failure or user name already taken.'
login.addClass 'is-invalid'
login.focus()
else
showAlert 'danger', 'Unknown failure. Can you reproduce this?'

View file

@ -1,11 +0,0 @@
# libs
window.$ = require('jquery')
# import bootstrap
require './style/custom.scss'
require 'bootstrap/js/dist/alert'
require 'bootstrap/js/dist/collapse'
# on load
$ ->
return

View file

@ -1,6 +0,0 @@
doctype html
html
head
title Crafty Things
script(src='/game.bundle.js')
body

View file

@ -1,53 +0,0 @@
doctype html
html
head
title Crafty Things
script(src='/index.bundle.js')
body
header.jumbotron.jumbotron-fluid.py-4.bg-primary.text-light.text-center
div.container
h1 Hello World!
h2 App under development, please don't submit any valuable data!
div.container.bg-light
div#alert-area
div.row
div.col-md-6
h3 Yavook!FFTCG
p Lorem ipsum dolor sit amet
div.col-md-3
h3 Login
form(name="login")
div.form-group
label(for="login") User name:
input.form-control(name="login" required)
div.form-group
label(for="password") Password:
input.form-control(name="password" type="password" required)
div.form-group
button.btn.btn-primary.w-100(type="submit") Login
div.col-md-3
h3 Register
form(name="register")
div.form-group
label(for="login") User name:
input.form-control(name="login" required)
div.invalid-feedback User name invalid or taken.
div.form-group
label(for="password") Password:
input.form-control(name="password" type="password" required)
label(for="confirm") Confirm password:
input.form-control(name="confirm" type="password")
div.invalid-feedback Passwords do not match.
button.btn.btn-primary.w-100(type="submit") Register